diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 03c8099..d9b1943 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -2,21 +2,21 @@ name: build-docker-images on: push: - branches: [ "main" ] - paths-ignore: [ "*.md" ] + branches: ["main"] + paths-ignore: ["*.md"] pull_request: - branches: [ "main" ] - paths-ignore: [ "*.md" ] + branches: ["main"] + paths-ignore: ["*.md"] - workflow_dispatch: # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: # Allows you to run this workflow manually from the Actions tab concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true env: - BUILDKIT_PROGRESS: "plain" # Full logs for CI build. + BUILDKIT_PROGRESS: "plain" # Full logs for CI build. REGISTRY_SRC: ${{ vars.REGISTRY_SRC || 'docker.io' }} # For BASE_NAMESPACE of images: where to pull base images from, docker.io or other source registry URL. REGISTRY_DST: ${{ vars.REGISTRY_DST || 'docker.io' }} # For tags of built images: where to push images to, docker.io or other destination registry URL. # DOCKER_REGISTRY_USERNAME and DOCKER_REGISTRY_PASSWORD is required for docker image push, they should be set in CI secrets. @@ -30,7 +30,7 @@ env: jobs: ## Clash docker_clash: - name: 'app-clash' + name: "app-clash" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -39,7 +39,7 @@ jobs: ## Casdoor docker_casdoor: - name: 'casdoor' + name: "casdoor" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -48,7 +48,7 @@ jobs: ## Keycloak docker_keycloak: - name: 'keycloak' + name: "keycloak" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -57,7 +57,7 @@ jobs: ## DevHub job-dev-hub: - name: 'dev-hub' + name: "dev-hub" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -70,7 +70,7 @@ jobs: ## OpenResty as gateway job-openresty: - name: 'openresty' + name: "openresty" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -79,7 +79,7 @@ jobs: ## SearchNGX for searching job-searxng: - name: 'searxng' + name: "searxng" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -88,7 +88,7 @@ jobs: ## StoreBox job-storebox: - name: 'storebox' + name: "storebox" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -98,7 +98,7 @@ jobs: ## lognet for log management job-logent: - name: 'logent' + name: "logent" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -108,7 +108,7 @@ jobs: ## nocobase for low-code development platform job-nocobase: - name: 'nocobase' + name: "nocobase" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -116,10 +116,19 @@ jobs: source ./tool.sh build_image nocobase latest docker_nocobase/nocobase.Dockerfile && push_image nocobase + ## OpenClaw + job-openclaw: + name: "openclaw" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - run: | + source ./tool.sh + build_image openclaw latest docker_openclaw/openclaw.Dockerfile && push_image openclaw ## DevBox - base job-base-dev: - name: 'developer,base-dev' + name: "developer,base-dev" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -133,7 +142,7 @@ jobs: ## DevBox - data science stack job-data-science-dev: - name: 'data-science-dev' + name: "data-science-dev" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -148,7 +157,7 @@ jobs: ## DevBox - full stack job-full-stack-dev: - name: 'full-stack-dev' + name: "full-stack-dev" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -163,7 +172,7 @@ jobs: ## DevBox - cuda job-cuda-dev: - name: 'full-cuda,cuda-dev' + name: "full-cuda,cuda-dev" runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -175,10 +184,25 @@ jobs: --build-arg "ARG_PROFILE_VSCODE=base" alias_image cuda-dev latest full-cuda latest && push_image dev - ## Sync all images in this build (listed by "names") to mirror registry. sync_images: - needs: ["job-cuda-dev", "job-data-science-dev", "job-full-stack-dev", "job-base-dev", "job-nocobase", "job-logent", "job-storebox", "job-searxng", "job-openresty", "job-dev-hub", "docker_keycloak", "docker_casdoor", "docker_clash"] + needs: + [ + "job-cuda-dev", + "job-data-science-dev", + "job-full-stack-dev", + "job-base-dev", + "job-nocobase", + "job-openclaw", + "job-logent", + "job-storebox", + "job-searxng", + "job-openresty", + "job-dev-hub", + "docker_keycloak", + "docker_casdoor", + "docker_clash", + ] runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 diff --git a/docker_devbox/dev.Dockerfile b/docker_devbox/dev.Dockerfile index e452d9f..dc22b18 100644 --- a/docker_devbox/dev.Dockerfile +++ b/docker_devbox/dev.Dockerfile @@ -21,30 +21,30 @@ COPY work /opt/utils/ RUN set -eux && source /opt/utils/script-utils.sh \ && chmod +x /opt/utils/*.sh \ - # ----------------------------- Setup Jupyter: Basic Configurations and Extensions + ## ----------------------------- Setup Jupyter: Basic Configurations and Extensions && mkdir -pv /opt/conda/etc/jupyter/ \ && mv /opt/utils/etc_jupyter/* /opt/conda/etc/jupyter/ && rm -rf /opt/utils/etc_jupyter \ && mv /opt/utils/start-*.sh /usr/local/bin/ && chmod +x /usr/local/bin/start-*.sh \ && ln -sf /usr/local/bin/start-jupyterlab.sh /usr/local/bin/start-notebook.sh \ && source /opt/utils/script-devbox-jupyter.sh \ && for profile in $(echo $ARG_PROFILE_JUPYTER | tr "," "\n") ; do ( setup_jupyter_${profile} || true ) ; done \ - # ----------------------------- If installing coder-server # https://github.com/cdr/code-server/releases + ## ----------------------------- If installing coder-server # https://github.com/cdr/code-server/releases && source /opt/utils/script-devbox-vscode.sh \ && for profile in $(echo $ARG_PROFILE_VSCODE | tr "," "\n") ; do ( setup_vscode_${profile} || true ) ; done \ - # ----------------------------- If not keeping NodeJS, remove NoedJS to reduce image size + ## ----------------------------- If not keeping NodeJS, remove NoedJS to reduce image size && if [ ${ARG_KEEP_NODEJS} = "false" ] ; then \ echo "Removing Node/NPM..." && rm -rf /usr/bin/node /usr/bin/npm /usr/bin/npx /opt/node ; \ else \ echo "Keep NodeJS as ARG_KEEP_NODEJS defiend as: ${ARG_KEEP_NODEJS}" ; \ fi \ - # ----------------------------- If installing R IDEs: R_rstudio and R_rshiny + ## ----------------------------- If installing R IDEs: R_rstudio and R_rshiny && source /opt/utils/script-devbox-rstudio.sh \ && for profile in $(echo $ARG_PROFILE_R | tr "," "\n") ; do ( setup_R_${profile} ) ; done \ - # ----------------------------- Install supervisord + ## ----------------------------- Install supervisord && source /opt/utils/script-setup-sys.sh && setup_supervisord \ - # ----------------------------- Install caddy + ## ----------------------------- Install caddy && source /opt/utils/script-setup-net.sh && setup_caddy \ - # Clean up and display components version information... + ## Clean up and display components version information... && list_installed_packages && install__clean ENTRYPOINT ["tini", "-g", "--"] diff --git a/docker_devbox/hub.Dockerfile b/docker_devbox/hub.Dockerfile index 0319e9a..24df020 100644 --- a/docker_devbox/hub.Dockerfile +++ b/docker_devbox/hub.Dockerfile @@ -15,23 +15,23 @@ COPY work /opt/utils/ RUN set -eux \ && chmod +x /opt/utils/*.sh && rm -rf /opt/utils/etc_jupyter \ - # Setup JupyterHub + ## Setup JupyterHub && source /opt/utils/script-devbox-jupyter.sh \ && for profile in $(echo $ARG_PROFILE_JUPYTER | tr "," "\n") ; do ( setup_jupyter_${profile} ) ; done \ - # If not keeping NodeJS, remove NoedJS to reduce image size, and install Traefik instead + ## If not keeping NodeJS, remove NoedJS to reduce image size, and install Traefik instead && if [ ${ARG_KEEP_NODEJS} = "false" ] ; then \ echo "Removing Node/NPM..." && rm -rf /usr/bin/node /usr/bin/npm /usr/bin/npx /opt/node ; \ echo "Installing Traefik to server as proxy:" && source /opt/utils/script-setup-net.sh && setup_traefik ; \ else \ echo "Keep NodeJS as ARG_KEEP_NODEJS defiend as: ${ARG_KEEP_NODEJS}" ; \ fi \ - # network-tools https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/main/images/network-tools/Dockerfile + ## network-tools https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/main/images/network-tools/Dockerfile && apt-get update && apt-get install -y --no-install-recommends \ iptables dnsutils libcurl4 libpq5 sqlite3 \ && curl -fsSL -o /usr/local/bin/start-configurable-http-proxy.sh https://raw.githubusercontent.com/jupyterhub/configurable-http-proxy/refs/heads/main/chp-docker-entrypoint \ && mv /opt/utils/start-*.sh /usr/local/bin/ \ && chmod +x /usr/local/bin/start-*.sh \ - # Clean up and display components version information... + ## Clean up and display components version information... && source /opt/utils/script-utils.sh && install__clean && list_installed_packages ENTRYPOINT ["tini", "-g", "--"] diff --git a/docker_nocobase/nocobase.Dockerfile b/docker_nocobase/nocobase.Dockerfile index 79ecf71..c615c31 100644 --- a/docker_nocobase/nocobase.Dockerfile +++ b/docker_nocobase/nocobase.Dockerfile @@ -25,7 +25,7 @@ RUN set -eux \ && mv /opt/utils/docker-entrypoint.sh /opt/nocobase/ \ && chmod +x /opt/nocobase/*.sh \ && ls -alh \ - # Clean up and display components version information... + ## Clean up and display components version information... && find ./node_modules -type f \( -name "README.md" -o -name "License" \) -delete 2>/dev/null \ && find ./node_modules -type d \( -name "test" -o -name "tests" -o -name "__tests__" -o -name "docs" -o -name "doc" \) -exec rm -rf {} + 2>/dev/null \ && list_installed_packages && install__clean diff --git a/docker_openclaw/demo/docker-compose.yml b/docker_openclaw/demo/docker-compose.yml new file mode 100644 index 0000000..e7cc0f1 --- /dev/null +++ b/docker_openclaw/demo/docker-compose.yml @@ -0,0 +1,35 @@ +name: "svc-openclaw" + +services: + openclaw-gateway: + container_name: svc-openclaw-gateway + hostname: svc-openclaw-gateway + image: "quay.io/labnow0dev/openclaw:latest" + pull_policy: if_not_present + restart: unless-stopped + environment: + - TZ=Asia/Shanghai + - PROFILE_LOCALIZE=aliyun-pub + volumes: + - /data/openclaw:/opt/openclaw/data + ports: + - "${OPENCLAW_GATEWAY_PORT:-18789}:18789" + - "${OPENCLAW_BRIDGE_PORT:-18790}:18790" + init: true + + openclaw-cli: + container_name: svc-openclaw-cli + hostname: svc-openclaw-cli + image: "quay.io/labnow0dev/openclaw:latest" + pull_policy: if_not_present + restart: "no" + environment: + - TZ=Asia/Shanghai + - PROFILE_LOCALIZE=aliyun-pub + - BROWSER=echo + volumes: + - /data/openclaw:/opt/openclaw/data + init: true + stdin_open: true + tty: true + entrypoint: ["node", "openclaw.mjs"] diff --git a/docker_openclaw/openclaw.Dockerfile b/docker_openclaw/openclaw.Dockerfile new file mode 100644 index 0000000..c569dd2 --- /dev/null +++ b/docker_openclaw/openclaw.Dockerfile @@ -0,0 +1,34 @@ +# Distributed under the terms of the Modified BSD License. + +ARG BASE_NAMESPACE +ARG BASE_IMG="node" +FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} + +LABEL maintainer="postmaster@labnow.ai" +ENV NODE_ENV=production +ENV PNPM_HOME=/opt/node/pnpm +ENV PNPM_STORE_DIR=/opt/node/pnpm-store +ENV PNPM_NODE_LINKER=hoisted +ENV PATH="${PNPM_HOME}:${PATH}" + +COPY work /opt/openclaw/ + +RUN set -eux && source /opt/utils/script-setup.sh \ + && chmod +x /opt/openclaw/start-openclaw.sh && ln -sf /opt/openclaw/start-openclaw.sh /usr/local/bin/ \ + && mkdir -pv /opt/openclaw/data \ + && ln -sfn /opt/openclaw/data /opt/openclaw/.openclaw \ + ## curl -fsSL https://openclaw.ai/install.sh | NO_PROMPT=1 bash -s -- --no-onboard --install-method npm \ + && export SHARP_IGNORE_GLOBAL_LIBVIPS=1 \ + && setup_node_pnpm 10 \ + && pnpm config set enable-pre-post-scripts true \ + && pnpm install -g openclaw@latest --ignore-scripts=false \ + && openclaw --version \ + ## Clean up and display components version information... + && list_installed_packages && install__clean + +ENV HOME=/opt/openclaw/ +ENV XDG_CONFIG_HOME=/opt/openclaw/data +WORKDIR /opt/openclaw +VOLUME ["/opt/openclaw/data"] +EXPOSE 18789 18790 +CMD ["sh", "start-openclaw.sh", "gateway", "--allow-unconfigured", "--bind", "${OPENCLAW_GATEWAY_BIND:-lan}", "--port", "${OPENCLAW_GATEWAY_PORT:-18789}"] diff --git a/docker_openclaw/work/openclaw-plugin-installer.js b/docker_openclaw/work/openclaw-plugin-installer.js new file mode 100644 index 0000000..b5bcdcd --- /dev/null +++ b/docker_openclaw/work/openclaw-plugin-installer.js @@ -0,0 +1,368 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { spawnSync } = require('child_process'); + +function buildDefaultConfig() { + return { + agents: { + defaults: { + workspace: '/opt/openclaw/data/workspace' + } + }, + channels: { + feishu: { + enabled: true, + appId: '', + appSecret: '', + domain: 'feishu', + connectionMode: 'websocket', + requireMention: true, + dmPolicy: 'pairing', + groupPolicy: 'open', + allowFrom: [], + groupAllowFrom: [] + } + }, + gateway: { + controlUi: { + dangerouslyAllowHostHeaderOriginFallback: true, + dangerouslyDisableDeviceAuth: true + } + } + }; +} + +function parseArgs(argv) { + const args = { _: [] }; + for (let i = 0; i < argv.length; i += 1) { + const token = argv[i]; + if (!token.startsWith('--')) { + args._.push(token); + continue; + } + + const eqIndex = token.indexOf('='); + if (eqIndex > -1) { + const key = token.slice(2, eqIndex); + const value = token.slice(eqIndex + 1); + args[key] = value; + continue; + } + + const key = token.slice(2); + const next = argv[i + 1]; + if (!next || next.startsWith('--')) { + args[key] = true; + continue; + } + + args[key] = next; + i += 1; + } + + return args; +} + +function parseCommaList(value) { + if (!value || value === true) return []; + return String(value) + .split(',') + .map((item) => item.trim()) + .filter(Boolean); +} + +function pluginIdFromPackage(packageName) { + return packageName.split('/').pop(); +} + +function ensureConfigShape(config) { + if (!config.plugins) config.plugins = {}; + if (!Array.isArray(config.plugins.allow)) config.plugins.allow = []; + if (!config.plugins.entries) config.plugins.entries = {}; +} + +function loadConfig(configPath) { + const raw = fs.readFileSync(configPath, 'utf8'); + return JSON.parse(raw); +} + +function saveConfig(configPath, config) { + fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8'); +} + +function ensureConfigFile(configPath) { + fs.mkdirSync(path.dirname(configPath), { recursive: true }); + if (fs.existsSync(configPath) && fs.statSync(configPath).size > 0) { + return; + } + saveConfig(configPath, buildDefaultConfig()); +} + +function mergeDefaultConfig(configPath) { + const config = loadConfig(configPath); + + if (!config.agents) config.agents = {}; + if (!config.agents.defaults) config.agents.defaults = {}; + if (!config.agents.defaults.workspace) { + config.agents.defaults.workspace = '/opt/openclaw/data/workspace'; + } + + if (!config.gateway) config.gateway = {}; + if (!config.gateway.controlUi) config.gateway.controlUi = {}; + if (typeof config.gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback !== 'boolean') { + config.gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback = true; + } + if (typeof config.gateway.controlUi.dangerouslyDisableDeviceAuth !== 'boolean') { + config.gateway.controlUi.dangerouslyDisableDeviceAuth = true; + } + + saveConfig(configPath, config); +} + +function runOpenclawInstall(packageName, env) { + const result = spawnSync('openclaw', ['plugins', 'install', packageName], { + encoding: 'utf8', + env + }); + + if (result.stdout) process.stdout.write(result.stdout); + if (result.stderr) process.stderr.write(result.stderr); + + if (result.status === 0) { + return { ok: true, alreadyExists: false }; + } + + const output = `${result.stdout || ''}\n${result.stderr || ''}`; + if (output.includes('plugin already exists')) { + return { ok: true, alreadyExists: true }; + } + + const err = new Error(`Command failed: openclaw plugins install ${packageName}`); + err.status = result.status; + err.output = output; + throw err; +} + +function safeRemove(targetPath) { + if (!fs.existsSync(targetPath)) return; + const stat = fs.lstatSync(targetPath); + if (stat.isDirectory() && !stat.isSymbolicLink()) { + fs.rmSync(targetPath, { recursive: true, force: true }); + } else { + fs.unlinkSync(targetPath); + } +} + +function isSelfReferencingSymlink(targetPath) { + try { + const stat = fs.lstatSync(targetPath); + if (!stat.isSymbolicLink()) return false; + const linkValue = fs.readlinkSync(targetPath); + const resolved = path.resolve(path.dirname(targetPath), linkValue); + return resolved === path.resolve(targetPath); + } catch (_err) { + return false; + } +} + +function ensurePluginAtTarget(options) { + const { homeClaw, stateDir, extensionsDir, pluginDirName } = options; + const targetPath = path.join(extensionsDir, pluginDirName); + const resolvedTargetPath = path.resolve(targetPath); + + if (isSelfReferencingSymlink(targetPath)) { + safeRemove(targetPath); + } + + if (fs.existsSync(targetPath)) { + return targetPath; + } + + const candidates = [ + path.join(stateDir, 'extensions', pluginDirName), + path.join(homeClaw, 'extensions', pluginDirName), + ]; + + const actualPath = candidates.find((candidate) => fs.existsSync(candidate)); + if (!actualPath) { + return ''; + } + const resolvedActualPath = path.resolve(actualPath); + if (resolvedActualPath === resolvedTargetPath) { + return targetPath; + } + + fs.mkdirSync(path.dirname(targetPath), { recursive: true }); + + try { + fs.renameSync(actualPath, targetPath); + } catch (err) { + if (!err || err.code !== 'EXDEV') throw err; + fs.cpSync(actualPath, targetPath, { recursive: true }); + safeRemove(actualPath); + } + + return targetPath; +} + +function applyInstallConfig(configPath, pluginId) { + const config = loadConfig(configPath); + ensureConfigShape(config); + + if (!config.plugins.allow.includes(pluginId)) { + config.plugins.allow.push(pluginId); + } + config.plugins.entries[pluginId] = { enabled: true }; + + saveConfig(configPath, config); +} + +function applyDisableConfig(configPath, entryIds) { + const config = loadConfig(configPath); + ensureConfigShape(config); + + for (const entryId of entryIds) { + config.plugins.entries[entryId] = { enabled: false }; + } + + saveConfig(configPath, config); +} + +function installCommand(args) { + const packageName = args.package; + const configPath = args.config; + const homeClaw = path.resolve(args.home || '/opt/openclaw'); + const stateDir = path.resolve(args['state-dir'] || path.dirname(configPath || '')); + const extensionsDir = path.resolve(args['extensions-dir'] || path.join(stateDir, 'extensions')); + const pluginId = args.id || pluginIdFromPackage(packageName || ''); + const pluginDirName = args['plugin-dir'] || pluginId; + const forceInstall = Boolean(args.force); + + if (!packageName || !configPath) { + throw new Error('Missing required args: --package, --config'); + } + + ensureConfigFile(configPath); + mergeDefaultConfig(configPath); + + fs.mkdirSync(stateDir, { recursive: true }); + fs.mkdirSync(extensionsDir, { recursive: true }); + + const targetPath = path.join(extensionsDir, pluginDirName); + const installEnv = { + ...process.env, + XDG_CONFIG_HOME: stateDir, + OPENCLAW_DIR_STATE: stateDir, + }; + + if (forceInstall || !fs.existsSync(targetPath)) { + console.log(`[plugin-installer] Installing ${packageName} ...`); + const result = runOpenclawInstall(packageName, installEnv); + if (result.alreadyExists) { + console.log(`[plugin-installer] ${pluginId} already exists, treat as idempotent success.`); + } + } else { + console.log(`[plugin-installer] ${pluginId} already exists at ${targetPath}, skip install.`); + } + + const finalPath = ensurePluginAtTarget({ homeClaw, stateDir, extensionsDir, pluginDirName }); + if (!finalPath) { + console.warn(`[plugin-installer] WARN: unable to locate installed plugin ${pluginId}.`); + } else { + console.log(`[plugin-installer] plugin path: ${finalPath}`); + } + + applyInstallConfig(configPath, pluginId); + console.log(`[plugin-installer] ${packageName} install flow completed.`); +} + +function disableCommand(args) { + const configPath = args.config; + const entryIds = parseCommaList(args.entry || args.entries); + + if (!configPath || entryIds.length === 0) { + throw new Error('Missing required args: --config, --entry '); + } + + ensureConfigFile(configPath); + mergeDefaultConfig(configPath); + applyDisableConfig(configPath, entryIds); + console.log(`[plugin-installer] disabled entries: ${entryIds.join(', ')}`); +} + +function initConfigCommand(args) { + const configPath = args.config; + if (!configPath) { + throw new Error('Missing required args: --config'); + } + + ensureConfigFile(configPath); + mergeDefaultConfig(configPath); + console.log(`[plugin-installer] config ready: ${configPath}`); +} + +function printHelp() { + console.log(`Usage: + node openclaw-plugin-installer.js [options] + +Commands: + init-config Ensure config file exists and apply default base settings + install Install plugin package and enable corresponding plugin entry + disable Disable plugin entries in config + +Common options: + --config OpenClaw config path + +Install options: + --package NPM package, e.g. @larksuite/openclaw-lark + --id Optional plugin id (default: package basename) + --home OpenClaw home (default: /opt/openclaw) + --state-dir State dir (default: dirname(--config)) + --extensions-dir Extensions dir (default: /extensions) + --plugin-dir Plugin directory name (default: plugin id) + --force Force install even if target plugin dir exists + +Disable options: + --entry Comma separated plugin entry ids to disable +`); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + const command = args._[0]; + + if (!command || command === 'help' || command === '--help') { + printHelp(); + process.exit(command ? 0 : 1); + } + + if (command === 'init-config') { + initConfigCommand(args); + return; + } + + if (command === 'install') { + installCommand(args); + return; + } + + if (command === 'disable') { + disableCommand(args); + return; + } + + throw new Error(`Unsupported command: ${command}`); +} + +try { + main(); +} catch (err) { + console.error(`[plugin-installer] ${err.message}`); + if (err.output) { + console.error(err.output); + } + process.exit(1); +} diff --git a/docker_openclaw/work/start-openclaw.sh b/docker_openclaw/work/start-openclaw.sh new file mode 100644 index 0000000..166d185 --- /dev/null +++ b/docker_openclaw/work/start-openclaw.sh @@ -0,0 +1,25 @@ +#!/bin/sh +set -eu + +export OPENCLAW_HOME="${OPENCLAW_HOME:-/opt/openclaw}" +export OPENCLAW_DIR_STATE="${OPENCLAW_DIR_STATE:-${XDG_CONFIG_HOME:-$OPENCLAW_HOME/data}}" +export OPENCLAW_CONFIG="${OPENCLAW_CONFIG:-$OPENCLAW_DIR_STATE/openclaw.json}" + +export OPENCLAW_HIDE_BANNER=1 + +bootstrap() { + mkdir -pv "${OPENCLAW_DIR_STATE}" "$(dirname "${OPENCLAW_CONFIG}")" + + local PATH_PLUGIN_INSTALLER="${OPENCLAW_PLUGIN_INSTALLER:-$OPENCLAW_HOME/openclaw-plugin-installer.js}" + local CLAW_EXEC="node ${PATH_PLUGIN_INSTALLER} --config ${OPENCLAW_CONFIG}" + + $CLAW_EXEC init-config + openclaw config set skills.install.nodeManager pnpm + + $CLAW_EXEC disable --entry "feishu" + $CLAW_EXEC install --package "@larksuite/openclaw-lark" +} + +/opt/utils/script-localize.sh "${PROFILE_LOCALIZE:-default}" +bootstrap +exec openclaw "$@" diff --git a/docker_searxng/searxng.Dockerfile b/docker_searxng/searxng.Dockerfile index 8339bc6..ec6c807 100644 --- a/docker_searxng/searxng.Dockerfile +++ b/docker_searxng/searxng.Dockerfile @@ -25,11 +25,11 @@ RUN set -eux \ && pip install --use-pep517 --no-build-isolation -e . \ && mv /tmp/searxng/* /opt/searxng && ln -sf /opt/searxng/etc /etc/searxng \ && ln -sf /opt/searxng /usr/local/ \ - # ----------------------------- Install supervisord + ## ----------------------------- Install supervisord && source /opt/utils/script-setup-sys.sh && setup_supervisord \ - # ----------------------------- Install caddy + ## ----------------------------- Install caddy && source /opt/utils/script-setup-net.sh && setup_caddy \ - # Clean up and display components version information... + ## Clean up and display components version information... && fix_permission searxng /opt/searxng/ \ && chmod +x /opt/searxng/*.sh \ && chmod -R ugo+rws /var/log /var/run \ diff --git a/docker_storebox/storebox.Dockerfile b/docker_storebox/storebox.Dockerfile index 581a992..50db42b 100644 --- a/docker_storebox/storebox.Dockerfile +++ b/docker_storebox/storebox.Dockerfile @@ -8,13 +8,13 @@ FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} COPY work /opt/utils RUN set -eux \ - # ----------------------------- Install supervisord + ## ----------------------------- Install supervisord && source /opt/utils/script-setup-sys.sh && setup_supervisord \ - # ----------------------------- Install caddy + ## ----------------------------- Install caddy && source /opt/utils/script-setup-net.sh && setup_caddy \ - # ----------------------------- Install alist + ## ----------------------------- Install alist && source /opt/utils/script-setup-alist.sh && setup_alist \ - # ----------------------------- Install rclone + ## ----------------------------- Install rclone && source /opt/utils/script-setup-rclone.sh && setup_rclone \ - # Clean up and display components version information... + ## Clean up and display components version information... && list_installed_packages && install__clean