openclaw-multi-auto 1.5.8 → 1.6.0

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.5.8",
3
- "commit": "d59a4444ec442856e44d6d919acf9d12d5bc0acd",
4
- "builtAt": "2026-03-15T02:48:49.454Z"
2
+ "version": "1.6.0",
3
+ "commit": "265aa6b9223a6f8027612a9edfc80604359cb6b6",
4
+ "builtAt": "2026-03-15T03:12:31.302Z"
5
5
  }
@@ -1 +1 @@
1
- 2d05c326c20e3a4286d096f6adfb7cdec3c32aff6cde0c9f0a59fb5ee06d681c
1
+ 509714fc39cac067ff5b9fa2d176ef567d1053553c22847b2550fe6dd48e6424
@@ -4,7 +4,7 @@ import chalk, { Chalk } from "chalk";
4
4
  import fs from "node:fs";
5
5
  import { Logger } from "tslog";
6
6
  import os from "node:os";
7
- import JSON5 from "json5";
7
+ import json5 from "json5";
8
8
  import { promisify } from "node:util";
9
9
  import fs$1 from "node:fs/promises";
10
10
  import "@clack/prompts";
@@ -761,7 +761,7 @@ function readLoggingConfig() {
761
761
  try {
762
762
  if (!fs.existsSync(configPath)) return;
763
763
  const raw = fs.readFileSync(configPath, "utf-8");
764
- const logging = JSON5.parse(raw)?.logging;
764
+ const logging = json5.parse(raw)?.logging;
765
765
  if (!logging || typeof logging !== "object" || Array.isArray(logging)) return;
766
766
  return logging;
767
767
  } catch {
@@ -5,7 +5,7 @@ import fs, { constants } from "node:fs";
5
5
  import os from "node:os";
6
6
  import chalk, { Chalk } from "chalk";
7
7
  import { Logger } from "tslog";
8
- import JSON5 from "json5";
8
+ import json5 from "json5";
9
9
  import util, { promisify } from "node:util";
10
10
  import fs$1 from "node:fs/promises";
11
11
  import process$1 from "node:process";
@@ -400,7 +400,7 @@ function readLoggingConfig() {
400
400
  try {
401
401
  if (!fs.existsSync(configPath)) return;
402
402
  const raw = fs.readFileSync(configPath, "utf-8");
403
- const logging = JSON5.parse(raw)?.logging;
403
+ const logging = json5.parse(raw)?.logging;
404
404
  if (!logging || typeof logging !== "object" || Array.isArray(logging)) return;
405
405
  return logging;
406
406
  } catch {
@@ -4481,7 +4481,7 @@ function resolveOpenClawManifestBlock(params) {
4481
4481
  const raw = getFrontmatterString(params.frontmatter, params.key ?? "metadata");
4482
4482
  if (!raw) return;
4483
4483
  try {
4484
- const parsed = JSON5.parse(raw);
4484
+ const parsed = json5.parse(raw);
4485
4485
  if (!parsed || typeof parsed !== "object") return;
4486
4486
  const manifestKeys = [MANIFEST_KEY, ...LEGACY_MANIFEST_KEYS];
4487
4487
  for (const key of manifestKeys) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-multi-auto",
3
- "version": "1.5.8",
3
+ "version": "1.6.0",
4
4
  "description": "Multi-channel AI gateway with extensible messaging integrations",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/openclaw/openclaw#readme",
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env bash
2
2
  # =================================================================
3
3
  # OpenClaw 深度集成初始化工具 (create-instance.sh)
4
- # 功能:安装全局运行时、安装扩展、创建实例目录、复制文件、配置模型、启动服务
5
- # 正确顺序:安装全局 openclaw 安装 page-action-cache 创建实例
4
+ # 功能:创建实例目录、复制文件、安装依赖、配置模型、启动服务
5
+ # 增强:支持环境变量 OPENCLAW_SOURCE_DIR 定位源码,自动复制 docs 到根目录供 TUI 使用
6
+ # 增强:支持 --profile 命令行习惯,自动配置 profile 软链接
6
7
  # =================================================================
7
8
 
8
9
  set -e
@@ -14,130 +15,75 @@ YELLOW='\033[1;33m'
14
15
  BLUE='\033[0;34m'
15
16
  NC='\033[0m'
16
17
 
17
- # --- 0. 检查必要命令 ---
18
- echo -e "${BLUE}🔍 检查必要命令...${NC}"
18
+ # --- 检查必要命令 ---
19
19
  for cmd in node pnpm; do
20
20
  if ! command -v "$cmd" &> /dev/null; then
21
21
  echo -e "${RED}❌ 错误: 未找到命令 '$cmd',请先安装${NC}"
22
22
  exit 1
23
23
  fi
24
24
  done
25
- echo -e "${GREEN}✅ 必要命令检查完成${NC}"
26
25
 
27
- # --- 1. 设置全局目录 ---
28
- GLOBAL_DIR="$HOME/openclaw-runtime"
29
- echo -e "${BLUE}📂 全局运行时目录: $GLOBAL_DIR${NC}"
30
-
31
- # 创建全局目录
32
- if [ ! -d "$GLOBAL_DIR" ]; then
33
- echo -e "${YELLOW}📁 创建全局目录...${NC}"
34
- mkdir -p "$GLOBAL_DIR"
35
- fi
36
-
37
- cd "$GLOBAL_DIR"
38
- echo -e "${GREEN}✅ 切换到全局目录: $(pwd)${NC}"
39
-
40
- # --- 2. 安装全局 openclaw-multi-auto ---
41
- echo -e "${BLUE}🤖 正在检查/安装全局 openclaw-multi-auto...${NC}"
42
-
43
- # 检查是否已安装 openclaw-multi-auto
44
- if pnpm list openclaw-multi-auto 2>&1 | grep -q "openclaw-multi-auto"; then
45
- echo -e "${YELLOW}⚠️ openclaw-multi-auto 已在全局安装${NC}"
46
- echo -e "${YELLOW}💡 如需更新,请使用: pnpm install openclaw-multi-auto@latest${NC}"
26
+ # --- 1. 路径溯源与环境检查 ---
27
+ if [ -n "$OPENCLAW_SOURCE_DIR" ] && [ -d "$OPENCLAW_SOURCE_DIR" ]; then
28
+ SOURCE_CODE="$OPENCLAW_SOURCE_DIR"
29
+ echo -e "${BLUE}📂 使用环境变量指定的源码路径: $SOURCE_CODE${NC}"
47
30
  else
48
- echo -e "${YELLOW}📦 正在安装 openclaw-multi-auto 到全局目录...${NC}"
49
- if ! pnpm install openclaw-multi-auto --registry=https://registry.npmmirror.com 2>&1; then
50
- echo -e "${RED}❌ openclaw-multi-auto 安装失败${NC}"
51
- echo -e "${YELLOW}💡 提示: 请检查网络连接或包名是否正确${NC}"
52
- exit 1
31
+ LOCAL_SOURCE="$HOME/openclaw-runtime/node_modules/openclaw-multi-auto"
32
+ if [ -d "$LOCAL_SOURCE" ]; then
33
+ SOURCE_CODE="$LOCAL_SOURCE"
34
+ echo -e "${BLUE}📂 使用本地 pnpm 安装的源码路径: $SOURCE_CODE${NC}"
35
+ else
36
+ GLOBAL_PREFIX=$(npm config get prefix)
37
+ SOURCE_CODE="${GLOBAL_PREFIX}/lib/node_modules/openclaw-multi-auto"
38
+ echo -e "${YELLOW}⚠️ 未找到环境变量和本地路径,尝试使用全局安装路径: $SOURCE_CODE${NC}"
53
39
  fi
54
- echo -e "${GREEN}✅ openclaw-multi-auto 安装成功${NC}"
55
40
  fi
56
41
 
57
- # 检查全局安装结果
58
- if [ ! -d "node_modules/openclaw-multi-auto" ]; then
59
- echo -e "${RED} 严重错误: openclaw-multi-auto 未正确安装到 node_modules${NC}"
42
+ if [ ! -d "$SOURCE_CODE" ]; then
43
+ echo -e "${RED}❌ 错误: 未找到 OpenClaw 源码目录: $SOURCE_CODE${NC}"
44
+ echo -e "${YELLOW}请确认已正确安装 openclaw-multi-auto,或设置 OPENCLAW_SOURCE_DIR 环境变量指向正确路径。${NC}"
60
45
  exit 1
61
46
  fi
62
47
 
63
- SOURCE_CODE="$GLOBAL_DIR/node_modules/openclaw-multi-auto"
64
- echo -e "${GREEN}✅ 全局 openclaw-multi-auto 路径: $SOURCE_CODE${NC}"
65
-
66
- # --- 3. 安装 page-action-cache 扩展到全局目录 ---
67
- echo -e "${BLUE}🤖 正在安装 page-action-cache 扩展到全局目录...${NC}"
68
-
69
- # 创建 extensions 目录
70
- EXTENSIONS_DIR="$GLOBAL_DIR/extensions"
71
- if [ ! -d "$EXTENSIONS_DIR" ]; then
72
- echo -e "${YELLOW}📁 创建 extensions 目录...${NC}"
73
- mkdir -p "$EXTENSIONS_DIR"
74
- fi
75
-
76
- # 检查 page-action-cache 是否已安装
77
- if [ -d "$EXTENSIONS_DIR/page-action-cache" ]; then
78
- echo -e "${YELLOW}⚠️ page-action-cache 已在全局安装${NC}"
79
- echo -e "${YELLOW}💡 如需更新,请手动更新${NC}"
80
- else
81
- echo -e "${YELLOW}📦 正在安装 page-action-cache 到全局 extensions 目录...${NC}"
82
- if ! pnpm add page-action-cache --registry=https://registry.npmmirror.com 2>&1; then
83
- echo -e "${RED}❌ page-action-cache 安装失败${NC}"
84
- echo -e "${YELLOW}💡 提示: 请检查网络连接或包名是否正确${NC}"
85
- exit 1
86
- fi
87
-
88
- # 复制 page-action-cache 到 extensions 目录
89
- if [ -d "node_modules/page-action-cache" ]; then
90
- echo -e "${YELLOW}📁 复制 page-action-cache 到 extensions 目录...${NC}"
91
- cp -r "node_modules/page-action-cache" "$EXTENSIONS_DIR/"
92
- echo -e "${GREEN}✅ page-action-cache 安装并复制成功${NC}"
93
- else
94
- echo -e "${YELLOW}⚠️ page-action-cache 已安装但未在 node_modules 中找到${NC}"
95
- fi
96
- fi
97
-
98
- echo -e "${GREEN}✅ 全局扩展安装完成${NC}"
99
- echo -e "${BLUE}📝 全局运行时已就绪${NC}"
48
+ INSTANCES_BASE=$(eval echo "$HOME/openclaws")
100
49
 
101
- # --- 4. 获取实例名称 ---
50
+ # --- 2. 获取实例名称 ---
102
51
  INSTANCE_NAME="${1:-}"
103
52
  if [ -z "$INSTANCE_NAME" ]; then
104
53
  read -p "请输入实例名称 (默认: yunwei): " INPUT_NAME
105
54
  INSTANCE_NAME="${INPUT_NAME:-yunwei}"
106
55
  fi
107
56
 
108
- # --- 5. 获取端口 ---
57
+ # --- 3. 获取端口 ---
109
58
  if [ -n "$2" ]; then
110
59
  PORT="$2"
111
60
  else
112
- INSTANCES_BASE=$(eval echo "$HOME/openclaws")
113
61
  EXISTING_COUNT=$(find "$INSTANCES_BASE" -maxdepth 1 -type d -name "*" ! -name ".*" 2>/dev/null | wc -l | tr -d ' ')
114
62
  PORT=$((18789 + EXISTING_COUNT * 100))
115
63
  fi
116
64
 
117
- # --- 6. 定义实例目录并清理旧残留 ---
118
- INSTANCES_BASE=$(eval echo "$HOME/openclaws")
65
+ # --- 4. 定义实例目录并清理旧残留 ---
119
66
  INSTANCE_DIR="$INSTANCES_BASE/${INSTANCE_NAME}"
120
67
  DIST_DIR="${INSTANCE_DIR}/dist"
121
68
 
122
69
  echo -e "${BLUE}🏗️ 正在深度初始化实例: ${INSTANCE_NAME} (端口 ${PORT})${NC}"
123
70
  echo "SOURCE_CODE = $SOURCE_CODE"
124
- echo "GLOBAL_DIR = $GLOBAL_DIR"
125
71
 
126
72
  if [ -d "$INSTANCE_DIR" ]; then
127
73
  echo -e "${YELLOW}⚠️ 清理旧实例目录...${NC}"
128
74
  rm -rf "$INSTANCE_DIR"
129
75
  fi
76
+ [ -d "${INSTANCES_BASE}/node_modules" ] && rm -rf "${INSTANCES_BASE}/node_modules"
77
+ [ -f "${INSTANCES_BASE}/pnpm-workspace.yaml" ] && rm -f "${INSTANCES_BASE}/pnpm-workspace.yaml"
130
78
 
131
- # --- 7. 完整目录结构创建 ---
132
- echo -e "${YELLOW}📁 创建实例目录结构...${NC}"
79
+ # --- 5. 完整目录结构创建 ---
133
80
  mkdir -p "${INSTANCE_DIR}/config" "${INSTANCE_DIR}/tmp" "${INSTANCE_DIR}/workspace"
134
81
  mkdir -p "${INSTANCE_DIR}/state"
135
82
  mkdir -p "${INSTANCE_DIR}/workspace/memory"
136
83
  mkdir -p "${INSTANCE_DIR}/agents/main/agent/sessions"
137
84
  mkdir -p "${INSTANCE_DIR}/credentials" "${INSTANCE_DIR}/media"
138
- echo -e "${GREEN}✅ 目录结构创建完成${NC}"
139
85
 
140
- # --- 8. 动态提取母本版本号 ---
86
+ # --- 6. 动态提取母本版本号 ---
141
87
  echo -e "${BLUE}🔍 正在提取母本版本信息...${NC}"
142
88
  PKG_PATH="${SOURCE_CODE}/package.json"
143
89
  if [ -f "$PKG_PATH" ]; then
@@ -148,15 +94,13 @@ else
148
94
  echo -e "${YELLOW}⚠️ 未找到 package.json,使用兜底版本: ${CURRENT_VERSION}${NC}"
149
95
  fi
150
96
 
151
- # --- 9. 从全局目录复制到实例目录 ---
152
- echo -e "${BLUE}🔄 从全局运行时复制到实例目录...${NC}"
97
+ # --- 7. 核心代码同步 (完整复制) ---
98
+ echo -e "${BLUE}🔄 完整复制 OpenClaw 源码目录...${NC}"
153
99
 
154
100
  # 定义需要复制的目录和文件
155
101
  DIRS_TO_COPY="dist extensions scripts skills docs ui assets"
156
102
  FILES_TO_COPY="package.json openclaw.mjs"
157
103
 
158
- cd "$SOURCE_CODE"
159
-
160
104
  # 复制所有必要目录
161
105
  for dir in $DIRS_TO_COPY; do
162
106
  if [ -d "${SOURCE_CODE}/${dir}" ]; then
@@ -186,15 +130,19 @@ fi
186
130
 
187
131
  echo -e "${GREEN}✅ 核心代码复制完成${NC}"
188
132
 
189
- # --- 10. 安装实例依赖 ---
190
133
  export SHARP_BINARY_HOST="https://npmmirror.com/mirrors/sharp"
191
134
  export SHARP_LIBVIPS_BINARY_HOST="https://npmmirror.com/mirrors/sharp-libvips"
192
135
 
193
136
  cd "${INSTANCE_DIR}"
194
137
  echo -e "${YELLOW}📍 安装路径确认: $(pwd)${NC}"
195
138
 
139
+ if [ -f "${INSTANCES_BASE}/pnpm-workspace.yaml" ]; then
140
+ echo -e "${YELLOW}⚠️ 检测到 ${INSTANCES_BASE}/pnpm-workspace.yaml,临时重命名以避免干扰${NC}"
141
+ mv "${INSTANCES_BASE}/pnpm-workspace.yaml" "${INSTANCES_BASE}/pnpm-workspace.yaml.bak.$(date +%s)"
142
+ fi
143
+
196
144
  echo -e "${BLUE}📦 安装依赖包...${NC}"
197
- pnpm install --shamefully-hoist --ignore-workspace --registry=https://registry.npmmirror.com
145
+ pnpm install --shamefully-hoist --ignore-workspace --registry=https://registry.npmmirror.com --no-frozen-lockfile
198
146
 
199
147
  if [ ! -d "node_modules" ]; then
200
148
  echo -e "${RED}❌ 严重错误: pnpm install 完成但 node_modules 目录未创建!${NC}"
@@ -202,7 +150,90 @@ if [ ! -d "node_modules" ]; then
202
150
  fi
203
151
  echo -e "${GREEN}✅ 依赖安装成功,node_modules 已生成在实例目录${NC}"
204
152
 
205
- # --- 11. 模型配置 ---
153
+ # --- 8.5. 安装 page-action-cache 扩展到 openclaw-multi-auto ---
154
+ echo -e "${BLUE}🤖 正在安装 page-action-cache 扩展到 openclaw-multi-auto...${NC}"
155
+
156
+ # 全局目录路径
157
+ GLOBAL_DIR="$HOME/openclaw-runtime"
158
+ echo -e "${BLUE}📂 全局目录: $GLOBAL_DIR${NC}"
159
+
160
+ # openclaw-multi-auto 扩展目录
161
+ OPENCLAW_DIR="$GLOBAL_DIR/node_modules/openclaw-multi-auto"
162
+ OPENCLAW_EXTENSIONS_DIR="$OPENCLAW_DIR/extensions"
163
+
164
+ # 检测可用的包管理器
165
+ if command -v pnpm &> /dev/null; then
166
+ PACKAGE_MANAGER="pnpm"
167
+ echo -e "${BLUE}📦 检测到包管理器: pnpm${NC}"
168
+ elif command -v npm &> /dev/null; then
169
+ PACKAGE_MANAGER="npm"
170
+ echo -e "${BLUE}📦 检测到包管理器: npm${NC}"
171
+ else
172
+ echo -e "${RED}❌ 未找到 npm 或 pnpm 命令${NC}"
173
+ echo -e "${YELLOW}💡 请先安装 Node.js 和包管理器${NC}"
174
+ exit 1
175
+ fi
176
+
177
+ # 确定包名
178
+ PACKAGE_NAME="page-action-cache"
179
+
180
+ # 安装 page-action-cache 到 openclaw-multi-auto/extensions
181
+ echo -e "${YELLOW}📦 正在安装 $PACKAGE_NAME 到 openclaw-multi-auto/extensions...${NC}"
182
+ cd "$GLOBAL_DIR"
183
+
184
+ # 检查扩展目录
185
+ if [ ! -d "$OPENCLAW_EXTENSIONS_DIR" ]; then
186
+ echo -e "${YELLOW}📁 创建 openclaw-multi-auto/extensions 目录...${NC}"
187
+ mkdir -p "$OPENCLAW_EXTENSIONS_DIR"
188
+ fi
189
+
190
+ # 检查全局安装状态
191
+ if [ -d "$OPENCLAW_EXTENSIONS_DIR/$PACKAGE_NAME" ]; then
192
+ echo -e "${YELLOW}⚠️ $PACKAGE_NAME 已在 openclaw-multi-auto 安装${NC}"
193
+ echo -e "${YELLOW}💡 如需更新,请手动更新${NC}"
194
+ else
195
+ # 尝试从 npm 安装
196
+ echo -ne "${YELLOW}📦 尝试从 npm registry 安装 $PACKAGE_NAME...${NC}"
197
+ if [ "$PACKAGE_MANAGER" = "pnpm" ]; then
198
+ pnpm add $PACKAGE_NAME --registry=https://registry.npmmirror.com 2>&1
199
+ else
200
+ npm install $PACKAGE_NAME --registry=https://registry.npmmirror.com --no-save 2>&1
201
+ fi
202
+
203
+ if [ $? -eq 0 ]; then
204
+ echo -e "${GREEN}✅ $PACKAGE_NAME 安装成功${NC}"
205
+ # 复制到扩展目录
206
+ if [ -d "node_modules/$PACKAGE_NAME" ]; then
207
+ echo -e "${YELLOW}📁 复制 $PACKAGE_NAME 到 openclaw-multi-auto/extensions...${NC}"
208
+ cp -r "node_modules/$PACKAGE_NAME" "$OPENCLAW_EXTENSIONS_DIR/"
209
+ echo -e "${GREEN}✅ 复制完成${NC}"
210
+ fi
211
+ else
212
+ echo -e "${RED}❌ $PACKAGE_NAME 安装失败${NC}"
213
+ echo -e "${YELLOW}💡 提示: 请检查网络连接或包名是否正确${NC}"
214
+ fi
215
+ fi
216
+
217
+ # 检查全局安装结果
218
+ INSTALLED=$($PACKAGE_MANAGER list $PACKAGE_NAME 2>&1 | grep -q "$PACKAGE_NAME")
219
+ if [ $? -eq 0 ]; then
220
+ echo -e "${GREEN}✅ $PACKAGE_NAME 已安装到全局目录${NC}"
221
+
222
+ # 获取安装信息
223
+ PACKAGE_INFO=$($PACKAGE_MANAGER list $PACKAGE_NAME 2>&1)
224
+ echo -e "${BLUE}📦 $PACKAGE_NAME 全局安装信息:${NC}"
225
+ echo "$PACKAGE_INFO"
226
+ else
227
+ echo -e "${YELLOW}⚠️ $PACKAGE_NAME 安装状态不确定${NC}"
228
+ echo -e "${YELLOW}💡 提示: 请手动检查安装状态: $PACKAGE_MANAGER list $PACKAGE_NAME --global${NC}"
229
+ fi
230
+
231
+ echo -e "${GREEN}✅ page-action-cache 全局扩展安装完成${NC}"
232
+ echo -e "${BLUE}📝 yunwei 实例将从全局目录复制代码和依赖${NC}"
233
+ echo -e "${YELLOW}🔄 多实例架构:全局运行时 + 实例从运行时复制${NC}"
234
+
235
+ # 返回到实例目录
236
+ cd "${INSTANCE_DIR}"
206
237
  MODEL_PROVIDER="${3:-}"
207
238
  if [ -z "$MODEL_PROVIDER" ]; then
208
239
  echo -e "${BLUE}--- 请选择模型供应商 ---${NC}"
@@ -223,7 +254,7 @@ if [ -z "$API_KEY" ]; then
223
254
  read -p "请输入您的 ${MODEL_PROVIDER} API Key: " API_KEY
224
255
  fi
225
256
 
226
- # --- 12. 生成深度配置文件 ---
257
+ # --- 9. 生成深度配置文件 ---
227
258
  DEFAULT_MODEL="zai/glm-5"
228
259
  ZAI_KEY=""; DS_KEY=""; MX_KEY=""; KIMI_KEY=""; QWEN_KEY=""
229
260
 
@@ -233,88 +264,336 @@ case "$MODEL_PROVIDER" in
233
264
  minimax) PRIMARY_MODEL="minimax-cn/MiniMax-M2.5-highspeed"; MX_KEY="$API_KEY" ;;
234
265
  kimi) PRIMARY_MODEL="kimi/moonshot-v1-8k"; KIMI_KEY="$API_KEY" ;;
235
266
  qwen) PRIMARY_MODEL="qwen/qwen-plus"; QWEN_KEY="$API_KEY" ;;
236
- *) PRIMARY_MODEL="zai/glm-5"; ZAI_KEY="$API_KEY" ;;
237
267
  esac
238
268
 
239
- echo -e "${BLUE}⚙️ 生成配置文件...${NC}"
240
- cat > "${INSTANCE_DIR}/config/deep.json" << EOF
269
+ if date -u +"%Y-%m-%dT%H:%M:%S.%3NZ" 2>/dev/null; then
270
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
271
+ else
272
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
273
+ fi
274
+
275
+ cat > "${INSTANCE_DIR}/config/openclaw.json" << EOF
241
276
  {
242
- "gateway": {
243
- "mode": "local",
244
- "port": ${PORT},
245
- "bind": "127.0.0.1",
246
- "autoStart": true
247
- },
248
- "plugins": {
249
- "entries": {
250
- "page-action-cache": {
251
- "path": "${INSTANCE_DIR}/extensions/page-action-cache",
252
- "enabled": true,
253
- "config": {
254
- "enabled": true,
255
- "autoUseCache": true,
256
- "scenarioRecognitionEnabled": true,
257
- "llmClassificationThreshold": 0.8,
258
- "cacheLevelStrategy": "auto",
259
- "defaultCacheLevel": "L1",
260
- "pageChangeDetectionEnabled": true,
261
- "changeInvalidationThreshold": 0.5,
262
- "invalidationStrategy": "soft",
263
- "variableExtractionEnabled": true,
264
- "allowUserConfirmVariables": true,
265
- "allowUserForcedRefresh": true,
266
- "enableUserCacheErrorReport": true,
267
- "trackExecutionStats": true,
268
- "statsUpdateInterval": 60000
269
- }
270
- }
271
- }
277
+ "meta": {
278
+ "lastTouchedVersion": "${CURRENT_VERSION}",
279
+ "lastTouchedAt": "${TIMESTAMP}"
272
280
  },
273
- "model": {
274
- "defaultProvider": "${MODEL_PROVIDER}",
281
+ "models": {
275
282
  "providers": {
276
283
  "zai": {
284
+ "baseUrl": "https://open.bigmodel.cn/api/paas/v4",
277
285
  "apiKey": "${ZAI_KEY}",
278
- "baseURL": "https://open.bigmodel.cn/api/paas/v4",
279
- "models": ["zai/glm-5"]
286
+ "api": "openai-completions",
287
+ "models": [
288
+ {
289
+ "id": "glm-5",
290
+ "name": "GLM-5",
291
+ "input": ["text"],
292
+ "contextWindow": 32768,
293
+ "maxTokens": 4096
294
+ }
295
+ ]
280
296
  },
281
297
  "deepseek": {
298
+ "baseUrl": "https://api.deepseek.com",
282
299
  "apiKey": "${DS_KEY}",
283
- "baseURL": "https://api.deepseek.com/v1",
284
- "models": ["deepseek/deepseek-chat"]
300
+ "api": "openai-completions",
301
+ "models": [
302
+ {
303
+ "id": "deepseek-chat",
304
+ "name": "DeepSeek-Chat",
305
+ "input": ["text"],
306
+ "contextWindow": 32768,
307
+ "maxTokens": 4096
308
+ }
309
+ ]
285
310
  },
286
311
  "minimax-cn": {
312
+ "baseUrl": "https://api.minimax.chat/v1",
287
313
  "apiKey": "${MX_KEY}",
288
- "baseURL": "https://api.minimax.chat/v1",
289
- "models": ["minimax-cn/MiniMax-M2.5-highspeed"]
314
+ "api": "openai-completions",
315
+ "models": [
316
+ {
317
+ "id": "MiniMax-M2.5-highspeed",
318
+ "name": "MiniMax-M2.5-highspeed",
319
+ "input": ["text"],
320
+ "cost": { "input": 0.000002, "output": 0.000006 },
321
+ "contextWindow": 65536,
322
+ "maxTokens": 8192
323
+ }
324
+ ]
290
325
  },
291
- "kimi": {
292
- "apiKey": "${KIMI_KEY}",
293
- "baseURL": "https://api.moonshot.cn/v1",
294
- "models": ["kimi/moonshot-v1-8k"]
295
- },
296
- "qwen": {
297
- "apiKey": "${QWEN_KEY}",
298
- "baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
299
- "models": ["qwen/qwen-plus"]
326
+ "ollama": {
327
+ "baseUrl": "http://127.0.0.1:11434",
328
+ "api": "ollama",
329
+ "models": [
330
+ {
331
+ "id": "qwen3-vl:8b",
332
+ "name": "Qwen3-VL-8B",
333
+ "input": ["text", "image"],
334
+ "contextWindow": 32768,
335
+ "maxTokens": 4096
336
+ }
337
+ ]
300
338
  }
301
339
  }
302
- }
340
+ },
341
+ "agents": {
342
+ "defaults": {
343
+ "model": { "primary": "${PRIMARY_MODEL}" },
344
+ "imageModel": {
345
+ "primary": "ollama/qwen3-vl:8b",
346
+ "fallbacks": [
347
+ "ollama/qwen3-vl:8b"
348
+ ]
349
+ },
350
+ "models": {
351
+ "ollama/qwen3-vl:8b": {}
352
+ },
353
+ "workspace": "${INSTANCE_DIR}/workspace",
354
+ "compaction": { "mode": "safeguard" }
355
+ }
356
+ },
357
+ "commands": { "native": "auto", "restart": false },
358
+ "gateway": { "port": ${PORT}, "mode": "local" }
303
359
  }
304
360
  EOF
305
361
 
306
- echo -e "${GREEN}✅ 配置文件生成完成${NC}"
362
+ # --- 10. 预装可选技能 (失败不影响主流程) ---
363
+ echo -e "${BLUE}🤖 正在注入飞书运维机器人引导...${NC}"
364
+ SKILLS_DIR="${INSTANCE_DIR}/workspace/skills"
365
+ mkdir -p "$SKILLS_DIR"
366
+
367
+ SKILL_PKG="jinyu-skill-feishu-config"
368
+ REGISTRY="https://registry.npmmirror.com"
369
+
370
+ TEMP_DIR=$(mktemp -d)
371
+ cd "$TEMP_DIR"
372
+
373
+ if npm pack "$SKILL_PKG@latest" --registry="$REGISTRY" --quiet > /dev/null; then
374
+ TARBALL=$(ls *.tgz)
375
+ mkdir -p "$SKILLS_DIR/feishu-config"
376
+ tar -xzf "$TARBALL" -C "$SKILLS_DIR/feishu-config" --strip-components=1
377
+ echo -e "${GREEN}✅ 技能 feishu-config 安装成功${NC}"
378
+ else
379
+ echo -e "${YELLOW}⚠️ 技能 feishu-config 下载失败,跳过(可手动安装)${NC}"
380
+ fi
381
+
382
+ cd - > /dev/null
383
+ rm -rf "$TEMP_DIR"
384
+
385
+ # --- 如果实例是 yunwei,安装角色包并初始化 workspace ---
386
+ if [ "$INSTANCE_NAME" = "yunwei" ]; then
387
+ echo -e "${BLUE}🛠️ 检测到运维实例,正在安装角色包 role-openclaw-yunwei...${NC}"
388
+ TEMP_ROLE_DIR=$(mktemp -d)
389
+ cd "$TEMP_ROLE_DIR"
390
+ if npm pack role-openclaw-yunwei@latest --registry=https://registry.npmmirror.com --quiet > /dev/null; then
391
+ TARBALL=$(ls *.tgz)
392
+ tar -xzf "$TARBALL" --strip-components=1
393
+ rm "$TARBALL"
394
+
395
+ # 1. 将 memory、skills 等目录复制到 workspace 根目录(排除 .md 文件)
396
+ for item in *; do
397
+ if [ -d "$item" ]; then
398
+ # 目录(如 memory、skills)复制到 workspace
399
+ cp -r "$item" "$INSTANCE_DIR/workspace/"
400
+ elif [ -f "$item" ]; then
401
+ # 非 .md 文件(如 package.json)也复制到 workspace
402
+ cp "$item" "$INSTANCE_DIR/workspace/" 2>/dev/null || true
403
+ fi
404
+ done
405
+
406
+ # 2. 创建实例根目录下的 docs 目录,并将所有 .md 文件复制过去
407
+ mkdir -p "$INSTANCE_DIR/docs/reference/templates"
408
+ cp *.md "$INSTANCE_DIR/docs/reference/templates/" 2>/dev/null || true
409
+
410
+ echo -e "${GREEN}✅ 角色包安装完成,workspace 已初始化${NC}"
411
+ else
412
+ echo -e "${YELLOW}⚠️ 角色包下载失败,请检查网络或手动安装${NC}"
413
+ fi
414
+ cd - > /dev/null
415
+ rm -rf "$TEMP_ROLE_DIR"
416
+ fi
417
+
418
+ # --- 设置 profile 链接以便 openclaw --profile 使用 ---
419
+ echo -e "${BLUE}🔗 配置 profile 链接以支持 --profile 命令行...${NC}"
420
+ PROFILES_DIR="$HOME/.openclaw/profiles"
421
+ mkdir -p "$PROFILES_DIR"
422
+
423
+ # 配置文件软链接
424
+ ln -sf "$INSTANCE_DIR/config/openclaw.json" "$PROFILES_DIR/$INSTANCE_NAME.json"
307
425
 
308
- # --- 13. 完成 ---
309
- echo -e "${GREEN}🎉 ${INSTANCE_NAME} 实例创建完成!${NC}"
310
- echo -e "${BLUE}📂 实例路径: ${INSTANCE_DIR}${NC}"
311
- echo -e "${BLUE}🔌 端口: ${PORT}${NC}"
312
- echo -e "${BLUE}🤖 模型: ${PRIMARY_MODEL}${NC}"
313
- echo -e "${BLUE}📦 全局运行时: ${GLOBAL_DIR}${NC}"
314
- echo -e "${BLUE}📝 配置文件: ${INSTANCE_DIR}/config/deep.json${NC}"
426
+ # 状态目录软链接(profile 默认状态目录为 ~/.openclaw/profiles/<profile>/)
427
+ # 使用 -sfn 以确保目录链接正确
428
+ ln -sfn "$INSTANCE_DIR/state" "$PROFILES_DIR/$INSTANCE_NAME"
315
429
 
316
- echo -e "${YELLOW}--- 启动命令 ---${NC}"
317
- echo -e "${BLUE}cd ${INSTANCE_DIR}${NC}"
318
- echo -e "${BLUE}node openclaw.mjs gateway run --config config/deep.json${NC}"
430
+ echo -e "${GREEN} 现在可以使用 'openclaw --profile $INSTANCE_NAME ...' 管理此实例${NC}"
431
+
432
+ # --- 11. 生成增强型启动脚本 ---
433
+ cat > "${INSTANCE_DIR}/start.sh" << 'EOF'
434
+ #!/usr/bin/env bash
435
+ # =================================================================
436
+ # OpenClaw 实例启动脚本 (yunwei 优化版)
437
+ # 功能:启动网关、运行 TUI 或其他命令
438
+ # =================================================================
439
+
440
+ # 确保全局安装的 openclaw 命令可用
441
+ export PATH="$HOME/.npm-global/bin:$PATH"
442
+
443
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
444
+ cd "$SCRIPT_DIR"
445
+ INSTANCE_NAME=$(basename "$SCRIPT_DIR")
446
+
447
+ # 导出核心配置路径
448
+ export OPENCLAW_CONFIG_PATH="$SCRIPT_DIR/config/openclaw.json"
449
+ export OPENCLAW_TMP_DIR="$SCRIPT_DIR/tmp"
450
+ export OPENCLAW_STATE_DIR="$SCRIPT_DIR/state"
451
+
452
+ # 从配置中提取 workspace 路径并导出
453
+ if [ -f "$OPENCLAW_CONFIG_PATH" ]; then
454
+ export OPENCLAW_WORKSPACE=$(node -e "
455
+ const cfg = require('$OPENCLAW_CONFIG_PATH');
456
+ console.log(cfg.agents?.defaults?.workspace || '');
457
+ ")
458
+ fi
319
459
 
320
- echo -e "${GREEN}🚀 已就绪,可以启动实例!${NC}"
460
+ # 从配置中导出 API Key(如果存在 env 字段)
461
+ if [ -f "$OPENCLAW_CONFIG_PATH" ]; then
462
+ eval $(node -e "
463
+ const env = require('$OPENCLAW_CONFIG_PATH').env || {};
464
+ Object.keys(env).forEach(k => {
465
+ if (env[k]) console.log('export ' + k + '=\"' + env[k] + '\"');
466
+ });
467
+ ")
468
+ fi
469
+
470
+ # macOS launchd 守护配置(可选)
471
+ if [[ "$OSTYPE" == "darwin"* ]]; then
472
+ PLIST_LABEL="ai.openclaw.$INSTANCE_NAME"
473
+ PLIST_PATH="$HOME/Library/LaunchAgents/$PLIST_LABEL.plist"
474
+ if [ ! -f "$PLIST_PATH" ]; then
475
+ cat > "$PLIST_PATH" <<EOP
476
+ <?xml version="1.0" encoding="UTF-8"?>
477
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
478
+ <plist version="1.0">
479
+ <dict>
480
+ <key>Label</key><string>$PLIST_LABEL</string>
481
+ <key>ProgramArguments</key><array><string>/bin/bash</string><string>$SCRIPT_DIR/start.sh</string></array>
482
+ <key>RunAtLoad</key><true/><key>KeepAlive</key><true/>
483
+ <key>WorkingDirectory</key><string>$SCRIPT_DIR</string>
484
+ </dict>
485
+ </plist>
486
+ EOP
487
+ launchctl load "$PLIST_PATH" 2>/dev/null || true
488
+ fi
489
+ fi
490
+
491
+ # 定义可执行文件路径:优先使用全局 openclaw,否则用绝对路径 node
492
+ if command -v openclaw &> /dev/null; then
493
+ OPENCLAW_EXEC="openclaw"
494
+ else
495
+ # 使用完整复制的目录中的 openclaw.mjs 或 dist/index.js
496
+ if [ -f "$SCRIPT_DIR/openclaw.mjs" ]; then
497
+ OPENCLAW_EXEC="node $SCRIPT_DIR/openclaw.mjs"
498
+ elif [ -f "$SCRIPT_DIR/dist/index.js" ]; then
499
+ OPENCLAW_EXEC="node $SCRIPT_DIR/dist/index.js"
500
+ else
501
+ echo -e "${RED}❌ 错误: 未找到可执行文件${NC}"
502
+ exit 1
503
+ fi
504
+ fi
505
+
506
+ # 根据命令行参数执行对应操作
507
+ if [ $# -eq 0 ]; then
508
+ # 无参数:启动网关
509
+ GATEWAY_PORT=$(node -e "console.log(require('$OPENCLAW_CONFIG_PATH').gateway.port)")
510
+ echo "🚀 使用 $OPENCLAW_EXEC 启动 OpenClaw-$INSTANCE_NAME 网关..."
511
+ exec $OPENCLAW_EXEC gateway run --port "$GATEWAY_PORT"
512
+ else
513
+ if [ "$1" = "tui" ]; then
514
+ # TUI 必须在 workspace 目录下运行,以正确加载模板文件
515
+ echo "🚀 启动 OpenClaw-$INSTANCE_NAME TUI (workspace mode)..."
516
+ cd "$OPENCLAW_WORKSPACE"
517
+ # 使用绝对路径调用 node,避免相对路径问题
518
+ exec node "$SCRIPT_DIR/dist/index.js" tui
519
+ else
520
+ # 其他命令直接在实例目录执行
521
+ echo "🚀 使用 $OPENCLAW_EXEC 执行 OpenClaw-$INSTANCE_NAME 命令: $@"
522
+ exec $OPENCLAW_EXEC "$@"
523
+ fi
524
+ fi
525
+ EOF
526
+
527
+ chmod +x "${INSTANCE_DIR}/start.sh"
528
+
529
+ # --- 12. 执行拉起 ---
530
+ echo -e "${BLUE}⚡ 正在后台启动服务...${NC}"
531
+ nohup "${INSTANCE_DIR}/start.sh" > "${INSTANCE_DIR}/workspace/server.log" 2>&1 &
532
+ PID=$!
533
+
534
+ sleep 5
535
+
536
+ check_port() {
537
+ if command -v lsof &> /dev/null; then
538
+ lsof -i :$PORT -sTCP:LISTEN -t &> /dev/null
539
+ elif command -v nc &> /dev/null; then
540
+ nc -z localhost $PORT 2>/dev/null
541
+ elif command -v curl &> /dev/null; then
542
+ curl --head --connect-timeout 1 http://localhost:$PORT &> /dev/null
543
+ else
544
+ return 0
545
+ fi
546
+ }
547
+
548
+ if kill -0 $PID 2>/dev/null; then
549
+ if check_port; then
550
+ echo -e "${GREEN}================================================${NC}"
551
+ echo -e "${GREEN}🎉 实例 [${INSTANCE_NAME}] 初始化成功!${NC}"
552
+ echo -e "🌐 本地网关: http://localhost:${PORT}"
553
+ echo -e "📄 实时日志: tail -f ${INSTANCE_DIR}/workspace/server.log"
554
+ echo -e "${GREEN}================================================${NC}"
555
+
556
+ # --- 交互式菜单 ---
557
+ if [ -t 0 ]; then
558
+ echo
559
+ echo -e "${BLUE}请选择下一步操作:${NC}"
560
+ echo "1) 启动 TUI (终端交互界面)"
561
+ echo "2) 打开 Web UI (浏览器)"
562
+ echo "3) 退出"
563
+ read -p "请输入数字 [1-3]: " choice
564
+ case $choice in
565
+ 1)
566
+ echo -e "${YELLOW}启动 TUI...${NC}"
567
+ cd "$INSTANCE_DIR"
568
+ ./start.sh tui
569
+ ;;
570
+ 2)
571
+ TOKEN=$(node -e "console.log(require('$INSTANCE_DIR/config/openclaw.json').gateway?.auth?.token || '')")
572
+ if [ -n "$TOKEN" ]; then
573
+ URL="http://localhost:$PORT/?token=$TOKEN"
574
+ echo -e "${GREEN}请在浏览器中打开: ${BLUE}$URL${NC}"
575
+ if [[ "$OSTYPE" == "darwin"* ]]; then
576
+ open "$URL"
577
+ elif command -v xdg-open &> /dev/null; then
578
+ xdg-open "$URL"
579
+ fi
580
+ else
581
+ echo -e "${RED}未找到 token,请手动查看配置文件。${NC}"
582
+ fi
583
+ ;;
584
+ 3)
585
+ echo "退出"
586
+ exit 0
587
+ ;;
588
+ *)
589
+ echo "无效选择"
590
+ ;;
591
+ esac
592
+ fi
593
+ else
594
+ echo -e "${YELLOW}⚠️ 进程存在但端口 ${PORT} 未监听(可能启动较慢或检查工具问题),请查看日志: ${INSTANCE_DIR}/workspace/server.log${NC}"
595
+ fi
596
+ else
597
+ echo -e "${RED}❌ 启动失败,请查看日志: tail -n 20 ${INSTANCE_DIR}/workspace/server.log${NC}"
598
+ exit 1
599
+ fi