create-openclaw-bot 5.2.1 → 5.2.3

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,27 @@
1
1
  # Changelog (English)
2
2
 
3
3
 
4
+ ## [5.2.3] — 2026-04-10
5
+
6
+ ### 🐛 Bug Fixes & Encoding Improvements
7
+
8
+ - **Fix: `ReferenceError: projectDir is not defined`** — Crash when clicking "Generate Configs" in multi-bot mode. `nativeProjectOpenClawRoot` in `buildTelegramPostInstallChecklist()` referenced an undefined `projectDir` variable and was dead code (unused in return value). Removed.
9
+ - **Fix: Step 3 "Next" button validation** — `state._activeBotTab` was a typo of `state.activeBotIndex`, causing multi-bot validation to always read the wrong tab index.
10
+ - **Fix: `saveFormData()` always saved bot tab name to `bots[0]`** — In multi-bot mode, the active bot name was always written to `bots[0]` regardless of which tab was active. Now correctly saves to `bots[state.activeBotIndex]`.
11
+ - **UX: Inline hint for disabled "Generate Configs" button** — When the button is blocked, a warning now appears showing exactly which fields are still missing (e.g. "Missing: GOOGLE_API_KEY").
12
+ - **Fix: Vietnamese diacritics in generated `.bat` and `.sh` scripts** — All Vietnamese echo/Write-Host strings in the generated Windows setup script and Linux/macOS bash script have been converted to ASCII (no diacritics) to prevent encoding errors on systems with non-UTF-8 codepages.
13
+
14
+ ## [5.2.2] — 2026-04-10
15
+
16
+
17
+ ### 🐛 Docker & Native PM2 Bug Fixes
18
+
19
+ - **Fix Docker crash loop (socat port conflict)**: `socat TCP-LISTEN:18791` was binding `0.0.0.0:18791` before `openclaw gateway run` started, causing `EADDRINUSE` on `127.0.0.1:18791`. Removed the broken gateway bridge from the generated Dockerfile CMD in both `cli.js` and `setup.js`.
20
+ - **Fix Docker dashboard not accessible from host**: Gateway `bind` was set to `'loopback'` — Docker port mapping cannot route to container loopback. Restored the v5.0.9 working pattern: `bind:'custom', customBindHost:'0.0.0.0'`.
21
+ - **Fix `delete c.gateway.customBindHost`**: A stray `delete` statement was erasing the `customBindHost` key right after setting it. Removed.
22
+ - **Fix Docker build re-downloading npm packages on every rebuild**: `ARG CACHEBUST=<epoch>` was cache-busting the `npm install -g openclaw` layer on every build (even config-only changes). Replaced with a version-stable `ARG OPENCLAW_VER` so Docker layer cache is reused between rebuilds.
23
+ - **Fix native PM2 double `.openclaw` nesting**: `ecosystem.config.js` was setting `OPENCLAW_HOME: projectDir/.openclaw`, causing OpenClaw to resolve workspace as `projectDir/.openclaw/.openclaw/workspace`. Removed `OPENCLAW_HOME` from PM2 env; OpenClaw discovers config via `cwd` (matching v5.0.9 behavior).
24
+
4
25
  ## [5.2.1] — 2026-04-09
5
26
 
6
27
  ### 🐛 Native Ubuntu/VPS Bug Fixes
package/CHANGELOG.vi.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # Changelog (Tiếng Việt)
2
2
 
3
3
 
4
+ ## [5.2.3] — 2026-04-10
5
+
6
+ ### 🐛 Sửa lỗi & Cải thiện encoding
7
+
8
+ - **Fix: `ReferenceError: projectDir is not defined`** — Crash khi bấm "Generate Configs" ở chế độ multi-bot. Biến `projectDir` không được khai báo trong `buildTelegramPostInstallChecklist()` và là dead code (không dùng trong return). Đã xoá.
9
+ - **Fix: Nút "Tiếp theo" ở Bước 3 bị validate sai** — `state._activeBotTab` là typo của `state.activeBotIndex`, khiến validation multi-bot luôn đọc sai tab index.
10
+ - **Fix: `saveFormData()` luôn lưu tên bot vào `bots[0]`** — Trong multi-bot mode, tên bot đang active bị ghi đè cố định vào `bots[0]` thay vì `bots[state.activeBotIndex]`. Đã sửa.
11
+ - **UX: Hiển thị gợi ý khi nút "Generate Configs" bị khoá** — Khi nút bị disable, một cảnh báo xuất hiện ngay bên dưới cho biết trường nào còn thiếu (ví dụ: "Còn thiếu: GOOGLE_API_KEY").
12
+ - **Fix: Tiếng Việt có dấu trong file `.bat` và `.sh` được tạo ra** — Toàn bộ chuỗi echo/Write-Host tiếng Việt có dấu trong script cài đặt cho Windows và Linux/macOS đã được chuyển về dạng không dấu (ASCII thuần) để tránh lỗi encoding trên các máy không dùng UTF-8.
13
+
14
+ ## [5.2.2] — 2026-04-10
15
+
16
+
17
+ ### 🐛 Sửa lỗi Docker & Native PM2
18
+
19
+ - **Sửa crash loop Docker (xung đột port socat)**: `socat TCP-LISTEN:18791` chiếm port `0.0.0.0:18791` trước khi `openclaw gateway run` khởi động, gây `EADDRINUSE`. Đã xóa gateway bridge khỏi Dockerfile CMD trong `cli.js` và `setup.js`.
20
+ - **Sửa Dashboard Docker không vào được từ host**: Gateway `bind` đặt là `'loopback'` — Docker port mapping không reach được loopback bên trong container. Khôi phục pattern đúng từ v5.0.9: `bind:'custom', customBindHost:'0.0.0.0'`.
21
+ - **Sửa `delete c.gateway.customBindHost`**: Một lệnh `delete` thừa đang xóa key `customBindHost` ngay sau khi set. Đã xóa dòng đó.
22
+ - **Sửa Docker tải lại npm mỗi lần build**: `ARG CACHEBUST=<timestamp>` bust cache layer `npm install -g openclaw` mỗi lần build dù chỉ đổi config. Thay bằng `ARG OPENCLAW_VER` ổn định theo version — Docker tái sử dụng cache giữa các lần rebuild.
23
+ - **Sửa lồng đôi `.openclaw` trong native PM2**: `ecosystem.config.js` đang đặt `OPENCLAW_HOME: projectDir/.openclaw`, khiến OpenClaw resolve workspace thành `projectDir/.openclaw/.openclaw/workspace`. Đã xóa `OPENCLAW_HOME` khỏi PM2 env; OpenClaw tự tìm config qua `cwd` (khớp với v5.0.9).
24
+
25
+
4
26
  ## [5.2.1] — 2026-04-09
5
27
 
6
28
  ### 🐛 Sửa Lỗi Ubuntu/VPS Native
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.2.1-0EA5E9?style=for-the-badge" alt="Version 5.2.1" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.2.3-0EA5E9?style=for-the-badge" alt="Version 5.2.3" /></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,7 +24,7 @@ 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.2.1
27
+ ## 🆕 What's new in v5.2.3
28
28
 
29
29
  - 🔄 **One-command upgrade** — Run `npx create-openclaw-bot@latest upgrade` in your bot folder to update OpenClaw without re-running the wizard. Auto-detects Docker vs Native mode.
30
30
  - 🪟 **Windows upgrade shortcut** — `upgrade.ps1` ships with the repo. Double-click it to upgrade instantly (no terminal knowledge required).
@@ -32,7 +32,7 @@ An interactive **CLI tool** and **Setup Wizard** to deploy your own free AI Bot
32
32
  - 🛡️ **All user data preserved** — `.env`, memory, sessions, credentials, and 9Router OAuth tokens are never touched during upgrade.
33
33
 
34
34
  <details>
35
- <summary><b>Previous: What's new in v5.2.1</b></summary>
35
+ <summary><b>Previous: What's new in v5.2.3</b></summary>
36
36
 
37
37
  - 🔒 **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.
38
38
  - 🐳 **Dockerfile fixes** — Fixed the Windows Docker flow so startup no longer breaks on bad command escaping or invalid generated `allowedOrigins`.
@@ -110,7 +110,7 @@ Run in your terminal → follow the interactive prompts → startup script is ge
110
110
  2. Open this repo as your workspace
111
111
  3. Paste into chat:
112
112
  ```
113
- Read SETUP.md and set up OpenClaw v5.2.1 for me.
113
+ Read SETUP.md and set up OpenClaw v5.2.3 for me.
114
114
  My bot token is X. Use 9Router (no API key).
115
115
  My project folder: <YOUR_PATH>
116
116
  ```
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.2.1-0EA5E9?style=for-the-badge" alt="Version 5.2.1" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.2.3-0EA5E9?style=for-the-badge" alt="Version 5.2.3" /></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,7 +24,7 @@ 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.2.1
27
+ ## 🆕 Có gì mới trong v5.2.3
28
28
 
29
29
  - 🔄 **Upgrade 1 lệnh** — Chạy `npx create-openclaw-bot@latest upgrade` trong thư mục bot để cập nhật OpenClaw mà không cần chạy lại wizard. Tự động nhận diện Docker hay Native.
30
30
  - 🪟 **Windows: double-click để upgrade** — File `upgrade.ps1` có sẵn trong repo. Nhấp đúp là xong — không cần biết terminal.
@@ -32,7 +32,7 @@ Công cụ **CLI tương tác** và **Setup Wizard** để tự triển khai Bot
32
32
  - 🛡️ **Dữ liệu cũ giữ nguyên hoàn toàn** — `.env`, memory, sessions, credentials, OAuth token 9Router không bao giờ bị xoá khi upgrade.
33
33
 
34
34
  <details>
35
- <summary><b>Trước đó: Có gì mới ở v5.2.1</b></summary>
35
+ <summary><b>Trước đó: Có gì mới ở v5.2.3</b></summary>
36
36
 
37
37
  - 🔒 **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.
38
38
  - 🐳 **Fix Dockerfile** — Sửa luồng Docker cho Windows để không còn lỗi startup do command/escaping sai và tránh lỗi `allowedOrigins` bị sinh ra không hợp lệ.
@@ -110,7 +110,7 @@ Chạy lệnh trên trong Terminal → làm theo các prompt tương tác → sc
110
110
  2. Mở repo này làm workspace
111
111
  3. Paste vào chat:
112
112
  ```
113
- Read SETUP.md and set up OpenClaw v5.2.1 for me.
113
+ Read SETUP.md and set up OpenClaw v5.2.3 for me.
114
114
  My bot token is X. Use 9Router (no API key).
115
115
  My project folder: <THƯ_MỤC_CỦA_BẠN>
116
116
  ```
package/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  import { input, select, checkbox, confirm } from '@inquirer/prompts';
4
4
  import fs from 'fs-extra';
@@ -1624,7 +1624,7 @@ async function main() {
1624
1624
  }
1625
1625
 
1626
1626
 
1627
- 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:'loopback',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});delete c.gateway.customBindHost;fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
1627
+ 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));}`;
1628
1628
  const b64Patch = Buffer.from(patchScript).toString('base64');
1629
1629
 
1630
1630
  // Browser Playwright (both desktop & server modes need chromium)
@@ -1639,7 +1639,9 @@ async function main() {
1639
1639
  // socat only for Desktop mode (bridge to host Chrome)
1640
1640
  const socatApt = ' socat';
1641
1641
  const socatBridge = hasBrowserDesktop ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 & ' : '';
1642
- const gatewayBridge = 'socat TCP-LISTEN:18791,fork,reuseaddr TCP:127.0.0.1:18791 & ';
1642
+ // gatewayBridge removed: socat on 0.0.0.0:18791 conflicts with openclaw binding 127.0.0.1:18791.
1643
+ // The openclaw gateway connects outbound to chat platforms — no inbound bridge needed.
1644
+ const gatewayBridge = '';
1643
1645
 
1644
1646
  // Skills install at RUNTIME (not build-time — requires openclaw config + ClawHub auth)
1645
1647
  const skillSlugs = SKILLS
@@ -1662,7 +1664,7 @@ async function main() {
1662
1664
  if (browserDockerLines) dockerfileLines.push(browserDockerLines);
1663
1665
  dockerfileLines.push(
1664
1666
  '',
1665
- `ARG CACHEBUST=${Date.now()}`,
1667
+ `ARG OPENCLAW_VER="${OPENCLAW_NPM_SPEC}"`,
1666
1668
  `RUN npm install -g ${OPENCLAW_NPM_SPEC} ${OPENCLAW_RUNTIME_PACKAGES}`,
1667
1669
  '',
1668
1670
  '# Fix chat.send dropping resolved agent timeout into reply pipeline.',
@@ -2138,7 +2140,7 @@ ${hasBrowserDesktop ? ` extra_hosts:
2138
2140
  ` interpreter: 'none',`,
2139
2141
  ` autorestart: true,`,
2140
2142
  ` watch: false,`,
2141
- ` env: { NODE_ENV: 'production', OPENCLAW_HOME: '${path.join(projectDir, '.openclaw').replace(/\\/g, '/')}', DATA_DIR: '${path.join(projectDir, '.9router').replace(/\\/g, '/')}' }`,
2143
+ ` env: { NODE_ENV: 'production', DATA_DIR: '${path.join(projectDir, '.9router').replace(/\\/g, '/')}' }`,
2142
2144
  ' },',
2143
2145
  ' {',
2144
2146
  ` name: '${botName || 'openclaw-multibot'}-auto-approve',`,
@@ -2148,7 +2150,7 @@ ${hasBrowserDesktop ? ` extra_hosts:
2148
2150
  ` interpreter: 'none',`,
2149
2151
  ` autorestart: true,`,
2150
2152
  ` watch: false,`,
2151
- ` env: { NODE_ENV: 'production', OPENCLAW_HOME: '${path.join(projectDir, '.openclaw').replace(/\\/g, '/')}', DATA_DIR: '${path.join(projectDir, '.9router').replace(/\\/g, '/')}' }`,
2153
+ ` env: { NODE_ENV: 'production', DATA_DIR: '${path.join(projectDir, '.9router').replace(/\\/g, '/')}' }`,
2152
2154
  ' }',
2153
2155
  ].join('\n');
2154
2156
  const ecosystemContent = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-openclaw-bot",
3
- "version": "5.2.1",
3
+ "version": "5.2.3",
4
4
  "description": "Interactive CLI installer for OpenClaw Bot",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/setup.js CHANGED
@@ -1,4 +1,4 @@
1
- /* ============================================
1
+ /* ============================================
2
2
  OpenClaw Setup Wizard — Logic v2
3
3
  Multi-model, Multi-plugin, Multi-channel
4
4
  ============================================ */
@@ -1061,7 +1061,7 @@
1061
1061
  if (state.botCount > 1) {
1062
1062
  // Multi-bot: require name for the currently active bot tab
1063
1063
  // Fallback to state.bots to handle re-render cases where DOM may not yet have the value
1064
- const activeTab = state._activeBotTab || 0;
1064
+ const activeTab = state.activeBotIndex || 0;
1065
1065
  const tabNameVal = document.getElementById('cfg-bot-tab-name')?.value?.trim()
1066
1066
  || state.bots[activeTab]?.name?.trim();
1067
1067
  if (!tabNameVal) isDisabled = true;
@@ -1099,6 +1099,36 @@
1099
1099
  btnNextLabel.textContent = state.currentStep === 4
1100
1100
  ? (lang === 'vi' ? 'Generate Configs' : 'Generate Configs')
1101
1101
  : (lang === 'vi' ? 'Tiếp theo' : 'Next');
1102
+
1103
+ // Show inline hint when Generate Configs is blocked
1104
+ let hintEl = document.getElementById('btn-next-hint');
1105
+ if (state.currentStep === 4 && isDisabled) {
1106
+ if (!hintEl) {
1107
+ hintEl = document.createElement('p');
1108
+ hintEl.id = 'btn-next-hint';
1109
+ hintEl.style.cssText = 'font-size:12px;color:#ffc107;text-align:center;margin:6px 16px 0;';
1110
+ const navEl = document.querySelector('.nav-buttons');
1111
+ if (navEl && navEl.parentNode) navEl.parentNode.insertBefore(hintEl, navEl.nextSibling);
1112
+ }
1113
+ const missing = [];
1114
+ const _prov = PROVIDERS[state.config.provider];
1115
+ if (state.channel === 'telegram' && state.botCount > 1) {
1116
+ const t0 = document.getElementById('key-bot-token-0')?.value?.trim() || state.bots[0]?.token?.trim() || '';
1117
+ if (!t0) missing.push(lang === 'vi' ? 'Token Bot 1' : 'Bot 1 Token');
1118
+ } else if (state.channel === 'telegram' || state.channel === 'zalo-bot') {
1119
+ const bt = document.getElementById('key-bot-token')?.value?.trim() || state.config.botToken?.trim() || '';
1120
+ if (!bt) missing.push('Bot Token');
1121
+ }
1122
+ if (_prov && !_prov.isProxy && !_prov.isLocal && _prov.envKey) {
1123
+ const ak = document.getElementById('key-api-key')?.value?.trim() || state.config.apiKey?.trim() || '';
1124
+ if (!ak) missing.push(_prov.envLabel || _prov.envKey);
1125
+ }
1126
+ if (missing.length) {
1127
+ hintEl.textContent = (lang === 'vi' ? '⚠️ Còn thiếu: ' : '⚠️ Missing: ') + missing.join(', ');
1128
+ }
1129
+ } else if (hintEl) {
1130
+ hintEl.remove();
1131
+ }
1102
1132
  }
1103
1133
  }
1104
1134
 
@@ -1382,9 +1412,12 @@
1382
1412
  state.config.userInfo = document.getElementById('cfg-user-info')?.value?.trim() || state.config.userInfo || '';
1383
1413
  state.config.securityRules = document.getElementById('cfg-security')?.value || state.config.securityRules || DEFAULT_SECURITY_RULES['vi'];
1384
1414
  // Also save bot-tab-name → bots[0].name so both state locations stay in sync
1415
+ // Save bot-tab-name to the ACTIVE bot (not always bots[0])
1385
1416
  const tabName = document.getElementById('cfg-bot-tab-name')?.value?.trim();
1386
- if (tabName && state.bots[0]) state.bots[0].name = tabName;
1387
- else if (state.config.botName && state.bots[0] && !state.bots[0].name) {
1417
+ if (tabName && state.bots[state.activeBotIndex]) {
1418
+ state.bots[state.activeBotIndex].name = tabName;
1419
+ if (state.botCount <= 1) state.config.botName = tabName;
1420
+ } else if (state.config.botName && state.bots[0] && !state.bots[0].name) {
1388
1421
  state.bots[0].name = state.config.botName;
1389
1422
  }
1390
1423
  if (state.bots[state.activeBotIndex]) {
@@ -1682,7 +1715,6 @@
1682
1715
 
1683
1716
  function buildTelegramPostInstallChecklist() {
1684
1717
  const groupId = state.groupId || '';
1685
- const nativeProjectOpenClawRoot = `${projectDir.replace(/\\/g, '/')}/.openclaw`;
1686
1718
  const botList = state.bots.slice(0, state.botCount).map((bot, idx) => `- **${bot?.name || `Bot ${idx + 1}`}**`).join('\n');
1687
1719
  const isVi = lang === 'vi';
1688
1720
  return isVi
@@ -2083,9 +2115,10 @@ model:
2083
2115
  const browserPrefix = hasBrowser
2084
2116
  ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 & '
2085
2117
  : '';
2086
- const gatewayBridgePrefix = 'socat TCP-LISTEN:18791,fork,reuseaddr TCP:127.0.0.1:18791 & ';
2118
+ // gatewayBridgePrefix removed: socat on 0.0.0.0:18791 conflicts with openclaw binding 127.0.0.1:18791.
2119
+ const gatewayBridgePrefix = '';
2087
2120
  // Patch config on every startup to keep gateway settings stable
2088
- 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:'loopback',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});delete c.gateway.customBindHost;fs.writeFileSync(p,JSON.stringify(c,null,2));}\\" && `;
2121
+ 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));}\\" && `;
2089
2122
  // Auto-approve device pairing after gateway starts (required since v2026.3.x)
2090
2123
  const autoApproveCmd = '(while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done) & ';
2091
2124
  const finalCmd = `CMD sh -c "${pluginInstallCmd}${patchCmd}${browserPrefix}${gatewayBridgePrefix}${autoApproveCmd}${gatewayCmd}"`;
@@ -2095,7 +2128,7 @@ model:
2095
2128
  RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /var/lib/apt/lists/*
2096
2129
 
2097
2130
 
2098
- ARG CACHEBUST=${Date.now()}
2131
+ ARG OPENCLAW_VER="openclaw@2026.4.5"
2099
2132
  RUN npm install -g openclaw@2026.4.5 ${openClawRuntimePackages}${skillLines}${browserInstallLines}
2100
2133
  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);}"
2101
2134
  WORKDIR /root/.openclaw
@@ -4156,7 +4189,7 @@ Write-Host ""
4156
4189
 
4157
4190
  try {
4158
4191
  # [1/4] Create directories
4159
- Write-Host "[1/4] ${isVi ? 'Tạo thư mục...' : 'Creating directories...'}" -ForegroundColor Yellow
4192
+ Write-Host "[1/4] ${isVi ? 'Tao thu muc...' : 'Creating directories...'}" -ForegroundColor Yellow
4160
4193
 
4161
4194
  # Ensure root directory exists first
4162
4195
  New-Item -ItemType Directory -Force -Path "$projectDir" | Out-Null
@@ -4172,7 +4205,7 @@ New-Item -ItemType Directory -Force -Path "$projectDir" | Out-Null
4172
4205
  const winDir = dir.replace(/\//g, '\\');
4173
4206
  ps += `New-Item -ItemType Directory -Force -Path "$projectDir\\${winDir}" | Out-Null\n`;
4174
4207
  });
4175
- ps += `Write-Host " ✅ ${isVi ? 'Thư mục đã tạo' : 'Directories created'}" -ForegroundColor Green\n\n`;
4208
+ ps += `Write-Host " ✅ ${isVi ? 'Thu muc da tao' : 'Directories created'}" -ForegroundColor Green\n\n`;
4176
4209
 
4177
4210
  // [2/4] Write config files
4178
4211
  ps += `# [2/4] ${isVi ? 'Ghi config files...' : 'Writing config files...'}\nWrite-Host "[2/4] ${isVi ? 'Ghi config files...' : 'Writing config files...'}" -ForegroundColor Yellow\n`;
@@ -4186,50 +4219,50 @@ New-Item -ItemType Directory -Force -Path "$projectDir" | Out-Null
4186
4219
  ps += `\n[IO.File]::WriteAllText("$projectDir\\${winPath}", @'\n${safeContent}\n'@, $utf8)\n`;
4187
4220
  });
4188
4221
 
4189
- ps += `\nWrite-Host " ✅ ${isVi ? 'Config files đã ghi' : 'Config files written'}" -ForegroundColor Green\n\n`;
4222
+ ps += `\nWrite-Host " ✅ ${isVi ? 'Config files da ghi' : 'Config files written'}" -ForegroundColor Green\n\n`;
4190
4223
 
4191
4224
  // [3/4] Docker build
4192
4225
  ps += `# [3/4] Docker build
4193
- Write-Host "[3/4] ${isVi ? 'Build Docker image ( thể mất vài phút)...' : 'Building Docker image (may take a few minutes)...'}" -ForegroundColor Yellow
4226
+ Write-Host "[3/4] ${isVi ? 'Build Docker image (co the mat vai phut)...' : 'Building Docker image (may take a few minutes)...'}" -ForegroundColor Yellow
4194
4227
  Set-Location "$projectDir\\docker\\openclaw"
4195
4228
  docker compose build
4196
4229
  if ($LASTEXITCODE -ne 0) {
4197
- Write-Host " ❌ ${isVi ? 'Docker build thất bại. Docker Desktop đã chạy chưa?' : 'Docker build failed. Is Docker Desktop running?'}" -ForegroundColor Red
4198
- Read-Host "${isVi ? 'Nhấn Enter để thoát' : 'Press Enter to exit'}"
4230
+ Write-Host " ❌ ${isVi ? 'Docker build that bai. Docker Desktop da chay chua?' : 'Docker build failed. Is Docker Desktop running?'}" -ForegroundColor Red
4231
+ Read-Host "${isVi ? 'Nhan Enter de thoat' : 'Press Enter to exit'}"
4199
4232
  exit 1
4200
4233
  }
4201
- Write-Host " ✅ ${isVi ? 'Docker image đã build' : 'Docker image built'}" -ForegroundColor Green
4234
+ Write-Host " ✅ ${isVi ? 'Docker image da build' : 'Docker image built'}" -ForegroundColor Green
4202
4235
 
4203
4236
  `;
4204
4237
 
4205
4238
  // [4/4] Docker up
4206
4239
  ps += `# [4/4] Start bot
4207
- Write-Host "[4/4] ${isVi ? 'Khởi động bot...' : 'Starting bot...'}" -ForegroundColor Yellow
4240
+ Write-Host "[4/4] ${isVi ? 'Khoi dong bot...' : 'Starting bot...'}" -ForegroundColor Yellow
4208
4241
  docker compose up -d
4209
- Write-Host " ✅ ${isVi ? 'Bot đang chạy!' : 'Bot is running!'}" -ForegroundColor Green
4242
+ Write-Host " ✅ ${isVi ? 'Bot dang chay!' : 'Bot is running!'}" -ForegroundColor Green
4210
4243
 
4211
4244
  Write-Host ""
4212
- Write-Host " 🎉 ${isVi ? 'Setup hoàn tất!' : 'Setup complete!'}" -ForegroundColor Cyan
4245
+ Write-Host " 🎉 ${isVi ? 'Setup hoan tat!' : 'Setup complete!'}" -ForegroundColor Cyan
4213
4246
  `;
4214
4247
 
4215
4248
  // Post-setup notes
4216
4249
  const is9Router = state.config.provider === '9router';
4217
4250
  if (is9Router) {
4218
- ps += `Write-Host " ${isVi ? 'Mở http://localhost:30128/dashboard để login OAuth' : 'Open http://localhost:30128/dashboard to login OAuth'}" -ForegroundColor White\n`;
4251
+ ps += `Write-Host " ${isVi ? 'Mo http://localhost:30128/dashboard de login OAuth' : 'Open http://localhost:30128/dashboard to login OAuth'}" -ForegroundColor White\n`;
4219
4252
  }
4220
4253
  if (state.channel === 'zalo-personal') {
4221
- ps += `Write-Host " ${isVi ? 'Chạy: docker compose exec -it ai-bot openclaw channels login --channel zalouser --verbose' : 'Run: docker compose exec -it ai-bot openclaw channels login --channel zalouser --verbose'}" -ForegroundColor White\n`;
4222
- ps += `Write-Host " ${isVi ? 'QR sẽ nằm tại /tmp/openclaw/openclaw-zalouser-qr-default.png' : 'QR will be written to /tmp/openclaw/openclaw-zalouser-qr-default.png'}" -ForegroundColor DarkGray\n`;
4223
- ps += `Write-Host " ${isVi ? 'Copy QR ra ngoài: docker compose cp ai-bot:/tmp/openclaw/openclaw-zalouser-qr-default.png ./zalo-login-qr.png' : 'Copy the QR out: docker compose cp ai-bot:/tmp/openclaw/openclaw-zalouser-qr-default.png ./zalo-login-qr.png'}" -ForegroundColor DarkGray\n`;
4254
+ ps += `Write-Host " ${isVi ? 'Chay: docker compose exec -it ai-bot openclaw channels login --channel zalouser --verbose' : 'Run: docker compose exec -it ai-bot openclaw channels login --channel zalouser --verbose'}" -ForegroundColor White\n`;
4255
+ ps += `Write-Host " ${isVi ? 'QR se nam tai /tmp/openclaw/openclaw-zalouser-qr-default.png' : 'QR will be written to /tmp/openclaw/openclaw-zalouser-qr-default.png'}" -ForegroundColor DarkGray\n`;
4256
+ ps += `Write-Host " ${isVi ? 'Copy QR ra ngoai: docker compose cp ai-bot:/tmp/openclaw/openclaw-zalouser-qr-default.png ./zalo-login-qr.png' : 'Copy the QR out: docker compose cp ai-bot:/tmp/openclaw/openclaw-zalouser-qr-default.png ./zalo-login-qr.png'}" -ForegroundColor DarkGray\n`;
4224
4257
  }
4225
4258
 
4226
4259
  ps += `Write-Host ""
4227
4260
  } catch {
4228
4261
  Write-Host ""
4229
- Write-Host " ❌ LỖI / ERROR: $($_.Exception.Message)" -ForegroundColor Red
4262
+ Write-Host " ❌ LOI / ERROR: $($_.Exception.Message)" -ForegroundColor Red
4230
4263
  Write-Host ""
4231
4264
  }
4232
- Read-Host "${isVi ? 'Nhấn Enter để thoát' : 'Press Enter to exit'}"
4265
+ Read-Host "${isVi ? 'Nhan Enter de thoat' : 'Press Enter to exit'}"
4233
4266
  `;
4234
4267
 
4235
4268
  // Wrap in a .bat that extracts the PS section to a temp .ps1 then runs it.
@@ -4335,7 +4368,7 @@ ${ps}`;
4335
4368
 
4336
4369
  let script = `#!/bin/bash
4337
4370
  # 🦞 OpenClaw Setup Script${isMultiBot ? ` — Multi-Bot (${state.botCount} bots)` : ''}
4338
- # ${isVi ? 'Tạo bởi OpenClaw Wizard — paste vào terminal trong thư mục project' : 'Generated by OpenClaw Wizard — paste into terminal in your project folder'}
4371
+ # ${isVi ? 'Tao boi OpenClaw Wizard — paste vao terminal trong thu muc project' : 'Generated by OpenClaw Wizard — paste into terminal in your project folder'}
4339
4372
  set -e
4340
4373
  echo "🦞 OpenClaw Setup${isMultiBot ? ` (${state.botCount} bots)` : ''}..."
4341
4374
  echo ""
@@ -4348,7 +4381,7 @@ echo ""
4348
4381
  if (dir) dirs.add(dir);
4349
4382
  });
4350
4383
 
4351
- script += `# \${isVi ? 'Tạo thư mục' : 'Create directories'}\n`;
4384
+ script += `# \${isVi ? 'Tao thu muc' : 'Create directories'}\n`;
4352
4385
  Array.from(dirs).sort().forEach(dir => {
4353
4386
  script += `mkdir -p "${dir}"\n`;
4354
4387
  });
@@ -4364,16 +4397,16 @@ echo ""
4364
4397
  });
4365
4398
 
4366
4399
  script += `echo ""\n`;
4367
- script += `echo "\${isVi ? '✅ Tạo file xong!' : '✅ Files created!'}"\n`;
4400
+ script += `echo "\${isVi ? '✅ Tao file xong!' : '✅ Files created!'}"\n`;
4368
4401
  script += `echo ""\n`;
4369
- script += `echo "\${isVi ? '🐳 Đang khởi động Docker ( thể mất vài phút)...' : '🐳 Starting Docker (may take a few minutes)...'}"\n`;
4370
- script += `if docker compose version > /dev/null 2>&1; then\n COMPOSE_CMD="docker compose"\nelif docker-compose version > /dev/null 2>&1; then\n COMPOSE_CMD="docker-compose"\nelse\n echo "\${isVi ? '❌ Không tìm thấy Docker Compose! Cài bằng: sudo apt-get install docker-compose-plugin' : '❌ Docker Compose not found! Install: sudo apt-get install docker-compose-plugin'}"\n exit 1\nfi\n`;
4371
- script += `# Check Docker daemon is actually running\nif ! docker info > /dev/null 2>&1; then\n echo "${isVi ? '❌ Docker daemon chưa chạy! Hãy mở Docker Desktop rồi chạy lại.' : '❌ Docker daemon is not running! Open Docker Desktop first, then re-run this script.'}"; exit 1\nfi\n`;
4402
+ script += `echo "\${isVi ? '🐳 Dang khoi dong Docker (co the mat vai phut)...' : '🐳 Starting Docker (may take a few minutes)...'}"\n`;
4403
+ script += `if docker compose version > /dev/null 2>&1; then\n COMPOSE_CMD="docker compose"\nelif docker-compose version > /dev/null 2>&1; then\n COMPOSE_CMD="docker-compose"\nelse\n echo "\${isVi ? '❌ Khong tim thay Docker Compose! Cai bang: sudo apt-get install docker-compose-plugin' : '❌ Docker Compose not found! Install: sudo apt-get install docker-compose-plugin'}"\n exit 1\nfi\n`;
4404
+ script += `# Check Docker daemon is actually running\nif ! docker info > /dev/null 2>&1; then\n echo "${isVi ? '❌ Docker daemon chua chay! Hay mo Docker Desktop roi chay lai.' : '❌ Docker daemon is not running! Open Docker Desktop first, then re-run this script.'}"; exit 1\nfi\n`;
4372
4405
 
4373
4406
  if (isMultiBot) {
4374
4407
  script += `cd "docker/openclaw"\n`;
4375
4408
  script += `$COMPOSE_CMD up --detach --build\n`;
4376
- script += `if [ $? -ne 0 ]; then\n echo "\${isVi ? '❌ Docker build thất bại.' : '❌ Docker build failed.'}"\n exit 1\nfi\n`;
4409
+ script += `if [ $? -ne 0 ]; then\n echo "\${isVi ? '❌ Docker build that bai.' : '❌ Docker build failed.'}"\n exit 1\nfi\n`;
4377
4410
  script += `echo ""\n`;
4378
4411
  script += `echo "${isVi ? 'OK: ${state.botCount} bot dang chay!' : 'OK: ${state.botCount} bots are running!'}"\n`;
4379
4412
  for (let i = 0; i < state.botCount; i++) {
@@ -4384,8 +4417,8 @@ echo ""
4384
4417
  } else {
4385
4418
  script += `cd "docker/openclaw"\n`;
4386
4419
  script += `$COMPOSE_CMD up --detach --build\n`;
4387
- script += `if [ $? -ne 0 ]; then\n echo "\${isVi ? '❌ Docker build thất bại.' : '❌ Docker build failed.'}"\n exit 1\nfi\n`;
4388
- script += `echo "\${isVi ? '🎉 Bot đang chạy! Xem log qua:' : '🎉 Bot is running! View logs:'}"\n`;
4420
+ script += `if [ $? -ne 0 ]; then\n echo "\${isVi ? '❌ Docker build that bai.' : '❌ Docker build failed.'}"\n exit 1\nfi\n`;
4421
+ script += `echo "\${isVi ? '🎉 Bot dang chay! Xem log qua:' : '🎉 Bot is running! View logs:'}"\n`;
4389
4422
  script += `echo " docker logs -f openclaw-bot"\n`;
4390
4423
  script += `echo ""\n`;
4391
4424
  }
@@ -241,11 +241,12 @@ checks.push(() => expectMatch(
241
241
  checks.push(() => expect(
242
242
  cli.includes("a.add('http://' + entry.address + ':18791')")
243
243
  && cli.includes('allowedOrigins:Array.from(a).filter(Boolean)')
244
- && cli.includes("bind:'loopback'")
245
- && cli.includes("delete c.gateway.customBindHost;")
246
- && cli.includes("const gatewayBridge = 'socat TCP-LISTEN:18791,fork,reuseaddr TCP:127.0.0.1:18791 & ';")
244
+ && cli.includes("bind:'custom',customBindHost:'0.0.0.0'")
245
+ && !cli.includes("bind:'loopback'")
246
+ && !cli.includes("delete c.gateway.customBindHost;")
247
+ && !cli.includes("const gatewayBridge = 'socat TCP-LISTEN:18791")
247
248
  && !cli.includes("a.add(`http://${entry.address}:18791`)"),
248
- 'Docker CLI patch script must keep the gateway loopback-local behind a socat bridge and avoid shell-expanding ${entry.address}'
249
+ 'Docker CLI patch script must use bind:custom+customBindHost:0.0.0.0, skip socat gateway bridge, and avoid shell-expanding ${entry.address}'
249
250
  ));
250
251
 
251
252
  checks.push(() => expectMatch(
@@ -361,11 +362,12 @@ checks.push(() => expectMatch(
361
362
  checks.push(() => expect(
362
363
  setup.includes("a.add('http://' + entry.address + ':18791')")
363
364
  && setup.includes('allowedOrigins:Array.from(a).filter(Boolean)')
364
- && setup.includes("bind:'loopback'")
365
- && setup.includes("delete c.gateway.customBindHost;")
366
- && setup.includes("const gatewayBridgePrefix = 'socat TCP-LISTEN:18791,fork,reuseaddr TCP:127.0.0.1:18791 & ';")
365
+ && setup.includes("bind:'custom',customBindHost:'0.0.0.0'")
366
+ && !setup.includes("bind:'loopback'")
367
+ && !setup.includes("delete c.gateway.customBindHost;")
368
+ && !setup.includes("const gatewayBridgePrefix = 'socat TCP-LISTEN:18791")
367
369
  && !setup.includes("a.add(\\`http://\\${entry.address}:18791\\`)"),
368
- 'Wizard Docker patch command must keep the gateway loopback-local behind a socat bridge and avoid shell-expanding ${entry.address}'
370
+ 'Wizard Docker patch command must use bind:custom+customBindHost:0.0.0.0, skip socat gateway bridge, and avoid shell-expanding ${entry.address}'
369
371
  ));
370
372
 
371
373
  checks.push(() => expectMatch(