create-openclaw-bot 5.7.6 → 5.7.8

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.8-0EA5E9?style=for-the-badge" alt="Version 5.7.8" /></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.8
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
+ - 🧹 **Zalo Mod Plugin Cleanup** — Removed auto-injection of `zalo-mod` into generated configs. The plugin now must be installed manually via ClawHub, eliminating persistent installation loops and Docker permission conflicts.
30
+ - 🔧 **Cleaner Docker Build** — `openclaw-zalo-mod` is no longer baked into the Docker image during build or runtime entrypoint, reducing image size and startup errors.
31
+ - 📝 **Standardized Release Workflow** — Added `.agent/workflows/update.md` as the canonical release checklist for this repo.
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.7</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
+ - 🛠️ **Infrastructure & Zalo Bot Stabilization** — Automatically pins `openclaw@2026.4.15` across all deployment scripts, eliminating gateway crashes caused by version mismatch when installing Zalo Personal.
37
+ - 📦 **Docker Volume & Gateway Deadlock Optimization** — Redesigned the `.openclaw` mount mechanism and implemented `tmpfs` for `plugin-runtime-deps`, preventing I/O lock conditions on Windows/WSL2.
38
+ - 🔄 **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.
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.8-0EA5E9?style=for-the-badge" alt="Version 5.7.8" /></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.8
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
+ - 🧹 **Dọn dẹp Plugin Zalo Mod** — Gỡ bỏ auto-inject `zalo-mod` khỏi config được generate. Plugin giờ phải cài thủ công qua ClawHub, loại bỏ vòng lặp cài đặt liên tục xung đột quyền trong Docker.
30
+ - 🔧 **Docker Build Sạch Hơn** — `openclaw-zalo-mod` không còn được nhúng vào Docker image khi build hoặc trong entrypoint runtime, giảm kích thước image lỗi khởi động.
31
+ - 📝 **Chuẩn Hóa Workflow Release** — Thêm `.agent/workflows/update.md` làm checklist release chuẩn cho repo này.
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.7</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 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
+ - 🛠️ **Ổ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.
37
+ - 📦 **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.
38
+ - 🔄 **9Router Smart-Sync** Tự động nhận diện đồ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.
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,16 @@ 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 deviceApproveLoop = 'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &';
2175
2175
 
2176
2176
  // buildDockerArtifacts joins runtimeCommandParts with spaces, then appends 'openclaw gateway run'
2177
2177
  // Each part should be a standalone command fragment (no trailing &&)
@@ -2183,14 +2183,12 @@ async function main() {
2183
2183
  isMultiBot,
2184
2184
  hasBrowser: hasBrowserDesktop || hasBrowserServer,
2185
2185
  selectedModel: modelsPrimary,
2186
- agentId,
2187
- runtimeCommandParts: [
2188
- skillInstallCmd ? skillInstallCmd + ' &&' : '',
2189
- relayInstallCmd ? relayInstallCmd + ' &&' : '',
2190
- zaloModInstallCmd ? zaloModInstallCmd + ' &&' : '',
2191
- socatBridge,
2192
- deviceApproveLoop,
2193
- ].filter(Boolean),
2186
+ agentId,
2187
+ runtimeCommandParts: [
2188
+ relayInstallCmd,
2189
+ skillInstallCmd,
2190
+ deviceApproveLoop,
2191
+ ].filter(Boolean),
2194
2192
  volumeMount: '../..:/root/project',
2195
2193
  singleComposeName: `oc-${agentId}`,
2196
2194
  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',
@@ -297,21 +305,9 @@
297
305
 
298
306
  const allow = ['memory-core'];
299
307
 
300
- // zalo-mod plugin for Zalo Personal
308
+ // Zalo Personal channel is native; install openclaw-zalo-mod manually via ClawHub when needed.
301
309
  if (isZaloPersonal(channelKey)) {
302
- allow.push('zalo-mod', 'zalouser');
303
- entries['zalo-mod'] = {
304
- enabled: true,
305
- config: {
306
- botName: botName,
307
- groupNames: {},
308
- zaloDisplayNames: [botName],
309
- welcomeEnabled: true,
310
- spamRepeatN: 3,
311
- spamWindowSeconds: 300,
312
- },
313
- };
314
- entries.zalouser = { enabled: true };
310
+ allow.push('zalouser');
315
311
  }
316
312
 
317
313
  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',
@@ -1735,21 +1743,9 @@ if (typeof exports !== 'undefined' && workspaceRoot.__openclawWorkspace) {
1735
1743
 
1736
1744
  const allow = ['memory-core'];
1737
1745
 
1738
- // zalo-mod plugin for Zalo Personal
1746
+ // Zalo Personal channel is native; install openclaw-zalo-mod manually via ClawHub when needed.
1739
1747
  if (isZaloPersonal(channelKey)) {
1740
- allow.push('zalo-mod', 'zalouser');
1741
- entries['zalo-mod'] = {
1742
- enabled: true,
1743
- config: {
1744
- botName: botName,
1745
- groupNames: {},
1746
- zaloDisplayNames: [botName],
1747
- welcomeEnabled: true,
1748
- spamRepeatN: 3,
1749
- spamWindowSeconds: 300,
1750
- },
1751
- };
1752
- entries.zalouser = { enabled: true };
1748
+ allow.push('zalouser');
1753
1749
  }
1754
1750
 
1755
1751
  const plugins = { entries };
@@ -2513,11 +2509,26 @@ const sync = async () => {
2513
2509
  if (!res.ok) { console.log('[sync-combo] API not ready, retrying...'); return; }
2514
2510
  const d = await res.json();
2515
2511
  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; }
2512
+ const activeConns = rawConnections.filter(c => c && c.provider && c.isActive !== false && !c.disabled);
2513
+ const a = [...new Set(activeConns.map(c => c.provider))];
2514
+ if (!a.length) { console.log('[sync-combo] No active providers reported; keeping existing smart-route'); return; }
2518
2515
  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; }
2516
+ const m = [];
2517
+ for (const pv of a) {
2518
+ if (PM[pv]) m.push(...PM[pv]);
2519
+ const conns = activeConns.filter(c => c.provider === pv);
2520
+ for (const c of conns) {
2521
+ if (Array.isArray(c.models)) {
2522
+ for (const mdl of c.models) {
2523
+ const mdlId = typeof mdl === 'string' ? mdl : mdl.id;
2524
+ if (mdlId && !m.includes(mdlId) && !m.includes(pv + '/' + mdlId)) {
2525
+ m.push(pv + '/' + mdlId);
2526
+ }
2527
+ }
2528
+ }
2529
+ }
2530
+ }
2531
+ if (!m.length) { console.log('[sync-combo] No mapped models for active providers; keeping existing smart-route'); return; }
2521
2532
  const c = { id: 'smart-route', name: 'smart-route', alias: 'smart-route', models: m };
2522
2533
  const i = db.combos.findIndex(x => x.id === 'smart-route');
2523
2534
  if (i >= 0) {
@@ -2629,7 +2640,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
2629
2640
  dockerfilePlugins = [],
2630
2641
  dockerfileSkillInstallMode = 'none',
2631
2642
  runtimeCommandParts = [],
2632
- volumeMount = '../..:/root/project',
2643
+ volumeMount = '../../.openclaw:/root/project/.openclaw\\n - ../../:/mnt/project',
2633
2644
  singleComposeName = 'oc-bot',
2634
2645
  multiComposeName = 'oc-multibot',
2635
2646
  singleAppContainerName = 'openclaw-bot',
@@ -2727,7 +2738,7 @@ RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /v
2727
2738
  ${browserInstallLines}
2728
2739
  ARG OPENCLAW_VER="${openClawNpmSpec}"
2729
2740
  ARG CACHE_BUST=""
2730
- RUN npm install -g ${openClawNpmSpec} ${openClawRuntimePackages}${skillLines}${pluginLines}
2741
+ RUN echo "CACHE_BUST=$CACHE_BUST" && npm install -g $OPENCLAW_VER ${openClawRuntimePackages}${skillLines}${pluginLines}
2731
2742
  ${patchLine}
2732
2743
  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
2744
  WORKDIR /root/project
@@ -2738,12 +2749,12 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
2738
2749
 
2739
2750
  const syncScript = build9RouterSmartRouteSyncScript('/root/.9router/db.json');
2740
2751
  const syncScriptBase64 = encodeBase64Utf8(syncScript);
2741
- const patchScript = build9RouterPatchScript();
2752
+ const patchScript = build9RouterPatchScript();
2742
2753
  const patchScriptBase64 = encodeBase64Utf8(patchScript);
2743
2754
  const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64);
2744
2755
  const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
2745
2756
 
2746
- const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n';
2757
+ 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
2758
 
2748
2759
  let compose;
2749
2760
  if (isMultiBot) {
@@ -2996,7 +3007,6 @@ function buildNativeScriptCtx(options) {
2996
3007
  const p = PLUGINS.find((x) => x.id === pid);
2997
3008
  if (p) allPlugins.push(p.package);
2998
3009
  });
2999
- if (ch && ch.hasZaloPersonal) allPlugins.push('openclaw-zalo-mod');
3000
3010
  if (isMultiBot && state.channel === 'telegram') allPlugins.push(relayPluginSpec);
3001
3011
  const uniquePlugins = [...new Set(allPlugins)];
3002
3012
  const pluginCmd = uniquePlugins.length > 0 ? uniquePlugins.map(function(pkg) { return 'call npm exec -- openclaw plugins install ' + pkg + ' || echo [WARN] Plugin ' + pkg + ' cai dat that bai (co the do rate limit). Ban co the cai thu cong sau.'; }).join('\r\n') : '';
@@ -3963,7 +3973,7 @@ function generateWinBat(ctx) {
3963
3973
  'echo [1/5] Kiem tra Node.js...',
3964
3974
  'where node >nul 2>&1 || (echo ERROR: Node.js chua cai! Tai tai: https://nodejs.org && pause && exit /b 1)',
3965
3975
  'echo [2/5] Cai OpenClaw CLI...',
3966
- `call npm install -g openclaw@latest ${openClawRuntimePackages} || goto :fail`,
3976
+ `call npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} || goto :fail`,
3967
3977
  'echo [OK] OpenClaw da duoc cai dat thanh cong.',
3968
3978
  ];
3969
3979
 
@@ -4153,7 +4163,7 @@ function generateMacOsSh(ctx) {
4153
4163
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.zshrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.zshrc"',
4154
4164
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
4155
4165
  '# Install openclaw (user-local first, sudo fallback)',
4156
- `npm install -g openclaw@latest ${openClawRuntimePackages} || sudo npm install -g openclaw@latest ${openClawRuntimePackages}`,
4166
+ `npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} || sudo npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages}`,
4157
4167
  ];
4158
4168
  providerLines(sh, 'sh');
4159
4169
  if (pluginCmd) sh.push(pluginCmd);
@@ -4219,7 +4229,7 @@ function generateVpsSh(ctx) {
4219
4229
  'export DATA_DIR="$PROJECT_DIR/.9router"',
4220
4230
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
4221
4231
  '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`,
4232
+ `npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} pm2@latest`,
4223
4233
  ];
4224
4234
  providerLines(vps, 'sh');
4225
4235
  if (pluginCmd) vps.push(pluginCmd);
@@ -4342,7 +4352,7 @@ function generateLinuxSh(ctx) {
4342
4352
  'export DATA_DIR="$PROJECT_DIR/.9router"',
4343
4353
  'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
4344
4354
  '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}`,
4355
+ `npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages}`,
4346
4356
  ];
4347
4357
  providerLines(lnx, 'sh');
4348
4358
  if (pluginCmd) lnx.push(pluginCmd);
@@ -5832,7 +5842,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
5832
5842
  };
5833
5843
  clawConfig.plugins = {
5834
5844
  entries: {
5835
- ...(ch.hasZaloPersonal ? { 'zalo-mod': { enabled: true, config: {} } } : {}),
5836
5845
  'memory-core': {
5837
5846
  config: { dreaming: { enabled: state.config.skills.includes('memory') } },
5838
5847
  },
@@ -5846,9 +5855,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
5846
5855
  if (!plugin || plugin.hidden) return;
5847
5856
  pluginEntries[plugin.package || pid] = { enabled: true };
5848
5857
  });
5849
- if (ch.hasZaloPersonal) {
5850
- pluginEntries['zalo-mod'] = { enabled: true, config: {} };
5851
- }
5852
5858
  pluginEntries['memory-core'] = {
5853
5859
  config: { dreaming: { enabled: state.config.skills.includes('memory') } },
5854
5860
  };
@@ -5888,7 +5894,6 @@ model:
5888
5894
  // 3. Dockerfile + docker-compose.yml
5889
5895
  const allPlugins = [];
5890
5896
  if (ch.pluginInstall) allPlugins.push(ch.pluginInstall);
5891
- if (ch.hasZaloPersonal) allPlugins.push('openclaw-zalo-mod');
5892
5897
  state.config.plugins.forEach((pid) => {
5893
5898
  const plug = PLUGINS.find((p) => p.id === pid);
5894
5899
  if (plug) allPlugins.push(plug.package);
@@ -5904,7 +5909,6 @@ model:
5904
5909
  const relayPluginInstallCmd = isMultiBot ? buildRelayPluginInstallCommand('openclaw') : '';
5905
5910
  const pluginRuntimeSpecs = allPlugins.filter((p) => p && p !== '@openclaw/zalouser');
5906
5911
  const pluginIdForSpec = (spec) => {
5907
- if (String(spec).includes('zalo-mod')) return 'zalo-mod';
5908
5912
  return String(spec).replace(/^@openclaw\//, '').replace(/^openclaw-/, '');
5909
5913
  };
5910
5914
  const pluginInstallCmd = [
@@ -5925,7 +5929,6 @@ model:
5925
5929
  dockerfileSkillInstallMode: 'build',
5926
5930
  runtimeCommandParts: [
5927
5931
  pluginInstallCmd,
5928
- hasBrowser ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 &' : '',
5929
5932
  'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &'
5930
5933
  ],
5931
5934
  plainSingleExtraHosts: true,
@@ -6561,7 +6564,7 @@ fi
6561
6564
  : 'Ubuntu / VPS: The script auto-installs Node.js 20 LTS, OpenClaw CLI, and PM2 to keep the bot running after reboot.');
6562
6565
  }
6563
6566
  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>)');
6567
+ 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
6568
  if (_is9Router) {
6566
6569
  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
6570
  } 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.8",
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
+ }