openclaw-multi-auto 1.3.9 → 1.4.2

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.3.9",
3
- "commit": "16f67b708ec4e569affd30e09d96848a200f3245",
4
- "builtAt": "2026-03-11T05:05:38.234Z"
2
+ "version": "1.4.2",
3
+ "commit": "4d33f6faf051053cb6466549efb2873b0fc8a050",
4
+ "builtAt": "2026-03-11T07:49:13.547Z"
5
5
  }
@@ -1 +1 @@
1
- 54111af2cd311a7c250fb4907f71eac6dfcb07c50ca88129d7d3ec4c27d9d7c1
1
+ 9e8e5de87afb3f28d195c8ffe1cb139728ac16ea73ea35c53b2bf0158a4abb9b
@@ -4,7 +4,7 @@ import chalk, { Chalk } from "chalk";
4
4
  import fs, { constants } 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 { isDeepStrictEqual, promisify } from "node:util";
9
9
  import fs$1 from "node:fs/promises";
10
10
  import { execFile, execFileSync, spawn } from "node:child_process";
@@ -802,7 +802,7 @@ function readLoggingConfig() {
802
802
  try {
803
803
  if (!fs.existsSync(configPath)) return;
804
804
  const raw = fs.readFileSync(configPath, "utf-8");
805
- const logging = JSON5.parse(raw)?.logging;
805
+ const logging = json5.parse(raw)?.logging;
806
806
  if (!logging || typeof logging !== "object" || Array.isArray(logging)) return;
807
807
  return logging;
808
808
  } catch {
@@ -5861,7 +5861,7 @@ const defaultResolver = {
5861
5861
  resolvedPath,
5862
5862
  rootRealDir
5863
5863
  }),
5864
- parseJson: (raw) => JSON5.parse(raw)
5864
+ parseJson: (raw) => json5.parse(raw)
5865
5865
  };
5866
5866
  /**
5867
5867
  * Resolves all $include directives in a parsed config object.
@@ -13216,7 +13216,7 @@ function resolveConfigPathForDeps(deps) {
13216
13216
  function normalizeDeps(overrides = {}) {
13217
13217
  return {
13218
13218
  fs: overrides.fs ?? fs,
13219
- json5: overrides.json5 ?? JSON5,
13219
+ json5: overrides.json5 ?? json5,
13220
13220
  env: overrides.env ?? process.env,
13221
13221
  homedir: overrides.homedir ?? (() => resolveRequiredHomeDir(overrides.env ?? process.env, os.homedir)),
13222
13222
  configPath: overrides.configPath ?? "",
@@ -13227,11 +13227,11 @@ function maybeLoadDotEnvForConfig(env) {
13227
13227
  if (env !== process.env) return;
13228
13228
  loadDotEnv({ quiet: true });
13229
13229
  }
13230
- function parseConfigJson5(raw, json5 = JSON5) {
13230
+ function parseConfigJson5(raw, json5$1 = json5) {
13231
13231
  try {
13232
13232
  return {
13233
13233
  ok: true,
13234
- parsed: json5.parse(raw)
13234
+ parsed: json5$1.parse(raw)
13235
13235
  };
13236
13236
  } catch (err) {
13237
13237
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-multi-auto",
3
- "version": "1.3.9",
3
+ "version": "1.4.2",
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,8 @@
1
1
  #!/usr/bin/env bash
2
2
  # =================================================================
3
3
  # OpenClaw 深度集成初始化工具 (create-instance.sh)
4
- # 修复说明:避免 workspace 提升导致 node_modules 出现在父目录
5
- # 增强:支持环境变量 OPENCLAW_SOURCE_DIR 定位源码
4
+ # 功能:创建实例目录、复制文件、安装依赖、配置模型、启动服务
5
+ # 增强:支持环境变量 OPENCLAW_SOURCE_DIR 定位源码,自动复制 docs 到根目录供 TUI 使用
6
6
  # =================================================================
7
7
 
8
8
  set -e
@@ -23,25 +23,21 @@ for cmd in node pnpm; do
23
23
  done
24
24
 
25
25
  # --- 1. 路径溯源与环境检查 ---
26
- # 优先使用环境变量 OPENCLAW_SOURCE_DIR(可在调用脚本前设置)
27
26
  if [ -n "$OPENCLAW_SOURCE_DIR" ] && [ -d "$OPENCLAW_SOURCE_DIR" ]; then
28
27
  SOURCE_CODE="$OPENCLAW_SOURCE_DIR"
29
28
  echo -e "${BLUE}📂 使用环境变量指定的源码路径: $SOURCE_CODE${NC}"
30
29
  else
31
- # 其次检查本地 pnpm 安装的路径(与部署脚本中的 openclaw-runtime 一致)
32
30
  LOCAL_SOURCE="$HOME/openclaw-runtime/node_modules/openclaw-multi-auto"
33
31
  if [ -d "$LOCAL_SOURCE" ]; then
34
32
  SOURCE_CODE="$LOCAL_SOURCE"
35
33
  echo -e "${BLUE}📂 使用本地 pnpm 安装的源码路径: $SOURCE_CODE${NC}"
36
34
  else
37
- # 最后回退到全局 npm 安装路径(兼容旧版)
38
35
  GLOBAL_PREFIX=$(npm config get prefix)
39
36
  SOURCE_CODE="${GLOBAL_PREFIX}/lib/node_modules/openclaw-multi-auto"
40
37
  echo -e "${YELLOW}⚠️ 未找到环境变量和本地路径,尝试使用全局安装路径: $SOURCE_CODE${NC}"
41
38
  fi
42
39
  fi
43
40
 
44
- # 检查源码目录是否存在
45
41
  if [ ! -d "$SOURCE_CODE" ]; then
46
42
  echo -e "${RED}❌ 错误: 未找到 OpenClaw 源码目录: $SOURCE_CODE${NC}"
47
43
  echo -e "${YELLOW}请确认已正确安装 openclaw-multi-auto,或设置 OPENCLAW_SOURCE_DIR 环境变量指向正确路径。${NC}"
@@ -61,7 +57,6 @@ fi
61
57
  if [ -n "$2" ]; then
62
58
  PORT="$2"
63
59
  else
64
- # 更稳健的现有实例计数:使用 find 统计目录数
65
60
  EXISTING_COUNT=$(find "$INSTANCES_BASE" -maxdepth 1 -type d -name "*" ! -name ".*" 2>/dev/null | wc -l | tr -d ' ')
66
61
  PORT=$((18790 + EXISTING_COUNT))
67
62
  fi
@@ -73,12 +68,10 @@ DIST_DIR="${INSTANCE_DIR}/dist"
73
68
  echo -e "${BLUE}🏗️ 正在深度初始化实例: ${INSTANCE_NAME} (端口 ${PORT})${NC}"
74
69
  echo "SOURCE_CODE = $SOURCE_CODE"
75
70
 
76
- # 清理旧实例目录(如果存在)
77
71
  if [ -d "$INSTANCE_DIR" ]; then
78
72
  echo -e "${YELLOW}⚠️ 清理旧实例目录...${NC}"
79
73
  rm -rf "$INSTANCE_DIR"
80
74
  fi
81
- # 删除可能存在的父目录 node_modules 和 workspace 文件(避免干扰)
82
75
  [ -d "${INSTANCES_BASE}/node_modules" ] && rm -rf "${INSTANCES_BASE}/node_modules"
83
76
  [ -f "${INSTANCES_BASE}/pnpm-workspace.yaml" ] && rm -f "${INSTANCES_BASE}/pnpm-workspace.yaml"
84
77
 
@@ -106,7 +99,6 @@ if [ -d "${SOURCE_CODE}/dist" ]; then
106
99
  cp -r "${SOURCE_CODE}/dist/." "${DIST_DIR}/"
107
100
  echo "cp exit code: $?"
108
101
 
109
- # 检查所有被引用的 utils 文件是否存在
110
102
  if [ -f "${DIST_DIR}/index.js" ]; then
111
103
  for chunk in $(grep -oE "utils-[A-Za-z0-9]+\.js" "${DIST_DIR}/index.js" 2>/dev/null | sort -u); do
112
104
  if [ ! -f "${DIST_DIR}/${chunk}" ]; then
@@ -124,22 +116,24 @@ fi
124
116
  cp "${SOURCE_CODE}/package.json" "${INSTANCE_DIR}/package.json"
125
117
  [ -f "${SOURCE_CODE}/pnpm-lock.yaml" ] && cp "${SOURCE_CODE}/pnpm-lock.yaml" "${INSTANCE_DIR}/pnpm-lock.yaml"
126
118
 
119
+ # 复制 control-ui(如果存在)
120
+ if [ -d "${SOURCE_CODE}/dist/control-ui" ]; then
121
+ cp -r "${SOURCE_CODE}/dist/control-ui" "${INSTANCE_DIR}/dist/"
122
+ fi
123
+
127
124
  export SHARP_BINARY_HOST="https://npmmirror.com/mirrors/sharp"
128
125
  export SHARP_LIBVIPS_BINARY_HOST="https://npmmirror.com/mirrors/sharp-libvips"
129
126
 
130
127
  cd "${INSTANCE_DIR}"
131
128
  echo -e "${YELLOW}📍 安装路径确认: $(pwd)${NC}"
132
129
 
133
- # 检查并移除可能影响 workspace 的文件
134
130
  if [ -f "${INSTANCES_BASE}/pnpm-workspace.yaml" ]; then
135
131
  echo -e "${YELLOW}⚠️ 检测到 ${INSTANCES_BASE}/pnpm-workspace.yaml,临时重命名以避免干扰${NC}"
136
132
  mv "${INSTANCES_BASE}/pnpm-workspace.yaml" "${INSTANCES_BASE}/pnpm-workspace.yaml.bak.$(date +%s)"
137
133
  fi
138
134
 
139
- # 强制安装依赖,添加 --ignore-workspace 避免 workspace 提升
140
135
  pnpm install --shamefully-hoist --ignore-workspace --registry=https://registry.npmmirror.com --no-frozen-lockfile
141
136
 
142
- # 验证 node_modules 是否生成
143
137
  if [ ! -d "node_modules" ]; then
144
138
  echo -e "${RED}❌ 严重错误: pnpm install 完成但 node_modules 目录未创建!${NC}"
145
139
  exit 1
@@ -179,11 +173,9 @@ case "$MODEL_PROVIDER" in
179
173
  qwen) PRIMARY_MODEL="qwen/qwen-plus"; QWEN_KEY="$API_KEY" ;;
180
174
  esac
181
175
 
182
- # 生成时间戳(兼容 macOS/Linux)
183
176
  if date -u +"%Y-%m-%dT%H:%M:%S.%3NZ" 2>/dev/null; then
184
177
  TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
185
178
  else
186
- # macOS 不支持 %3N,改用秒级精度
187
179
  TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
188
180
  fi
189
181
 
@@ -288,7 +280,6 @@ fi
288
280
  cd - > /dev/null
289
281
  rm -rf "$TEMP_DIR"
290
282
 
291
- # --- 如果实例是 yunwei,安装角色包并初始化 workspace ---
292
283
  # --- 如果实例是 yunwei,安装角色包并初始化 workspace ---
293
284
  if [ "$INSTANCE_NAME" = "yunwei" ]; then
294
285
  echo -e "${BLUE}🛠️ 检测到运维实例,正在安装角色包 role-openclaw-yunwei...${NC}"
@@ -298,12 +289,22 @@ if [ "$INSTANCE_NAME" = "yunwei" ]; then
298
289
  TARBALL=$(ls *.tgz)
299
290
  tar -xzf "$TARBALL" --strip-components=1
300
291
  rm "$TARBALL"
301
- # 将角色包内容复制到 workspace(包含 docs、memory 等)
302
- cp -rn "$TEMP_ROLE_DIR"/. "$INSTANCE_DIR/workspace/"
303
- # 关键:将 workspace 内的 docs 目录复制到实例根目录,供 TUI 使用
304
- if [ -d "$INSTANCE_DIR/workspace/docs" ]; then
305
- cp -r "$INSTANCE_DIR/workspace/docs" "$INSTANCE_DIR/"
306
- fi
292
+
293
+ # 1. memory、skills 等目录复制到 workspace 根目录(排除 .md 文件)
294
+ for item in *; do
295
+ if [ -d "$item" ]; then
296
+ # 目录(如 memory、skills)复制到 workspace
297
+ cp -r "$item" "$INSTANCE_DIR/workspace/"
298
+ elif [ -f "$item" ] && [[ "$item" != *.md ]]; then
299
+ # 非 .md 文件(如 package.json)也复制到 workspace
300
+ cp "$item" "$INSTANCE_DIR/workspace/" 2>/dev/null || true
301
+ fi
302
+ done
303
+
304
+ # 2. 创建实例根目录下的 docs 目录,并将所有 .md 文件复制过去
305
+ mkdir -p "$INSTANCE_DIR/docs/reference/templates"
306
+ cp *.md "$INSTANCE_DIR/docs/reference/templates/" 2>/dev/null || true
307
+
307
308
  echo -e "${GREEN}✅ 角色包安装完成,workspace 已初始化${NC}"
308
309
  else
309
310
  echo -e "${YELLOW}⚠️ 角色包下载失败,请检查网络或手动安装${NC}"
@@ -312,10 +313,6 @@ if [ "$INSTANCE_NAME" = "yunwei" ]; then
312
313
  rm -rf "$TEMP_ROLE_DIR"
313
314
  fi
314
315
 
315
- if [ -d "${SOURCE_CODE}/dist/control-ui" ]; then
316
- cp -r "${SOURCE_CODE}/dist/control-ui" "${INSTANCE_DIR}/dist/"
317
- fi
318
-
319
316
  # --- 11. 生成增强型启动脚本 ---
320
317
  cat > "${INSTANCE_DIR}/start.sh" << 'EOF'
321
318
  #!/usr/bin/env bash
@@ -335,7 +332,7 @@ INSTANCE_NAME=$(basename "$SCRIPT_DIR")
335
332
  export OPENCLAW_CONFIG_PATH="$SCRIPT_DIR/config/openclaw.json"
336
333
  export OPENCLAW_TMP_DIR="$SCRIPT_DIR/tmp"
337
334
 
338
- # 从配置中提取 workspace 路径并导出(供 TUI 等使用)
335
+ # 从配置中提取 workspace 路径并导出
339
336
  if [ -f "$OPENCLAW_CONFIG_PATH" ]; then
340
337
  export OPENCLAW_WORKSPACE=$(node -e "
341
338
  const cfg = require('$OPENCLAW_CONFIG_PATH');
@@ -353,7 +350,7 @@ if [ -f "$OPENCLAW_CONFIG_PATH" ]; then
353
350
  ")
354
351
  fi
355
352
 
356
- # macOS launchd 守护配置(可选,用于开机自启)
353
+ # macOS launchd 守护配置(可选)
357
354
  if [[ "$OSTYPE" == "darwin"* ]]; then
358
355
  PLIST_LABEL="ai.openclaw.$INSTANCE_NAME"
359
356
  PLIST_PATH="$HOME/Library/LaunchAgents/$PLIST_LABEL.plist"
@@ -374,42 +371,43 @@ EOP
374
371
  fi
375
372
  fi
376
373
 
377
- # 检测 openclaw 命令(通常已在 PATH 中,此处保留为兼容性)
374
+ # 定义可执行文件路径:优先使用全局 openclaw,否则用绝对路径 node
378
375
  if command -v openclaw &> /dev/null; then
379
- CMD="openclaw"
376
+ OPENCLAW_EXEC="openclaw"
380
377
  else
381
- CMD="node ./dist/index.js"
378
+ OPENCLAW_EXEC="node $SCRIPT_DIR/dist/index.js"
382
379
  fi
383
380
 
384
381
  # 根据命令行参数执行对应操作
385
382
  if [ $# -eq 0 ]; then
386
- # 无参数:启动网关(默认行为)
383
+ # 无参数:启动网关
387
384
  GATEWAY_PORT=$(node -e "console.log(require('$OPENCLAW_CONFIG_PATH').gateway.port)")
388
- echo "🚀 使用 $CMD 启动 OpenClaw-$INSTANCE_NAME 网关..."
389
- exec $CMD gateway run --port "$GATEWAY_PORT"
385
+ echo "🚀 使用 $OPENCLAW_EXEC 启动 OpenClaw-$INSTANCE_NAME 网关..."
386
+ exec $OPENCLAW_EXEC gateway run --port "$GATEWAY_PORT"
390
387
  else
391
388
  if [ "$1" = "tui" ]; then
392
- # TUI 需要在 workspace 目录下运行,才能正确加载模板文件
393
- echo "🚀 使用 $CMD 启动 OpenClaw-$INSTANCE_NAME TUI (workspace mode)..."
389
+ # TUI 必须在 workspace 目录下运行,以正确加载模板文件
390
+ echo "🚀 启动 OpenClaw-$INSTANCE_NAME TUI (workspace mode)..."
394
391
  cd "$OPENCLAW_WORKSPACE"
395
- exec $CMD tui
392
+ # 使用绝对路径调用 node,避免相对路径问题
393
+ exec node "$SCRIPT_DIR/dist/index.js" tui
396
394
  else
397
- # 其他命令(如 --help)直接在实例目录运行
398
- echo "🚀 使用 $CMD 执行 OpenClaw-$INSTANCE_NAME 命令: $@"
399
- exec $CMD "$@"
395
+ # 其他命令直接在实例目录执行
396
+ echo "🚀 使用 $OPENCLAW_EXEC 执行 OpenClaw-$INSTANCE_NAME 命令: $@"
397
+ exec $OPENCLAW_EXEC "$@"
400
398
  fi
401
399
  fi
402
400
  EOF
401
+
403
402
  chmod +x "${INSTANCE_DIR}/start.sh"
404
403
 
405
404
  # --- 12. 执行拉起 ---
406
405
  echo -e "${BLUE}⚡ 正在后台启动服务...${NC}"
407
- # 使用完整路径启动,避免相对路径问题
408
406
  nohup "${INSTANCE_DIR}/start.sh" > "${INSTANCE_DIR}/workspace/server.log" 2>&1 &
409
407
  PID=$!
410
408
 
411
- # 等待几秒检查进程是否存活,并验证端口监听
412
409
  sleep 5
410
+
413
411
  check_port() {
414
412
  if command -v lsof &> /dev/null; then
415
413
  lsof -i :$PORT -sTCP:LISTEN -t &> /dev/null
@@ -418,7 +416,7 @@ check_port() {
418
416
  elif command -v curl &> /dev/null; then
419
417
  curl --head --connect-timeout 1 http://localhost:$PORT &> /dev/null
420
418
  else
421
- return 0 # 无工具,跳过端口检查
419
+ return 0
422
420
  fi
423
421
  }
424
422
 
@@ -429,6 +427,44 @@ if kill -0 $PID 2>/dev/null; then
429
427
  echo -e "🌐 本地网关: http://localhost:${PORT}"
430
428
  echo -e "📄 实时日志: tail -f ${INSTANCE_DIR}/workspace/server.log"
431
429
  echo -e "${GREEN}================================================${NC}"
430
+
431
+ # --- 交互式菜单 ---
432
+ if [ -t 0 ]; then
433
+ echo
434
+ echo -e "${BLUE}请选择下一步操作:${NC}"
435
+ echo "1) 启动 TUI (终端交互界面)"
436
+ echo "2) 打开 Web UI (浏览器)"
437
+ echo "3) 退出"
438
+ read -p "请输入数字 [1-3]: " choice
439
+ case $choice in
440
+ 1)
441
+ echo -e "${YELLOW}启动 TUI...${NC}"
442
+ cd "$INSTANCE_DIR"
443
+ ./start.sh tui
444
+ ;;
445
+ 2)
446
+ TOKEN=$(node -e "console.log(require('$INSTANCE_DIR/config/openclaw.json').gateway?.auth?.token || '')")
447
+ if [ -n "$TOKEN" ]; then
448
+ URL="http://localhost:$PORT/?token=$TOKEN"
449
+ echo -e "${GREEN}请在浏览器中打开: ${BLUE}$URL${NC}"
450
+ if [[ "$OSTYPE" == "darwin"* ]]; then
451
+ open "$URL"
452
+ elif command -v xdg-open &> /dev/null; then
453
+ xdg-open "$URL"
454
+ fi
455
+ else
456
+ echo -e "${RED}未找到 token,请手动查看配置文件。${NC}"
457
+ fi
458
+ ;;
459
+ 3)
460
+ echo "退出"
461
+ exit 0
462
+ ;;
463
+ *)
464
+ echo "无效选择"
465
+ ;;
466
+ esac
467
+ fi
432
468
  else
433
469
  echo -e "${YELLOW}⚠️ 进程存在但端口 ${PORT} 未监听(可能启动较慢或检查工具问题),请查看日志: ${INSTANCE_DIR}/workspace/server.log${NC}"
434
470
  fi
@@ -2,6 +2,7 @@
2
2
  # =================================================================
3
3
  # OpenClaw 离线增强版部署脚本 (适配 bundledDependencies + 中国区镜像)
4
4
  # 核心逻辑:修复权限 -> 固化环境 -> 本地 pnpm 安装 -> 实例初始化
5
+ # 新增:可选安装 Ollama 本地模型(用于截屏识图)
5
6
  # =================================================================
6
7
 
7
8
  set -e
@@ -150,6 +151,96 @@ if [ ! -d "$OPENCLAW_SOURCE_DIR" ]; then
150
151
  fi
151
152
  echo -e "${GREEN}✅ 源码路径验证通过${NC}"
152
153
 
154
+ # ==================== 8.5 可选安装本地模型(用于截屏识图)====================
155
+ echo
156
+ echo -e "${YELLOW}📷 是否安装本地模型用于截屏识图?(需要约6GB内存,模型:qwen2.5-vl:7b-instruct-q4_k_m)${NC}"
157
+ read -p "请输入 y/N: " install_model_choice
158
+
159
+ if [[ "$install_model_choice" == "y" || "$install_model_choice" == "Y" ]]; then
160
+ echo -e "${YELLOW}🔍 检查 Ollama 环境...${NC}"
161
+
162
+ # 设置国内镜像源(关键!)
163
+ # 使用 GitHub 镜像加速下载安装脚本和二进制文件
164
+ export GITHUB_MIRROR="https://ghproxy.com"
165
+
166
+ if ! command -v ollama &> /dev/null; then
167
+ echo -e "${YELLOW}未检测到 Ollama,正在从国内镜像安装 Ollama...${NC}"
168
+
169
+ # 方法1:使用官方安装脚本(通过镜像加速)
170
+ echo -e "${BLUE}尝试通过镜像加速安装...${NC}"
171
+ if curl -fsSL ${GITHUB_MIRROR}/https://ollama.com/install.sh | sh; then
172
+ echo -e "${GREEN}✅ Ollama 安装成功${NC}"
173
+ else
174
+ echo -e "${YELLOW}脚本安装失败,尝试直接下载二进制包...${NC}"
175
+ # 方法2:直接下载二进制包(适用于 Linux/macOS)
176
+ if [[ "$OS" == "Linux" ]]; then
177
+ wget ${GITHUB_MIRROR}/https://github.com/ollama/ollama/releases/latest/download/ollama-linux-amd64.tgz
178
+ sudo tar -C /usr -xzf ollama-linux-amd64.tgz
179
+ rm ollama-linux-amd64.tgz
180
+ elif [[ "$OS" == "Darwin" ]]; then
181
+ # macOS 用户建议直接访问官网下载,或使用 homebrew
182
+ echo -e "${YELLOW}macOS 用户请手动下载安装包:${NC}"
183
+ echo -e "${BLUE}访问 https://ollama.com/download 或使用镜像:${NC}"
184
+ echo -e "${BLUE}curl -L ${GITHUB_MIRROR}/https://ollama.com/download/Ollama-darwin.zip -o Ollama.zip${NC}"
185
+ echo -e "${YELLOW}安装完成后重新运行此脚本${NC}"
186
+ exit 1
187
+ fi
188
+
189
+ if command -v ollama &> /dev/null; then
190
+ echo -e "${GREEN}✅ Ollama 二进制安装成功${NC}"
191
+ else
192
+ echo -e "${RED}❌ Ollama 安装失败,请手动安装后重试。${NC}"
193
+ echo -e "${YELLOW}您可以访问 https://ollama.com 下载安装包。${NC}"
194
+ fi
195
+ fi
196
+ else
197
+ echo -e "${GREEN}✅ Ollama 已安装${NC}"
198
+ fi
199
+
200
+ # 再次检查 ollama 是否可用
201
+ if command -v ollama &> /dev/null; then
202
+ echo -e "${YELLOW}配置国内模型镜像源加速下载...${NC}"
203
+
204
+ # 配置模型下载镜像源
205
+ # 方法A:通过环境变量(临时生效)
206
+ export OLLAMA_MIRROR="https://ollama.modelscope.cn" # 魔搭社区镜像
207
+
208
+ # 方法B:创建配置文件(永久生效)
209
+ mkdir -p ~/.ollama
210
+ cat > ~/.ollama/config.json << EOF
211
+ {
212
+ "registry": {
213
+ "mirrors": {
214
+ "registry.ollama.ai": "https://ollama.modelscope.cn"
215
+ }
216
+ }
217
+ }
218
+ EOF
219
+ echo -e "${GREEN}✅ 镜像源配置完成${NC}"
220
+
221
+ echo -e "${YELLOW}正在拉取模型 qwen2.5-vl:7b-instruct-q4_k_m,这可能需要一些时间...${NC}"
222
+ echo -e "${BLUE}使用魔搭社区镜像加速下载...${NC}"
223
+
224
+ # 使用镜像源拉取模型(如果失败则尝试其他源)
225
+ if ollama pull modelscope.cn/qwen/Qwen2.5-7B-Instruct-GGUF; then
226
+ echo -e "${GREEN}✅ 模型拉取成功${NC}"
227
+ else
228
+ echo -e "${YELLOW}从魔搭拉取失败,尝试从官方源(已配置镜像)拉取...${NC}"
229
+ if ollama pull qwen2.5-vl:7b-instruct-q4_k_m; then
230
+ echo -e "${GREEN}✅ 模型拉取成功${NC}"
231
+ else
232
+ echo -e "${RED}❌ 模型拉取失败,您稍后可以手动运行以下命令重试:${NC}"
233
+ echo -e "${YELLOW}export OLLAMA_MIRROR=https://ollama.modelscope.cn${NC}"
234
+ echo -e "${YELLOW}ollama pull qwen2.5-vl:7b-instruct-q4_k_m${NC}"
235
+ fi
236
+ fi
237
+ else
238
+ echo -e "${YELLOW}⚠️ Ollama 不可用,跳过模型安装。${NC}"
239
+ fi
240
+ else
241
+ echo -e "${BLUE}跳过本地模型安装。${NC}"
242
+ fi
243
+
153
244
  # ==================== 9. 自动化实例初始化 (直接调用 create-instance.sh) ====================
154
245
  CREATE_SCRIPT="$OPENCLAW_SOURCE_DIR/scripts/create-instance.sh"
155
246