create-openclaw-bot 5.17.1 → 5.17.2
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 +62 -62
- package/README.vi.md +57 -57
- package/dist/cli.js +4 -4
- package/dist/server/local-server.js +249 -210
- package/dist/setup/data/channels.js +7 -7
- package/dist/setup/data/header.js +1 -1
- package/dist/setup/data/index.js +1 -1
- package/dist/setup/data/plugins.js +3 -3
- package/dist/setup/data/providers.js +7 -7
- package/dist/setup/shared/bot-config-gen.js +34 -34
- package/dist/setup/shared/common-gen.js +6 -6
- package/dist/setup/shared/docker-gen.js +23 -23
- package/dist/setup/shared/host-ui-ps1.js +1 -1
- package/dist/setup/shared/install-gen.js +9 -9
- package/dist/setup/shared/windows-launcher-gen.js +22 -8
- package/dist/setup/shared/workspace-gen.js +144 -144
- package/dist/web/app.js +112 -33
- package/dist/web/styles.css +6 -6
- package/package.json +1 -1
|
@@ -196,17 +196,17 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
196
196
|
|
|
197
197
|
// Idempotent config upgrade replayed on every runtime start. Docker embeds it in the container
|
|
198
198
|
// entrypoint; the native runtime (local-server.js) runs it via `node -e` before every gateway
|
|
199
|
-
// (re)start
|
|
199
|
+
// (re)start - one script, both deploy modes, so native bots stop missing config fixes like the
|
|
200
200
|
// smart-route contextWindow 200000/131072 → 1048576 (Kent chot 01/09/2026; chi dung den DUNG
|
|
201
201
|
// hai gia tri setup tung ghi, custom tuning giu nguyen). Full rationale sits with the
|
|
202
202
|
// entrypoint block inside buildDockerArtifacts.
|
|
203
203
|
// ⚠️ toolResultMaxChars: openclaw ≥2026.8 BO key nay khoi schema va TU CHOI BOOT khi thay no.
|
|
204
|
-
// Ban cu cua script nay them key vo dieu kien moi lan container start
|
|
204
|
+
// Ban cu cua script nay them key vo dieu kien moi lan container start - nen mot khach rebuild
|
|
205
205
|
// image (Dockerfile keo openclaw moi) la roi vao vong: gateway chet vi key ⇒ xoa tay ⇒ entrypoint
|
|
206
206
|
// them lai ⇒ chet tiep, khong lo ra thu pham (ca that 103.98.149.154, 31/08/2026, 66 lan restart).
|
|
207
207
|
// Gio gate theo version openclaw THAT trong container: <2026.8 thi backfill nhu cu, ≥2026.8 thi
|
|
208
208
|
// GO key neu con (tu chua cac project da nhiem). Khong doc duoc version thi KHONG dong nao chay
|
|
209
|
-
//
|
|
209
|
+
// - tha thieu mot default con hon gieo key lam gateway tu choi boot.
|
|
210
210
|
const contextDefaultsScript = `const fs=require('fs'),path=require('path');const p=path.join(process.cwd(),'.openclaw','openclaw.json');if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));let ch=false;c.skills=c.skills||{};c.skills.workshop=c.skills.workshop||{};if(!c.skills.workshop.approvalPolicy){c.skills.workshop.approvalPolicy='auto';ch=true;}if(c.browser&&c.browser.enabled!==false){c.tools=c.tools||{};const dn=Array.isArray(c.tools.deny)?c.tools.deny:[];if(!dn.includes('browser')){dn.push('browser');c.tools.deny=dn;ch=true;}}let ocMajorMinor=0;try{const v=String(require('child_process').execSync('openclaw --version',{stdio:['ignore','pipe','ignore']})).match(/(\\d{4})\\.(\\d+)/);if(v)ocMajorMinor=Number(v[1])*100+Number(v[2]);}catch(e){}const d=(c.agents&&c.agents.defaults)?c.agents.defaults:null;if(d){if(d.imageMaxDimensionPx===undefined){d.imageMaxDimensionPx=1024;ch=true;}if(d.imageQuality===undefined){d.imageQuality='efficient';ch=true;}if(ocMajorMinor&&ocMajorMinor<202608){d.contextLimits=d.contextLimits||{};if(d.contextLimits.toolResultMaxChars===undefined){d.contextLimits.toolResultMaxChars=12000;ch=true;}}else if(ocMajorMinor>=202608&&d.contextLimits&&d.contextLimits.toolResultMaxChars!==undefined){delete d.contextLimits.toolResultMaxChars;ch=true;}}if(ocMajorMinor>=202609){if(c.messages&&c.messages.removeAckAfterReply!==undefined){delete c.messages.removeAckAfterReply;ch=true;console.log('[migrate] go messages.removeAckAfterReply (2026.9 khong con nhan khoa nay)');}if(c.meta&&c.meta.lastTouchedAt!==undefined){delete c.meta.lastTouchedAt;ch=true;console.log('[migrate] go meta.lastTouchedAt (2026.9 khong con nhan khoa nay)');}if(c.browser&&c.browser.profiles&&typeof c.browser.profiles==='object'){for(const pn of Object.keys(c.browser.profiles)){const bp=c.browser.profiles[pn];if(bp&&typeof bp==='object'&&bp.color!==undefined){delete bp.color;ch=true;console.log('[migrate] go browser.profiles.'+pn+'.color (2026.9 khong con nhan khoa nay)');}}}}c.gateway=(c.gateway&&typeof c.gateway==='object')?c.gateway:{};if(c.gateway.mode===undefined){c.gateway.mode='local';ch=true;console.log('[migrate] gateway.mode=local (2026.9 tu choi chay neu thieu)');}c.tools=c.tools||{};c.tools.sessions=(c.tools.sessions&&typeof c.tools.sessions==='object')?c.tools.sessions:{};if(c.tools.sessions.visibility===undefined){c.tools.sessions.visibility='agent';ch=true;console.log('[migrate] tools.sessions.visibility=agent (khong cho bot doc phien cua bot khac)');}if(ocMajorMinor>=202608&&d&&d.modelSelectionScope===undefined){d.modelSelectionScope='session';ch=true;console.log('[migrate] agents.defaults.modelSelectionScope=session (khong ghi de model trong config)');}if(ocMajorMinor>=202608){const ag=c.agents||{};const nEntries=(Array.isArray(ag.list)?ag.list.length:0)+(ag.entries&&typeof ag.entries==='object'?Object.keys(ag.entries).length:0);if(nEntries>1&&ag.ownership!=='explicit'){ag.ownership='explicit';c.agents=ag;ch=true;}try{const agRoot=path.join(process.cwd(),'.openclaw','agents');for(const id of fs.readdirSync(agRoot)){const sf=path.join(agRoot,id,'sessions','sessions.json');if(fs.existsSync(sf)){fs.renameSync(sf,sf+'.bak-legacy-'+Date.now());console.log('[migrate] parked legacy session store '+sf);}}}catch(e){}if(c.commands&&c.commands.ownerDisplay!==undefined){delete c.commands.ownerDisplay;ch=true;}if(c.plugins&&c.plugins.bundledDiscovery!==undefined){delete c.plugins.bundledDiscovery;ch=true;}if(Array.isArray(ag.list)){ag.entries=(ag.entries&&typeof ag.entries==='object'&&!Array.isArray(ag.entries))?ag.entries:{};for(const a of ag.list){if(a&&a.id&&!ag.entries[a.id]){const{id:_aid,...rest}=a;ag.entries[_aid]=rest;}}delete ag.list;c.agents=ag;ch=true;console.log('[migrate] moved agents.list into agents.entries');}try{const ea=path.join(process.cwd(),'.openclaw','exec-approvals.json');if(fs.existsSync(ea)){fs.renameSync(ea,ea+'.bak-legacy-'+Date.now());console.log('[migrate] parked legacy exec approvals '+ea);}}catch(e){}try{const ag2=c.agents||{};const ids=(ag2.entries&&typeof ag2.entries==='object')?Object.keys(ag2.entries):(Array.isArray(ag2.list)?ag2.list.map(function(a){return a&&a.id;}).filter(Boolean):[]);if(ids.length>1&&d){if(!(d.heartbeat&&d.heartbeat.agentId)){d.heartbeat=(d.heartbeat&&typeof d.heartbeat==='object')?d.heartbeat:{};d.heartbeat.agentId=ids[0];ch=true;console.log('[migrate] agents.defaults.heartbeat.agentId='+ids[0]+' (khong thi heartbeat tat cam)');}if(!(d.systemAgent&&d.systemAgent.agentId)){d.systemAgent=(d.systemAgent&&typeof d.systemAgent==='object')?d.systemAgent:{};d.systemAgent.agentId=ids[0];ch=true;console.log('[migrate] agents.defaults.systemAgent.agentId='+ids[0]+' (khong thi cron.list vo ca trang Automations)');}const tk=(c.talk&&typeof c.talk==='object')?c.talk:{};if(!tk.agentId){tk.agentId=ids[0];c.talk=tk;ch=true;console.log('[migrate] talk.agentId='+ids[0]+' (khong thi talk.catalog loi khi mo Control UI)');}}}catch(e){}}const pr=c.models&&c.models.providers&&c.models.providers['9router'];if(pr&&Array.isArray(pr.models)){for(const m of pr.models){if(m&&m.id==='smart-route'&&(m.contextWindow===200000||m.contextWindow===131072)){m.contextWindow=1048576;ch=true;}}}if(ch)fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
|
|
211
211
|
|
|
212
212
|
function buildDockerArtifacts(options) {
|
|
@@ -249,11 +249,11 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
249
249
|
const extVolMount = useExtensionsVolume ? '\n - openclaw-extensions:/home/node/project/.openclaw/extensions' : '';
|
|
250
250
|
const extVolDecl = useExtensionsVolume ? '\n openclaw-extensions:' : '';
|
|
251
251
|
// SQLite state on Docker Desktop (macOS/Windows): the host bind mount goes through a
|
|
252
|
-
// virtualized file share (virtiofs/gRPC-FUSE) whose locking/mmap semantics break SQLite WAL
|
|
252
|
+
// virtualized file share (virtiofs/gRPC-FUSE) whose locking/mmap semantics break SQLite WAL -
|
|
253
253
|
// OpenClaw crashes with `Error: disk I/O error` on write (e.g. when a Zalo message arrives).
|
|
254
254
|
// Keep `.openclaw/state` on a named volume (the Linux VM's native filesystem) instead; the
|
|
255
255
|
// rest of `.openclaw` stays bind-mounted so workspaces/config remain visible on the host.
|
|
256
|
-
// Linux/VPS bind mounts are native ext4
|
|
256
|
+
// Linux/VPS bind mounts are native ext4 - unchanged there (and state stays host-visible).
|
|
257
257
|
const useStateVolume = osChoice === 'macos' || osChoice === 'win';
|
|
258
258
|
const stateVolMount = useStateVolume ? '\n - openclaw-state:/home/node/project/.openclaw/state' : '';
|
|
259
259
|
const stateVolDecl = useStateVolume ? '\n openclaw-state:' : '';
|
|
@@ -278,7 +278,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
278
278
|
const deprecatedCleanupScript = `const fs=require('fs'),path=require('path');const p=path.join(process.cwd(),'.openclaw','openclaw.json');if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));let ch=false;if(c.plugins&&c.plugins.entries&&c.plugins.entries['memory-tencentdb']){delete c.plugins.entries['memory-tencentdb'];ch=true;}if(c.plugins&&Array.isArray(c.plugins.allow)){const n=c.plugins.allow.filter(x=>x!=='memory-tencentdb'&&x!=='@tencentdb-agent-memory/memory-tencentdb');if(n.length!==c.plugins.allow.length){c.plugins.allow=n;ch=true;}}if(c.skills&&c.skills.entries&&c.skills.entries['learning-memory']){delete c.skills.entries['learning-memory'];ch=true;}if(ch)fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
|
|
279
279
|
// One-shot upgrade for projects created by an older setup (their openclaw.json was
|
|
280
280
|
// generated before these defaults existed, and bot-config-gen only runs when a bot is
|
|
281
|
-
// created/regenerated
|
|
281
|
+
// created/regenerated - so a plain rebuild would never pick them up):
|
|
282
282
|
// • skills.workshop.approvalPolicy:'auto' → the assistant can author a workspace
|
|
283
283
|
// skill end-to-end on request instead of stopping at "proposal awaiting approval".
|
|
284
284
|
// • tools.deny gains `browser` on projects that have browsing enabled, so the model
|
|
@@ -288,19 +288,19 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
288
288
|
// heavy turn (deep research, 4K chart read-back) from overflowing the context
|
|
289
289
|
// window mid tool-loop, which cannot be compacted and poisons the session.
|
|
290
290
|
// • smart-route contextWindow 200000 → 131072: the old declared window exceeded the
|
|
291
|
-
// smallest upstream in typical free-model combos, so full sessions deadlocked
|
|
291
|
+
// smallest upstream in typical free-model combos, so full sessions deadlocked -
|
|
292
292
|
// the compaction summarize call itself overflowed and only /new recovered. Only the
|
|
293
293
|
// exact setup-written 200000 is rewritten; an operator's custom value is left alone.
|
|
294
294
|
// Each key is only filled in when absent, so an operator's own tuning is never clobbered.
|
|
295
|
-
// (The script itself lives at module scope
|
|
295
|
+
// (The script itself lives at module scope - the native runtime replays the exact same
|
|
296
296
|
// migration before every gateway (re)start, since native projects have no entrypoint.)
|
|
297
297
|
// Companion backfill for the same older projects: their TOOLS.md was generated before the
|
|
298
298
|
// skill-authoring / long-turn guidance existed, and workspace files are only written when a
|
|
299
|
-
// bot is created
|
|
299
|
+
// bot is created - so a rebuild alone leaves the assistant stopping at "proposal awaiting
|
|
300
300
|
// approval" even once approvalPolicy is 'auto'. (TOOLS.md is listed in AGENTS.md as required
|
|
301
301
|
// reading, so guidance lands there rather than in the main manual.) Appends the block once
|
|
302
302
|
// per workspace, keyed off the `skill_workshop` marker, never rewriting a file that has it.
|
|
303
|
-
const agentsGuidanceScript = `const fs=require('fs'),path=require('path');const vi=['','## 🛠️ Tự tạo skill & việc dài','','**Tự tạo skill:** Khi user nhờ tạo một kỹ năng/quy trình dùng lại (vd _"tạo skill X"_), bạn TỰ làm từ đầu đến cuối
|
|
303
|
+
const agentsGuidanceScript = `const fs=require('fs'),path=require('path');const vi=['','## 🛠️ Tự tạo skill & việc dài','','**Tự tạo skill:** Khi user nhờ tạo một kỹ năng/quy trình dùng lại (vd _"tạo skill X"_), bạn TỰ làm từ đầu đến cuối - dùng tool **skill_workshop**: tạo proposal RỒI **apply luôn trong cùng lượt** (môi trường này bật approvalPolicy auto, không cần chờ ai duyệt). Skill ghi vào skills/<tên>/SKILL.md và **tự nạp** qua watcher - KHÔNG cần sửa openclaw.json. Đừng dừng ở _"đã tạo proposal, chờ duyệt"_. KHÔNG nhúng bí mật vào skill - đọc từ biến môi trường lúc chạy.','','**Việc dài, nhiều bước (research sâu, dựng báo cáo/PDF):** ảnh/chart bạn vừa tạo thì **đừng đọc lại** bằng tool ảnh (chèn thẳng file vào tài liệu; kiểm bằng file tồn tại / build thành công) - đọc lại ảnh lớn ngốn ngữ cảnh gấp nhiều lần bạn tưởng. Tạo hình cạnh dài khoảng 1280px, đừng 4K trừ khi user yêu cầu. Research nhiều nguồn thì dùng **sessions_spawn** mỗi nhánh một subagent, bảo chúng **ghi dữ liệu thô ra file** và **chỉ trả tóm tắt ngắn kèm đường dẫn**; bạn tổng hợp từ file.',''].join('\\n');const en=['','## 🛠️ Authoring skills & long work','','**Authoring skills:** When the user asks for a reusable capability (e.g. _"make a skill for X"_), do it end-to-end - use the **skill_workshop** tool: create the proposal AND **apply it in the same turn** (this environment sets approvalPolicy auto, so no separate approval is needed). The skill lands in skills/<name>/SKILL.md and **auto-loads** via the watcher - no openclaw.json edit required. Do not stop at _"proposal created, awaiting approval"_. Never hardcode secrets into a skill - read them from environment variables at runtime.','','**Long multi-step work (deep research, building reports/PDFs):** do not read back an image or chart you just made (drop the file straight in; verify via file exists / build succeeded) - re-reading a large image costs far more context than it looks. Render at about 1280px on the long edge, skip 4K unless asked. For multi-source research, use **sessions_spawn** with one subagent per branch, have them **write raw findings to files** and **return only a short summary plus paths**; synthesize from the files.',''].join('\\n');const root=path.join(process.cwd(),'.openclaw');let dirs=[];try{dirs=fs.readdirSync(root).filter(n=>n.indexOf('workspace')===0);}catch(e){}for(const d of dirs){const f=path.join(root,d,'TOOLS.md');try{if(!fs.existsSync(f))continue;const cur=fs.readFileSync(f,'utf8');if(cur.indexOf('skill_workshop')!==-1)continue;const isVi=/Kỹ năng|Ghi chú|Xử lý lỗi|môi trường/.test(cur);fs.appendFileSync(f,(cur.endsWith('\\n')?'':'\\n')+(isVi?vi:en));}catch(e){}}`;
|
|
304
304
|
const securityCompatScript = `const fs=require('fs'),path=require('path');const scopes=['operator.admin','operator.pairing','operator.approvals'];function uniq(a){return Array.from(new Set([...(Array.isArray(a)?a:[]),...scopes]));}function walk(v){if(!v||typeof v!=='object')return;if(Array.isArray(v)){v.forEach(walk);return;}if(Array.isArray(v.scopes)||Array.isArray(v.approvedScopes)){v.scopes=uniq(v.scopes);v.approvedScopes=uniq(v.approvedScopes);}Object.values(v).forEach(walk);}const home=process.env.OPENCLAW_HOME||path.join(process.cwd(),'.openclaw');const state=process.env.OPENCLAW_STATE_DIR||home;const cfgPath=path.join(process.cwd(),'.openclaw','openclaw.json');if(fs.existsSync(cfgPath)){const c=JSON.parse(fs.readFileSync(cfgPath,'utf8'));const p=c.models&&c.models.providers&&c.models.providers['9router'];if(p){p.request=Object.assign({},p.request,{allowPrivateNetwork:true});}fs.writeFileSync(cfgPath,JSON.stringify(c,null,2));}for(const root of Array.from(new Set([home,state]))){const f=path.join(root,'devices','paired.json');if(fs.existsSync(f)){const d=JSON.parse(fs.readFileSync(f,'utf8'));walk(d);fs.writeFileSync(f,JSON.stringify(d,null,2));}}`;
|
|
305
305
|
|
|
306
306
|
const runtimeParts = runtimeCommandParts.filter(Boolean);
|
|
@@ -309,7 +309,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
309
309
|
'export OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-$OPENCLAW_HOME}"',
|
|
310
310
|
'mkdir -p "$OPENCLAW_HOME" "$OPENCLAW_STATE_DIR"',
|
|
311
311
|
// `openclaw plugins install` unpacks into extensions/.openclaw-install-stage-XXXXXX and removes
|
|
312
|
-
// it when it finishes. An interrupted install leaves the staging copy behind
|
|
312
|
+
// it when it finishes. An interrupted install leaves the staging copy behind - and it still
|
|
313
313
|
// carries a plugin manifest, so the gateway logs "duplicate plugin id detected" on every boot
|
|
314
314
|
// and a stale build competes with the real one for the same id. Found on a production host: a
|
|
315
315
|
// zalo-connect 3.0.7 stage dir shadowing 3.0.17 for a week. Nothing is installing at entrypoint
|
|
@@ -381,8 +381,8 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
381
381
|
// Backfill the inbound-message ack reaction for projects created before it was
|
|
382
382
|
// seeded. Kept out of the shared migration because zalo-connect reads the GLOBAL
|
|
383
383
|
// messages.ackReaction, and that same key also feeds Telegram/Discord/Slack/
|
|
384
|
-
// WhatsApp
|
|
385
|
-
// arbitrary emoji. Absent-only, so an operator's own choice is never overwritten
|
|
384
|
+
// WhatsApp - which accept only their own fixed reaction sets and would reject an
|
|
385
|
+
// arbitrary emoji. Absent-only, so an operator's own choice is never overwritten -
|
|
386
386
|
// with one exception: the 🦞 this script itself used to seed is rewritten to
|
|
387
387
|
// `/-heart`. 🦞 only ships as a Zalo CUSTOM reaction (needs zalo-connect ≥3.0.15,
|
|
388
388
|
// silently dropped below that); `/-heart` is a built-in every version can send.
|
|
@@ -399,11 +399,11 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
399
399
|
// Backfill skill-authoring + context defaults for configs from an older setup (see above).
|
|
400
400
|
runtimeParts.push(`node - <<'NODE'\n${contextDefaultsScript}\nNODE`);
|
|
401
401
|
runtimeParts.push(`node - <<'NODE'\n${agentsGuidanceScript}\nNODE`);
|
|
402
|
-
// browser-tool.js is a CDP client only
|
|
402
|
+
// browser-tool.js is a CDP client only - it has no code to launch a browser, so it
|
|
403
403
|
// needs something listening on a debug port. On a desktop that is the operator's own
|
|
404
404
|
// Chrome (started by start-chrome), reached through the host gateway. On a server there
|
|
405
405
|
// is no such Chrome, and browsing simply failed. Start a headless Chromium on loopback
|
|
406
|
-
// 9222
|
|
406
|
+
// 9222 - the second entry in browser-tool.js's candidate list - so the same tool works
|
|
407
407
|
// on every OS.
|
|
408
408
|
//
|
|
409
409
|
// Emitted unconditionally and gated at RUNTIME on the plugin being installed, not on
|
|
@@ -411,7 +411,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
411
411
|
// browser-automation on later (the common path) would otherwise never get this block.
|
|
412
412
|
//
|
|
413
413
|
// Chromium is baked into the image only when hasBrowser was known at build time. When it
|
|
414
|
-
// is missing
|
|
414
|
+
// is missing - every project whose image predates the plugin - download it once instead
|
|
415
415
|
// of telling the bot to give up; that message is what makes it answer "there is no
|
|
416
416
|
// browser in my environment". The download goes to a path under $OPENCLAW_HOME, which is
|
|
417
417
|
// a bind mount, so recreating the container does not pay for it again. It runs in the
|
|
@@ -463,7 +463,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
463
463
|
' echo "[entrypoint] Chromium ready at $installed_bin"',
|
|
464
464
|
' launch_headless_chrome "$installed_bin"',
|
|
465
465
|
' else',
|
|
466
|
-
' echo "[entrypoint] Chromium download failed; see /tmp/openclaw-chromium-install.log
|
|
466
|
+
' echo "[entrypoint] Chromium download failed; see /tmp/openclaw-chromium-install.log - browsing still works if the operator runs start-chrome on the host"',
|
|
467
467
|
' fi',
|
|
468
468
|
' ) &',
|
|
469
469
|
'}',
|
|
@@ -473,9 +473,9 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
473
473
|
// openclaw ≥2026.8 TACH duckduckgo khoi bundle thanh plugin external co capability consent.
|
|
474
474
|
// Config do setup sinh (bot chon skill web-search) van khai `plugins.entries.duckduckgo`,
|
|
475
475
|
// va gateway 2026.8.x TU CHOI ready khi entry khai ma plugin chua cai ("Plugin verification
|
|
476
|
-
// failed … requires capability consent")
|
|
476
|
+
// failed … requires capability consent") - do that tren 103.98.149.154, 31/08/2026.
|
|
477
477
|
// Cai o day, truoc gateway run, dung lenh + co ma chinh gateway goi y; `yes |` cho cau hoi
|
|
478
|
-
// consent; loi khong chan boot (|| true)
|
|
478
|
+
// consent; loi khong chan boot (|| true) - thieu web search chi la mat mot tool phu.
|
|
479
479
|
runtimeParts.push([
|
|
480
480
|
'if grep -q \'"duckduckgo"\' "$OPENCLAW_HOME/openclaw.json" 2>/dev/null && [ ! -d "$OPENCLAW_HOME/extensions/duckduckgo" ]; then',
|
|
481
481
|
' echo "[entrypoint] installing external duckduckgo plugin (openclaw >=2026.8 unbundled it)"',
|
|
@@ -485,10 +485,10 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
485
485
|
// ── Doctor-on-upgrade ─────────────────────────────────────────────────────────────────
|
|
486
486
|
// Update openclaw khong bao gio chi la "doi so version": schema config doi (key cu bi TU CHOI
|
|
487
487
|
// chu khong bo qua) va state DB doi migration (audit-events-v2…), va doctor chi chay sach khi
|
|
488
|
-
// gateway DANG TAT
|
|
488
|
+
// gateway DANG TAT - tuc dung ngay tai day, truoc `gateway run`, trong container vua boot.
|
|
489
489
|
// So version hien tai voi lan boot truoc (marker trong $OPENCLAW_HOME); khac nhau moi chay,
|
|
490
490
|
// hai luot vi doctor boc migration theo LOP (ca that 103.98.149.154 can nhieu luot). `yes |`
|
|
491
|
-
// vi doctor co cau hoi tuong tac; loi doctor khong chan boot
|
|
491
|
+
// vi doctor co cau hoi tuong tac; loi doctor khong chan boot - gateway se tu noi not phan con
|
|
492
492
|
// thieu, con hon container chet cung khong ai chan doan duoc.
|
|
493
493
|
runtimeParts.push([
|
|
494
494
|
'OC_VER="$(openclaw --version 2>/dev/null | head -1)"',
|
|
@@ -566,7 +566,7 @@ ${indentBlock(docker9RouterEntrypointScript, 8)}
|
|
|
566
566
|
- HOSTNAME=0.0.0.0
|
|
567
567
|
- CI=true
|
|
568
568
|
# 9router blocks the default password for "remote" access, and inside Docker every
|
|
569
|
-
# host request arrives via the bridge network, so it always counts as remote
|
|
569
|
+
# host request arrives via the bridge network, so it always counts as remote - without
|
|
570
570
|
# this the user can NEVER log in with the documented default (measured 02/09/2026).
|
|
571
571
|
- INITIAL_PASSWORD=123456
|
|
572
572
|
volumes:
|
|
@@ -664,7 +664,7 @@ ${indentBlock(docker9RouterEntrypointScript, 8)}
|
|
|
664
664
|
- HOSTNAME=0.0.0.0
|
|
665
665
|
- CI=true
|
|
666
666
|
# 9router blocks the default password for "remote" access, and inside Docker every
|
|
667
|
-
# host request arrives via the bridge network, so it always counts as remote
|
|
667
|
+
# host request arrives via the bridge network, so it always counts as remote - without
|
|
668
668
|
# this the user can NEVER log in with the documented default (measured 02/09/2026).
|
|
669
669
|
- INITIAL_PASSWORD=123456
|
|
670
670
|
volumes:
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
(function (root) {
|
|
11
11
|
const HOST_UI_PS1_VERSION = '1';
|
|
12
12
|
|
|
13
|
-
const HOST_UI_PS1 = String.raw`# OpenClaw host UI helper
|
|
13
|
+
const HOST_UI_PS1 = String.raw`# OpenClaw host UI helper - version __VERSION__
|
|
14
14
|
# Generated by openclaw-setup. Edits are overwritten when the version changes.
|
|
15
15
|
param(
|
|
16
16
|
[Parameter(Mandatory = $true)][string]$Action,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
// install-gen.js
|
|
2
|
+
// install-gen.js - Build install/runtime artifacts (Chrome debug, uninstall, skill catalog)
|
|
3
3
|
// Workspace .md files are in workspace-gen.js (single source of truth).
|
|
4
4
|
(function (root) {
|
|
5
5
|
function buildSkillCatalogMarkdown(options = {}) {
|
|
@@ -366,7 +366,7 @@ fi
|
|
|
366
366
|
|
|
367
367
|
function buildUpgradePs1() {
|
|
368
368
|
return [
|
|
369
|
-
"# OpenClaw Upgrade Script
|
|
369
|
+
"# OpenClaw Upgrade Script - Windows (PowerShell)",
|
|
370
370
|
"# Cach dung:",
|
|
371
371
|
"# Nhan dup upgrade.ps1 hoac: .\\upgrade.ps1",
|
|
372
372
|
"# irm https://raw.githubusercontent.com/tuanminhhole/openclaw-setup/main/upgrade.ps1 | iex",
|
|
@@ -396,7 +396,7 @@ fi
|
|
|
396
396
|
"foreach ($l in $logo) { Write-Host $l -ForegroundColor Red }",
|
|
397
397
|
"Write-Host \"\"",
|
|
398
398
|
"",
|
|
399
|
-
"# Box
|
|
399
|
+
"# Box - node render (handles emoji visual width correctly on all terminals)",
|
|
400
400
|
"$env:L1 = \" 🦞 OpenClaw Setup$VER_STR | Upgrade Script\"",
|
|
401
401
|
"$env:L2 = \" Windows (PowerShell)\"",
|
|
402
402
|
"node -e @\"\nconst RED='\\x1b[0;31m',NC='\\x1b[0m';\nfunction vw(s){let w=0;for(const c of[...s]){const cp=c.codePointAt(0);w+=(cp>=0x1F000&&cp<=0x1FFFF?2:1);}return w;}\nconst L1=process.env.L1,L2=process.env.L2;\nconst INNER=Math.max(vw(L1),vw(L2))+2;\nconst D='─'.repeat(INNER);const pad=s=>' '.repeat(Math.max(0,INNER-vw(s)));\nconsole.log(RED+'╭'+D+'╮'+NC);\nconsole.log(RED+'│'+NC+L1+pad(L1)+RED+'│'+NC);\nconsole.log(RED+'│'+NC+L2+pad(L2)+RED+'│'+NC);\nconsole.log(RED+'╰'+D+'╯'+NC);\n\"@",
|
|
@@ -426,7 +426,7 @@ fi
|
|
|
426
426
|
"",
|
|
427
427
|
"# ── 3. Chay upgrade ──────────────────────────────────────────────────────────",
|
|
428
428
|
"Write-Host \" 🔄 Dang lay CLI moi nhat va chay upgrade...\" -ForegroundColor Cyan",
|
|
429
|
-
"Write-Host \" npx luon tai create-openclaw-bot@latest
|
|
429
|
+
"Write-Host \" npx luon tai create-openclaw-bot@latest - khong can cap nhat tay\" -ForegroundColor DarkGray",
|
|
430
430
|
"Write-Host \"\"",
|
|
431
431
|
"",
|
|
432
432
|
"try {",
|
|
@@ -442,7 +442,7 @@ fi
|
|
|
442
442
|
" Write-Host \" 🎉 Upgrade hoan tat!\" -ForegroundColor Green",
|
|
443
443
|
" Write-Host \" Dashboard: http://localhost:18789\" -ForegroundColor Cyan",
|
|
444
444
|
"} else {",
|
|
445
|
-
" Write-Host \" ⚠️ Ma loi: $exitCode
|
|
445
|
+
" Write-Host \" ⚠️ Ma loi: $exitCode - xem log o tren.\" -ForegroundColor Yellow",
|
|
446
446
|
"}",
|
|
447
447
|
"Write-Host \"\"",
|
|
448
448
|
"Read-Host \"Nhan Enter de dong\"",
|
|
@@ -452,7 +452,7 @@ fi
|
|
|
452
452
|
function buildUpgradeSh() {
|
|
453
453
|
return [
|
|
454
454
|
"#!/bin/bash",
|
|
455
|
-
"# OpenClaw Upgrade Script
|
|
455
|
+
"# OpenClaw Upgrade Script - Linux / macOS / Ubuntu",
|
|
456
456
|
"# Cach dung:",
|
|
457
457
|
"# bash upgrade.sh",
|
|
458
458
|
"# curl -fsSL https://raw.githubusercontent.com/tuanminhhole/openclaw-setup/main/upgrade.sh | bash",
|
|
@@ -484,7 +484,7 @@ fi
|
|
|
484
484
|
"echo ' ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝'",
|
|
485
485
|
"echo -e \"${NC}\"",
|
|
486
486
|
"",
|
|
487
|
-
"# Box
|
|
487
|
+
"# Box - node render (handles emoji visual width correctly on all terminals)",
|
|
488
488
|
"L1=\" 🦞 OpenClaw Setup${VER_STR} | Upgrade Script\"",
|
|
489
489
|
"L2=\" Linux / macOS / Ubuntu\"",
|
|
490
490
|
"L1=\"$L1\" L2=\"$L2\" node -e \"\nconst RED='\\x1b[0;31m',NC='\\x1b[0m';\nfunction vw(s){let w=0;for(const c of[...s]){const cp=c.codePointAt(0);w+=(cp>=0x1F000&&cp<=0x1FFFF?2:1);}return w;}\nconst L1=process.env.L1,L2=process.env.L2;\nconst INNER=Math.max(vw(L1),vw(L2))+2;\nconst D='─'.repeat(INNER);const pad=s=>' '.repeat(Math.max(0,INNER-vw(s)));\nconsole.log(RED+'╭'+D+'╮'+NC);\nconsole.log(RED+'│'+NC+L1+pad(L1)+RED+'│'+NC);\nconsole.log(RED+'│'+NC+L2+pad(L2)+RED+'│'+NC);\nconsole.log(RED+'╰'+D+'╯'+NC);\n\"",
|
|
@@ -520,7 +520,7 @@ fi
|
|
|
520
520
|
"",
|
|
521
521
|
"# ── 3. Chay upgrade ──────────────────────────────────────────────────────────",
|
|
522
522
|
"echo -e \"${CYAN} 🔄 Dang lay CLI moi nhat va chay upgrade...${NC}\"",
|
|
523
|
-
"echo -e \"${GRAY} npx luon tai create-openclaw-bot@latest
|
|
523
|
+
"echo -e \"${GRAY} npx luon tai create-openclaw-bot@latest - khong can cap nhat tay${NC}\"",
|
|
524
524
|
"echo \"\"",
|
|
525
525
|
"",
|
|
526
526
|
"npx create-openclaw-bot@latest upgrade",
|
|
@@ -531,7 +531,7 @@ fi
|
|
|
531
531
|
" echo -e \"${GREEN} 🎉 Upgrade hoan tat!${NC}\"",
|
|
532
532
|
" echo -e \"${CYAN} Dashboard: http://localhost:18789${NC}\"",
|
|
533
533
|
"else",
|
|
534
|
-
" echo -e \"${YELLOW} ⚠️ Ma loi: $EXIT_CODE
|
|
534
|
+
" echo -e \"${YELLOW} ⚠️ Ma loi: $EXIT_CODE - xem log o tren.${NC}\"",
|
|
535
535
|
"fi",
|
|
536
536
|
"echo \"\"",
|
|
537
537
|
""
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* • anything started over SSH dies the moment the session closes (LastTaskResult 0xC000013A);
|
|
10
10
|
* • a task set to run at boot is refused outright, because "at startup" and "only while
|
|
11
11
|
* someone is logged in" contradict each other (0x800710E0).
|
|
12
|
-
* Making it run without a login needs the account password stored in the task
|
|
12
|
+
* Making it run without a login needs the account password stored in the task - Task Scheduler
|
|
13
13
|
* rejected that too ("The user account is unknown, the password is incorrect"). So the owner
|
|
14
14
|
* drives it by hand, exactly like the .command files on macOS.
|
|
15
15
|
*
|
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
*
|
|
18
18
|
* 1. `.cmd` MUST be CRLF. LF-only files break on Windows.
|
|
19
19
|
* 2. Never name a launcher after the command it calls. `9router.cmd` in the project dir plus
|
|
20
|
-
* `cd /d <project>` makes `call 9router` re-enter the same file
|
|
20
|
+
* `cd /d <project>` makes `call 9router` re-enter the same file - BATCH RECURSION, and the
|
|
21
21
|
* process dies before doing anything.
|
|
22
22
|
* 3. Never append to a fixed log file. 9router holds its log open for its whole lifetime, so
|
|
23
23
|
* the SECOND run cannot open it and exits with "The process cannot access the file because
|
|
24
|
-
* it is being used by another process"
|
|
24
|
+
* it is being used by another process" - invisible on the first run, which is why it is easy
|
|
25
25
|
* to ship broken.
|
|
26
26
|
* 4. 9router shows a `Choose Interface` menu when its stdout looks like a real console. Started
|
|
27
27
|
* hidden, nobody can answer it, so it hangs and never opens its port. `> NUL` is what tells
|
|
28
28
|
* it to run unattended. Symptom without it: works when run by hand, silently dead in the
|
|
29
|
-
* background
|
|
29
|
+
* background - same command.
|
|
30
30
|
* 5. `Start-Process -WindowStyle Hidden` does NOT hide a console a .cmd opens for itself. Only
|
|
31
31
|
* WScript.Shell.Run(..., 0, False) truly hides it. Leaving a visible window is not cosmetic:
|
|
32
32
|
* it IS the bot, and closing it kills the bot.
|
|
33
33
|
* 6. Anchor the working directory. Agents may carry relative workspace paths, which resolve
|
|
34
|
-
* against the launcher's cwd
|
|
34
|
+
* against the launcher's cwd - move the files into a folder and those bots die with
|
|
35
35
|
* WORKSPACE_VANISHED while the others keep working.
|
|
36
36
|
*/
|
|
37
37
|
|
|
@@ -45,7 +45,7 @@ function buildRunHiddenVbs() {
|
|
|
45
45
|
);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
/** Starts 9router. Named start-9router.cmd on purpose
|
|
48
|
+
/** Starts 9router. Named start-9router.cmd on purpose - see trap 2. */
|
|
49
49
|
function build9RouterCmd({ projectDir, routerPort }) {
|
|
50
50
|
return CRLF(
|
|
51
51
|
'@echo off\n' +
|
|
@@ -89,7 +89,7 @@ function buildGatewayCmd({ projectDir, gatewayPort }) {
|
|
|
89
89
|
'@echo off\n' +
|
|
90
90
|
'rem Goi thang node, KHONG qua gateway.cmd cua openclaw: tep do chay kem --task-supervisor,\n' +
|
|
91
91
|
'rem no di tim Scheduled Task de ban giao; khong co task thi no de them tien trinh + cua so.\n' +
|
|
92
|
-
'rem Khong redirect ra tep co dinh (xem trap 3)
|
|
92
|
+
'rem Khong redirect ra tep co dinh (xem trap 3) - openclaw tu ghi nhat ky trong %TEMP%\\openclaw.\n' +
|
|
93
93
|
`cd /d ${projectDir}\n` +
|
|
94
94
|
'set "HOME=%USERPROFILE%"\n' +
|
|
95
95
|
`set "OPENCLAW_GATEWAY_PORT=${gatewayPort}"\n` +
|
|
@@ -105,7 +105,12 @@ function buildSetupUiCmd({ projectDir, setupPort }) {
|
|
|
105
105
|
'rem Ten tep nhat ky kem gio, de lan chay sau khong dung vao tep dang bi giu (trap 3).\n' +
|
|
106
106
|
`cd /d ${projectDir}\n` +
|
|
107
107
|
'for /f "tokens=1-4 delims=/: " %%a in ("%TIME%") do set "T=%%a%%b%%c"\n' +
|
|
108
|
-
`
|
|
108
|
+
// `--yes` is not optional. Whenever the installed version differs from what npx resolves - which
|
|
109
|
+
// is EVERY time a new version is published - npx stops at "Need to install the following
|
|
110
|
+
// packages ... Ok to proceed? (y)". The launcher runs hidden, so nobody can answer it: the
|
|
111
|
+
// window sits there forever and the dashboard simply never opens. Measured on a customer
|
|
112
|
+
// machine, where it looked like the tunnel was broken rather than a prompt waiting offscreen.
|
|
113
|
+
`call npx --yes create-openclaw-bot --host=127.0.0.1 --port=${setupPort} --no-open --project-dir=${projectDir}` +
|
|
109
114
|
` > "${projectDir}\\setup-ui-%T%.log" 2>&1\n`,
|
|
110
115
|
);
|
|
111
116
|
}
|
|
@@ -131,6 +136,15 @@ function buildStartBotCmd({ projectDir, gatewayPort, routerPort }) {
|
|
|
131
136
|
'echo Cho bot san sang (co the mat 30-60 giay)...\n' +
|
|
132
137
|
'echo.\n' +
|
|
133
138
|
`powershell -NoProfile -Command "$ok=$false; for($i=0;$i -lt 40;$i++){ try{ Invoke-WebRequest 'http://127.0.0.1:${gatewayPort}/health' -UseBasicParsing -TimeoutSec 3 | Out-Null; $ok=$true; break } catch { Start-Sleep -Seconds 3 } }; if($ok){ Write-Host ' [OK] Bot da chay.' -ForegroundColor Green } else { Write-Host ' [LOI] Bot chua len.' -ForegroundColor Red }"\n` +
|
|
139
|
+
// Bring screen control back up too. The node host dies with the login session like everything
|
|
140
|
+
// else, and nothing else restarts it: PC control would quietly stop working after every logout
|
|
141
|
+
// or reboot, with the dashboard still showing it as ON. Only start it when .openclaw-node
|
|
142
|
+
// exists - that directory is written when the operator turns PC control on, so a project that
|
|
143
|
+
// never enabled it starts nothing extra.
|
|
144
|
+
`if exist "${projectDir}\\.openclaw-node\\openclaw.json" (\n` +
|
|
145
|
+
' echo Dang bat dieu khien may...\n' +
|
|
146
|
+
` powershell -NoProfile -Command "if (-not (Get-CimInstance Win32_Process -Filter \\"Name='node.exe'\\" | Where-Object { $_.CommandLine -like '*node*run*--host*' })) { Start-Process wscript -ArgumentList '${projectDir}\\run-hidden.vbs','${projectDir}\\node-host.cmd' -WindowStyle Hidden }" >nul 2>&1\n` +
|
|
147
|
+
')\n' +
|
|
134
148
|
'echo.\n' +
|
|
135
149
|
'echo --- Trang thai ---\n' +
|
|
136
150
|
`powershell -NoProfile -Command "foreach($x in @(@('Bot (gateway)','http://127.0.0.1:${gatewayPort}/health'),@('9Router','http://127.0.0.1:${routerPort}/'),@('Bang dieu khien Zalo','http://127.0.0.1:${dashPort}/dashboard'))){ try{ (Invoke-WebRequest $x[1] -UseBasicParsing -TimeoutSec 6) | Out-Null; Write-Host (' {0,-22} DANG CHAY' -f $x[0]) -ForegroundColor Green } catch { Write-Host (' {0,-22} TAT' -f $x[0]) -ForegroundColor Red } }"\n` +
|