create-openclaw-bot 5.6.7 → 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 +18 -19
- package/README.vi.md +18 -19
- package/dist/cli.js +214 -101
- package/dist/setup/data/channels.js +11 -1
- package/dist/setup/shared/common-gen.js +86 -0
- package/dist/setup/shared/docker-gen.js +73 -30
- package/dist/setup/shared/install-gen.js +23 -3
- package/dist/setup.js +217 -121
- package/package.json +1 -1
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.
|
|
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.
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
<details>
|
|
36
|
-
<summary><b>Previous: What's new in v5.
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
|
|
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.
|
|
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.
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
<details>
|
|
36
|
-
<summary><b>Trước đó: Có gì mới ở v5.
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
|
|
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ự vá source files 9Router khi setup, upgrade và 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 có thể chọn model cụ thể.
|
|
33
|
+
- 💬 **Config nhóm Zalo Personal** — Bổ sung `defaultAccount`, `groupAllowFrom`, `historyLimit`, wildcard group config và `autoReply` để xử lý 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" và 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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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,
|
|
@@ -186,32 +193,39 @@ function resolveNative9RouterDesktopLaunch() {
|
|
|
186
193
|
args: ['-n', '-H', '0.0.0.0', '-p', '20128', '--skip-update'],
|
|
187
194
|
env: {
|
|
188
195
|
PORT: '20128',
|
|
189
|
-
HOSTNAME: '0.0.0.0'
|
|
196
|
+
HOSTNAME: '0.0.0.0',
|
|
197
|
+
// Ensures 9router stores data in the user home dir, matching where sync script writes db.json
|
|
198
|
+
DATA_DIR: getNative9RouterDataDir(),
|
|
190
199
|
}
|
|
191
200
|
};
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
function build9RouterSmartRouteSyncScript(dbPath) {
|
|
195
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);
|
|
196
208
|
return `function bootstrap() {
|
|
197
209
|
const fs = require('fs');
|
|
198
210
|
const path = require('path');
|
|
199
211
|
const dbPath = ${safeDbPath};
|
|
200
|
-
const ROUTER
|
|
201
|
-
const MODEL_PRIORITY
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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 = {};
|
|
215
229
|
try {
|
|
216
230
|
db = JSON.parse(fs.readFileSync(dbPath, 'utf8'));
|
|
217
231
|
} catch {}
|
|
@@ -225,11 +239,12 @@ function build9RouterSmartRouteSyncScript(dbPath) {
|
|
|
225
239
|
console.log('Removed smart-route (no active providers)');
|
|
226
240
|
}
|
|
227
241
|
};
|
|
228
|
-
if (!a.length) {
|
|
229
|
-
removeSmartRoute();
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
|
|
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] || []);
|
|
233
248
|
if (!m.length) {
|
|
234
249
|
removeSmartRoute();
|
|
235
250
|
return;
|
|
@@ -426,13 +441,69 @@ function resolveCommandOnPath(command) {
|
|
|
426
441
|
}
|
|
427
442
|
}
|
|
428
443
|
|
|
429
|
-
async function writeNative9RouterSyncScript(projectDir) {
|
|
430
|
-
const syncScriptPath = path.join(projectDir, '.openclaw', '9router-smart-route-sync.js');
|
|
431
|
-
await fs.ensureDir(path.dirname(syncScriptPath));
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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
|
+
}
|
|
436
507
|
|
|
437
508
|
function getGatewayAllowedOrigins(port) {
|
|
438
509
|
const normalizedPort = Number(port) || 18791;
|
|
@@ -855,8 +926,26 @@ async function runUpgradeCommand() {
|
|
|
855
926
|
isVi: false,
|
|
856
927
|
}));
|
|
857
928
|
}
|
|
858
|
-
|
|
859
|
-
|
|
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.'));
|
|
860
949
|
if (deployMode === 'docker') {
|
|
861
950
|
console.log(chalk.white(` Next: cd ${path.join(projectDir, 'docker', 'openclaw')} && docker compose up -d --build`));
|
|
862
951
|
} else {
|
|
@@ -866,6 +955,7 @@ async function runUpgradeCommand() {
|
|
|
866
955
|
|
|
867
956
|
function startNative9RouterPm2({ isVi, projectDir, appName, syncScriptPath }) {
|
|
868
957
|
const routerAppName = `${appName}-9router`;
|
|
958
|
+
const syncAppName = `${appName}-9router-sync`;
|
|
869
959
|
const routerLaunch = resolveNative9RouterDesktopLaunch();
|
|
870
960
|
const normalizedProjectDir = projectDir.replace(/\\/g, '/');
|
|
871
961
|
const normalizedSyncScriptPath = syncScriptPath ? syncScriptPath.replace(/\\/g, '/') : '';
|
|
@@ -895,7 +985,6 @@ function startNative9RouterPm2({ isVi, projectDir, appName, syncScriptPath }) {
|
|
|
895
985
|
env: { ...process.env, ...routerLaunch.env }
|
|
896
986
|
});
|
|
897
987
|
if (syncScriptPath) {
|
|
898
|
-
const syncAppName = `${appName}-9router-sync`;
|
|
899
988
|
try {
|
|
900
989
|
execSync(`pm2 delete ${syncAppName}`, {
|
|
901
990
|
cwd: projectDir,
|
|
@@ -2126,13 +2215,13 @@ async function main() {
|
|
|
2126
2215
|
} else if (providerKey === '9router') {
|
|
2127
2216
|
authProfilesJson = {
|
|
2128
2217
|
version: 1,
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2218
|
+
profiles: {
|
|
2219
|
+
'9router-proxy': {
|
|
2220
|
+
provider: '9router',
|
|
2221
|
+
type: 'api_key',
|
|
2222
|
+
key: NINE_ROUTER_PROXY_API_KEY,
|
|
2223
|
+
},
|
|
2224
|
+
},
|
|
2136
2225
|
order: { '9router': ['9router-proxy'] },
|
|
2137
2226
|
};
|
|
2138
2227
|
}
|
|
@@ -2204,21 +2293,14 @@ async function main() {
|
|
|
2204
2293
|
model: { primary: modelsPrimary, fallbacks: [] },
|
|
2205
2294
|
})),
|
|
2206
2295
|
},
|
|
2207
|
-
...(providerKey === '9router' ? {
|
|
2208
|
-
models: {
|
|
2209
|
-
mode: 'merge',
|
|
2210
|
-
providers: {
|
|
2211
|
-
'9router':
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
models: [
|
|
2216
|
-
{ id: 'smart-route', name: 'Smart Proxy (Auto Route)', contextWindow: 200000, maxTokens: 8192 },
|
|
2217
|
-
],
|
|
2218
|
-
},
|
|
2219
|
-
},
|
|
2220
|
-
},
|
|
2221
|
-
} : provider.isLocal ? {
|
|
2296
|
+
...(providerKey === '9router' ? {
|
|
2297
|
+
models: {
|
|
2298
|
+
mode: 'merge',
|
|
2299
|
+
providers: {
|
|
2300
|
+
'9router': build9RouterProviderConfig(get9RouterBaseUrl(deployMode)),
|
|
2301
|
+
},
|
|
2302
|
+
},
|
|
2303
|
+
} : provider.isLocal ? {
|
|
2222
2304
|
models: {
|
|
2223
2305
|
mode: 'merge',
|
|
2224
2306
|
providers: {
|
|
@@ -2273,14 +2355,28 @@ async function main() {
|
|
|
2273
2355
|
sharedConfig.skills = { entries: skillEntries };
|
|
2274
2356
|
}
|
|
2275
2357
|
|
|
2276
|
-
await fs.writeJson(path.join(rootClawDir, 'openclaw.json'), sharedConfig, { spaces: 2 });
|
|
2277
|
-
await fs.writeFile(
|
|
2278
|
-
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),
|
|
2279
2361
|
buildTelegramPostInstallChecklist({ isVi, bots, groupId }),
|
|
2280
2362
|
'utf8',
|
|
2281
2363
|
);
|
|
2282
2364
|
// Generate ecosystem.config.js for PM2 native multi-bot
|
|
2283
2365
|
if (deployMode === 'native') {
|
|
2366
|
+
// Also write config to ~/.openclaw/ — openclaw binary on Linux/Mac reads from home dir
|
|
2367
|
+
const homeClawDir = path.join(os.homedir(), '.openclaw');
|
|
2368
|
+
await fs.ensureDir(homeClawDir);
|
|
2369
|
+
const homeConfig = JSON.parse(JSON.stringify(sharedConfig));
|
|
2370
|
+
for (const agent of (homeConfig.agents && homeConfig.agents.list || [])) {
|
|
2371
|
+
// workspace is relative to projectDir (.openclaw/workspace-X); agentDir is relative to rootClawDir (agents/X/agent)
|
|
2372
|
+
if (agent.workspace && !path.isAbsolute(agent.workspace)) agent.workspace = path.join(projectDir, agent.workspace);
|
|
2373
|
+
if (agent.agentDir && !path.isAbsolute(agent.agentDir)) agent.agentDir = path.join(rootClawDir, agent.agentDir);
|
|
2374
|
+
}
|
|
2375
|
+
await fs.writeJson(path.join(homeClawDir, 'openclaw.json'), homeConfig, { spaces: 2 });
|
|
2376
|
+
if (Object.keys(authProfilesJson).length > 0) {
|
|
2377
|
+
await fs.writeJson(path.join(homeClawDir, 'auth-profiles.json'), authProfilesJson, { spaces: 2 });
|
|
2378
|
+
}
|
|
2379
|
+
const safeRootClawDir = rootClawDir.replace(/\\/g, '/');
|
|
2284
2380
|
const pm2Apps = [
|
|
2285
2381
|
' {',
|
|
2286
2382
|
` name: 'openclaw-multibot',`,
|
|
@@ -2290,7 +2386,11 @@ async function main() {
|
|
|
2290
2386
|
` interpreter: 'none',`,
|
|
2291
2387
|
` autorestart: true,`,
|
|
2292
2388
|
` watch: false,`,
|
|
2293
|
-
` env: {
|
|
2389
|
+
` env: {`,
|
|
2390
|
+
` NODE_ENV: 'production',`,
|
|
2391
|
+
` OPENCLAW_HOME: '\',`,
|
|
2392
|
+
` OPENCLAW_STATE_DIR: '\',`,
|
|
2393
|
+
` }`,
|
|
2294
2394
|
' }',
|
|
2295
2395
|
].join('\n');
|
|
2296
2396
|
const ecosystemContent = [
|
|
@@ -2392,21 +2492,14 @@ async function main() {
|
|
|
2392
2492
|
model: { primary: modelsPrimary, fallbacks: [] }
|
|
2393
2493
|
}]
|
|
2394
2494
|
},
|
|
2395
|
-
...(providerKey === '9router' ? {
|
|
2396
|
-
models: {
|
|
2397
|
-
mode: 'merge',
|
|
2398
|
-
providers: {
|
|
2399
|
-
'9router':
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
models: [
|
|
2404
|
-
{ id: 'smart-route', name: 'Smart Proxy (Auto Route)', contextWindow: 200000, maxTokens: 8192 }
|
|
2405
|
-
]
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
} : provider.isLocal ? {
|
|
2495
|
+
...(providerKey === '9router' ? {
|
|
2496
|
+
models: {
|
|
2497
|
+
mode: 'merge',
|
|
2498
|
+
providers: {
|
|
2499
|
+
'9router': build9RouterProviderConfig(get9RouterBaseUrl(deployMode))
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
} : provider.isLocal ? {
|
|
2410
2503
|
models: {
|
|
2411
2504
|
mode: 'merge',
|
|
2412
2505
|
providers: {
|
|
@@ -2477,19 +2570,30 @@ async function main() {
|
|
|
2477
2570
|
};
|
|
2478
2571
|
}
|
|
2479
2572
|
botConfig.channels['telegram'] = telegramConfig;
|
|
2480
|
-
} else if (hasZaloPersonal(channelKey)) {
|
|
2481
|
-
botConfig.channels['zalouser'] = {
|
|
2482
|
-
enabled: true,
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
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
|
+
};
|
|
2486
2590
|
} else if (channelKey === 'zalo-bot') {
|
|
2487
2591
|
botConfig.channels['zalo'] = { enabled: true, provider: 'official_account' };
|
|
2488
2592
|
}
|
|
2489
2593
|
|
|
2490
|
-
await fs.writeJson(path.join(loopBotDir, '.openclaw', 'openclaw.json'), botConfig, { spaces: 2 });
|
|
2491
|
-
|
|
2492
|
-
// ── 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() ──────────────────────
|
|
2493
2597
|
const dockerWorkspaceDir = path.join(loopBotDir, '.openclaw', loopWorkspaceDir);
|
|
2494
2598
|
const dockerOwnAliases = [loopBotName, bots[bIndex]?.slashCmd || '', `bot ${bIndex + 1}`].filter(Boolean);
|
|
2495
2599
|
const dockerOtherAgents = teamRoster
|
|
@@ -2700,10 +2804,19 @@ async function main() {
|
|
|
2700
2804
|
}
|
|
2701
2805
|
}
|
|
2702
2806
|
|
|
2703
|
-
let native9RouterSyncScriptPath = null;
|
|
2704
|
-
if (providerKey === '9router') {
|
|
2705
|
-
|
|
2706
|
-
|
|
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
|
+
}
|
|
2707
2820
|
|
|
2708
2821
|
await ensureProjectRuntimeDirs(projectDir, isVi);
|
|
2709
2822
|
|
|
@@ -2773,10 +2886,10 @@ async function main() {
|
|
|
2773
2886
|
cwd: projectDir,
|
|
2774
2887
|
env: getProjectRuntimeEnv(projectDir, native9RouterLaunch.env)
|
|
2775
2888
|
}).unref();
|
|
2776
|
-
const routerHealth = await waitFor9RouterApiReady();
|
|
2777
|
-
if (native9RouterSyncScriptPath) {
|
|
2778
|
-
spawnBackgroundProcess(process.execPath, [native9RouterSyncScriptPath], {
|
|
2779
|
-
cwd: projectDir
|
|
2889
|
+
const routerHealth = await waitFor9RouterApiReady();
|
|
2890
|
+
if (native9RouterSyncScriptPath) {
|
|
2891
|
+
spawnBackgroundProcess(process.execPath, [native9RouterSyncScriptPath], {
|
|
2892
|
+
cwd: projectDir
|
|
2780
2893
|
}).unref();
|
|
2781
2894
|
}
|
|
2782
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
|
-
|