create-openclaw-bot 5.6.8 → 5.6.10

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.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  # 🦞 OpenClaw Setup
4
4
 
5
5
  <p align="center">
6
- <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.5.0-0EA5E9?style=for-the-badge" alt="Version 5.5.0" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.6.10-0EA5E9?style=for-the-badge" alt="Version 5.6.9" /></a>
7
7
  <a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
8
8
  <a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
9
9
  <a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
@@ -24,24 +24,23 @@ An interactive **CLI tool** and **Setup Wizard** to deploy your own free AI Bot
24
24
 
25
25
  ---
26
26
 
27
- ## 🆕 What's new in v5.6.0
28
-
29
- - 🧠 **Memory & Dreaming enabled by default** — Long-term Memory skill is now pre-selected for all new installations. The `memory-core` plugin with `dreaming.enabled: true` is auto-injected into `openclaw.json`, and `DREAMS.md` is seeded in every workspace.
30
- - 🤝 **Relay plugin card auto-shows** — When selecting Telegram multi-bot (≥2 bots), the Relay plugin card appears with an "Auto-enabled" badge and locked checkbox. Switching back to 1 bot hides it.
31
- - 🔑 **Relay trigger keywords in TEAMS.md** — `TEAMS.md` now documents all relay trigger keywords (question/task/reminder patterns) from the v5.0.9 relay plugin, helping bots understand and coordinate cross-bot communication.
32
- - 🌍 **Proper Vietnamese diacritics** — All workspace `.md` files now use proper UTF-8 Vietnamese with full diacritics, eliminating mojibake.
33
- - 👍 **Tool-based reaction** — `TOOLS.md` mandates bots call the `react` action with 👍 before replying, replacing unreliable gateway auto-ack.
34
-
35
- <details>
36
- <summary><b>Previous: What's new in v5.5.0</b></summary>
37
-
38
- - 📦 **OpenClaw 2026.4.14** — Bumped from 2026.4.5. Includes the new experimental Dreaming memory system, active-memory improvements, Telegram approval button deadlock fix, and WebSocket keepalive stability.
39
- - 📄 **Modular workspace docs** — Multi-bot deployments now generate `TEAM.md` and `RELAY.md` as separate files.
40
- - 🔐 **Full security rules everywhere** — All `AGENTS.md` files now include the complete 4-section security ruleset.
41
- - 🗑️ **Removed `.yaml` agent files** OpenClaw Core reads config exclusively from `openclaw.json`.
42
- - 🤖 **Anti-hallucination handoff** — Relay-variant `AGENTS.md` now mandates tool-first `react` actions.
43
- - 🏗️ **Scaffold-based generation** — Both Wizard and CLI now call shared scaffold builders.
44
-
27
+ ## 🆕 What's new in v5.6.10
28
+
29
+ - 🔧 **OpenAI Codex provider fix** — Updated Codex model registry to match OpenAI's current API. Removed 6 deprecated models, retained 4 active ones: `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.2`, `gpt-5.4-mini`.
30
+ - 🔀 **9Router API mode switch** — Switched from `openai-completions` to `openai-responses` to align with OpenAI's Responses API.
31
+ - 🩹 **Auto-patch 9Router** — New `patch-9router.js` automatically patches 9Router source files on setup, upgrade, and before every launch to stay compatible with Codex API changes.
32
+ - 🎯 **Direct Codex model targeting** — 9Router config now exposes individual Codex models alongside `smart-route` so users can pick a specific model.
33
+ - 💬 **Zalo Personal group config** — Added `defaultAccount`, `groupAllowFrom`, `historyLimit`, wildcard group config and `autoReply` for better out-of-the-box group handling.
34
+
35
+ <details>
36
+ <summary><b>Previous: What's new in v5.6.0</b></summary>
37
+
38
+ - 🧠 **Memory & Dreaming enabled by default** — Long-term Memory skill is now pre-selected for all new installations. The `memory-core` plugin with `dreaming.enabled: true` is auto-injected into `openclaw.json`, and `DREAMS.md` is seeded in every workspace.
39
+ - 🤝 **Relay plugin card auto-shows** — When selecting Telegram multi-bot (≥2 bots), the Relay plugin card appears with an "Auto-enabled" badge and locked checkbox. Switching back to 1 bot hides it.
40
+ - 🔑 **Relay trigger keywords in TEAMS.md** — `TEAMS.md` now documents all relay trigger keywords (question/task/reminder patterns) from the v5.0.9 relay plugin, helping bots understand and coordinate cross-bot communication.
41
+ - 🌍 **Proper Vietnamese diacritics** — All workspace `.md` files now use proper UTF-8 Vietnamese with full diacritics, eliminating mojibake.
42
+ - 👍 **Tool-based reaction** — `TOOLS.md` mandates bots call the `react` action with 👍 before replying, replacing unreliable gateway auto-ack.
43
+
45
44
  </details>
46
45
 
47
46
  ---
package/README.vi.md CHANGED
@@ -3,7 +3,7 @@
3
3
  # 🦞 OpenClaw Setup
4
4
 
5
5
  <p align="center">
6
- <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.5.0-0EA5E9?style=for-the-badge" alt="Version 5.5.0" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.6.10-0EA5E9?style=for-the-badge" alt="Version 5.6.9" /></a>
7
7
  <a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
8
8
  <a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
9
9
  <a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
@@ -24,24 +24,23 @@ Công cụ **CLI tương tác** và **Setup Wizard** để tự triển khai Bot
24
24
 
25
25
  ---
26
26
 
27
- ## 🆕 Có gì mới trong v5.6.0
28
-
29
- - 🧠 **Memory & Dreaming bật mặc định** — Long-term Memory skill giờ được bật sẵn cho mọi cài đặt mới. Plugin `memory-core` với `dreaming.enabled: true` được inject tự động vào `openclaw.json`, `DREAMS.md` được tạo sẵn trong workspace.
30
- - 🤝 **Card Relay plugin tự động hiển thị** Khi chọn Telegram multi-bot (≥2 bots), card Relay plugin hiện ra với badge "Tự động bật" và checkbox bị khóa. Chuyển về 1 bot sẽ ẩn card.
31
- - 🔑 **Từ khóa relay trong TEAMS.md** — `TEAMS.md` giờ liệt đầy đủ từ khóa kích hoạt relay (hỏi/giao việc/nhắc nhở) từ plugin v5.0.9, giúp bot hiểu phối hợp tốt hơn.
32
- - 🌍 **Tiếng Việt dấu chuẩn** — Tất cả file `.md` workspace giờ dùng UTF-8 chuẩn với dấu tiếng Việt đầy đủ, hết lỗi mojibake.
33
- - 👍 **Tool-based reaction** — `TOOLS.md` bắt buộc bot gọi action `react` thả 👍 trước khi trả lời, thay dùng gateway auto-ack không ổn định.
34
-
35
- <details>
36
- <summary><b>Trước đó: Có gì mới ở v5.5.0</b></summary>
37
-
38
- - 📦 **OpenClaw 2026.4.14** — Nâng từ 2026.4.5. Bao gồm hệ thống Dreaming, cải thiện active-memory, sửa deadlock nút approve Telegram, ổn định WebSocket keepalive.
39
- - 📄 **Tách file workspace docs**Multi-bot giờ sinh `TEAM.md``RELAY.md` thành file riêng.
40
- - 🔐 **Quy tắc bảo mật đầy đủ mọi nơi** — Tất cả `AGENTS.md` giờ đủ 4 section bảo mật.
41
- - 🗑️ **Xóa file `.yaml` agent** OpenClaw Core chỉ đọc từ `openclaw.json`.
42
- - 🤖 **Chống ảo giác handoff** — `AGENTS.md` relay bắt buộc `react` action.
43
- - 🏗️ **Scaffold-based generation** — Cả Wizard lẫn CLI gọi chung scaffold builders.
44
-
27
+ ## 🆕 Có gì mới trong v5.6.10
28
+
29
+ - 🔧 **Sửa provider OpenAI Codex** — Cập nhật registry model Codex phù hợp API hiện tại của OpenAI. Loại 6 model đã dừng, giữ 4 model đang hoạt động: `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.2`, `gpt-5.4-mini`.
30
+ - 🔀 **Chuyển chế độ API 9Router**Đổi từ `openai-completions` sang `openai-responses` cho khớp với Responses API mới của OpenAI.
31
+ - 🩹 **Tự động patch 9Router** — Script `patch-9router.js` mới tự source files 9Router khi setup, upgrade trước mỗi lần khởi động để tương thích thay đổi API Codex.
32
+ - 🎯 **Chọn model Codex trực tiếp** — Config 9Router giờ hiển thị từng model Codex bên cạnh `smart-route` để người dùng thể chọn model cụ thể.
33
+ - 💬 **Config nhóm Zalo Personal** — Bổ sung `defaultAccount`, `groupAllowFrom`, `historyLimit`, wildcard group config `autoReply` để xử nhóm tốt hơn ngay từ đầu.
34
+
35
+ <details>
36
+ <summary><b>Trước đó: Có gì mới ở v5.6.0</b></summary>
37
+
38
+ - 🧠 **Memory & Dreaming bật mặc định** — Long-term Memory skill giờ được bật sẵn cho mọi cài đặt mới. Plugin `memory-core` với `dreaming.enabled: true` được inject tự động vào `openclaw.json`, `DREAMS.md` được tạo sẵn trong workspace.
39
+ - 🤝 **Card Relay plugin tự động hiển thị** Khi chọn Telegram multi-bot (≥2 bots), card Relay plugin hiện ra với badge "Tự động bật" checkbox bị khóa. Chuyển về 1 bot sẽ ẩn card.
40
+ - 🔑 **Từ khóa relay trong TEAMS.md** — `TEAMS.md` giờ liệt kê đầy đủ từ khóa kích hoạt relay (hỏi/giao việc/nhắc nhở) từ plugin v5.0.9, giúp bot hiểu và phối hợp tốt hơn.
41
+ - 🌍 **Tiếng Việt có dấu chuẩn** — Tất cả file `.md` workspace giờ dùng UTF-8 chuẩn với dấu tiếng Việt đầy đủ, hết lỗi mojibake.
42
+ - 👍 **Tool-based reaction** — `TOOLS.md` bắt buộc bot gọi action `react` thả 👍 trước khi trả lời, thay vì dùng gateway auto-ack không ổn định.
43
+
45
44
  </details>
46
45
 
47
46
  ---
package/dist/cli.js CHANGED
@@ -20,18 +20,25 @@ function loadSharedModule(modulePath, globalName) {
20
20
  return globalThis[globalName] || loaded || {};
21
21
  }
22
22
 
23
- const {
24
- OPENCLAW_NPM_SPEC,
25
- OPENCLAW_RUNTIME_PACKAGES,
26
- TELEGRAM_RELAY_PLUGIN_SPEC,
27
- TELEGRAM_SETUP_GUIDE_FILENAME,
28
- buildRelayPluginInstallCommand,
29
- buildTelegramPostInstallChecklist,
30
- } = loadSharedModule('./setup/shared/common-gen.js', '__openclawCommon');
31
-
32
- const {
33
- buildDockerArtifacts,
34
- } = loadSharedModule('./setup/shared/docker-gen.js', '__openclawDockerGen');
23
+ const {
24
+ OPENCLAW_NPM_SPEC,
25
+ OPENCLAW_RUNTIME_PACKAGES,
26
+ NINE_ROUTER_PROXY_API_KEY,
27
+ NINE_ROUTER_API_BASE_URL,
28
+ SMART_ROUTE_PROVIDER_MODELS,
29
+ SMART_ROUTE_PROVIDER_ORDER,
30
+ TELEGRAM_RELAY_PLUGIN_SPEC,
31
+ TELEGRAM_SETUP_GUIDE_FILENAME,
32
+ buildRelayPluginInstallCommand,
33
+ buildTelegramPostInstallChecklist,
34
+ get9RouterBaseUrl,
35
+ build9RouterProviderConfig,
36
+ } = loadSharedModule('./setup/shared/common-gen.js', '__openclawCommon');
37
+
38
+ const {
39
+ buildDockerArtifacts,
40
+ build9RouterPatchScript,
41
+ } = loadSharedModule('./setup/shared/docker-gen.js', '__openclawDockerGen');
35
42
 
36
43
  const {
37
44
  buildWorkspaceFileMap,
@@ -195,47 +202,30 @@ function resolveNative9RouterDesktopLaunch() {
195
202
 
196
203
  function build9RouterSmartRouteSyncScript(dbPath) {
197
204
  const safeDbPath = JSON.stringify(dbPath);
205
+ const safeRouterBaseUrl = JSON.stringify(NINE_ROUTER_API_BASE_URL);
206
+ const safeModelPriority = JSON.stringify(SMART_ROUTE_PROVIDER_MODELS);
207
+ const safeProviderOrder = JSON.stringify(SMART_ROUTE_PROVIDER_ORDER);
198
208
  return `function bootstrap() {
199
209
  const fs = require('fs');
200
210
  const path = require('path');
201
211
  const dbPath = ${safeDbPath};
202
- const ROUTER='http://localhost:20128';
203
- const MODEL_PRIORITY = {
204
- codex: ['cx/gpt-5.4', 'cx/gpt-5.3-codex', 'cx/gpt-5.3-codex-high', 'cx/gpt-5.2-codex', 'cx/gpt-5.2', 'cx/gpt-5.1-codex-max', 'cx/gpt-5.1-codex', 'cx/gpt-5.1', 'cx/gpt-5-codex'],
205
- 'claude-code': ['cc/claude-opus-4-6', 'cc/claude-sonnet-4-6', 'cc/claude-opus-4-5-20251101', 'cc/claude-sonnet-4-5-20250929', 'cc/claude-haiku-4-5-20251001'],
206
- github: ['gh/gpt-5.4', 'gh/gpt-5.3-codex', 'gh/gpt-5.2-codex', 'gh/gpt-5.2', 'gh/gpt-5.1-codex-max', 'gh/gpt-5.1-codex', 'gh/gpt-5.1', 'gh/gpt-5', 'gh/gpt-4.1', 'gh/gpt-4o', 'gh/claude-opus-4.6', 'gh/claude-sonnet-4.6', 'gh/claude-sonnet-4.5', 'gh/claude-opus-4.5', 'gh/claude-haiku-4.5', 'gh/gemini-3-pro-preview', 'gh/gemini-3-flash-preview', 'gh/gemini-2.5-pro'],
207
- cursor: ['cu/default', 'cu/claude-4.6-opus-max', 'cu/claude-4.5-opus-high-thinking', 'cu/claude-4.5-sonnet-thinking', 'cu/claude-4.5-sonnet', 'cu/gpt-5.3-codex', 'cu/gpt-5.2-codex', 'cu/gemini-3-flash-preview'],
208
- kilo: ['kc/anthropic/claude-sonnet-4-20250514', 'kc/anthropic/claude-opus-4-20250514', 'kc/google/gemini-2.5-pro', 'kc/google/gemini-2.5-flash', 'kc/openai/gpt-4.1', 'kc/deepseek/deepseek-chat'],
209
- cline: ['cl/anthropic/claude-sonnet-4.6', 'cl/anthropic/claude-opus-4.6', 'cl/openai/gpt-5.3-codex', 'cl/openai/gpt-5.4', 'cl/google/gemini-3.1-pro-preview'],
210
- 'gemini-cli': ['gc/gemini-3-flash-preview', 'gc/gemini-3-pro-preview'],
211
- iflow: ['if/qwen3-coder-plus', 'if/kimi-k2', 'if/kimi-k2-thinking', 'if/glm-4.7', 'if/deepseek-r1', 'if/deepseek-v3.2', 'if/deepseek-v3', 'if/qwen3-max', 'if/qwen3-235b', 'if/iflow-rome-30ba3b'],
212
- qwen: ['qw/qwen3-coder-plus', 'qw/qwen3-coder-flash', 'qw/vision-model', 'qw/coder-model'],
213
- kiro: ['kr/claude-sonnet-4.5', 'kr/claude-haiku-4.5', 'kr/deepseek-3.2', 'kr/deepseek-3.1', 'kr/qwen3-coder-next'],
214
- ollama: ['ollama/gemma4:e2b', 'ollama/gemma4:e4b', 'ollama/gemma4:26b', 'ollama/gemma4:31b', 'ollama/qwen3.5', 'ollama/kimi-k2.5', 'ollama/glm-5', 'ollama/glm-4.7-flash', 'ollama/minimax-m2.5', 'ollama/gpt-oss:120b'],
215
- 'kimi-coding': ['kmc/kimi-k2.5', 'kmc/kimi-k2.5-thinking', 'kmc/kimi-latest'],
216
- glm: ['glm/glm-5.1', 'glm/glm-5', 'glm/glm-4.7'],
217
- 'glm-cn': ['glm/glm-5.1', 'glm/glm-5', 'glm/glm-4.7'],
218
- minimax: ['minimax/MiniMax-M2.7', 'minimax/MiniMax-M2.5', 'minimax/MiniMax-M2.1'],
219
- kimi: ['kimi/kimi-k2.5', 'kimi/kimi-k2.5-thinking', 'kimi/kimi-latest'],
220
- deepseek: ['deepseek/deepseek-chat', 'deepseek/deepseek-reasoner'],
221
- xai: ['xai/grok-4', 'xai/grok-4-fast-reasoning', 'xai/grok-code-fast-1'],
222
- mistral: ['mistral/mistral-large-latest', 'mistral/codestral-latest'],
223
- groq: ['groq/llama-3.3-70b-versatile', 'groq/openai/gpt-oss-120b'],
224
- cerebras: ['cerebras/gpt-oss-120b'],
225
- alicode: ['alicode/qwen3.5-plus', 'alicode/qwen3-coder-plus'],
226
- openai: ['openai/gpt-4o', 'openai/gpt-4.1'],
227
- anthropic: ['anthropic/claude-sonnet-4', 'anthropic/claude-haiku-3.5'],
228
- gemini: ['gemini/gemini-2.5-flash', 'gemini/gemini-2.5-pro'],
229
- };
230
- const sync = async () => {
231
- try {
232
- const response = await fetch(ROUTER + '/api/providers');
233
- if (!response.ok) return;
234
- const payload = await response.json();
235
- const a = (payload.connections || [])
236
- .filter((item) => item && item.provider && item.isActive !== false && !item.disabled)
237
- .map((item) => item.provider);
238
- let db = {};
212
+ const ROUTER=${safeRouterBaseUrl};
213
+ const MODEL_PRIORITY=${safeModelPriority};
214
+ const PREF=${safeProviderOrder};
215
+ const sync = async () => {
216
+ try {
217
+ const response = await fetch(ROUTER + '/api/providers');
218
+ if (!response.ok) return;
219
+ const payload = await response.json();
220
+ const rawConnections = Array.isArray(payload.connections)
221
+ ? payload.connections
222
+ : Array.isArray(payload.providerConnections)
223
+ ? payload.providerConnections
224
+ : [];
225
+ const a = [...new Set(rawConnections
226
+ .filter((item) => item && item.provider && item.isActive !== false && !item.disabled)
227
+ .map((item) => item.provider))];
228
+ let db = {};
239
229
  try {
240
230
  db = JSON.parse(fs.readFileSync(dbPath, 'utf8'));
241
231
  } catch {}
@@ -249,11 +239,12 @@ function build9RouterSmartRouteSyncScript(dbPath) {
249
239
  console.log('Removed smart-route (no active providers)');
250
240
  }
251
241
  };
252
- if (!a.length) {
253
- removeSmartRoute();
254
- return;
255
- }
256
- const m = a.flatMap((provider) => MODEL_PRIORITY[provider] || []);
242
+ if (!a.length) {
243
+ removeSmartRoute();
244
+ return;
245
+ }
246
+ a.sort((x, y) => (PREF.indexOf(x) === -1 ? 99 : PREF.indexOf(x)) - (PREF.indexOf(y) === -1 ? 99 : PREF.indexOf(y)));
247
+ const m = a.flatMap((provider) => MODEL_PRIORITY[provider] || []);
257
248
  if (!m.length) {
258
249
  removeSmartRoute();
259
250
  return;
@@ -450,15 +441,69 @@ function resolveCommandOnPath(command) {
450
441
  }
451
442
  }
452
443
 
453
- async function writeNative9RouterSyncScript(projectDir) {
454
- const syncScriptPath = path.join(projectDir, '.openclaw', '9router-smart-route-sync.js');
455
- await fs.ensureDir(path.dirname(syncScriptPath));
456
- // Use native home data dir so sync script writes to same place 9router binary reads from
457
- const nativeDataDir = getNative9RouterDataDir();
458
- await fs.ensureDir(nativeDataDir);
459
- await fs.writeFile(syncScriptPath, build9RouterSmartRouteSyncScript(path.join(nativeDataDir, 'db.json')));
460
- return syncScriptPath;
461
- }
444
+ async function writeNative9RouterSyncScript(projectDir) {
445
+ const syncScriptPath = path.join(projectDir, '.openclaw', '9router-smart-route-sync.js');
446
+ await fs.ensureDir(path.dirname(syncScriptPath));
447
+ // Use native home data dir so sync script writes to same place 9router binary reads from
448
+ const nativeDataDir = getNative9RouterDataDir();
449
+ await fs.ensureDir(nativeDataDir);
450
+ await fs.writeFile(syncScriptPath, build9RouterSmartRouteSyncScript(path.join(nativeDataDir, 'db.json')));
451
+ return syncScriptPath;
452
+ }
453
+
454
+ async function writeNative9RouterPatchScript(projectDir) {
455
+ const patchScriptPath = path.join(projectDir, '.openclaw', 'patch-9router.js');
456
+ await fs.ensureDir(path.dirname(patchScriptPath));
457
+ await fs.writeFile(patchScriptPath, build9RouterPatchScript());
458
+ return patchScriptPath;
459
+ }
460
+
461
+ async function patchProject9RouterOpenClawConfig(projectDir) {
462
+ const configPath = path.join(projectDir, '.openclaw', 'openclaw.json');
463
+ if (!await fs.pathExists(configPath)) return false;
464
+ const config = await fs.readJson(configPath);
465
+ const provider = config?.models?.providers?.['9router'];
466
+ if (!provider) return false;
467
+ provider.baseUrl = get9RouterBaseUrl(detectProjectDeployMode(projectDir));
468
+ provider.apiKey = NINE_ROUTER_PROXY_API_KEY;
469
+ provider.api = 'openai-completions';
470
+ provider.models = build9RouterProviderConfig(provider.baseUrl).models;
471
+ await fs.writeJson(configPath, config, { spaces: 2 });
472
+ return true;
473
+ }
474
+
475
+ async function patchProjectDocker9Router(projectDir) {
476
+ const dockerDir = path.join(projectDir, 'docker', 'openclaw');
477
+ const composePath = path.join(dockerDir, 'docker-compose.yml');
478
+ if (!await fs.pathExists(composePath)) return false;
479
+
480
+ await fs.ensureDir(dockerDir);
481
+ await fs.writeFile(path.join(dockerDir, 'sync.js'), build9RouterSmartRouteSyncScript('/root/.9router/db.json'));
482
+ await fs.writeFile(path.join(dockerDir, 'patch-9router.js'), build9RouterPatchScript());
483
+ let compose = await fs.readFile(composePath, 'utf8');
484
+ compose = compose.replace(
485
+ /node -e "require\('fs'\)\.writeFileSync\('\/tmp\/sync\.js',Buffer\.from\('[^']*','base64'\)\.toString\(\)\)"/,
486
+ "cp /opt/sync.js /tmp/sync.js"
487
+ );
488
+ compose = compose.replace(
489
+ /(npm install -g [^\n]+\n)/,
490
+ `$1 cp /opt/patch-9router.js /tmp/patch-9router.js\n`
491
+ );
492
+ if (!compose.includes('node /tmp/patch-9router.js || true')) {
493
+ compose = compose.replace(
494
+ /(\s*node \/tmp\/sync\.js > \/tmp\/sync\.log 2>&1 &\n)/,
495
+ ` node /tmp/patch-9router.js || true\n$1`
496
+ );
497
+ }
498
+ if (!compose.includes('./sync.js:/opt/sync.js:ro')) {
499
+ compose = compose.replace(
500
+ /(\s*-\s*9router-data:\/root\/\.9router\s*\n)/,
501
+ `$1 - ./sync.js:/opt/sync.js:ro\n - ./patch-9router.js:/opt/patch-9router.js:ro\n`
502
+ );
503
+ }
504
+ await fs.writeFile(composePath, compose, 'utf8');
505
+ return true;
506
+ }
462
507
 
463
508
  function getGatewayAllowedOrigins(port) {
464
509
  const normalizedPort = Number(port) || 18791;
@@ -881,8 +926,26 @@ async function runUpgradeCommand() {
881
926
  isVi: false,
882
927
  }));
883
928
  }
884
-
885
- console.log(chalk.green('\nUpgrade artifacts refreshed successfully.'));
929
+
930
+ if (is9Router) {
931
+ await writeNative9RouterPatchScript(projectDir);
932
+ await patchProject9RouterOpenClawConfig(projectDir);
933
+ if (deployMode === 'docker') {
934
+ await patchProjectDocker9Router(projectDir);
935
+ } else {
936
+ await writeNative9RouterSyncScript(projectDir);
937
+ try {
938
+ execFileSync(process.execPath, [path.join(projectDir, '.openclaw', 'patch-9router.js')], {
939
+ cwd: projectDir,
940
+ stdio: 'ignore',
941
+ });
942
+ } catch {
943
+ // Best effort: start scripts also retry the patch before launch.
944
+ }
945
+ }
946
+ }
947
+
948
+ console.log(chalk.green('\nUpgrade artifacts refreshed successfully.'));
886
949
  if (deployMode === 'docker') {
887
950
  console.log(chalk.white(` Next: cd ${path.join(projectDir, 'docker', 'openclaw')} && docker compose up -d --build`));
888
951
  } else {
@@ -892,6 +955,7 @@ async function runUpgradeCommand() {
892
955
 
893
956
  function startNative9RouterPm2({ isVi, projectDir, appName, syncScriptPath }) {
894
957
  const routerAppName = `${appName}-9router`;
958
+ const syncAppName = `${appName}-9router-sync`;
895
959
  const routerLaunch = resolveNative9RouterDesktopLaunch();
896
960
  const normalizedProjectDir = projectDir.replace(/\\/g, '/');
897
961
  const normalizedSyncScriptPath = syncScriptPath ? syncScriptPath.replace(/\\/g, '/') : '';
@@ -921,7 +985,6 @@ function startNative9RouterPm2({ isVi, projectDir, appName, syncScriptPath }) {
921
985
  env: { ...process.env, ...routerLaunch.env }
922
986
  });
923
987
  if (syncScriptPath) {
924
- const syncAppName = `${appName}-9router-sync`;
925
988
  try {
926
989
  execSync(`pm2 delete ${syncAppName}`, {
927
990
  cwd: projectDir,
@@ -2152,13 +2215,13 @@ async function main() {
2152
2215
  } else if (providerKey === '9router') {
2153
2216
  authProfilesJson = {
2154
2217
  version: 1,
2155
- profiles: {
2156
- '9router-proxy': {
2157
- provider: '9router',
2158
- type: 'api_key',
2159
- key: 'sk-no-key',
2160
- },
2161
- },
2218
+ profiles: {
2219
+ '9router-proxy': {
2220
+ provider: '9router',
2221
+ type: 'api_key',
2222
+ key: NINE_ROUTER_PROXY_API_KEY,
2223
+ },
2224
+ },
2162
2225
  order: { '9router': ['9router-proxy'] },
2163
2226
  };
2164
2227
  }
@@ -2230,21 +2293,14 @@ async function main() {
2230
2293
  model: { primary: modelsPrimary, fallbacks: [] },
2231
2294
  })),
2232
2295
  },
2233
- ...(providerKey === '9router' ? {
2234
- models: {
2235
- mode: 'merge',
2236
- providers: {
2237
- '9router': {
2238
- baseUrl: deployMode === 'native' ? 'http://localhost:20128/v1' : 'http://9router:20128/v1',
2239
- apiKey: 'sk-no-key',
2240
- api: 'openai-completions',
2241
- models: [
2242
- { id: 'smart-route', name: 'Smart Proxy (Auto Route)', contextWindow: 200000, maxTokens: 8192 },
2243
- ],
2244
- },
2245
- },
2246
- },
2247
- } : provider.isLocal ? {
2296
+ ...(providerKey === '9router' ? {
2297
+ models: {
2298
+ mode: 'merge',
2299
+ providers: {
2300
+ '9router': build9RouterProviderConfig(get9RouterBaseUrl(deployMode)),
2301
+ },
2302
+ },
2303
+ } : provider.isLocal ? {
2248
2304
  models: {
2249
2305
  mode: 'merge',
2250
2306
  providers: {
@@ -2299,9 +2355,9 @@ async function main() {
2299
2355
  sharedConfig.skills = { entries: skillEntries };
2300
2356
  }
2301
2357
 
2302
- await fs.writeJson(path.join(rootClawDir, 'openclaw.json'), sharedConfig, { spaces: 2 });
2303
- await fs.writeFile(
2304
- path.join(projectDir, TELEGRAM_SETUP_GUIDE_FILENAME),
2358
+ await fs.writeJson(path.join(rootClawDir, 'openclaw.json'), sharedConfig, { spaces: 2 });
2359
+ await fs.writeFile(
2360
+ path.join(projectDir, TELEGRAM_SETUP_GUIDE_FILENAME),
2305
2361
  buildTelegramPostInstallChecklist({ isVi, bots, groupId }),
2306
2362
  'utf8',
2307
2363
  );
@@ -2436,21 +2492,14 @@ async function main() {
2436
2492
  model: { primary: modelsPrimary, fallbacks: [] }
2437
2493
  }]
2438
2494
  },
2439
- ...(providerKey === '9router' ? {
2440
- models: {
2441
- mode: 'merge',
2442
- providers: {
2443
- '9router': {
2444
- baseUrl: deployMode === 'native' ? 'http://localhost:20128/v1' : 'http://9router:20128/v1',
2445
- apiKey: 'sk-no-key',
2446
- api: 'openai-completions',
2447
- models: [
2448
- { id: 'smart-route', name: 'Smart Proxy (Auto Route)', contextWindow: 200000, maxTokens: 8192 }
2449
- ]
2450
- }
2451
- }
2452
- }
2453
- } : provider.isLocal ? {
2495
+ ...(providerKey === '9router' ? {
2496
+ models: {
2497
+ mode: 'merge',
2498
+ providers: {
2499
+ '9router': build9RouterProviderConfig(get9RouterBaseUrl(deployMode))
2500
+ }
2501
+ }
2502
+ } : provider.isLocal ? {
2454
2503
  models: {
2455
2504
  mode: 'merge',
2456
2505
  providers: {
@@ -2521,19 +2570,30 @@ async function main() {
2521
2570
  };
2522
2571
  }
2523
2572
  botConfig.channels['telegram'] = telegramConfig;
2524
- } else if (hasZaloPersonal(channelKey)) {
2525
- botConfig.channels['zalouser'] = {
2526
- enabled: true,
2527
- dmPolicy: 'open',
2528
- allowFrom: ['*']
2529
- };
2573
+ } else if (hasZaloPersonal(channelKey)) {
2574
+ botConfig.channels['zalouser'] = {
2575
+ enabled: true,
2576
+ defaultAccount: 'default',
2577
+ dmPolicy: 'open',
2578
+ allowFrom: ['*'],
2579
+ groupPolicy: 'allowlist',
2580
+ groupAllowFrom: ['*'],
2581
+ historyLimit: 50,
2582
+ groups: {
2583
+ '*': {
2584
+ enabled: true,
2585
+ requireMention: false,
2586
+ },
2587
+ },
2588
+ autoReply: true,
2589
+ };
2530
2590
  } else if (channelKey === 'zalo-bot') {
2531
2591
  botConfig.channels['zalo'] = { enabled: true, provider: 'official_account' };
2532
2592
  }
2533
2593
 
2534
- await fs.writeJson(path.join(loopBotDir, '.openclaw', 'openclaw.json'), botConfig, { spaces: 2 });
2535
-
2536
- // ── Workspace files: use shared writeWorkspaceFiles() ──────────────────────
2594
+ await fs.writeJson(path.join(loopBotDir, '.openclaw', 'openclaw.json'), botConfig, { spaces: 2 });
2595
+
2596
+ // ── Workspace files: use shared writeWorkspaceFiles() ──────────────────────
2537
2597
  const dockerWorkspaceDir = path.join(loopBotDir, '.openclaw', loopWorkspaceDir);
2538
2598
  const dockerOwnAliases = [loopBotName, bots[bIndex]?.slashCmd || '', `bot ${bIndex + 1}`].filter(Boolean);
2539
2599
  const dockerOtherAgents = teamRoster
@@ -2744,10 +2804,19 @@ async function main() {
2744
2804
  }
2745
2805
  }
2746
2806
 
2747
- let native9RouterSyncScriptPath = null;
2748
- if (providerKey === '9router') {
2749
- native9RouterSyncScriptPath = await writeNative9RouterSyncScript(projectDir);
2750
- }
2807
+ let native9RouterSyncScriptPath = null;
2808
+ if (providerKey === '9router') {
2809
+ await writeNative9RouterPatchScript(projectDir);
2810
+ native9RouterSyncScriptPath = await writeNative9RouterSyncScript(projectDir);
2811
+ try {
2812
+ execFileSync(process.execPath, [path.join(projectDir, '.openclaw', 'patch-9router.js')], {
2813
+ cwd: projectDir,
2814
+ stdio: 'ignore',
2815
+ });
2816
+ } catch {
2817
+ // Start scripts retry this patch before launching 9router.
2818
+ }
2819
+ }
2751
2820
 
2752
2821
  await ensureProjectRuntimeDirs(projectDir, isVi);
2753
2822
 
@@ -2817,10 +2886,10 @@ async function main() {
2817
2886
  cwd: projectDir,
2818
2887
  env: getProjectRuntimeEnv(projectDir, native9RouterLaunch.env)
2819
2888
  }).unref();
2820
- const routerHealth = await waitFor9RouterApiReady();
2821
- if (native9RouterSyncScriptPath) {
2822
- spawnBackgroundProcess(process.execPath, [native9RouterSyncScriptPath], {
2823
- cwd: projectDir
2889
+ const routerHealth = await waitFor9RouterApiReady();
2890
+ if (native9RouterSyncScriptPath) {
2891
+ spawnBackgroundProcess(process.execPath, [native9RouterSyncScriptPath], {
2892
+ cwd: projectDir
2824
2893
  }).unref();
2825
2894
  }
2826
2895
  console.log(chalk.gray(isVi
@@ -65,15 +65,26 @@
65
65
  channelConfig: {
66
66
  zalouser: {
67
67
  enabled: true,
68
+ defaultAccount: 'default',
68
69
  accounts: {
69
70
  default: {
70
71
  dmPolicy: 'open',
71
72
  allowFrom: ['*'],
72
73
  groupPolicy: 'allowlist',
74
+ groupAllowFrom: ['*'],
73
75
  },
74
76
  },
75
77
  dmPolicy: 'open',
78
+ allowFrom: ['*'],
76
79
  groupPolicy: 'allowlist',
80
+ groupAllowFrom: ['*'],
81
+ historyLimit: 50,
82
+ groups: {
83
+ '*': {
84
+ enabled: true,
85
+ requireMention: false,
86
+ },
87
+ },
77
88
  },
78
89
  },
79
90
  pluginInstall: '@openclaw/zalouser',
@@ -161,4 +172,3 @@
161
172
  - ❌ DO NOT run containers with --privileged
162
173
  - ✅ Limit exposed ports (only 38789)`,
163
174
  };
164
-