create-openclaw-bot 5.1.13 → 5.1.14

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/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Changelog (English)
2
2
 
3
- ## [5.1.13] — 2026-04-08
3
+
4
+ ## [5.1.14] — 2026-04-08
5
+
6
+ ### OpenClaw stability and Docker fixes
7
+
8
+ - Pinned OpenClaw back to `openclaw@2026.4.5` because the update published on `April 8, 2026` is currently broken.
9
+ - Fixed Dockerfile generation for Windows Docker setups to avoid startup failures caused by bad command escaping and invalid `allowedOrigins`.
10
+ - Added guidance to use `Node.js 20` through `24`, and to avoid `Node.js 25` for now for better OpenClaw stability.
11
+
12
+ ## [5.1.13] — 2026-04-08
4
13
 
5
14
  ### 🐛 macOS Install Fixes & Wizard Stability
6
15
 
@@ -403,3 +412,4 @@ All notable changes to this project will be documented in this file.
403
412
  - Configured Telegram-only support.
404
413
  - Configured Google Gemini single provider support.
405
414
  - Included manual configuration file setup instructions.
415
+
package/CHANGELOG.vi.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Changelog (Tiếng Việt)
2
2
 
3
- ## [5.1.13] — 2026-04-08
3
+
4
+ ## [5.1.14] — 2026-04-08
5
+
6
+ ### Sửa lỗi ổn định OpenClaw và Docker
7
+
8
+ - Pin lại OpenClaw về `openclaw@2026.4.5` vì bản cập nhật ngày `08/04/2026` đang lỗi.
9
+ - Sửa Dockerfile cho các case Docker trên Windows để tránh lỗi startup do escape command sai và lỗi `allowedOrigins`.
10
+ - Thêm ghi chú khuyên dùng `Node.js 20` đến `24`, tạm tránh `Node.js 25` để ổn định hơn với OpenClaw.
11
+
12
+ ## [5.1.13] — 2026-04-08
4
13
 
5
14
  ### 🐛 Sửa lỗi cài macOS & ổn định Wizard
6
15
 
@@ -395,3 +404,4 @@ Tất cả những thay đổi nổi bật của dự án sẽ được ghi ché
395
404
  - Telegram-only configuration
396
405
  - Google Gemini single provider support
397
406
  - Manual config file instructions
407
+
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.1.13-0EA5E9?style=for-the-badge" alt="Version 5.1.13" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.1.14-0EA5E9?style=for-the-badge" alt="Version 5.1.14" /></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,16 +24,11 @@ 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.1.13
27
+ ## 🆕 What's new in v5.1.14
28
28
 
29
- - 💻 **OS-First Setup** — Step 1 is now choosing your OS (Windows, macOS, Ubuntu, VPS). All scripts, configs, and instructions are generated to match.
30
- - 🧠 **Gemma 44 sizes** `gemma4:e2b` (~4 GB), `gemma4:e4b` (~8 GB), `gemma4:26b` (~18 GB), `gemma4:31b` (~24 GB). Auto-pulled on first launch.
31
- - 📄 **Consistent script naming** — Scripts are generated per OS: `setup-openclaw-docker-win.bat`, `setup-openclaw-docker-macos.sh`, `setup-openclaw-vps.sh`... No more environment confusion.
32
- - 🌐 **Native Install for Ubuntu/VPS** — No Docker needed. Both CLI and Web Wizard support running directly with PM2 — less RAM overhead, stable 24/7.
33
- - 🤖 **Multi-Bot Deployment** — Deploy up to **5 independent Telegram bots** in one setup. Each bot runs in its own isolated workspace (`bot1/`, `bot2/`...) with its own token, name, slash command, and AI personality.
34
- - 💬 **Department Room Model** — Add all bots to one Telegram group and they behave like a professional team. Bots stay silent by default, only responding when @mentioned or their slash command is used — no spam, no chaos.
35
- - 🔗 **Group ID Helper** — "Get Group ID" button in Web Wizard + step-by-step guide in CLI. Opens @userinfobot directly — no documentation hunting needed.
36
- - 🔐 **Zalo Personal QR Login** — Zalo Personal now uses direct QR login flow for both native and Docker. Setup prints exact QR path + copy/login commands — no need to go through `openclaw onboard`.
29
+ - 🔒 **Pinned OpenClaw version** — The OpenClaw update published on `April 8, 2026` is currently broken, so setup now stays on `openclaw@2026.4.5` for stability.
30
+ - 🐳 **Dockerfile fixes**Fixed the Windows Docker flow so startup no longer breaks on bad command escaping or invalid generated `allowedOrigins`.
31
+ - 🟢 **Stable Node.js note** — Added guidance to use `Node.js 20` through `24`, and to avoid `Node.js 25` for now due to reported OpenClaw issues.
37
32
 
38
33
  <details>
39
34
  <summary><b>Previous: What's new in v5.0.0</b></summary>
@@ -102,7 +97,9 @@ npx create-openclaw-bot
102
97
 
103
98
  Run in your terminal → follow the interactive prompts → startup script is generated automatically.
104
99
 
105
- > Requires: **Node.js 20 LTS** or newer. Check: `node -v`
100
+ > Requires: **Node.js 20/22/24**. Check: `node -v`
101
+ >
102
+ > Note: **avoid Node.js 25 for now**. There are reports of OpenClaw failing on Node 25.
106
103
 
107
104
  <details>
108
105
  <summary><b>3️⃣ Option C — AI Agent (Antigravity)</b></summary>
@@ -112,7 +109,7 @@ Run in your terminal → follow the interactive prompts → startup script is ge
112
109
  2. Open this repo as your workspace
113
110
  3. Paste into chat:
114
111
  ```
115
- Read SETUP.md and set up OpenClaw v5.1.11 for me.
112
+ Read SETUP.md and set up OpenClaw v5.1.14 for me.
116
113
  My bot token is X. Use 9Router (no API key).
117
114
  My project folder: <YOUR_PATH>
118
115
  ```
@@ -127,7 +124,7 @@ Run in your terminal → follow the interactive prompts → startup script is ge
127
124
 
128
125
  | Requirement | Notes |
129
126
  | ----------------------- | ------------------------------------------------------------------------- |
130
- | **Node.js 20 LTS** | [Download](https://nodejs.org/) · Check: `node -v` |
127
+ | **Node.js 20/22/24** | [Download](https://nodejs.org/) · Check: `node -v` · Avoid Node 25 for now |
131
128
  | **An AI provider** | 9Router (free) or Gemini/Claude/GPT-4o |
132
129
  | **Bot Token** | From Telegram BotFather or Zalo Developer |
133
130
  | **Ollama** _(optional)_ | Only if you want to run Gemma 4 locally · [Download](https://ollama.com/) |
@@ -136,7 +133,7 @@ Run in your terminal → follow the interactive prompts → startup script is ge
136
133
 
137
134
  | Requirement | Notes |
138
135
  | ------------------------------- | --------------------------------------------------------------------------------------------- |
139
- | **Node.js 20 LTS** | [Download](https://nodejs.org/) · Check: `node -v` |
136
+ | **Node.js 20/22/24** | [Download](https://nodejs.org/) · Check: `node -v` · Avoid Node 25 for now |
140
137
  | **Docker Desktop + Compose V2** | [Download](https://www.docker.com/products/docker-desktop/) · Check: `docker compose version` |
141
138
  | **An AI provider** | 9Router runs as a sidecar container — no separate install needed |
142
139
  | **Bot Token** | From Telegram BotFather or Zalo Developer |
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.1.11-0EA5E9?style=for-the-badge" alt="Version 5.1.13" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.1.14-0EA5E9?style=for-the-badge" alt="Version 5.1.14" /></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,16 +24,11 @@ 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.1.13
27
+ ## 🆕 Có gì mới trong v5.1.14
28
28
 
29
- - 💻 **OS-First Setup** — Bước đầu tiên bây giờ chọn hệ điều hành của bạn (Windows, macOS, Ubuntu, VPS). Toàn bộ script, cấu hình và hướng dẫn được tạo ra phù hợp với lựa chọn đó.
30
- - 🧠 **Gemma 44 kích thước** `gemma4:e2b` (~4 GB), `gemma4:e4b` (~8 GB), `gemma4:26b` (~18 GB), `gemma4:31b` (~24 GB). Tự pull về khi bot khởi động lần đầu.
31
- - 📄 **Tên script nhất quán** — Script sinh ra theo đúng OS đã chọn: `setup-openclaw-docker-win.bat`, `setup-openclaw-docker-macos.sh`, `setup-openclaw-vps.sh`... Không còn nhầm lẫn môi trường.
32
- - 🌐 **Native Install cho Ubuntu/VPS** — Không cần Docker. CLI và Web Wizard đều hỗ trợ chạy trực tiếp với PM2 — tiết kiệm RAM, ổn định 24/7.
33
- - 🤖 **Triển khai nhiều Bot** — Setup tới **5 Telegram bot độc lập** chỉ trong một lần cài. Mỗi bot sống trong thư mục riêng (`bot1/`, `bot2/`...) với token, tên, slash command và cá tính AI riêng biệt.
34
- - 💬 **Chế độ Phòng Ban** — Thêm tất cả bot vào một Telegram group, chúng sẽ hoạt động như một đội nhân viên chuyên nghiệp. Bot im lặng theo mặc định — chỉ phản hồi khi được @tag hoặc gọi đúng lệnh slash, không spam, không ồn ào.
35
- - 🔗 **Nút lấy Group ID tự động** — Nút "Lấy Group ID" ngay trong Web Wizard + hướng dẫn từng bước trong CLI. Mở @userinfobot thẳng luôn — không cần mò docs.
36
- - 🔐 **Zalo Personal QR Login** — Zalo Personal giờ dùng flow login `zalouser` trực tiếp cho cả native lẫn Docker. Setup in sẵn lệnh login, lệnh copy QR và đường dẫn file QR, không cần vòng qua `openclaw onboard`.
29
+ - 🔒 **Pin lại OpenClaw** — Bản OpenClaw cập nhật ngày `08/04/2026` đang lỗi, nên setup được fix để giữ `openclaw@2026.4.5` cho ổn định.
30
+ - 🐳 **Fix Dockerfile**Sửa luồng Docker cho Windows để không còn lỗi startup do command/escaping sai tránh lỗi `allowedOrigins` bị sinh ra không hợp lệ.
31
+ - 🟢 **Ghi chú Node.js ổn định** — Thêm note khuyên dùng `Node.js 20` đến `24`, tạm tránh `Node.js 25` report lỗi với OpenClaw.
37
32
 
38
33
  <details>
39
34
  <summary><b>Trước đó: Có gì mới ở v5.0.0</b></summary>
@@ -102,7 +97,9 @@ npx create-openclaw-bot
102
97
 
103
98
  Chạy lệnh trên trong Terminal → làm theo các prompt tương tác → script khởi động được tạo tự động.
104
99
 
105
- > Yêu cầu: **Node.js 20 LTS** trở lên. Kiểm tra: `node -v`
100
+ > Yêu cầu: **Node.js 20/22/24**. Kiểm tra: `node -v`
101
+ >
102
+ > Lưu ý: **tạm tránh Node.js 25**. Đã có báo cáo OpenClaw lỗi với Node 25.
106
103
 
107
104
  <details>
108
105
  <summary><b>3️⃣ Cách C — AI Agent (Antigravity)</b></summary>
@@ -112,7 +109,7 @@ Chạy lệnh trên trong Terminal → làm theo các prompt tương tác → sc
112
109
  2. Mở repo này làm workspace
113
110
  3. Paste vào chat:
114
111
  ```
115
- Read SETUP.md and set up OpenClaw v5.1.11 for me.
112
+ Read SETUP.md and set up OpenClaw v5.1.14 for me.
116
113
  My bot token is X. Use 9Router (no API key).
117
114
  My project folder: <THƯ_MỤC_CỦA_BẠN>
118
115
  ```
@@ -127,7 +124,7 @@ Chạy lệnh trên trong Terminal → làm theo các prompt tương tác → sc
127
124
 
128
125
  | Yêu cầu | Ghi chú |
129
126
  | ----------------------- | ------------------------------------------------------------------- |
130
- | **Node.js 20 LTS** | [Tải về](https://nodejs.org/) · Kiểm tra: `node -v` |
127
+ | **Node.js 20/22/24** | [Tải về](https://nodejs.org/) · Kiểm tra: `node -v` · Tạm tránh Node 25 |
131
128
  | **Một AI provider** | 9Router (miễn phí) hoặc Gemini/Claude/GPT-4o |
132
129
  | **Bot Token** | Từ Telegram BotFather hoặc Zalo Developer |
133
130
  | **Ollama** _(tuỳ chọn)_ | Chỉ cần nếu muốn chạy Gemma 4 local · [Tải về](https://ollama.com/) |
@@ -136,7 +133,7 @@ Chạy lệnh trên trong Terminal → làm theo các prompt tương tác → sc
136
133
 
137
134
  | Yêu cầu | Ghi chú |
138
135
  | ------------------------------- | ---------------------------------------------------------------------------------------------- |
139
- | **Node.js 20 LTS** | [Tải về](https://nodejs.org/) · Kiểm tra: `node -v` |
136
+ | **Node.js 20/22/24** | [Tải về](https://nodejs.org/) · Kiểm tra: `node -v` · Tạm tránh Node 25 |
140
137
  | **Docker Desktop + Compose V2** | [Tải về](https://www.docker.com/products/docker-desktop/) · Kiểm tra: `docker compose version` |
141
138
  | **Một AI provider** | 9Router chạy như sidecar container — không cần cài riêng |
142
139
  | **Bot Token** | Từ Telegram BotFather hoặc Zalo Developer |
package/cli.js CHANGED
@@ -6,7 +6,8 @@ import path from 'path';
6
6
  import os from 'os';
7
7
  import chalk from 'chalk';
8
8
  import { spawn, execSync, execFileSync } from 'child_process';
9
- const TELEGRAM_RELAY_PLUGIN_ID = 'openclaw-telegram-multibot-relay';
9
+ const TELEGRAM_RELAY_PLUGIN_ID = 'openclaw-telegram-multibot-relay';
10
+ const OPENCLAW_NPM_SPEC = 'openclaw@2026.4.5';
10
11
  // Use plain npm package name — clawhub: protocol not supported in all OpenClaw versions
11
12
  const TELEGRAM_RELAY_PLUGIN_SPEC = TELEGRAM_RELAY_PLUGIN_ID;
12
13
 
@@ -345,11 +346,11 @@ function installLatestOpenClaw({ isVi, osChoice }) {
345
346
  return;
346
347
  }
347
348
 
348
- console.log(chalk.cyan(isVi
349
- ? '\n📦 Dang cai/cap nhat openclaw@latest...'
350
- : '\n📦 Installing/updating openclaw@latest...'));
351
-
352
- if (!installGlobalPackage('openclaw@latest', { isVi, osChoice, displayName: 'openclaw' })) {
349
+ console.log(chalk.cyan(isVi
350
+ ? `\n📦 Dang cai/cap nhat ${OPENCLAW_NPM_SPEC}...`
351
+ : `\n📦 Installing/updating ${OPENCLAW_NPM_SPEC}...`));
352
+
353
+ if (!installGlobalPackage(OPENCLAW_NPM_SPEC, { isVi, osChoice, displayName: 'openclaw' })) {
353
354
  process.exit(1);
354
355
  }
355
356
 
@@ -1370,7 +1371,7 @@ async function main() {
1370
1371
  }
1371
1372
 
1372
1373
 
1373
- const patchScript = `const fs=require('fs'),os=require('os'),p='/root/.openclaw/openclaw.json';if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const a=new Set(['http://localhost:18791','http://127.0.0.1:18791','http://0.0.0.0:18791']);for(const entries of Object.values(os.networkInterfaces()||{})){for(const entry of entries||[]){if(!entry||entry.internal||entry.family!=='IPv4'||!entry.address)continue;a.add(\`http://\${entry.address}:18791\`);}}c.tools=Object.assign({},c.tools,{profile:'full',exec:{host:'gateway',security:'full',ask:'off'}});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'custom',customBindHost:'0.0.0.0',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a)})});fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
1374
+ const patchScript = `const fs=require('fs'),os=require('os'),p='/root/.openclaw/openclaw.json';if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const a=new Set(['http://localhost:18791','http://127.0.0.1:18791','http://0.0.0.0:18791']);for(const entries of Object.values(os.networkInterfaces()||{})){for(const entry of entries||[]){if(!entry||entry.internal||entry.family!=='IPv4'||!entry.address)continue;a.add('http://' + entry.address + ':18791');}}c.tools=Object.assign({},c.tools,{profile:'full',exec:{host:'gateway',security:'full',ask:'off'}});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'custom',customBindHost:'0.0.0.0',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
1374
1375
  const b64Patch = Buffer.from(patchScript).toString('base64');
1375
1376
 
1376
1377
  // Browser Playwright (both desktop & server modes need chromium)
@@ -1405,10 +1406,10 @@ async function main() {
1405
1406
 
1406
1407
  ];
1407
1408
  if (browserDockerLines) dockerfileLines.push(browserDockerLines);
1408
- dockerfileLines.push(
1409
+ dockerfileLines.push(
1409
1410
  '',
1410
1411
  `ARG CACHEBUST=${Date.now()}`,
1411
- 'RUN npm install -g openclaw@latest',
1412
+ `RUN npm install -g ${OPENCLAW_NPM_SPEC} grammy`,
1412
1413
  '',
1413
1414
  '# Fix chat.send dropping resolved agent timeout into reply pipeline.',
1414
1415
  '# Without this, Telegram/WebChat paths fall back to an internal 300s default even when',
@@ -1420,10 +1421,12 @@ async function main() {
1420
1421
  'EXPOSE 18791',
1421
1422
  '',
1422
1423
  `CMD sh -c "node -e \\"eval(Buffer.from('${b64Patch}','base64').toString())\\" && ${skillInstallCmd}${relayInstallCmd}${socatBridge}(while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done) & openclaw gateway run"`
1423
- );
1424
- const dockerfile = dockerfileLines.join('\n');
1425
-
1426
- await fs.writeFile(path.join(projectDir, 'docker', 'openclaw', 'Dockerfile'), dockerfile);
1424
+ );
1425
+ const dockerfile = dockerfileLines.join('\n');
1426
+
1427
+ const dockerDir = path.join(projectDir, 'docker', 'openclaw');
1428
+ await fs.ensureDir(dockerDir);
1429
+ await fs.writeFile(path.join(dockerDir, 'Dockerfile'), dockerfile);
1427
1430
 
1428
1431
  // agentId no longer tightly coupled here, handled inside bot processes
1429
1432
  const agentId = botName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-$/, '') || 'chat';
@@ -1658,7 +1661,8 @@ ${hasBrowserDesktop ? ` extra_hosts:
1658
1661
  - ../../.openclaw:/root/.openclaw`;
1659
1662
  }
1660
1663
 
1661
- await fs.writeFile(path.join(projectDir, 'docker', 'openclaw', 'docker-compose.yml'), compose);
1664
+ await fs.ensureDir(dockerDir);
1665
+ await fs.writeFile(path.join(dockerDir, 'docker-compose.yml'), compose);
1662
1666
 
1663
1667
  let authProfilesJson = {};
1664
1668
  if (provider.isLocal) {
@@ -2378,15 +2382,15 @@ fi
2378
2382
  const isOpenClawInstalled = () => { try { execSync('openclaw --version', { stdio: 'ignore' }); return true; } catch { return false; } };
2379
2383
  if (!isOpenClawInstalled()) {
2380
2384
  console.log(chalk.cyan(isVi
2381
- ? '\n📦 Đang cài openclaw binary (npm install -g openclaw)...'
2382
- : '\n📦 Installing openclaw binary (npm install -g openclaw)...'));
2383
- try {
2384
- execSync('npm install -g openclaw', { stdio: 'inherit' });
2385
- console.log(chalk.green(isVi ? '✅ openclaw đã cài xong!' : '✅ openclaw installed!'));
2386
- } catch {
2387
- console.log(chalk.yellow(isVi
2388
- ? '⚠️ Không tự cài được. Chạy thủ công: sudo npm install -g openclaw'
2389
- : '⚠️ Could not auto-install. Run manually: sudo npm install -g openclaw'));
2385
+ ? `\n📦 Đang cài openclaw binary (npm install -g ${OPENCLAW_NPM_SPEC})...`
2386
+ : `\n📦 Installing openclaw binary (npm install -g ${OPENCLAW_NPM_SPEC})...`));
2387
+ try {
2388
+ execSync(`npm install -g ${OPENCLAW_NPM_SPEC}`, { stdio: 'inherit' });
2389
+ console.log(chalk.green(isVi ? '✅ openclaw đã cài xong!' : '✅ openclaw installed!'));
2390
+ } catch {
2391
+ console.log(chalk.yellow(isVi
2392
+ ? `⚠️ Không tự cài được. Chạy thủ công: sudo npm install -g ${OPENCLAW_NPM_SPEC}`
2393
+ : `⚠️ Could not auto-install. Run manually: sudo npm install -g ${OPENCLAW_NPM_SPEC}`));
2390
2394
  }
2391
2395
  }
2392
2396
 
@@ -2413,9 +2417,9 @@ fi
2413
2417
  } else {
2414
2418
  if (!isOpenClawInstalled()) {
2415
2419
  console.log(chalk.cyan(isVi
2416
- ? '\n📦 Dang cai openclaw binary (npm install -g openclaw)...'
2417
- : '\n📦 Installing openclaw binary (npm install -g openclaw)...'));
2418
- if (!installGlobalPackage('openclaw@latest', { isVi, osChoice, displayName: 'openclaw' })) {
2420
+ ? `\n📦 Dang cai openclaw binary (npm install -g ${OPENCLAW_NPM_SPEC})...`
2421
+ : `\n📦 Installing openclaw binary (npm install -g ${OPENCLAW_NPM_SPEC})...`));
2422
+ if (!installGlobalPackage(OPENCLAW_NPM_SPEC, { isVi, osChoice, displayName: 'openclaw' })) {
2419
2423
  process.exit(1);
2420
2424
  }
2421
2425
  console.log(chalk.green(isVi ? '✅ openclaw da cai xong!' : '✅ openclaw installed!'));
@@ -22,8 +22,9 @@ Docker works well, but it has a learning curve. Review this table before proceed
22
22
 
23
23
  Before installing Docker, ensure the following:
24
24
 
25
- - **Node.js 20 LTS** or newer: [nodejs.org](https://nodejs.org/)
26
- - Node.js 20 LTS is the minimum recommended version as of 2025. Node.js 22 LTS is also fully supported.
25
+ - **Node.js 20/22/24**: [nodejs.org](https://nodejs.org/)
26
+ - Node.js 20 is the minimum recommended version. Node.js 22 and 24 are also fine.
27
+ - Avoid Node.js 25 for now; there are reports of OpenClaw failing on it.
27
28
  - Verify: `node -v`
28
29
  - **Docker Engine with Compose v2 plugin**: Instructions below.
29
30
  - Verify Compose v2: `docker compose version` (Note: `docker compose`, not `docker-compose`)
@@ -22,8 +22,9 @@ Docker hiệu quả nhưng có yêu cầu kỹ thuật nhất định. Hãy xem
22
22
 
23
23
  Trước khi cài Docker, hãy đảm bảo có đủ:
24
24
 
25
- - **Node.js 20 LTS** trở lên: [nodejs.org](https://nodejs.org/)
26
- - Node.js 20 LTS phiên bản tối thiểu được khuyên dùng từ 2025 trở đi. Node.js 22 LTS cũng được hỗ trợ đầy đủ.
25
+ - **Node.js 20/22/24**: [nodejs.org](https://nodejs.org/)
26
+ - Node.js 20 là mức tối thiểu khuyên dùng. Node.js 22 24 cũng ổn.
27
+ - Tạm tránh Node.js 25 vì đã có report OpenClaw lỗi trên bản này.
27
28
  - Kiểm tra: `node -v`
28
29
  - **Docker Engine kèm plugin Compose V2**: Hướng dẫn cài bên dưới.
29
30
  - Kiểm tra Compose V2: `docker compose version` (Lưu ý: `docker compose`, không phải `docker-compose`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-openclaw-bot",
3
- "version": "5.1.13",
3
+ "version": "5.1.14",
4
4
  "description": "Interactive CLI installer for OpenClaw Bot",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/setup.js CHANGED
@@ -804,8 +804,8 @@
804
804
  icon: '🐧',
805
805
  titleVi: 'Ubuntu / VPS — Khuyên dùng Native (Không Docker)',
806
806
  titleEn: 'Ubuntu / VPS — Recommended: Native (No Docker)',
807
- descVi: 'Chạy thẳng trên máy, tiết kiệm RAM, khởi động nhanh. Script tự cài Node.js 20 LTS, OpenClaw CLI, PM2, 9Router/Ollama và giữ bot chạy liên tục sau reboot.',
808
- descEn: 'Run directly on machine — lower RAM, faster startup. Script auto-installs Node.js 20 LTS, OpenClaw CLI, PM2, 9Router/Ollama and keeps bot running across reboots.',
807
+ descVi: 'Chạy thẳng trên máy, tiết kiệm RAM, khởi động nhanh. Script tự cài Node.js 20 LTS, OpenClaw CLI, PM2, 9Router/Ollama và giữ bot chạy liên tục sau reboot. Tạm tránh Node 25.',
808
+ descEn: 'Run directly on machine — lower RAM, faster startup. Script auto-installs Node.js 20 LTS, OpenClaw CLI, PM2, 9Router/Ollama and keeps bot running across reboots. Avoid Node 25 for now.',
809
809
  deploy: 'native',
810
810
  badgeVi: '💻 Native + PM2',
811
811
  badgeEn: '💻 Native + PM2',
@@ -815,8 +815,8 @@
815
815
  icon: '🖥️',
816
816
  titleVi: 'Linux Desktop — Khuyên dùng Native',
817
817
  titleEn: 'Linux Desktop — Recommended: Native',
818
- descVi: 'Không cần Docker. Script tự cài Node.js 20 LTS nếu chưa có, cài OpenClaw CLI, rồi cài 9Router hoặc Ollama theo provider bạn chọn và khởi động bot ngay.',
819
- descEn: 'No Docker needed. Script auto-installs Node.js 20 LTS if missing, installs OpenClaw CLI, then installs 9Router or Ollama based on your provider choice and starts the bot immediately.',
818
+ descVi: 'Không cần Docker. Script tự cài Node.js 20 LTS nếu chưa có, cài OpenClaw CLI, rồi cài 9Router hoặc Ollama theo provider bạn chọn và khởi động bot ngay. Tạm tránh Node 25.',
819
+ descEn: 'No Docker needed. Script auto-installs Node.js 20 LTS if missing, installs OpenClaw CLI, then installs 9Router or Ollama based on your provider choice and starts the bot immediately. Avoid Node 25 for now.',
820
820
  deploy: 'native',
821
821
  badgeVi: '💻 Native',
822
822
  badgeEn: '💻 Native',
@@ -1940,7 +1940,7 @@ model:
1940
1940
  ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 & '
1941
1941
  : '';
1942
1942
  // Patch config on every startup to keep gateway settings stable
1943
- const patchCmd = `node -e \\"const fs=require('fs'),os=require('os'),p='/root/.openclaw/openclaw.json';if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const a=new Set(['http://localhost:18791','http://127.0.0.1:18791','http://0.0.0.0:18791']);for(const entries of Object.values(os.networkInterfaces()||{})){for(const entry of entries||[]){if(!entry||entry.internal||entry.family!=='IPv4'||!entry.address)continue;a.add(\\\`http://\\\${entry.address}:18791\\\`);}}c.tools=Object.assign({},c.tools,{profile:'full',exec:{host:'gateway',security:'full',ask:'off'}});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'custom',customBindHost:'0.0.0.0',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a)})});fs.writeFileSync(p,JSON.stringify(c,null,2));}\\" && `;
1943
+ const patchCmd = `node -e \\"const fs=require('fs'),os=require('os'),p='/root/.openclaw/openclaw.json';if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const a=new Set(['http://localhost:18791','http://127.0.0.1:18791','http://0.0.0.0:18791']);for(const entries of Object.values(os.networkInterfaces()||{})){for(const entry of entries||[]){if(!entry||entry.internal||entry.family!=='IPv4'||!entry.address)continue;a.add('http://' + entry.address + ':18791');}}c.tools=Object.assign({},c.tools,{profile:'full',exec:{host:'gateway',security:'full',ask:'off'}});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'custom',customBindHost:'0.0.0.0',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});fs.writeFileSync(p,JSON.stringify(c,null,2));}\\" && `;
1944
1944
  // Auto-approve device pairing after gateway starts (required since v2026.3.x)
1945
1945
  const autoApproveCmd = '(while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done) & ';
1946
1946
  const finalCmd = `CMD sh -c "${pluginInstallCmd}${patchCmd}${browserPrefix}${autoApproveCmd}${gatewayCmd}"`;
@@ -1951,7 +1951,7 @@ RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /v
1951
1951
 
1952
1952
 
1953
1953
  ARG CACHEBUST=${Date.now()}
1954
- RUN npm install -g openclaw@latest${skillLines}${browserInstallLines}
1954
+ RUN npm install -g openclaw@2026.4.5 grammy${skillLines}${browserInstallLines}
1955
1955
  RUN node -e "const fs=require('fs');const path=require('path');const dir='/usr/local/lib/node_modules/openclaw/dist';const from='\\t\\t\\t\\t\\tonAgentRunStart: (runId) => {';const to='\\t\\t\\t\\t\\ttimeoutOverrideSeconds: Math.max(1, Math.ceil(timeoutMs / 1e3)),\\n\\t\\t\\t\\t\\tonAgentRunStart: (runId) => {';const files=fs.readdirSync(dir).filter(n=>/\\.js$/.test(n));let patched=0;for(const file of files){const p=path.join(dir,file);let s='';try{s=fs.readFileSync(p,'utf8');}catch{continue;}if(s.includes(to)||!s.includes(from))continue;s=s.replace(from,to);fs.writeFileSync(p,s);patched++;}if(!patched){process.exit(0);}"
1956
1956
  WORKDIR /root/.openclaw
1957
1957
 
@@ -2979,25 +2979,24 @@ I am **${botName}**. When asked my name, I answer: _"I'm ${botName}"_.`;
2979
2979
  if (p) allPlugins.push(p.package);
2980
2980
  });
2981
2981
  if (isMultiBot && state.channel === 'telegram') allPlugins.push(relayPluginSpec);
2982
- const pluginCmd = allPlugins.length > 0 ? ('npm exec openclaw plugins install ' + allPlugins.join(' ')) : '';
2983
-
2984
- function native9RouterSyncScriptContent() {
2985
- return `const fs=require('fs');
2986
- const path=require('path');
2987
- const INTERVAL=30000;
2988
- const p=path.join(process.env.HOME||process.env.USERPROFILE||'.','.9router','db.json');
2989
- const PM={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'],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'],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'],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'],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'],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'],'gemini-cli':['gc/gemini-3-flash-preview','gc/gemini-3-pro-preview'],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'],qwen:['qw/qwen3-coder-plus','qw/qwen3-coder-flash','qw/vision-model','qw/coder-model'],kiro:['kr/claude-sonnet-4.5','kr/claude-haiku-4.5','kr/deepseek-3.2','kr/deepseek-3.1','kr/qwen3-coder-next'],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'],'kimi-coding':['kmc/kimi-k2.5','kmc/kimi-k2.5-thinking','kmc/kimi-latest'],glm:['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],'glm-cn':['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],minimax:['minimax/MiniMax-M2.7','minimax/MiniMax-M2.5','minimax/MiniMax-M2.1'],kimi:['kimi/kimi-k2.5','kimi/kimi-k2.5-thinking','kimi/kimi-latest'],deepseek:['deepseek/deepseek-chat','deepseek/deepseek-reasoner'],xai:['xai/grok-4','xai/grok-4-fast-reasoning','xai/grok-code-fast-1'],mistral:['mistral/mistral-large-latest','mistral/codestral-latest'],groq:['groq/llama-3.3-70b-versatile','groq/openai/gpt-oss-120b'],cerebras:['cerebras/gpt-oss-120b'],alicode:['alicode/qwen3.5-plus','alicode/qwen3-coder-plus'],openai:['openai/gpt-4o','openai/gpt-4.1'],anthropic:['anthropic/claude-sonnet-4','anthropic/claude-haiku-3.5'],gemini:['gemini/gemini-2.5-flash','gemini/gemini-2.5-pro']};
2990
- const sync=()=>{try{let db={};try{db=JSON.parse(fs.readFileSync(p,'utf8'));}catch{}if(!db.combos)db.combos=[];const removeSmartRoute=()=>{const next=db.combos.filter(x=>x.id!=='smart-route');if(next.length!==db.combos.length){db.combos=next;fs.writeFileSync(p,JSON.stringify(db,null,2));}};const a=(db.providerConnections||[]).filter(c=>c&&c.provider&&c.isActive!==false&&!c.disabled).map(c=>c.provider);if(!a.length){removeSmartRoute();return;}const PREF=['openai','anthropic','claude-code','codex','cursor','github','cline','kimi','minimax','deepseek','glm','alicode','xai','mistral','kilo','kiro','iflow','qwen','gemini-cli','ollama'];a.sort((x,y)=>(PREF.indexOf(x)===-1?99:PREF.indexOf(x))-(PREF.indexOf(y)===-1?99:PREF.indexOf(y)));const m=a.flatMap(provider=>PM[provider]||[]);if(!m.length){removeSmartRoute();return;}const c={id:'smart-route',name:'smart-route',alias:'smart-route',models:m};const i=db.combos.findIndex(x=>x.id==='smart-route');if(i>=0){if(JSON.stringify(db.combos[i].models)!==JSON.stringify(c.models)){db.combos[i]=c;fs.writeFileSync(p,JSON.stringify(db,null,2));}}else{db.combos.push(c);fs.writeFileSync(p,JSON.stringify(db,null,2));}}catch{}};sync();setInterval(sync,INTERVAL);`;
2991
- }
2982
+ const pluginCmd = allPlugins.length > 0 ? ('call npm exec -- openclaw plugins install ' + allPlugins.join(' ') + ' || goto :fail') : '';
2983
+
2984
+ function native9RouterSyncScriptContent() {
2985
+ return `const fs=require('fs');
2986
+ const path=require('path');
2987
+ const INTERVAL=30000;
2988
+ const p=path.join(process.env.HOME||process.env.USERPROFILE||'.','.9router','db.json');
2989
+ const PM={'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'],'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'],'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'],'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'],'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'],'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'],'gemini-cli':['gc/gemini-3-flash-preview','gc/gemini-3-pro-preview'],'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'],'qwen':['qw/qwen3-coder-plus','qw/qwen3-coder-flash','qw/vision-model','qw/coder-model'],'kiro':['kr/claude-sonnet-4.5','kr/claude-haiku-4.5','kr/deepseek-3.2','kr/deepseek-3.1','kr/qwen3-coder-next'],'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'],'kimi-coding':['kmc/kimi-k2.5','kmc/kimi-k2.5-thinking','kmc/kimi-latest'],'glm':['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],'glm-cn':['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],'minimax':['minimax/MiniMax-M2.7','minimax/MiniMax-M2.5','minimax/MiniMax-M2.1'],'kimi':['kimi/kimi-k2.5','kimi/kimi-k2.5-thinking','kimi/kimi-latest'],'deepseek':['deepseek/deepseek-chat','deepseek/deepseek-reasoner'],'xai':['xai/grok-4','xai/grok-4-fast-reasoning','xai/grok-code-fast-1'],'mistral':['mistral/mistral-large-latest','mistral/codestral-latest'],'groq':['groq/llama-3.3-70b-versatile','groq/openai/gpt-oss-120b'],'cerebras':['cerebras/gpt-oss-120b'],'alicode':['alicode/qwen3.5-plus','alicode/qwen3-coder-plus'],'openai':['openai/gpt-4o','openai/gpt-4.1'],'anthropic':['anthropic/claude-sonnet-4','anthropic/claude-haiku-3.5'],'gemini':['gemini/gemini-2.5-flash','gemini/gemini-2.5-pro']};
2990
+ const sync=()=>{try{let db={};try{db=JSON.parse(fs.readFileSync(p,'utf8'));}catch{}if(!db.combos)db.combos=[];const removeSmartRoute=()=>{const next=db.combos.filter(x=>x.id!=='smart-route');if(next.length!==db.combos.length){db.combos=next;fs.writeFileSync(p,JSON.stringify(db,null,2));}};const a=(db.providerConnections||[]).filter(c=>c&&c.provider&&c.isActive!==false&&!c.disabled).map(c=>c.provider);if(!a.length){removeSmartRoute();return;}const PREF=['openai','anthropic','claude-code','codex','cursor','github','cline','kimi','minimax','deepseek','glm','alicode','xai','mistral','kilo','kiro','iflow','qwen','gemini-cli','ollama'];a.sort((x,y)=>(PREF.indexOf(x)===-1?99:PREF.indexOf(x))-(PREF.indexOf(y)===-1?99:PREF.indexOf(y)));const m=a.flatMap(provider=>PM[provider]||[]);if(!m.length){removeSmartRoute();return;}const c={id:'smart-route',name:'smart-route',alias:'smart-route',models:m};const i=db.combos.findIndex(x=>x.id==='smart-route');if(i>=0){if(JSON.stringify(db.combos[i].models)!==JSON.stringify(c.models)){db.combos[i]=c;fs.writeFileSync(p,JSON.stringify(db,null,2));}}else{db.combos.push(c);fs.writeFileSync(p,JSON.stringify(db,null,2));}}catch{}};sync();setInterval(sync,INTERVAL);`;
2991
+ }
2992
2992
 
2993
2993
  // ─── Shared initializer (provider install) ───────────────────────────────
2994
2994
  function providerLines(arr, shell) {
2995
2995
  if (is9Router) {
2996
2996
  if (shell === 'bat') {
2997
- arr.push('npm install -g 9router');
2998
- arr.push('start "9Router" cmd /k "9router -n -l -H 0.0.0.0 -p 20128 --skip-update"');
2999
- arr.push('start "9Router Smart Route Sync" cmd /k "node .\\.openclaw\\9router-smart-route-sync.js"');
3000
- arr.push('timeout /t 5 /nobreak >nul');
2997
+ arr.push('call npm install -g 9router || goto :fail');
2998
+ arr.push('start "9Router" cmd /k "9router -n -l -H 0.0.0.0 -p 20128 --skip-update"');
2999
+ arr.push('timeout /t 5 /nobreak >nul');
3001
3000
  } else {
3002
3001
  arr.push('npm install -g 9router');
3003
3002
  arr.push('nohup env PORT=20128 HOSTNAME=0.0.0.0 node "$(npm root -g)/9router/app/server.js" >/tmp/9router.log 2>&1 &');
@@ -3588,32 +3587,43 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
3588
3587
  const isDocker = state.deployMode === 'docker';
3589
3588
  scriptName = isDocker ? 'setup-openclaw-docker-win.bat' : 'setup-openclaw-win.bat';
3590
3589
  const lines = [
3591
- '@echo off',
3592
- 'chcp 65001 >nul',
3590
+ '@echo off',
3591
+ 'setlocal EnableExtensions',
3592
+ 'chcp 65001 >nul',
3593
3593
  `echo === OpenClaw Setup — Windows${isDocker ? ' Docker' : ' Native'} ===`,
3594
3594
  'echo.',
3595
3595
  'echo [1/5] Kiem tra Node.js...',
3596
3596
  'where node >nul 2>&1 || (echo ERROR: Node.js chua cai! Tai tai: https://nodejs.org && pause && exit /b 1)',
3597
3597
  'echo [2/5] Cai OpenClaw CLI...',
3598
- 'npm install -g openclaw@latest',
3598
+ 'call npm install -g openclaw@2026.4.5 || goto :fail',
3599
3599
  ];
3600
3600
  providerLines(lines, 'bat');
3601
3601
  if (pluginCmd) { lines.push('echo Cai plugins...'); lines.push(pluginCmd); }
3602
3602
 
3603
- if (isMultiBot) {
3604
- lines.push('echo [4/5] Tao runtime multi-agent dung chung...');
3605
- appendBatWriteCommands(lines, sharedNativeFileMap());
3606
- lines.push('echo [5/5] Khoi dong gateway multi-bot...');
3607
- lines.push('openclaw gateway run');
3608
- } else {
3609
- lines.push('echo [4/5] Tao file cau hinh...');
3610
- appendBatWriteCommands(lines, botFiles(0));
3611
- lines.push('echo [5/5] Khoi dong bot...');
3612
- lines.push('openclaw gateway run');
3613
- }
3614
-
3615
- lines.push('pause');
3616
- scriptContent = lines.filter(Boolean).join('\r\n');
3603
+ if (isMultiBot) {
3604
+ lines.push('echo [4/5] Tao runtime multi-agent dung chung...');
3605
+ appendBatWriteCommands(lines, sharedNativeFileMap());
3606
+ if (is9Router) lines.push('start "9Router Smart Route Sync" cmd /k "node .\\.openclaw\\9router-smart-route-sync.js"');
3607
+ lines.push('echo [5/5] Khoi dong gateway multi-bot...');
3608
+ lines.push('call openclaw gateway run');
3609
+ } else {
3610
+ lines.push('echo [4/5] Tao file cau hinh...');
3611
+ appendBatWriteCommands(lines, botFiles(0));
3612
+ if (is9Router) lines.push('start "9Router Smart Route Sync" cmd /k "node .\\.openclaw\\9router-smart-route-sync.js"');
3613
+ lines.push('echo [5/5] Khoi dong bot...');
3614
+ lines.push('call openclaw gateway run');
3615
+ }
3616
+
3617
+ lines.push('goto :end');
3618
+ lines.push(':fail');
3619
+ lines.push('echo.');
3620
+ lines.push('echo Cai dat that bai. Kiem tra dong loi ngay phia tren.');
3621
+ lines.push('pause');
3622
+ lines.push('exit /b 1');
3623
+ lines.push(':end');
3624
+ lines.push('pause');
3625
+ lines.push('endlocal');
3626
+ scriptContent = lines.filter(Boolean).join('\r\n');
3617
3627
 
3618
3628
  // ─── macOS .SH ───────────────────────────────────────────────────────────
3619
3629
  } else if (state.nativeOs === 'linux') {
@@ -3653,7 +3663,7 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
3653
3663
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.zshrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.zshrc"',
3654
3664
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
3655
3665
  '# Install openclaw (user-local first, sudo fallback)',
3656
- 'npm install -g openclaw@latest || sudo npm install -g openclaw@latest',
3666
+ 'npm install -g openclaw@2026.4.5 || sudo npm install -g openclaw@2026.4.5',
3657
3667
  ];
3658
3668
  providerLines(sh, 'sh');
3659
3669
  if (pluginCmd) sh.push(pluginCmd);
@@ -3685,7 +3695,7 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
3685
3695
  'export PATH="$HOME/.local/bin:$PATH"',
3686
3696
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
3687
3697
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
3688
- 'npm install -g openclaw@latest pm2@latest',
3698
+ 'npm install -g openclaw@2026.4.5 pm2@latest',
3689
3699
  ];
3690
3700
  providerLines(vps, 'sh');
3691
3701
  if (pluginCmd) vps.push(pluginCmd);
@@ -3732,7 +3742,7 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
3732
3742
  'export PATH="$HOME/.local/bin:$PATH"',
3733
3743
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
3734
3744
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
3735
- 'npm install -g openclaw@latest',
3745
+ 'npm install -g openclaw@2026.4.5',
3736
3746
  ];
3737
3747
  providerLines(lnx, 'sh');
3738
3748
  if (pluginCmd) lnx.push(pluginCmd);
@@ -3766,7 +3776,7 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
3766
3776
  if (stepsList) {
3767
3777
  const steps = [];
3768
3778
  steps.push(isVi ? '✅ Kiểm tra Node.js (cài tự động trên Ubuntu/VPS nếu chưa có)' : '✅ Check Node.js (auto-install on Ubuntu/VPS if missing)');
3769
- steps.push(isVi ? '📦 Cài OpenClaw CLI (<code>npm install -g openclaw@latest</code>)' : '📦 Install OpenClaw CLI (<code>npm install -g openclaw@latest</code>)');
3779
+ steps.push(isVi ? '📦 Cài OpenClaw CLI (<code>npm install -g openclaw@2026.4.5</code>)' : '📦 Install OpenClaw CLI (<code>npm install -g openclaw@2026.4.5</code>)');
3770
3780
  if (is9Router) {
3771
3781
  steps.push(isVi ? '🔀 Cài 9Router (<code>npm install -g 9router</code>) và khởi động tự động' : '🔀 Install 9Router (<code>npm install -g 9router</code>) and start automatically');
3772
3782
  } else if (isOllama) {
@@ -52,8 +52,8 @@ checks.push(() => expectMatch(
52
52
 
53
53
  checks.push(() => expectMatch(
54
54
  cli,
55
- /function installLatestOpenClaw\(\{ isVi, osChoice \}\) \{[\s\S]*installGlobalPackage\('openclaw@latest', \{ isVi, osChoice, displayName: 'openclaw' \}\)[\s\S]*process\.exit\(1\)/,
56
- 'CLI must provide a shared helper that always installs or upgrades openclaw@latest'
55
+ /function installLatestOpenClaw\(\{ isVi, osChoice \}\) \{[\s\S]*installGlobalPackage\(OPENCLAW_NPM_SPEC, \{ isVi, osChoice, displayName: 'openclaw' \}\)[\s\S]*process\.exit\(1\)/,
56
+ 'CLI must provide a shared helper that always installs or upgrades the pinned openclaw version'
57
57
  ));
58
58
 
59
59
  checks.push(() => expectMatch(
@@ -70,7 +70,7 @@ checks.push(() => expectMatch(
70
70
 
71
71
  checks.push(() => expectMatch(
72
72
  cli,
73
- /if \(!isOpenClawInstalled\(\)\) \{[\s\S]*installGlobalPackage\('openclaw@latest', \{ isVi, osChoice, displayName: 'openclaw' \}\)/,
73
+ /if \(!isOpenClawInstalled\(\)\) \{[\s\S]*installGlobalPackage\(OPENCLAW_NPM_SPEC, \{ isVi, osChoice, displayName: 'openclaw' \}\)/,
74
74
  'Native branch must auto-install openclaw'
75
75
  ));
76
76
 
@@ -216,6 +216,25 @@ checks.push(() => expectMatch(
216
216
  'Native per-bot gateway config must seed control UI allowed origins for each port'
217
217
  ));
218
218
 
219
+ checks.push(() => expectMatch(
220
+ cli,
221
+ /const dockerDir = path\.join\(projectDir, 'docker', 'openclaw'\);\s*await fs\.ensureDir\(dockerDir\);\s*await fs\.writeFile\(path\.join\(dockerDir, 'Dockerfile'\), dockerfile\);[\s\S]*await fs\.ensureDir\(dockerDir\);\s*await fs\.writeFile\(path\.join\(dockerDir, 'docker-compose\.yml'\), compose\);/s,
222
+ 'Docker CLI flow must ensure docker/openclaw exists immediately before writing Dockerfile and docker-compose.yml'
223
+ ));
224
+
225
+ checks.push(() => expectMatch(
226
+ cli,
227
+ /RUN npm install -g \$\{OPENCLAW_NPM_SPEC\} grammy/,
228
+ 'Docker CLI image must install grammy alongside openclaw so Telegram runtime dependencies resolve'
229
+ ));
230
+
231
+ checks.push(() => expect(
232
+ cli.includes("a.add('http://' + entry.address + ':18791')")
233
+ && cli.includes('allowedOrigins:Array.from(a).filter(Boolean)')
234
+ && !cli.includes("a.add(`http://${entry.address}:18791`)"),
235
+ 'Docker CLI patch script must avoid shell-expanding ${entry.address} and must filter null origins'
236
+ ));
237
+
219
238
  checks.push(() => expectMatch(
220
239
  cli,
221
240
  /channelKey === 'zalo-personal'\) \{\s*botConfig\.channels\['zalouser'\] = \{\s*enabled: true,\s*dmPolicy: 'open',\s*autoReply: true/s,
@@ -303,19 +322,32 @@ checks.push(() => expectMatch(
303
322
 
304
323
  checks.push(() => expectMatch(
305
324
  setup,
306
- /if \(state\.nativeOs === 'win'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-win\.bat' : 'setup-openclaw-win\.bat';[\s\S]*npm install -g openclaw@latest[\s\S]*openclaw gateway run/s,
325
+ /if \(state\.nativeOs === 'win'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-win\.bat' : 'setup-openclaw-win\.bat';[\s\S]*npm install -g openclaw@2026\.4\.5[\s\S]*openclaw gateway run/s,
307
326
  'Windows native/docker script generation must use the correct file name and start command'
308
327
  ));
309
328
 
310
329
  checks.push(() => expectMatch(
311
330
  setup,
312
- /else if \(state\.nativeOs === 'linux'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-macos\.sh' : 'setup-openclaw-macos\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@latest[\s\S]*openclaw gateway run/s,
331
+ /else if \(state\.nativeOs === 'linux'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-macos\.sh' : 'setup-openclaw-macos\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@2026\.4\.5[\s\S]*openclaw gateway run/s,
313
332
  'macOS script generation must use the correct file name and start command'
314
333
  ));
315
334
 
316
335
  checks.push(() => expectMatch(
317
336
  setup,
318
- /else if \(state\.nativeOs === 'vps'\) \{[\s\S]*scriptName = 'setup-openclaw-vps\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@latest pm2@latest[\s\S]*pm2 save && pm2 startup/s,
337
+ /RUN npm install -g openclaw@2026\.4\.5 grammy/,
338
+ 'Wizard Dockerfile generation must install grammy alongside openclaw so Telegram runtime dependencies resolve'
339
+ ));
340
+
341
+ checks.push(() => expect(
342
+ setup.includes("a.add('http://' + entry.address + ':18791')")
343
+ && setup.includes('allowedOrigins:Array.from(a).filter(Boolean)')
344
+ && !setup.includes("a.add(\\`http://\\${entry.address}:18791\\`)"),
345
+ 'Wizard Docker patch command must avoid shell-expanding ${entry.address} and must filter null origins'
346
+ ));
347
+
348
+ checks.push(() => expectMatch(
349
+ setup,
350
+ /else if \(state\.nativeOs === 'vps'\) \{[\s\S]*scriptName = 'setup-openclaw-vps\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@2026\.4\.5 pm2@latest[\s\S]*pm2 save && pm2 startup/s,
319
351
  'VPS native script generation must install openclaw+pm2 and persist PM2 startup'
320
352
  ));
321
353
 
@@ -325,6 +357,12 @@ checks.push(() => expectMatch(
325
357
  'Native script generation must install and start a standalone 9Router dashboard on port 20128'
326
358
  ));
327
359
 
360
+ checks.push(() => expectMatch(
361
+ setup,
362
+ /} else if \(is9Router\) \{[\s\S]*container_name: openclaw-bot[\s\S]*depends_on:[\s\S]*- 9router[\s\S]*container_name: 9router[\s\S]*PORT=20128[\s\S]*HOSTNAME=0\.0\.0\.0[\s\S]*9router-data:/s,
363
+ 'Wizard single-bot Docker compose must include the 9Router sidecar service and named volume when provider is 9Router'
364
+ ));
365
+
328
366
  checks.push(() => expectMatch(
329
367
  setup,
330
368
  /function native9RouterSyncScriptContent\(\) \{[\s\S]*path\.join\(process\.env\.HOME\|\|process\.env\.USERPROFILE\|\|'\.'\,\'\.9router\'\,\'db\.json\'\)[\s\S]*providerConnections[\s\S]*smart-route/s,
@@ -381,7 +419,7 @@ checks.push(() => expectMatch(
381
419
 
382
420
  checks.push(() => expectMatch(
383
421
  setup,
384
- /else if \(state\.nativeOs === 'linux-desktop'\) \{[\s\S]*scriptName = 'setup-openclaw-linux\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@latest[\s\S]*openclaw gateway run/s,
422
+ /else if \(state\.nativeOs === 'linux-desktop'\) \{[\s\S]*scriptName = 'setup-openclaw-linux\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@2026\.4\.5[\s\S]*openclaw gateway run/s,
385
423
  'Linux Desktop native script generation must install openclaw and run the gateway'
386
424
  ));
387
425