create-openclaw-bot 5.7.6 → 5.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  # 🦞 OpenClaw Setup
4
4
 
5
5
  <p align="center">
6
- <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.7.6-0EA5E9?style=for-the-badge" alt="Version 5.7.6" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.7.7-0EA5E9?style=for-the-badge" alt="Version 5.7.7" /></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,19 +24,18 @@ 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.7.5
27
+ ## 🆕 What's new in v5.7.7
28
28
 
29
- - 🐛 **Hotfix: CLI crash on all platforms** — Fixed `ReferenceError: channelKey is not defined` that caused the CLI to crash immediately after completing the setup wizard on every platform (Telegram, Zalo). The `writeWorkspaceFiles()` function now correctly receives `channelKey` as an explicit parameter.
30
- - 🔤 **Fix: Vietnamese text encoding** — Restored proper UTF-8 encoding integrity in `cli.src.js` to prevent double-encoding of Vietnamese characters from Windows tools.
29
+ - 🛠️ **Infrastructure & Zalo Bot Stabilization** — Automatically pins `openclaw@2026.4.15` across all deployment scripts, completely eliminating gateway crashes caused by version mismatch when installing Zalo Personal.
30
+ - 📦 **Docker Volume & Gateway Deadlock Optimization** — Redesigned the `.openclaw` mount mechanism and implemented `tmpfs` for `plugin-runtime-deps`, entirely preventing I/O lock conditions on Windows/WSL2.
31
+ - 🔄 **9Router Smart-Sync** — Automatically detects and syncs models (Gemini, Claude, GPT) from active AI providers directly into the `smart-route` combination every time the system starts up.
31
32
 
32
33
  <details>
33
- <summary><b>Previous: What's new in v5.7.2</b></summary>
34
+ <summary><b>Previous: What's new in v5.7.6</b></summary>
34
35
 
35
- - 🏗️ **Centralized config architecture** — All `openclaw.json`, `.env`, and `exec-approvals.json` generation now flows through a single `bot-config-gen.js` module. Both the Web Wizard and CLI share the same builder, eliminating config drift between surfaces.
36
- - 🔄 **Rolling `@latest` versioning** — Installation scripts now use `openclaw@latest` instead of pinned versions, ensuring users always get the newest release without waiting for a setup update.
37
- - 🧪 **Comprehensive test matrix** — Added 422 new matrix tests covering all OS × Deploy × Channel × Bot Count combinations, plus Wizard IIFE sandbox evaluation and CLI structural validation.
38
- - 🐛 **Removed `autoReply` bug** — The `autoReply: true` field that caused gateway startup crashes on Zalo Personal has been permanently removed from all generators.
39
- - 💬 **Standardized Zalo Personal config** — Zalo Personal (`zalouser`) channel now uses production-matching config with `groups`, `groupPolicy`, `historyLimit`, and proper `bindings`.
36
+ - 🧹 **Automated Uninstall Scripts** — Generates an `uninstall-openclaw` script to cleanly remove system/container resources.
37
+ - 🐛 **Hotfix CLI Crash** — Permanently fixed the `channelKey is not defined` bug and double-encoding issues for Vietnamese texts.
38
+ - 🏗️ **Centralized config architecture** — All config logic is now unified through `bot-config-gen.js`, completely eradicating the `autoReply: true` bug.
40
39
 
41
40
  ## </details>
42
41
 
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.7.6-0EA5E9?style=for-the-badge" alt="Version 5.7.6" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.7.7-0EA5E9?style=for-the-badge" alt="Version 5.7.7" /></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,19 +24,18 @@ 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.7.5
27
+ ## 🆕 Có gì mới trong v5.7.7
28
28
 
29
- - 🐛 **Hotfix: CLI crash trên mọi nền tảng** — Sửa lỗi `ReferenceError: channelKey is not defined` khiến CLI crash ngay sau khi hoàn thành wizard trên mọi nền tảng (Telegram, Zalo). Hàm `writeWorkspaceFiles()` giờ nhận `channelKey` như một tham số tường minh.
30
- - 🔤 **Sửa: Encoding tiếng Việt trong CLI** — Khôi phục tính toàn vẹn UTF-8 trong `cli.src.js`, ngăn double-encoding tự tiếng Việt do công cụ Windows gây ra.
29
+ - 🛠️ **Ổn Định Infrastructure & Zalo Bot** — Tự động ghim `openclaw@2026.4.15` cho mọi nền tảng, loại bỏ hoàn toàn các lỗi crash do lệch version khi cài Zalo Personal.
30
+ - 📦 **Tối Ưu Docker Volume & Gateway Deadlock** — Thiết kế lại chế mount thư mục `.openclaw` triển khai `tmpfs` cho `plugin-runtime-deps`, triệt để ngăn chặn tình trạng I/O lock trên Windows/WSL2.
31
+ - 🔄 **9Router Smart-Sync** — Tự động nhận diện và đồng bộ danh sách models (Gemini, Claude, GPT) từ các AI provider đang kích hoạt trực tiếp vào combo `smart-route` mỗi khi khởi động hệ thống.
31
32
 
32
33
  <details>
33
- <summary><b>Trước đó: Có gì mới ở v5.7.2</b></summary>
34
+ <summary><b>Trước đó: Có gì mới ở v5.7.6</b></summary>
34
35
 
35
- - 🏗️ **Kiến trúc config tập trung** — Toàn bộ logic tạo `openclaw.json`, `.env`, và `exec-approvals.json` giờ chạy qua module duy nhất `bot-config-gen.js`. Cả Web Wizard và CLI dùng chung cùng một builder, loại bỏ sai lệch config giữa 2 bề mặt.
36
- - 🔄 **Phiên bản rolling `@latest`** Script cài đặt giờ dùng `openclaw@latest` thay version cố định, đảm bảo người dùng luôn nhận bản mới nhất.
37
- - 🧪 **Bộ test matrix toàn diện** — Thêm 422 test mới phủ tất cả tổ hợp OS × Deploy × Channel × Số bot, kèm sandbox Wizard IIFE kiểm tra cấu trúc CLI.
38
- - 🐛 **Xóa lỗi `autoReply`** — Trường `autoReply: true` gây crash gateway khi khởi động Zalo Personal đã bị loại bỏ vĩnh viễn khỏi mọi generator.
39
- - 💬 **Chuẩn hóa config Zalo Personal** — Kênh Zalo Personal (`zalouser`) giờ dùng config khớp production với `groups`, `groupPolicy`, `historyLimit`, và `bindings` đúng.
36
+ - 🧹 **Tự Động Tạo Script Gỡ Cài Đặt** — Sinh sẵn file `uninstall-openclaw` dọn sạch tài nguyên hệ thống/container.
37
+ - 🐛 **Hotfix CLI Crash**Fix triệt để lỗi `channelKey is not defined` double-encoding tiếng Việt.
38
+ - 🏗️ **Kiến trúc config tập trung** — Toàn bộ logic config giờ hợp nhất qua `bot-config-gen.js`, xoá triệt để lỗi `autoReply: true`.
40
39
 
41
40
  ## </details>
42
41
 
package/dist/cli.js CHANGED
@@ -488,14 +488,18 @@ async function patchProjectDocker9Router(projectDir) {
488
488
  await fs.writeFile(path.join(dockerDir, 'sync.js'), build9RouterSmartRouteSyncScript('/root/.9router/db.json'));
489
489
  await fs.writeFile(path.join(dockerDir, 'patch-9router.js'), build9RouterPatchScript());
490
490
  let compose = await fs.readFile(composePath, 'utf8');
491
- compose = compose.replace(
492
- /node -e "require\('fs'\)\.writeFileSync\('\/tmp\/sync\.js',Buffer\.from\('[^']*','base64'\)\.toString\(\)\)"/,
493
- "cp /opt/sync.js /tmp/sync.js"
494
- );
495
- compose = compose.replace(
496
- /(npm install -g [^\n]+\n)/,
497
- `$1 cp /opt/patch-9router.js /tmp/patch-9router.js\n`
498
- );
491
+ compose = compose.replace(
492
+ /node -e "require\('fs'\)\.writeFileSync\('\/tmp\/sync\.js',Buffer\.from\('[^']*','base64'\)\.toString\(\)\)"/,
493
+ "cp /opt/sync.js /tmp/sync.js"
494
+ );
495
+ compose = compose.replace(
496
+ /\s*node -e "require\('fs'\)\.writeFileSync\('\/tmp\/patch-9router\.js',Buffer\.from\('[^']*','base64'\)\.toString\(\)\)"\n/,
497
+ ''
498
+ );
499
+ compose = compose.replace(
500
+ /(npm install -g [^\n]+\n)/,
501
+ `$1 cp /opt/patch-9router.js /tmp/patch-9router.js\n`
502
+ );
499
503
  if (!compose.includes('node /tmp/patch-9router.js || true')) {
500
504
  compose = compose.replace(
501
505
  /(\s*node \/tmp\/sync\.js > \/tmp\/sync\.log 2>&1 &\n)/,
@@ -2158,20 +2162,19 @@ async function main() {
2158
2162
 
2159
2163
 
2160
2164
  // ── Docker artifacts: Dockerfile + docker-compose via shared buildDockerArtifacts() ──────
2161
- const skillSlugs = SKILLS
2162
- .filter(s => selectedSkills.includes(s.value) && s.slug)
2163
- .map(s => s.slug);
2164
- const skillInstallCmd = skillSlugs.length > 0
2165
- ? skillSlugs.map(s => `openclaw skills install ${s} 2>/dev/null || true`).join(' && ')
2166
- : '';
2165
+ const skillSlugs = SKILLS
2166
+ .filter(s => selectedSkills.includes(s.value) && s.slug)
2167
+ .map(s => s.slug);
2168
+ const skillInstallCmd = skillSlugs.length > 0
2169
+ ? skillSlugs.map(s => `ensure_skill ${s}`).join('\n')
2170
+ : '';
2167
2171
  const relayInstallCmd = (isMultiBot && channelKey === 'telegram')
2168
2172
  ? buildRelayPluginInstallCommand('openclaw')
2169
2173
  : '';
2170
- const zaloModInstallCmd = hasZaloPersonal(channelKey)
2171
- ? 'openclaw plugins install openclaw-zalo-mod 2>/dev/null || true'
2172
- : '';
2173
- const socatBridge = hasBrowserDesktop ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 &' : '';
2174
- const deviceApproveLoop = 'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &';
2174
+ const zaloModInstallCmd = hasZaloPersonal(channelKey)
2175
+ ? 'ensure_plugin zalo-mod openclaw-zalo-mod'
2176
+ : '';
2177
+ const deviceApproveLoop = 'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &';
2175
2178
 
2176
2179
  // buildDockerArtifacts joins runtimeCommandParts with spaces, then appends 'openclaw gateway run'
2177
2180
  // Each part should be a standalone command fragment (no trailing &&)
@@ -2183,14 +2186,13 @@ async function main() {
2183
2186
  isMultiBot,
2184
2187
  hasBrowser: hasBrowserDesktop || hasBrowserServer,
2185
2188
  selectedModel: modelsPrimary,
2186
- agentId,
2187
- runtimeCommandParts: [
2188
- skillInstallCmd ? skillInstallCmd + ' &&' : '',
2189
- relayInstallCmd ? relayInstallCmd + ' &&' : '',
2190
- zaloModInstallCmd ? zaloModInstallCmd + ' &&' : '',
2191
- socatBridge,
2192
- deviceApproveLoop,
2193
- ].filter(Boolean),
2189
+ agentId,
2190
+ runtimeCommandParts: [
2191
+ zaloModInstallCmd,
2192
+ relayInstallCmd,
2193
+ skillInstallCmd,
2194
+ deviceApproveLoop,
2195
+ ].filter(Boolean),
2194
2196
  volumeMount: '../..:/root/project',
2195
2197
  singleComposeName: `oc-${agentId}`,
2196
2198
  multiComposeName: 'oc-multibot',
@@ -261,6 +261,14 @@
261
261
  channels.zalouser = {
262
262
  enabled: true,
263
263
  defaultAccount: 'default',
264
+ accounts: {
265
+ default: {
266
+ dmPolicy: 'open',
267
+ allowFrom: ['*'],
268
+ groupPolicy: 'allowlist',
269
+ groupAllowFrom: ['*'],
270
+ },
271
+ },
264
272
  dmPolicy: 'open',
265
273
  allowFrom: ['*'],
266
274
  groupPolicy: 'allowlist',
@@ -304,6 +312,7 @@
304
312
  enabled: true,
305
313
  config: {
306
314
  botName: botName,
315
+ ownerId: "",
307
316
  groupNames: {},
308
317
  zaloDisplayNames: [botName],
309
318
  welcomeEnabled: true,
@@ -311,7 +320,6 @@
311
320
  spamWindowSeconds: 300,
312
321
  },
313
322
  };
314
- entries.zalouser = { enabled: true };
315
323
  }
316
324
 
317
325
  const plugins = { entries };
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  (function (root) {
3
- const OPENCLAW_NPM_SPEC = 'openclaw@latest';
3
+ const OPENCLAW_NPM_SPEC = 'openclaw@2026.4.15';
4
4
  const OPENCLAW_RUNTIME_PACKAGES = 'grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api';
5
5
  const NINE_ROUTER_NPM_SPEC = '9router@latest';
6
6
  const NINE_ROUTER_PORT = 20128;
@@ -39,11 +39,26 @@ const sync = async () => {
39
39
  if (!res.ok) { console.log('[sync-combo] API not ready, retrying...'); return; }
40
40
  const d = await res.json();
41
41
  const rawConnections = Array.isArray(d.connections) ? d.connections : Array.isArray(d.providerConnections) ? d.providerConnections : [];
42
- const a = [...new Set(rawConnections.filter(c => c && c.provider && c.isActive !== false && !c.disabled).map(c => c.provider))];
43
- if (!a.length) { removeSmartRoute(); return; }
42
+ const activeConns = rawConnections.filter(c => c && c.provider && c.isActive !== false && !c.disabled);
43
+ const a = [...new Set(activeConns.map(c => c.provider))];
44
+ if (!a.length) { console.log('[sync-combo] No active providers reported; keeping existing smart-route'); return; }
44
45
  a.sort((x, y) => (PREF.indexOf(x) === -1 ? 99 : PREF.indexOf(x)) - (PREF.indexOf(y) === -1 ? 99 : PREF.indexOf(y)));
45
- const m = a.flatMap(pv => PM[pv] || []);
46
- if (!m.length) { removeSmartRoute(); return; }
46
+ const m = [];
47
+ for (const pv of a) {
48
+ if (PM[pv]) m.push(...PM[pv]);
49
+ const conns = activeConns.filter(c => c.provider === pv);
50
+ for (const c of conns) {
51
+ if (Array.isArray(c.models)) {
52
+ for (const mdl of c.models) {
53
+ const mdlId = typeof mdl === 'string' ? mdl : mdl.id;
54
+ if (mdlId && !m.includes(mdlId) && !m.includes(pv + '/' + mdlId)) {
55
+ m.push(pv + '/' + mdlId);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ if (!m.length) { console.log('[sync-combo] No mapped models for active providers; keeping existing smart-route'); return; }
47
62
  const c = { id: 'smart-route', name: 'smart-route', alias: 'smart-route', models: m };
48
63
  const i = db.combos.findIndex(x => x.id === 'smart-route');
49
64
  if (i >= 0) {
@@ -155,7 +170,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
155
170
  dockerfilePlugins = [],
156
171
  dockerfileSkillInstallMode = 'none',
157
172
  runtimeCommandParts = [],
158
- volumeMount = '../..:/root/project',
173
+ volumeMount = '../../.openclaw:/root/project/.openclaw\\n - ../../:/mnt/project',
159
174
  singleComposeName = 'oc-bot',
160
175
  multiComposeName = 'oc-multibot',
161
176
  singleAppContainerName = 'openclaw-bot',
@@ -191,50 +206,50 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
191
206
  : '';
192
207
  const patchLine = `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);}"`;
193
208
 
194
- // Dynamic runtime configuration: backup config before any first-run install, restore after.
195
- // Missing plugin install may touch openclaw.json, so preserve critical fields.
209
+ // Dynamic runtime configuration: backup config before any first-run install, restore after.
210
+ // Missing plugin install may touch openclaw.json, so preserve critical fields.
196
211
  const backupConfigScript = `const fs=require('fs'),path=require('path'),p=path.join(process.cwd(),'.openclaw','openclaw.json'),b=p.replace('openclaw.json','.openclaw-config-backup.json');if(fs.existsSync(p)){fs.copyFileSync(p,b);}`;
197
212
  const backupConfigB64 = encodeBase64Utf8(backupConfigScript);
198
213
 
199
214
  const restoreConfigScript = `const fs=require('fs'),os=require('os'),path=require('path'),p=path.join(process.cwd(),'.openclaw','openclaw.json'),b=p.replace('openclaw.json','.openclaw-config-backup.json');if(fs.existsSync(p)&&fs.existsSync(b)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const bk=JSON.parse(fs.readFileSync(b,'utf8'));const keep=['agents','channels','bindings','commands','models','browser','skills'];for(const k of keep){if(bk[k]&&!c[k])c[k]=bk[k];}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',mode:c.gateway?.mode||bk.gateway?.mode||'local',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});fs.writeFileSync(p,JSON.stringify(c,null,2));fs.unlinkSync(b);}`;
200
215
  const restoreConfigB64 = encodeBase64Utf8(restoreConfigScript);
201
216
 
202
- const runtimeParts = runtimeCommandParts.filter(Boolean);
203
- const runtimePrelude = [
204
- 'export OPENCLAW_HOME="${OPENCLAW_HOME:-$PWD/.openclaw}"',
205
- 'export OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-$OPENCLAW_HOME}"',
206
- 'mkdir -p "$OPENCLAW_HOME" "$OPENCLAW_STATE_DIR"',
207
- 'if [ "$OPENCLAW_STATE_DIR" != "$OPENCLAW_HOME" ]; then',
208
- ' for path in "$OPENCLAW_HOME"/*; do',
209
- ' [ -e "$path" ] || continue',
210
- ' name="$(basename "$path")"',
211
- ' [ "$name" = "plugin-runtime-deps" ] && continue',
212
- ' [ "$name" = "logs" ] && continue',
213
- ' [ -e "$OPENCLAW_STATE_DIR/$name" ] || ln -s "$path" "$OPENCLAW_STATE_DIR/$name"',
214
- ' done',
215
- 'fi',
216
- 'ensure_plugin() {',
217
- ' id="$1"',
218
- ' spec="$2"',
219
- ' if [ -d "$OPENCLAW_HOME/extensions/$id" ]; then',
220
- ' echo "[entrypoint] plugin $id already installed"',
221
- ' return 0',
222
- ' fi',
223
- ' echo "[entrypoint] plugin $id missing; installing $spec"',
224
- ' openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec"',
225
- '}',
226
- 'ensure_skill() {',
227
- ' id="$1"',
228
- ' if find "$OPENCLAW_HOME" -maxdepth 4 -type d -path "*/skills/$id" -print -quit 2>/dev/null | grep -q .; then',
229
- ' echo "[entrypoint] skill $id already installed"',
230
- ' return 0',
231
- ' fi',
232
- ' echo "[entrypoint] skill $id missing; installing"',
233
- ' openclaw skills install "$id" 2>/dev/null || echo "[entrypoint] warning: failed to install skill $id"',
234
- '}',
235
- 'echo "[entrypoint] ensuring runtime assets, then starting gateway"',
236
- ];
237
- runtimeParts.unshift(...runtimePrelude);
217
+ const runtimeParts = runtimeCommandParts.filter(Boolean);
218
+ const runtimePrelude = [
219
+ 'export OPENCLAW_HOME="${OPENCLAW_HOME:-$PWD/.openclaw}"',
220
+ 'export OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-$OPENCLAW_HOME}"',
221
+ 'mkdir -p "$OPENCLAW_HOME" "$OPENCLAW_STATE_DIR"',
222
+ 'if [ "$OPENCLAW_STATE_DIR" != "$OPENCLAW_HOME" ]; then',
223
+ ' for path in "$OPENCLAW_HOME"/*; do',
224
+ ' [ -e "$path" ] || continue',
225
+ ' name="$(basename "$path")"',
226
+ ' [ "$name" = "plugin-runtime-deps" ] && continue',
227
+ ' [ "$name" = "logs" ] && continue',
228
+ ' [ -e "$OPENCLAW_STATE_DIR/$name" ] || ln -s "$path" "$OPENCLAW_STATE_DIR/$name"',
229
+ ' done',
230
+ 'fi',
231
+ 'ensure_plugin() {',
232
+ ' id="$1"',
233
+ ' spec="$2"',
234
+ ' if [ -d "$OPENCLAW_HOME/extensions/$id" ]; then',
235
+ ' echo "[entrypoint] plugin $id already installed"',
236
+ ' return 0',
237
+ ' fi',
238
+ ' echo "[entrypoint] plugin $id missing; installing $spec"',
239
+ ' openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec"',
240
+ '}',
241
+ 'ensure_skill() {',
242
+ ' id="$1"',
243
+ ' if find "$OPENCLAW_HOME" -maxdepth 4 -type d -path "*/skills/$id" -print -quit 2>/dev/null | grep -q .; then',
244
+ ' echo "[entrypoint] skill $id already installed"',
245
+ ' return 0',
246
+ ' fi',
247
+ ' echo "[entrypoint] skill $id missing; installing"',
248
+ ' openclaw skills install "$id" 2>/dev/null || echo "[entrypoint] warning: failed to install skill $id"',
249
+ '}',
250
+ 'echo "[entrypoint] ensuring runtime assets, then starting gateway"',
251
+ ];
252
+ runtimeParts.unshift(...runtimePrelude);
238
253
  // Backup config BEFORE plugin installs (runtimeCommandParts may contain plugin install commands)
239
254
  runtimeParts.unshift(`node -e 'eval(Buffer.from("${backupConfigB64}","base64").toString())'`);
240
255
  // Restore config AFTER plugin installs (which may clobber openclaw.json)
@@ -253,7 +268,7 @@ RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /v
253
268
  ${browserInstallLines}
254
269
  ARG OPENCLAW_VER="${openClawNpmSpec}"
255
270
  ARG CACHE_BUST=""
256
- RUN npm install -g ${openClawNpmSpec} ${openClawRuntimePackages}${skillLines}${pluginLines}
271
+ RUN echo "CACHE_BUST=$CACHE_BUST" && npm install -g $OPENCLAW_VER ${openClawRuntimePackages}${skillLines}${pluginLines}
257
272
  ${patchLine}
258
273
  RUN node -e "require('fs').writeFileSync('/usr/local/bin/openclaw-entrypoint.sh', Buffer.from('${runtimeScriptB64}','base64').toString())" && chmod +x /usr/local/bin/openclaw-entrypoint.sh
259
274
  WORKDIR /root/project
@@ -264,12 +279,12 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
264
279
 
265
280
  const syncScript = build9RouterSmartRouteSyncScript('/root/.9router/db.json');
266
281
  const syncScriptBase64 = encodeBase64Utf8(syncScript);
267
- const patchScript = build9RouterPatchScript();
282
+ const patchScript = build9RouterPatchScript();
268
283
  const patchScriptBase64 = encodeBase64Utf8(patchScript);
269
284
  const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64);
270
285
  const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
271
286
 
272
- const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n';
287
+ const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n - OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1\n tmpfs:\n - /root/project/.openclaw/plugin-runtime-deps\n';
273
288
 
274
289
  let compose;
275
290
  if (isMultiBot) {
@@ -462,7 +477,7 @@ ${appEnvironmentBlock}${plainSingleExtraHosts ? `${extraHostsBlock}\n` : ''}
462
477
  - "18791:18791"`;
463
478
  }
464
479
 
465
- return {
480
+ return {
466
481
  dockerfile,
467
482
  compose,
468
483
  syncScript,
package/dist/setup.js CHANGED
@@ -619,7 +619,7 @@
619
619
  // ── Shared runtime constants, relay helpers, auth profile builders (setup/shared/common-gen.js)
620
620
  // @ts-nocheck
621
621
  (function (root) {
622
- const OPENCLAW_NPM_SPEC = 'openclaw@latest';
622
+ const OPENCLAW_NPM_SPEC = 'openclaw@2026.4.15';
623
623
  const OPENCLAW_RUNTIME_PACKAGES = 'grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api';
624
624
  const NINE_ROUTER_NPM_SPEC = '9router@latest';
625
625
  const NINE_ROUTER_PORT = 20128;
@@ -1699,6 +1699,14 @@ if (typeof exports !== 'undefined' && workspaceRoot.__openclawWorkspace) {
1699
1699
  channels.zalouser = {
1700
1700
  enabled: true,
1701
1701
  defaultAccount: 'default',
1702
+ accounts: {
1703
+ default: {
1704
+ dmPolicy: 'open',
1705
+ allowFrom: ['*'],
1706
+ groupPolicy: 'allowlist',
1707
+ groupAllowFrom: ['*'],
1708
+ },
1709
+ },
1702
1710
  dmPolicy: 'open',
1703
1711
  allowFrom: ['*'],
1704
1712
  groupPolicy: 'allowlist',
@@ -1742,6 +1750,7 @@ if (typeof exports !== 'undefined' && workspaceRoot.__openclawWorkspace) {
1742
1750
  enabled: true,
1743
1751
  config: {
1744
1752
  botName: botName,
1753
+ ownerId: "",
1745
1754
  groupNames: {},
1746
1755
  zaloDisplayNames: [botName],
1747
1756
  welcomeEnabled: true,
@@ -1749,7 +1758,6 @@ if (typeof exports !== 'undefined' && workspaceRoot.__openclawWorkspace) {
1749
1758
  spamWindowSeconds: 300,
1750
1759
  },
1751
1760
  };
1752
- entries.zalouser = { enabled: true };
1753
1761
  }
1754
1762
 
1755
1763
  const plugins = { entries };
@@ -2513,11 +2521,26 @@ const sync = async () => {
2513
2521
  if (!res.ok) { console.log('[sync-combo] API not ready, retrying...'); return; }
2514
2522
  const d = await res.json();
2515
2523
  const rawConnections = Array.isArray(d.connections) ? d.connections : Array.isArray(d.providerConnections) ? d.providerConnections : [];
2516
- const a = [...new Set(rawConnections.filter(c => c && c.provider && c.isActive !== false && !c.disabled).map(c => c.provider))];
2517
- if (!a.length) { removeSmartRoute(); return; }
2524
+ const activeConns = rawConnections.filter(c => c && c.provider && c.isActive !== false && !c.disabled);
2525
+ const a = [...new Set(activeConns.map(c => c.provider))];
2526
+ if (!a.length) { console.log('[sync-combo] No active providers reported; keeping existing smart-route'); return; }
2518
2527
  a.sort((x, y) => (PREF.indexOf(x) === -1 ? 99 : PREF.indexOf(x)) - (PREF.indexOf(y) === -1 ? 99 : PREF.indexOf(y)));
2519
- const m = a.flatMap(pv => PM[pv] || []);
2520
- if (!m.length) { removeSmartRoute(); return; }
2528
+ const m = [];
2529
+ for (const pv of a) {
2530
+ if (PM[pv]) m.push(...PM[pv]);
2531
+ const conns = activeConns.filter(c => c.provider === pv);
2532
+ for (const c of conns) {
2533
+ if (Array.isArray(c.models)) {
2534
+ for (const mdl of c.models) {
2535
+ const mdlId = typeof mdl === 'string' ? mdl : mdl.id;
2536
+ if (mdlId && !m.includes(mdlId) && !m.includes(pv + '/' + mdlId)) {
2537
+ m.push(pv + '/' + mdlId);
2538
+ }
2539
+ }
2540
+ }
2541
+ }
2542
+ }
2543
+ if (!m.length) { console.log('[sync-combo] No mapped models for active providers; keeping existing smart-route'); return; }
2521
2544
  const c = { id: 'smart-route', name: 'smart-route', alias: 'smart-route', models: m };
2522
2545
  const i = db.combos.findIndex(x => x.id === 'smart-route');
2523
2546
  if (i >= 0) {
@@ -2629,7 +2652,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
2629
2652
  dockerfilePlugins = [],
2630
2653
  dockerfileSkillInstallMode = 'none',
2631
2654
  runtimeCommandParts = [],
2632
- volumeMount = '../..:/root/project',
2655
+ volumeMount = '../../.openclaw:/root/project/.openclaw\\n - ../../:/mnt/project',
2633
2656
  singleComposeName = 'oc-bot',
2634
2657
  multiComposeName = 'oc-multibot',
2635
2658
  singleAppContainerName = 'openclaw-bot',
@@ -2727,7 +2750,7 @@ RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /v
2727
2750
  ${browserInstallLines}
2728
2751
  ARG OPENCLAW_VER="${openClawNpmSpec}"
2729
2752
  ARG CACHE_BUST=""
2730
- RUN npm install -g ${openClawNpmSpec} ${openClawRuntimePackages}${skillLines}${pluginLines}
2753
+ RUN echo "CACHE_BUST=$CACHE_BUST" && npm install -g $OPENCLAW_VER ${openClawRuntimePackages}${skillLines}${pluginLines}
2731
2754
  ${patchLine}
2732
2755
  RUN node -e "require('fs').writeFileSync('/usr/local/bin/openclaw-entrypoint.sh', Buffer.from('${runtimeScriptB64}','base64').toString())" && chmod +x /usr/local/bin/openclaw-entrypoint.sh
2733
2756
  WORKDIR /root/project
@@ -2738,12 +2761,12 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
2738
2761
 
2739
2762
  const syncScript = build9RouterSmartRouteSyncScript('/root/.9router/db.json');
2740
2763
  const syncScriptBase64 = encodeBase64Utf8(syncScript);
2741
- const patchScript = build9RouterPatchScript();
2764
+ const patchScript = build9RouterPatchScript();
2742
2765
  const patchScriptBase64 = encodeBase64Utf8(patchScript);
2743
2766
  const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64);
2744
2767
  const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
2745
2768
 
2746
- const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n';
2769
+ const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n - OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1\n tmpfs:\n - /root/project/.openclaw/plugin-runtime-deps\n';
2747
2770
 
2748
2771
  let compose;
2749
2772
  if (isMultiBot) {
@@ -3963,7 +3986,7 @@ function generateWinBat(ctx) {
3963
3986
  'echo [1/5] Kiem tra Node.js...',
3964
3987
  'where node >nul 2>&1 || (echo ERROR: Node.js chua cai! Tai tai: https://nodejs.org && pause && exit /b 1)',
3965
3988
  'echo [2/5] Cai OpenClaw CLI...',
3966
- `call npm install -g openclaw@latest ${openClawRuntimePackages} || goto :fail`,
3989
+ `call npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} || goto :fail`,
3967
3990
  'echo [OK] OpenClaw da duoc cai dat thanh cong.',
3968
3991
  ];
3969
3992
 
@@ -4153,7 +4176,7 @@ function generateMacOsSh(ctx) {
4153
4176
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.zshrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.zshrc"',
4154
4177
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
4155
4178
  '# Install openclaw (user-local first, sudo fallback)',
4156
- `npm install -g openclaw@latest ${openClawRuntimePackages} || sudo npm install -g openclaw@latest ${openClawRuntimePackages}`,
4179
+ `npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} || sudo npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages}`,
4157
4180
  ];
4158
4181
  providerLines(sh, 'sh');
4159
4182
  if (pluginCmd) sh.push(pluginCmd);
@@ -4219,7 +4242,7 @@ function generateVpsSh(ctx) {
4219
4242
  'export DATA_DIR="$PROJECT_DIR/.9router"',
4220
4243
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
4221
4244
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
4222
- `npm install -g openclaw@latest ${openClawRuntimePackages} pm2@latest`,
4245
+ `npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} pm2@latest`,
4223
4246
  ];
4224
4247
  providerLines(vps, 'sh');
4225
4248
  if (pluginCmd) vps.push(pluginCmd);
@@ -4342,7 +4365,7 @@ function generateLinuxSh(ctx) {
4342
4365
  'export DATA_DIR="$PROJECT_DIR/.9router"',
4343
4366
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
4344
4367
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
4345
- `npm install -g openclaw@latest ${openClawRuntimePackages}`,
4368
+ `npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages}`,
4346
4369
  ];
4347
4370
  providerLines(lnx, 'sh');
4348
4371
  if (pluginCmd) lnx.push(pluginCmd);
@@ -5832,7 +5855,7 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
5832
5855
  };
5833
5856
  clawConfig.plugins = {
5834
5857
  entries: {
5835
- ...(ch.hasZaloPersonal ? { 'zalo-mod': { enabled: true, config: {} } } : {}),
5858
+ ...(ch.hasZaloPersonal ? { 'zalo-mod': { enabled: true, config: { botName: botName, ownerId: "", groupNames: {}, zaloDisplayNames: [botName], welcomeEnabled: true, spamRepeatN: 3, spamWindowSeconds: 300 } } } : {}),
5836
5859
  'memory-core': {
5837
5860
  config: { dreaming: { enabled: state.config.skills.includes('memory') } },
5838
5861
  },
@@ -5847,7 +5870,18 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
5847
5870
  pluginEntries[plugin.package || pid] = { enabled: true };
5848
5871
  });
5849
5872
  if (ch.hasZaloPersonal) {
5850
- pluginEntries['zalo-mod'] = { enabled: true, config: {} };
5873
+ pluginEntries['zalo-mod'] = {
5874
+ enabled: true,
5875
+ config: {
5876
+ botName: botName,
5877
+ ownerId: "",
5878
+ groupNames: {},
5879
+ zaloDisplayNames: [botName],
5880
+ welcomeEnabled: true,
5881
+ spamRepeatN: 3,
5882
+ spamWindowSeconds: 300
5883
+ }
5884
+ };
5851
5885
  }
5852
5886
  pluginEntries['memory-core'] = {
5853
5887
  config: { dreaming: { enabled: state.config.skills.includes('memory') } },
@@ -5925,7 +5959,6 @@ model:
5925
5959
  dockerfileSkillInstallMode: 'build',
5926
5960
  runtimeCommandParts: [
5927
5961
  pluginInstallCmd,
5928
- hasBrowser ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 &' : '',
5929
5962
  'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &'
5930
5963
  ],
5931
5964
  plainSingleExtraHosts: true,
@@ -6561,7 +6594,7 @@ fi
6561
6594
  : 'Ubuntu / VPS: The script auto-installs Node.js 20 LTS, OpenClaw CLI, and PM2 to keep the bot running after reboot.');
6562
6595
  }
6563
6596
  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)');
6564
- steps.push(_isVi ? '📦 Cài OpenClaw CLI (<code>npm install -g openclaw@latest</code>)' : '📦 Install OpenClaw CLI (<code>npm install -g openclaw@latest</code>)');
6597
+ steps.push(_isVi ? `📦 Cài OpenClaw CLI (<code>npm install -g ${common.OPENCLAW_NPM_SPEC}</code>)` : `📦 Install OpenClaw CLI (<code>npm install -g ${common.OPENCLAW_NPM_SPEC}</code>)`);
6565
6598
  if (_is9Router) {
6566
6599
  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');
6567
6600
  } else if (_isOllama) {
package/package.json CHANGED
@@ -1,39 +1,39 @@
1
- {
2
- "name": "create-openclaw-bot",
3
- "version": "5.7.6",
4
- "description": "Interactive CLI installer for OpenClaw Bot",
5
- "main": "dist/cli.js",
6
- "bin": {
7
- "create-openclaw-bot": "./dist/cli.js"
8
- },
9
- "files": [
10
- "dist"
11
- ],
12
- "scripts": {
13
- "build": "node src/build.mjs --deploy",
14
- "dev": "node src/build.mjs --deploy --watch",
15
- "test": "node src/tests/smoke-cli-logic.mjs && node src/tests/test-generation.mjs && node src/tests/test-matrix.mjs",
16
- "bump": "node src/bump-version.mjs"
17
- },
18
- "keywords": [
19
- "openclaw",
20
- "cli",
21
- "bot",
22
- "zalo",
23
- "telegram",
24
- "ai"
25
- ],
26
- "author": "tuanminhhole",
27
- "license": "MIT",
28
- "dependencies": {
29
- "@inquirer/prompts": "^4.3.1",
30
- "chalk": "^5.3.0",
31
- "fs-extra": "^11.2.0"
32
- },
33
- "bundleDependencies": [
34
- "@inquirer/prompts",
35
- "chalk",
36
- "fs-extra"
37
- ],
38
- "type": "module"
39
- }
1
+ {
2
+ "name": "create-openclaw-bot",
3
+ "version": "5.7.7",
4
+ "description": "Interactive CLI installer for OpenClaw Bot",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "create-openclaw-bot": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "node src/build.mjs --deploy",
14
+ "dev": "node src/build.mjs --deploy --watch",
15
+ "test": "node src/tests/smoke-cli-logic.mjs && node src/tests/test-generation.mjs && node src/tests/test-matrix.mjs",
16
+ "bump": "node src/bump-version.mjs"
17
+ },
18
+ "keywords": [
19
+ "openclaw",
20
+ "cli",
21
+ "bot",
22
+ "zalo",
23
+ "telegram",
24
+ "ai"
25
+ ],
26
+ "author": "tuanminhhole",
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "@inquirer/prompts": "^4.3.1",
30
+ "chalk": "^5.3.0",
31
+ "fs-extra": "^11.2.0"
32
+ },
33
+ "bundleDependencies": [
34
+ "@inquirer/prompts",
35
+ "chalk",
36
+ "fs-extra"
37
+ ],
38
+ "type": "module"
39
+ }