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 +21 -0
- package/CHANGELOG.vi.md +22 -0
- package/README.md +4 -4
- package/README.vi.md +4 -4
- package/cli.js +8 -6
- package/package.json +1 -1
- package/setup.js +66 -33
- package/tests/smoke-cli-logic.mjs +10 -8
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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:'
|
|
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
|
-
|
|
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
|
|
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',
|
|
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',
|
|
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
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.
|
|
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[
|
|
1387
|
-
|
|
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
|
-
|
|
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:'
|
|
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
|
|
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 ? '
|
|
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 ? '
|
|
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
|
|
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 (
|
|
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
|
|
4198
|
-
Read-Host "${isVi ? '
|
|
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
|
|
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 ? '
|
|
4240
|
+
Write-Host "[4/4] ${isVi ? 'Khoi dong bot...' : 'Starting bot...'}" -ForegroundColor Yellow
|
|
4208
4241
|
docker compose up -d
|
|
4209
|
-
Write-Host " ✅ ${isVi ? 'Bot
|
|
4242
|
+
Write-Host " ✅ ${isVi ? 'Bot dang chay!' : 'Bot is running!'}" -ForegroundColor Green
|
|
4210
4243
|
|
|
4211
4244
|
Write-Host ""
|
|
4212
|
-
Write-Host " 🎉 ${isVi ? 'Setup
|
|
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 ? '
|
|
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 ? '
|
|
4222
|
-
ps += `Write-Host " ${isVi ? 'QR
|
|
4223
|
-
ps += `Write-Host " ${isVi ? 'Copy QR ra
|
|
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 " ❌
|
|
4262
|
+
Write-Host " ❌ LOI / ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
|
4230
4263
|
Write-Host ""
|
|
4231
4264
|
}
|
|
4232
|
-
Read-Host "${isVi ? '
|
|
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 ? '
|
|
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 ? '
|
|
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 ? '✅
|
|
4400
|
+
script += `echo "\${isVi ? '✅ Tao file xong!' : '✅ Files created!'}"\n`;
|
|
4368
4401
|
script += `echo ""\n`;
|
|
4369
|
-
script += `echo "\${isVi ? '🐳
|
|
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 ? '❌
|
|
4371
|
-
script += `# Check Docker daemon is actually running\nif ! docker info > /dev/null 2>&1; then\n echo "${isVi ? '❌ Docker daemon
|
|
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
|
|
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
|
|
4388
|
-
script += `echo "\${isVi ? '🎉 Bot
|
|
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:'
|
|
245
|
-
&& cli.includes("
|
|
246
|
-
&& cli.includes("
|
|
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
|
|
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:'
|
|
365
|
-
&& setup.includes("
|
|
366
|
-
&& setup.includes("
|
|
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
|
|
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(
|