openclaw-multi-auto 1.0.2 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import "./run-with-concurrency-CwEpSWUB.js";
2
2
  import "./paths-CaA28K0s.js";
3
3
  import "./logger-DLNJPYG_.js";
4
4
  import "./model-selection-CGn4LwFd.js";
5
- import { B as countPendingDescendantRuns, H as isSubagentSessionRunActive, U as resolveRequesterForChildSession, V as countPendingDescendantRunsExcludingRun, z as countActiveDescendantRuns } from "./pi-embedded-DYU79yGe.js";
5
+ import { B as countPendingDescendantRuns, H as isSubagentSessionRunActive, U as resolveRequesterForChildSession, V as countPendingDescendantRunsExcludingRun, z as countActiveDescendantRuns } from "./pi-embedded-CgQ_W6Xs.js";
6
6
  import "./github-copilot-token-BWXANsA6.js";
7
7
  import "./thinking-BnMXBaoj.js";
8
8
  import "./tokens-J9QxdfW4.js";
@@ -10,14 +10,14 @@ import "./plugins-D32XloiU.js";
10
10
  import "./accounts-CSwQwmi-.js";
11
11
  import "./send-gxHdLxHb.js";
12
12
  import "./send-coHgGFcr.js";
13
- import "./deliver-B9cys0EZ.js";
13
+ import "./deliver-BXVcFIHL.js";
14
14
  import "./diagnostic-B6424ZSe.js";
15
15
  import "./accounts-D0b225eZ.js";
16
16
  import "./image-ops-Cdb65Ugz.js";
17
17
  import "./send-DEuQpTH0.js";
18
18
  import "./pi-model-discovery-BKJwRHhi.js";
19
- import "./pi-embedded-helpers-uTRAmQ4n.js";
20
- import "./chrome-D45SyhQL.js";
19
+ import "./pi-embedded-helpers-CwuBTKza.js";
20
+ import "./chrome-CMU2WVFh.js";
21
21
  import "./skills-DhJjHaBz.js";
22
22
  import "./path-alias-guards-B6LFrksx.js";
23
23
  import "./redact-DBcTOmRL.js";
@@ -28,8 +28,8 @@ import "./store-CSSX03Wl.js";
28
28
  import "./accounts-CTAmvqQt.js";
29
29
  import "./paths-BgCTr3-D.js";
30
30
  import "./tool-images-DpgWhBLv.js";
31
- import "./image-DAOPwVXi.js";
32
- import "./audio-transcription-runner-B-UvoDjZ.js";
31
+ import "./image-BCVLo0qw.js";
32
+ import "./audio-transcription-runner-DZbSWT9E.js";
33
33
  import "./fetch-Bz-lmDr4.js";
34
34
  import "./fetch-guard-BiA86VyP.js";
35
35
  import "./api-key-rotation-xR-rxS2R.js";
@@ -2,7 +2,7 @@ import { G as buildAgentMainSessionKey, W as DEFAULT_MAIN_KEY, X as normalizeAge
2
2
  import "./paths-CaA28K0s.js";
3
3
  import { C as sleep, G as getChildLogger, L as logVerbose, O as createSubsystemLogger, T as toWhatsappJid, h as normalizeE164, j as defaultRuntime, m as jidToE164, o as clamp, p as isSelfChatMode, v as resolveJidToE164, z as shouldLogVerbose } from "./logger-DLNJPYG_.js";
4
4
  import { Y as loadConfig, pr as formatCliCommand } from "./model-selection-CGn4LwFd.js";
5
- import { A as computeBackoff, C as formatInboundEnvelope, D as resolveAgentRoute, E as buildAgentSessionKey, F as hasControlCommand, I as shouldComputeCommandAuthorized, K as resolveIdentityNamePrefix, L as buildMentionRegexes, M as formatDurationPrecise, N as enqueueSystemEvent, O as normalizeGroupActivation, P as finalizeInboundContext, R as normalizeMentionText, S as resolveInboundDebounceMs, T as getReplyFromConfig, _ as resolvePinnedMainDmOwnerFromAllowlist, a as createReplyPrefixOptions, c as DEFAULT_GROUP_HISTORY_LIMIT, d as resolveDefaultGroupPolicy, f as resolveOpenProviderRuntimeGroupPolicy, g as resolveDmGroupAccessWithLists, h as resolveDmGroupAccessWithCommandGate, i as resolveInboundSessionEnvelopeContext, j as sleepWithAbort, k as parseActivationCommand, l as buildHistoryContextFromEntries, m as readStoreAllowFromForDmPolicy, o as buildPairingReply, p as warnMissingProviderGroupPolicyFallbackOnce, q as resolveMessagePrefix, s as resolveMentionGating, u as recordPendingHistoryEntryIfEnabled, v as shouldAckReactionForWhatsApp, w as createDedupeCache, x as createInboundDebouncer, y as dispatchReplyWithBufferedBlockDispatcher } from "./pi-embedded-DYU79yGe.js";
5
+ import { A as computeBackoff, C as formatInboundEnvelope, D as resolveAgentRoute, E as buildAgentSessionKey, F as hasControlCommand, I as shouldComputeCommandAuthorized, K as resolveIdentityNamePrefix, L as buildMentionRegexes, M as formatDurationPrecise, N as enqueueSystemEvent, O as normalizeGroupActivation, P as finalizeInboundContext, R as normalizeMentionText, S as resolveInboundDebounceMs, T as getReplyFromConfig, _ as resolvePinnedMainDmOwnerFromAllowlist, a as createReplyPrefixOptions, c as DEFAULT_GROUP_HISTORY_LIMIT, d as resolveDefaultGroupPolicy, f as resolveOpenProviderRuntimeGroupPolicy, g as resolveDmGroupAccessWithLists, h as resolveDmGroupAccessWithCommandGate, i as resolveInboundSessionEnvelopeContext, j as sleepWithAbort, k as parseActivationCommand, l as buildHistoryContextFromEntries, m as readStoreAllowFromForDmPolicy, o as buildPairingReply, p as warnMissingProviderGroupPolicyFallbackOnce, q as resolveMessagePrefix, s as resolveMentionGating, u as recordPendingHistoryEntryIfEnabled, v as shouldAckReactionForWhatsApp, w as createDedupeCache, x as createInboundDebouncer, y as dispatchReplyWithBufferedBlockDispatcher } from "./pi-embedded-CgQ_W6Xs.js";
6
6
  import "./github-copilot-token-BWXANsA6.js";
7
7
  import { h as resolveChannelGroupRequireMention, m as resolveChannelGroupPolicy } from "./thinking-BnMXBaoj.js";
8
8
  import "./tokens-J9QxdfW4.js";
@@ -10,14 +10,14 @@ import "./plugins-D32XloiU.js";
10
10
  import { a as logWebSelfId, c as pickWebChannel, i as getWebAuthAgeMs, m as webAuthExists, n as resolveWhatsAppAccount, r as WA_WEB_AUTH_DIR, u as readWebSelfId } from "./accounts-CSwQwmi-.js";
11
11
  import "./send-gxHdLxHb.js";
12
12
  import "./send-coHgGFcr.js";
13
- import "./deliver-B9cys0EZ.js";
13
+ import "./deliver-BXVcFIHL.js";
14
14
  import "./diagnostic-B6424ZSe.js";
15
15
  import "./accounts-D0b225eZ.js";
16
16
  import "./image-ops-Cdb65Ugz.js";
17
17
  import { X as toLocationContext, Y as formatLocationText, et as upsertChannelPairingRequest } from "./send-DEuQpTH0.js";
18
18
  import "./pi-model-discovery-BKJwRHhi.js";
19
- import { At as resolveGroupSessionKey, J as updateLastRoute, K as recordSessionMetaFromInbound, W as loadSessionStore } from "./pi-embedded-helpers-uTRAmQ4n.js";
20
- import "./chrome-D45SyhQL.js";
19
+ import { At as resolveGroupSessionKey, J as updateLastRoute, K as recordSessionMetaFromInbound, W as loadSessionStore } from "./pi-embedded-helpers-CwuBTKza.js";
20
+ import "./chrome-CMU2WVFh.js";
21
21
  import "./skills-DhJjHaBz.js";
22
22
  import "./path-alias-guards-B6LFrksx.js";
23
23
  import "./redact-DBcTOmRL.js";
@@ -28,8 +28,8 @@ import { i as saveMediaBuffer } from "./store-CSSX03Wl.js";
28
28
  import "./accounts-CTAmvqQt.js";
29
29
  import { s as resolveStorePath } from "./paths-BgCTr3-D.js";
30
30
  import "./tool-images-DpgWhBLv.js";
31
- import "./image-DAOPwVXi.js";
32
- import { h as registerUnhandledRejectionHandler } from "./audio-transcription-runner-B-UvoDjZ.js";
31
+ import "./image-BCVLo0qw.js";
32
+ import { h as registerUnhandledRejectionHandler } from "./audio-transcription-runner-DZbSWT9E.js";
33
33
  import { i as getAgentScopedMediaLocalRoots } from "./fetch-Bz-lmDr4.js";
34
34
  import "./fetch-guard-BiA86VyP.js";
35
35
  import "./api-key-rotation-xR-rxS2R.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-multi-auto",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "description": "Multi-channel AI gateway with extensible messaging integrations",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/openclaw/openclaw#readme",
@@ -218,7 +218,6 @@
218
218
  },
219
219
  "scripts": {
220
220
  "//_publish_pre_fix": "在发布前的 prepack 阶段,强制清理并重新拉取那些带 Git 依赖的包,并配置镜像隧道",
221
- "prepack": "node -e \"const {execSync} = require('child_process'); try { execSync('git config --global url.\\\"https://github.moeyy.xyz/https://github.com/\\\".insteadOf \\\"https://github.com/\\\"'); console.log('✅ GitHub Publish Tunnel Set'); } catch(e){}\" && pnpm build && pnpm ui:build",
222
221
  "android:assemble": "cd apps/android && ./gradlew :app:assembleDebug",
223
222
  "android:format": "cd apps/android && ./gradlew :app:ktlintFormat :benchmark:ktlintFormat",
224
223
  "android:install": "cd apps/android && ./gradlew :app:installDebug",
@@ -290,6 +289,7 @@
290
289
  "openclaw": "node scripts/run-node.mjs",
291
290
  "openclaw:rpc": "node scripts/run-node.mjs agent --mode rpc --json",
292
291
  "plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts",
292
+ "prepack": "node -e \"const {execSync} = require('child_process'); try { execSync('git config --global url.\\\"https://github.moeyy.xyz/https://github.com/\\\".insteadOf \\\"https://github.com/\\\"'); console.log('✅ GitHub Publish Tunnel Set'); } catch(e){}\" && pnpm build && pnpm ui:build",
293
293
  "prepare": "command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1 && git config core.hooksPath git-hooks || exit 0",
294
294
  "protocol:check": "pnpm protocol:gen && pnpm protocol:gen:swift && git diff --exit-code -- dist/protocol.schema.json apps/macos/Sources/OpenClawProtocol/GatewayModels.swift",
295
295
  "protocol:gen": "node --import tsx scripts/protocol-gen.ts",
@@ -390,10 +390,6 @@
390
390
  "yaml": "^2.8.2",
391
391
  "zod": "^4.3.6"
392
392
  },
393
- "bundledDependencies": [
394
- "@whiskeysockets/baileys",
395
- "@lydell/node-pty"
396
- ],
397
393
  "devDependencies": {
398
394
  "@grammyjs/types": "^3.25.0",
399
395
  "@lit-labs/signals": "^0.2.0",
@@ -419,12 +415,15 @@
419
415
  "@napi-rs/canvas": "^0.1.89",
420
416
  "node-llama-cpp": "3.16.2"
421
417
  },
418
+ "bundledDependencies": [
419
+ "@lydell/node-pty",
420
+ "@whiskeysockets/baileys"
421
+ ],
422
422
  "engines": {
423
423
  "node": ">=22.12.0"
424
424
  },
425
425
  "packageManager": "pnpm@10.23.0",
426
426
  "pnpm": {
427
- "minimumReleaseAge": 2880,
428
427
  "overrides": {
429
428
  "hono": "4.11.10",
430
429
  "fast-xml-parser": "5.3.8",
@@ -1,302 +1,221 @@
1
1
  #!/usr/bin/env bash
2
- # 创建新的 OpenClaw 实例脚本
3
- # 用法: ./create-instance.sh <instance-name> [port] [model_provider] [api_key]
2
+ # =================================================================
3
+ # OpenClaw 深度集成初始化工具 (init-instance.sh)
4
+ # 合并逻辑:全量配置生成 + 跨目录代码分发 + 依赖固化 + launchd 注册
5
+ # =================================================================
4
6
 
5
7
  set -e
6
8
 
7
- INSTANCE_NAME="${1:-new-instance}"
8
- PORT="${2:-$(echo $((18790 + $(ls -d ~/openclaws/*/ 2>/dev/null | wc -l | tr -d ' ')))}"
9
- MODEL_PROVIDER="${3:-}"
10
- API_KEY="${4:-}"
9
+ # 颜色定义
10
+ RED='\033[0;31m'
11
+ GREEN='\033[0;32m'
12
+ YELLOW='\033[1;33m'
13
+ BLUE='\033[0;34m'
14
+ NC='\033[0m'
11
15
 
12
- INSTANCE_DIR="$HOME/openclaws/${INSTANCE_NAME}"
16
+ # --- 1. 路径溯源与环境检查 ---
17
+ GLOBAL_PREFIX=$(npm config get prefix)
18
+ # 自动定位:先找全局安装路径,找不到则尝试本地开发路径
19
+ DEFAULT_SOURCE="${GLOBAL_PREFIX}/lib/node_modules/openclaw-multi-auto"
20
+ [ -d "$HOME/projects/openclaw" ] && DEFAULT_SOURCE="$HOME/projects/openclaw"
13
21
 
14
- echo "📦 创建新实例: ${INSTANCE_NAME} (端口 ${PORT})"
15
- echo " 实例目录: ${INSTANCE_DIR}"
16
- echo ""
22
+ SOURCE_CODE="$DEFAULT_SOURCE"
23
+ INSTANCES_BASE="$HOME/openclaws"
17
24
 
18
- # 检查实例目录是否已存在
19
- if [ -d "$INSTANCE_DIR" ]; then
20
- echo "❌ 实例目录已存在: ${INSTANCE_DIR}"
21
- echo " 请使用不同的实例名称或删除现有目录"
22
- exit 1
25
+ # --- 2. 参数与交互式获取 ---
26
+ INSTANCE_NAME="${1:-}"
27
+ if [ -z "$INSTANCE_NAME" ]; then
28
+ read -p "请输入实例名称 (默认: yunwei): " INPUT_NAME
29
+ INSTANCE_NAME="${INPUT_NAME:-yunwei}"
23
30
  fi
24
31
 
25
- # 创建目录结构
26
- echo "📁 创建目录结构..."
27
- mkdir -p "${INSTANCE_DIR}/config"
28
- mkdir -p "${INSTANCE_DIR}/tmp"
29
- mkdir -p "${INSTANCE_DIR}/workspace"
30
- mkdir -p "${INSTANCE_DIR}/agents/main/agent/sessions"
31
- mkdir -p "${INSTANCE_DIR}/credentials"
32
- mkdir -p "${INSTANCE_DIR}/delivery-queue/failed"
33
- mkdir -p "${INSTANCE_DIR}/media"
34
-
35
- # 在 code/ 目录下安装 openclaw-multi-auto
36
- echo "📋 安装 openclaw-multi-auto..."
37
- mkdir -p "${INSTANCE_DIR}/code"
38
- cd "${INSTANCE_DIR}/code"
32
+ # 端口自动计算逻辑
33
+ if [ -n "$2" ]; then
34
+ PORT="$2"
35
+ else
36
+ # 基础端口 18790,每增加一个实例 +1
37
+ EXISTING_COUNT=$(ls -d "$INSTANCES_BASE"/*/ 2>/dev/null | wc -l | tr -d ' ')
38
+ PORT=$((18790 + EXISTING_COUNT))
39
+ fi
39
40
 
40
- # 初始化 npm 项目(如果还没有)
41
- if [ ! -f "package.json" ]; then
42
- npm init -y > /dev/null 2>&1
41
+ MODEL_PROVIDER="${3:-}"
42
+ if [ -z "$MODEL_PROVIDER" ]; then
43
+ echo "--- 请选择模型供应商 ---"
44
+ echo "1) zai (智谱) 2) deepseek 3) minimax 4) kimi 5) qwen"
45
+ read -p "请输入编号 (1-5): " MODEL_INDEX
46
+ case $MODEL_INDEX in
47
+ 1) MODEL_PROVIDER="zai" ;;
48
+ 2) MODEL_PROVIDER="deepseek" ;;
49
+ 3) MODEL_PROVIDER="minimax" ;;
50
+ 4) MODEL_PROVIDER="kimi" ;;
51
+ 5) MODEL_PROVIDER="qwen" ;;
52
+ *) MODEL_PROVIDER="zai" ;;
53
+ esac
43
54
  fi
44
55
 
45
- # 安装 openclaw-multi-auto
46
- npm install openclaw-multi-auto
56
+ API_KEY="${4:-}"
57
+ if [ -z "$API_KEY" ]; then
58
+ read -p "请输入您的 ${MODEL_PROVIDER} API Key: " API_KEY
59
+ fi
47
60
 
48
- # 根据模型配置生成配置文件
49
- echo "⚙️ 生成配置文件..."
61
+ # 路径定义
62
+ INSTANCE_DIR="$INSTANCES_BASE/${INSTANCE_NAME}"
63
+ DIST_DIR="${INSTANCE_DIR}/dist"
50
64
 
51
- # 设置默认模型名称(用户选择的模型作为主模型)
52
- DEFAULT_MODEL="zai/glm-4-flash" # 默认值
53
- if [ -n "$MODEL_PROVIDER" ]; then
54
- case "$MODEL_PROVIDER" in
55
- zai)
56
- DEFAULT_MODEL="zai/glm-4-flash"
57
- ;;
58
- deepseek)
59
- DEFAULT_MODEL="deepseek/deepseek-chat"
60
- ;;
61
- minimax)
62
- DEFAULT_MODEL="minimax-cn/MiniMax-M2.5-highspeed"
63
- ;;
64
- kimi)
65
- DEFAULT_MODEL="kimi/moonshot-v1-8k"
66
- ;;
67
- qwen)
68
- DEFAULT_MODEL="qwen/qwen-plus"
69
- ;;
70
- esac
65
+ if [ -d "$INSTANCE_DIR" ]; then
66
+ echo -e "${RED}❌ 实例已存在: ${INSTANCE_DIR}${NC}"; exit 1
71
67
  fi
72
68
 
73
- # 设置 API key
74
- ZAI_API_KEY=""
75
- DEEPSEEK_API_KEY=""
76
- MINIMAX_API_KEY=""
77
- KIMI_API_KEY=""
78
- QWEN_API_KEY=""
69
+ echo -e "${BLUE}🏗️ 正在深度初始化实例: ${INSTANCE_NAME} (端口 ${PORT})${NC}"
79
70
 
80
- if [ -n "$MODEL_PROVIDER" ] && [ -n "$API_KEY" ]; then
81
- case "$MODEL_PROVIDER" in
82
- zai)
83
- ZAI_API_KEY="$API_KEY"
84
- ;;
85
- deepseek)
86
- DEEPSEEK_API_KEY="$API_KEY"
87
- ;;
88
- minimax)
89
- MINIMAX_API_KEY="$API_KEY"
90
- ;;
91
- kimi)
92
- KIMI_API_KEY="$API_KEY"
93
- ;;
94
- qwen)
95
- QWEN_API_KEY="$API_KEY"
96
- ;;
97
- esac
71
+ # --- 3. 完整目录结构创建 ---
72
+ mkdir -p "${INSTANCE_DIR}/config" "${INSTANCE_DIR}/tmp" "${INSTANCE_DIR}/workspace"
73
+ mkdir -p "${INSTANCE_DIR}/agents/main/agent/sessions"
74
+ mkdir -p "${INSTANCE_DIR}/credentials" "${INSTANCE_DIR}/media"
75
+
76
+ # --- 4. 生成深度配置文件 ---
77
+ # 默认值初始化
78
+ DEFAULT_MODEL="zai/glm-5"
79
+ ZAI_KEY=""; DS_KEY=""; MX_KEY=""; KIMI_KEY=""; QWEN_KEY=""
80
+
81
+ case "$MODEL_PROVIDER" in
82
+ zai) DEFAULT_MODEL="zai/glm-4-flash"; ZAI_KEY="$API_KEY" ;;
83
+ deepseek) DEFAULT_MODEL="deepseek/deepseek-chat"; DS_KEY="$API_KEY" ;;
84
+ minimax) DEFAULT_MODEL="minimax-cn/MiniMax-M2.5-highspeed"; MX_KEY="$API_KEY" ;;
85
+ kimi) DEFAULT_MODEL="kimi/moonshot-v1-8k"; KIMI_KEY="$API_KEY" ;;
86
+ qwen) DEFAULT_MODEL="qwen/qwen-plus"; QWEN_KEY="$API_KEY" ;;
87
+ esac
88
+
89
+ # --- 3.5 动态提取母本版本号 (精准定位) ---
90
+ echo -e "${BLUE}🔍 正在同步版本信息...${NC}"
91
+
92
+ PKG_PATH="${SOURCE_CODE}/package.json"
93
+
94
+ if [ -f "$PKG_PATH" ]; then
95
+ # 使用 Node.js 提取版本,确保与 package.json 严格一致
96
+ CURRENT_VERSION=$(node -p "require('$PKG_PATH').version")
97
+ echo -e "${GREEN}✅ 检测到母本版本: v${CURRENT_VERSION}${NC}"
98
+ else
99
+ # 兜底版本
100
+ CURRENT_VERSION="2026.3.8"
101
+ echo -e "${YELLOW}⚠️ 未找到母本 package.json,使用默认版本: ${CURRENT_VERSION}${NC}"
98
102
  fi
99
-
100
103
  cat > "${INSTANCE_DIR}/config/openclaw.json" << EOF
101
104
  {
102
105
  "meta": {
103
- "lastTouchedVersion": "2026.3.3",
106
+ "lastTouchedVersion": "${CURRENT_VERSION}",
104
107
  "lastTouchedAt": "$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")"
105
108
  },
106
109
  "agents": {
107
110
  "defaults": {
108
- "model": {
109
- "primary": "${DEFAULT_MODEL}"
110
- },
111
+ "model": { "primary": "${DEFAULT_MODEL}" },
111
112
  "workspace": "${INSTANCE_DIR}/workspace",
112
- "compaction": {
113
- "mode": "safeguard"
114
- }
113
+ "compaction": { "mode": "safeguard" }
115
114
  }
116
115
  },
117
- "commands": {
118
- "native": "auto",
119
- "nativeSkills": "auto",
120
- "restart": false,
121
- "ownerDisplay": "raw"
122
- },
116
+ "commands": { "native": "auto", "restart": false },
123
117
  "env": {
124
- "ZAI_API_KEY": "${ZAI_API_KEY}",
125
- "DEEPSEEK_API_KEY": "${DEEPSEEK_API_KEY}",
126
- "MINIMAX_API_KEY": "${MINIMAX_API_KEY}",
127
- "KIMI_API_KEY": "${KIMI_API_KEY}",
128
- "QWEN_API_KEY": "${QWEN_API_KEY}"
118
+ "ZAI_API_KEY": "${ZAI_KEY}",
119
+ "DEEPSEEK_API_KEY": "${DS_KEY}",
120
+ "MINIMAX_API_KEY": "${MX_KEY}",
121
+ "KIMI_API_KEY": "${KIMI_KEY}",
122
+ "QWEN_API_KEY": "${QWEN_KEY}"
129
123
  },
130
- "gateway": {
131
- "port": ${PORT},
132
- "mode": "local"
133
- }
124
+ "gateway": { "port": ${PORT}, "mode": "local" }
134
125
  }
135
126
  EOF
136
127
 
137
- # 生成启动脚本
138
- echo "🚀 生成启动脚本..."
139
- cat > "${INSTANCE_DIR}/start.sh" << 'EOF'
140
- #!/usr/bin/env bash
141
- # 设置 PATH 以确保 launchd 服务能找到 node
142
- export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:$PATH"
143
-
144
- # 切换到脚本所在目录并保存
145
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
146
-
147
- # 获取实例名称(从路径中提取)
148
- INSTANCE_NAME=$(basename "$SCRIPT_DIR")
149
-
150
- # 设置 OpenClaw 配置文件路径
151
- export OPENCLAW_CONFIG_PATH="$SCRIPT_DIR/config/openclaw.json"
152
-
153
- # 从配置文件中读取端口
154
- PORT=$(node -e "try { console.log(require('$OPENCLAW_CONFIG_PATH').gateway?.port || 18789); } catch { console.log(18789); }")
155
-
156
- # 从配置文件中读取 API keys 并导出(如果存在)
157
- ZAI_API_KEY=$(node -e "try { console.log(require('$OPENCLAW_CONFIG_PATH').env?.ZAI_API_KEY || ''); } catch { console.log(''); }")
158
- if [ -n "$ZAI_API_KEY" ]; then
159
- export ZAI_API_KEY
128
+ # --- 5. 核心代码同步 ---
129
+ echo -e "${BLUE}🔄 分发代码产物与元数据...${NC}"
130
+ mkdir -p "$DIST_DIR"
131
+ if [ -d "${SOURCE_CODE}/dist" ]; then
132
+ # 使用 rsync 确保实例中的代码是最新的快照
133
+ rsync -av --delete "${SOURCE_CODE}/dist/" "${DIST_DIR}/" 2>/dev/null | head -n 3
134
+ else
135
+ echo -e "${RED}❌ 错误: 母本 dist 不存在,请检查全局安装是否成功。${NC}"; exit 1
160
136
  fi
161
137
 
162
- DEEPSEEK_API_KEY=$(node -e "try { console.log(require('$OPENCLAW_CONFIG_PATH').env?.DEEPSEEK_API_KEY || ''); } catch { console.log(''); }")
163
- if [ -n "$DEEPSEEK_API_KEY" ]; then
164
- export DEEPSEEK_API_KEY
138
+ # 拷贝依赖描述文件,供后续 pnpm 使用
139
+ cp "${SOURCE_CODE}/package.json" "${INSTANCE_DIR}/package.json"
140
+ if [ -f "${SOURCE_CODE}/pnpm-lock.yaml" ]; then
141
+ cp "${SOURCE_CODE}/pnpm-lock.yaml" "${INSTANCE_DIR}/pnpm-lock.yaml"
165
142
  fi
166
143
 
167
- MINIMAX_API_KEY=$(node -e "try { console.log(require('$OPENCLAW_CONFIG_PATH').env?.MINIMAX_API_KEY || ''); } catch { console.log(''); }")
168
- if [ -n "$MINIMAX_API_KEY" ]; then
169
- export MINIMAX_API_KEY
170
- fi
144
+ # --- 6. 固化本地依赖 (提升依赖层级) ---
145
+ echo -e "${BLUE}📦 固化实例运行环境 (pnpm)...${NC}"
146
+ export SHARP_BINARY_HOST="https://npmmirror.com/mirrors/sharp"
147
+ export SHARP_LIBVIPS_BINARY_HOST="https://npmmirror.com/mirrors/sharp-libvips"
171
148
 
172
- KIMI_API_KEY=$(node -e "try { console.log(require('$OPENCLAW_CONFIG_PATH').env?.KIMI_API_KEY || ''); } catch { console.log(''); }")
173
- if [ -n "$KIMI_API_KEY" ]; then
174
- export KIMI_API_KEY
175
- fi
149
+ # 进入实例目录安装依赖,确保 node_modules 位于实例根目录
150
+ cd "${INSTANCE_DIR}"
151
+ pnpm install --shamefully-hoist --registry=https://registry.npmmirror.com 2>&1 | grep -v "WARN" | head -n 5
176
152
 
177
- QWEN_API_KEY=$(node -e "try { console.log(require('$OPENCLAW_CONFIG_PATH').env?.QWEN_API_KEY || ''); } catch { console.log(''); }")
178
- if [ -n "$QWEN_API_KEY" ]; then
179
- export QWEN_API_KEY
180
- fi
153
+ # --- 7. 注入 BOOTSTRAP.md 启动配置 飞书运维机器人 ---
154
+ npm install @jinyu-skill-git --prefix "$WORKSPACE/skills/workspace-git" --no-save
155
+ npm install @jinyu-skill-feishu-config --prefix "$WORKSPACE/skills/feishu-config" --no-save
156
+ cat > "${INSTANCE_DIR}/workspace/BOOTSTRAP.md" << 'EOF'
157
+ # 首次启动引导任务
181
158
 
182
- # 从配置文件中读取 workspace 路径
183
- WORKSPACE_PATH=$(node -e "try { const cfg = require('$OPENCLAW_CONFIG_PATH'); console.log(cfg.agents?.defaults?.workspace || process.env.HOME + '/.openclaw/workspace'); } catch { console.log(process.env.HOME + '/.openclaw/workspace'); }")
159
+ ## 任务一:配置飞书机器人
160
+ 由于这是实例首次启动,请执行以下步骤自动配置飞书机器人:
184
161
 
185
- # 设置基于 workspace 的状态目录路径
186
- export OPENCLAW_STATE_DIR="$(dirname "$WORKSPACE_PATH")"
162
+ 1. 调用 `feishu-config` 技能,开始飞书 创建机器人自动配置流程,机器人名称 运维
163
+ 2. 本文件(BOOTSTRAP.md)将在任务完成后自动删除
164
+ EOF
187
165
 
188
- # 设置临时目录路径
166
+ # --- 8. 生成增强型启动脚本 ---
167
+ cat > "${INSTANCE_DIR}/start.sh" << 'EOF'
168
+ #!/usr/bin/env bash
169
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
170
+ cd "$SCRIPT_DIR"
171
+ INSTANCE_NAME=$(basename "$SCRIPT_DIR")
172
+ export OPENCLAW_CONFIG_PATH="$SCRIPT_DIR/config/openclaw.json"
189
173
  export OPENCLAW_TMP_DIR="$SCRIPT_DIR/tmp"
190
174
 
191
- # 自动创建 launchd 服务(如果不存在)
192
- PLIST_LABEL="ai.openclaw.gateway.$INSTANCE_NAME"
193
- PLIST_PATH="$HOME/Library/LaunchAgents/$PLIST_LABEL"
175
+ # 从配置中导出 API Keys 环境变量 (增强兼容性)
176
+ if [ -f "$OPENCLAW_CONFIG_PATH" ]; then
177
+ eval $(node -e "const env = require('$OPENCLAW_CONFIG_PATH').env || {}; Object.keys(env).forEach(k => { if(env[k]) console.log('export ' + k + '=\"' + env[k] + '\"'); })")
178
+ fi
194
179
 
195
- if [ ! -f "$PLIST_PATH" ]; then
196
- echo "📦 为实例 '$INSTANCE_NAME' 创建 launchd 服务..."
197
- mkdir -p "$HOME/Library/LaunchAgents"
198
- cat > "$PLIST_PATH" <<EOPLIST
180
+ # macOS launchd 自动注册
181
+ if [[ "$OSTYPE" == "darwin"* ]]; then
182
+ PLIST_LABEL="ai.openclaw.$INSTANCE_NAME"
183
+ PLIST_PATH="$HOME/Library/LaunchAgents/$PLIST_LABEL.plist"
184
+ if [ ! -f "$PLIST_PATH" ]; then
185
+ echo "📦 注册后台服务 (launchd)..."
186
+ cat > "$PLIST_PATH" <<EOP
199
187
  <?xml version="1.0" encoding="UTF-8"?>
200
188
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
201
189
  <plist version="1.0">
202
190
  <dict>
203
- <key>Label</key>
204
- <string>$PLIST_LABEL</string>
205
- <key>ProgramArguments</key>
206
- <array>
207
- <string>/bin/bash</string>
208
- <string>$SCRIPT_DIR/start.sh</string>
209
- </array>
210
- <key>WorkingDirectory</key>
211
- <string>$SCRIPT_DIR</string>
212
- <key>RunAtLoad</key>
213
- <true/>
214
- <key>KeepAlive</key>
215
- <true/>
216
- <key>EnvironmentVariables</key>
217
- <dict>
218
- <key>PATH</key>
219
- <string>/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin</string>
220
- </dict>
221
- <key>StandardOutPath</key>
222
- <string>/tmp/openclaw-$INSTANCE_NAME.log</string>
223
- <key>StandardErrorPath</key>
224
- <string>/tmp/openclaw-$INSTANCE_NAME.err</string>
191
+ <key>Label</key><string>$PLIST_LABEL</string>
192
+ <key>ProgramArguments</key><array><string>/bin/bash</string><string>$SCRIPT_DIR/start.sh</string></array>
193
+ <key>RunAtLoad</key><true/><key>KeepAlive</key><true/>
194
+ <key>WorkingDirectory</key><string>$SCRIPT_DIR</string>
225
195
  </dict>
226
196
  </plist>
227
- EOPLIST
228
- echo " launchd 服务已创建: $PLIST_PATH"
229
- launchctl load "$PLIST_PATH"
230
- echo "✅ 服务已加载到 launchd"
231
- else
232
- # 检查服务是否已加载,如果没有则加载
233
- if ! launchctl list | grep -q "$PLIST_LABEL"; then
234
- echo "📦 加载现有的 launchd 服务: $PLIST_LABEL"
235
- launchctl load "$PLIST_PATH"
197
+ EOP
198
+ launchctl load "$PLIST_PATH" 2>/dev/null || true
236
199
  fi
237
200
  fi
238
201
 
239
- ROOT_DIR="$SCRIPT_DIR/code"
240
-
241
- echo "🚀 启动 OpenClaw-$INSTANCE_NAME (端口 $PORT)"
242
- echo " 脚本目录: $SCRIPT_DIR"
243
- echo " 工作目录: $(pwd)"
244
- echo " 配置文件: $OPENCLAW_CONFIG_PATH"
245
- echo " 工作空间: $WORKSPACE_PATH"
246
- echo " 状态目录: $OPENCLAW_STATE_DIR"
247
- echo " 临时目录: $OPENCLAW_TMP_DIR"
248
- if [ -n "$ZAI_API_KEY" ]; then
249
- echo " ZAI_API_KEY: ${ZAI_API_KEY:0:20}..."
250
- fi
251
- if [ -n "$DEEPSEEK_API_KEY" ]; then
252
- echo " DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:0:20}..."
253
- fi
254
- if [ -n "$MINIMAX_API_KEY" ]; then
255
- echo " MINIMAX_API_KEY: ${MINIMAX_API_KEY:0:20}..."
256
- fi
257
- if [ -n "$KIMI_API_KEY" ]; then
258
- echo " KIMI_API_KEY: ${KIMI_API_KEY:0:20}..."
259
- fi
260
- if [ -n "$QWEN_API_KEY" ]; then
261
- echo " QWEN_API_KEY: ${QWEN_API_KEY:0:20}..."
262
- fi
263
-
264
- # 使用 exec 替换 shell 进程
265
- if [ "$1" = "pairing" ]; then
266
- # pairing 命令需要直接调用,不要通过 gateway
267
- exec node "$ROOT_DIR/node_modules/openclaw-multi-auto/dist/index.js" "$@"
268
- elif [ $# -eq 0 ]; then
269
- exec node "$ROOT_DIR/node_modules/openclaw-multi-auto/dist/index.js" gateway run --port "$PORT"
270
- else
271
- exec node "$ROOT_DIR/node_modules/openclaw-multi-auto/dist/index.js" gateway --port "$PORT" --no-usage "$@"
272
- fi
202
+ echo "🚀 启动 OpenClaw-$INSTANCE_NAME..."
203
+ # 启动时直接指向本地 dist 产物
204
+ exec node "./dist/index.js" gateway run --port $(node -e "console.log(require('$OPENCLAW_CONFIG_PATH').gateway.port)")
273
205
  EOF
274
-
275
- # 设置执行权限
276
206
  chmod +x "${INSTANCE_DIR}/start.sh"
277
207
 
278
- echo ""
279
- echo " 实例创建完成!"
280
- echo ""
281
- echo "📋 实例信息:"
282
- echo " 名称: ${INSTANCE_NAME}"
283
- echo " 端口: ${PORT}"
284
- echo " 目录: ${INSTANCE_DIR}"
285
- echo " 代码: ${INSTANCE_DIR}/code/node_modules/openclaw-multi-auto/"
286
- if [ -n "$MODEL_PROVIDER" ]; then
287
- echo " 主模型: $DEFAULT_MODEL"
208
+ # --- 9. 全自动执行启动 ---
209
+ echo -e "${BLUE}⚡ 正在拉起服务进程...,飞书界面看到 运维 机器人后,发 你好 完成配对 ${NC}"
210
+ nohup ./start.sh > "${INSTANCE_DIR}/workspace/server.log" 2>&1 &
211
+
212
+ sleep 2
213
+ if ps -p $! > /dev/null; then
214
+ echo -e "${GREEN}================================================${NC}"
215
+ echo -e "${GREEN}🎉 实例 [${INSTANCE_NAME}] 已上线!${NC}"
216
+ echo -e "🌐 访问地址: ${BLUE}http://localhost:${PORT}${NC}"
217
+ echo -e "📄 日志监控: ${YELLOW}tail -f ${INSTANCE_DIR}/workspace/server.log${NC}"
218
+ echo -e "${GREEN}================================================${NC}"
219
+ else
220
+ echo -e "${RED}❌ 启动失败,请检查 ${INSTANCE_DIR}/workspace/server.log${NC}"
288
221
  fi
289
- echo ""
290
- echo "🚀 启动命令:"
291
- echo " cd ${INSTANCE_DIR}"
292
- echo " ./start.sh"
293
- echo ""
294
- echo "⚙️ 配置文件:"
295
- echo " ${INSTANCE_DIR}/config/openclaw.json"
296
- echo ""
297
- echo "📝 重要说明:"
298
- echo " - 所有数据路径都完全独立"
299
- echo " - 如需添加 API Key,编辑配置文件的 env 字段"
300
- echo " - 如需添加频道,编辑配置文件的 channels 字段"
301
- echo " - 代码已通过 npm install 安装到实例"
302
- echo ""