create-openclaw-bot 5.16.4 → 5.16.6

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
@@ -7,7 +7,7 @@
7
7
  *Run one command → open the dashboard → your bot is live. Windows · macOS · Linux · VPS — Docker-powered, auto-installed for you.*
8
8
 
9
9
  <p align="center">
10
- <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.16.4-0EA5E9?style=for-the-badge" alt="Version 5.16.4" /></a>
10
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.16.6-0EA5E9?style=for-the-badge" alt="Version 5.16.6" /></a>
11
11
  <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>
12
12
  <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>
13
13
  <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>
@@ -37,13 +37,23 @@
37
37
 
38
38
  ---
39
39
 
40
- ## 🆕 What's New in v5.16.4
40
+ ## 🆕 What's New in v5.16.6
41
41
 
42
- - 🚑 **The big OpenClaw 2026.8.1 catch-up the old setup had gone stale; this wave heals it all in one pass.** OpenClaw (the platform the bots run on) shipped a major upgrade and changed the rules: configs are strictly checked, data moved to a new home, several install commands were renamed. With the old setup that meant fresh installs could stall, running bots suddenly went **silent**, and the admin screen showed **0 bots** while the bot was alive. As of 5.16.3–5.16.4: fresh installs run smoothly on 2026.8.1 (Docker and native, Windows/macOS/Linux), and **existing machines heal themselves on upgrade** — stale config cleaned, data relocated, and the old file that could mute the bot retired automatically.
43
- - 🤖 **The bot stops claiming "I can't see the file"**: files sent through chat now come with clear directions for the AI even weaker models find them.
44
- - 🔁 **9Router (the AI model router) comes back on its own** after a server reboot or UI maintenance previously it could die silently and the bot lost its brain.
45
- - 🔄 **The in-app "Update" button really updates now**: on standard server installs it used to just restart the old version while reporting success — now it pulls the latest and relaunches itself.
46
- - 🧭 **One setup build manages both generations** (2026.7 and 2026.8) — renamed commands are tried the new way first with an automatic fallback, so nobody is forced to upgrade overnight.
42
+ - 🩹 **Native installs on OpenClaw 2026.8 are smooth from the first run** - this wave patches the remaining chain of issues measured on fresh customer machines: generated configs pass the new strict checks 100%, install steps run in the right order, and restarts/plugin installs no longer get blocked midway.
43
+ - 🔑 **9Router login works on Docker**: the new 9Router blocks the default password for "remote" access - and inside Docker every request counts as remote, so 123456 could never log in. It works now (still change the password once you're in).
44
+ - 🧹 **Deleting a project fully removes the old 9Router**: it used to keep running in the background holding the port, silently forking the next install onto a different port - now removal is clean and reinstalls land on the standard port.
45
+ - 🔌 **Native machines auto-install the web-search plugin** (DuckDuckGo) with its capability consent - no more boot loops over a missing nod.
46
+
47
+ <details>
48
+ <summary><b>Previous: What's new in v5.16.3</b></summary>
49
+
50
+ - 🚑 **The big OpenClaw 2026.8.1 catch-up**: fresh installs run smoothly (Docker and native, Windows/macOS/Linux), and existing machines heal themselves on upgrade - stale config cleaned, data relocated, and the old file that could mute the bot retired automatically.
51
+ - 🤖 **The bot stops claiming "I can't see the file"**: files sent through chat come with clear directions for the AI.
52
+ - 🔁 **9Router comes back on its own** after a server reboot or UI maintenance.
53
+ - 🔄 **The in-app "Update" button really updates** on standard server installs.
54
+ - 🧭 **One setup build manages both generations** (2026.7 and 2026.8).
55
+
56
+ </details>
47
57
 
48
58
  <details>
49
59
  <summary><b>Previous: What's new in v5.15.3</b></summary>
package/README.vi.md CHANGED
@@ -7,7 +7,7 @@
7
7
  *Chạy một lệnh → mở dashboard → bot lên sóng. Windows · macOS · Linux · VPS — chạy trên Docker, tự cài giúp bạn.*
8
8
 
9
9
  <p align="center">
10
- <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.16.4-0EA5E9?style=for-the-badge" alt="Version 5.16.4" /></a>
10
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.16.6-0EA5E9?style=for-the-badge" alt="Version 5.16.6" /></a>
11
11
  <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>
12
12
  <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>
13
13
  <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>
@@ -37,13 +37,23 @@
37
37
 
38
38
  ---
39
39
 
40
- ## 🆕 Có gì mới trong v5.16.4
40
+ ## 🆕 Có gì mới trong v5.16.6
41
41
 
42
- - 🚑 **Theo kịp OpenClaw 2026.8.1 bản setup đã lỗi thời, đợt này chữa hết một lượt.** OpenClaw (nền tảng chạy bot) nâng cấp lớn đổi nhiều "luật chơi": file cấu hình bị soát khắt khe hơn, chỗ lưu dữ liệu dời đi, vài lệnh cài đặt đổi tên. Với bản setup cũ, hệ quả cài bot mới thể đứng giữa chừng, bot đang chạy bỗng **im lặng không trả lời**, màn hình quản trị hiện **0 bot** dù bot vẫn sống. Từ 5.16.3–5.16.4: cài mới chạy mượt trên 2026.8.1 (đủ Docker lẫn native, Windows/macOS/Linux), **máy cũ tự được chữa khi nâng cấp** — tự dọn cấu hình lỗi thời, tự dời dữ liệu, tự gỡ file cũ từng khiến bot "câm".
43
- - 🤖 **Bot hết chối "không thấy file"**: file khách gửi qua chat giờ được chỉ đường tận nơi cho AI kể cả model yếu cũng tìm được.
44
- - 🔁 **9Router (bộ định tuyến model AI) tự sống lại** sau khi máy chủ khởi động lại hay giao diện bảo trì trước đây thể chết im không ai hay, bot mất não.
45
- - 🔄 **Nút "Cập nhật" trong giao diện giờ cập nhật thật**: trên máy chủ cài kiểu chuẩn, trước đây nút chỉ khởi động lại bản vẫn báo thành công — giờ bấm là setup tự kéo bản mới về rồi tự khởi động lại.
46
- - 🧭 **Một bản setup quản được cả máy đời cũ (2026.7) lẫn đời mới (2026.8)** — lệnh nào openclaw đổi tên thì setup tự thử tên mới rồi lùi về tên cũ, không bắt khách nâng cấp gấp.
42
+ - 🩹 **Cài native trên OpenClaw 2026.8 mượt từ phát đầu** - đợt này nốt chuỗi lỗi đo được khi dựng máy khách mới: cấu hình sinh ra sạch 100% với bộ soát khắt khe của OpenClaw mới, các bước cài tự chạy đúng thứ tự, mọi thao tác khởi động lại/cài plugin không còn bị chặn giữa chừng.
43
+ - 🔑 **Đăng nhập 9Router hoạt động trên Docker**: bản 9Router mới chặn mật khẩu mặc định với truy cập "từ xa" - trong Docker thì mọi truy cập đều bị tính là từ xa, nên trước đây không cách nào vào được bằng 123456. Giờ đăng nhập bình thường (vào rồi vẫn nên đổi mật khẩu).
44
+ - 🧹 **Xoá project gỡ sạch 9Router cũ**: trước đây 9Router còn chạy ngầm giữ cổng, làm lần cài mới tự tách sang cổng khác không ai hay - giờ xoá sạch, cài lại đúng cổng chuẩn.
45
+ - 🔌 **Máy native tự cài đủ plugin tìm kiếm web** (DuckDuckGo) kèm xác nhận quyền - hết cảnh bot khởi động vòng lặp thiếu một cái gật đầu.
46
+
47
+ <details>
48
+ <summary><b>Trước đó: Có gì mới trong v5.16.3</b></summary>
49
+
50
+ - 🚑 **Theo kịp OpenClaw 2026.8.1**: cài mới chạy mượt (đủ Docker lẫn native, Windows/macOS/Linux), máy cũ tự được chữa khi nâng cấp - tự dọn cấu hình lỗi thời, tự dời dữ liệu, tự gỡ file cũ từng khiến bot "câm".
51
+ - 🤖 **Bot hết chối "không thấy file"**: file khách gửi qua chat được chỉ đường tận nơi cho AI.
52
+ - 🔁 **9Router tự sống lại** sau khi máy chủ khởi động lại hay giao diện bảo trì.
53
+ - 🔄 **Nút "Cập nhật" trong giao diện cập nhật thật** trên máy chủ cài kiểu chuẩn.
54
+ - 🧭 **Một bản setup quản được cả máy đời cũ (2026.7) lẫn đời mới (2026.8)**.
55
+
56
+ </details>
47
57
 
48
58
  <details>
49
59
  <summary><b>Trước đó: Có gì mới trong v5.15.3</b></summary>
@@ -48,7 +48,11 @@ function specMajorMinor(spec) {
48
48
  }
49
49
  let hostOcMajorMinorCache = null;
50
50
  async function hostOpenclawMajorMinor() {
51
- if (hostOcMajorMinorCache !== null) return hostOcMajorMinorCache;
51
+ // Cache only a REAL version: during bot creation this is first called before
52
+ // `npm i -g openclaw` has run, and caching that 0 forever made prepareNativeStateHome
53
+ // skip the 2026.8 state-home move — daemon install then failed with "non-default
54
+ // state dir" (measured on a fresh native install, 03/09/2026).
55
+ if (hostOcMajorMinorCache) return hostOcMajorMinorCache;
52
56
  const r = await runCapture('openclaw', ['--version'], { shell: false }).catch(() => null);
53
57
  hostOcMajorMinorCache = specMajorMinor(r && (r.stdout || r.stderr));
54
58
  return hostOcMajorMinorCache;
@@ -1790,6 +1794,22 @@ function bindingChannelId(channel = '') {
1790
1794
  return channel;
1791
1795
  }
1792
1796
 
1797
+ // OpenClaw ≥2026.8 materialises a DEFAULT agent `main` ("Trợ lý OpenClaw") the first time a
1798
+ // gateway boots against a roster it considers empty — which is exactly what happens in Docker
1799
+ // mode, where `docker compose up` runs while the project still has zero bots (writeCoreProject
1800
+ // seeds agents with an empty list). The entry is legitimate OpenClaw state and is left alone in
1801
+ // openclaw.json, but it is NOT a bot the operator created: showing it next to the real bot made
1802
+ // customers think a second Zalo bot appeared out of nowhere (measured on vps_tracy-hong, 03/09).
1803
+ //
1804
+ // Identified by disk, not by name: every bot this setup creates gets `workspace` in the config
1805
+ // AND that directory on disk. The materialised default has neither, so an operator who really
1806
+ // does name their bot `main` is never hidden.
1807
+ function isPhantomMainAgent(agent, projectDir, agentCount) {
1808
+ if (!agent || agent.id !== 'main' || agentCount < 2) return false;
1809
+ if (!agent.workspace) return true;
1810
+ return !existsSync(join(projectDir, agent.workspace));
1811
+ }
1812
+
1793
1813
  async function listConfiguredBots(projectDir) {
1794
1814
  const cfgPath = join(projectDir || '', '.openclaw', 'openclaw.json');
1795
1815
  if (!projectDir || !existsSync(cfgPath)) return [];
@@ -1797,7 +1817,8 @@ async function listConfiguredBots(projectDir) {
1797
1817
  const cfg = ensureConfigShape(parseJsonText(raw));
1798
1818
  const normalized = JSON.stringify(cfg, null, 2) + '\n';
1799
1819
  if (normalized !== raw) await fsp.writeFile(cfgPath, normalized, 'utf8');
1800
- const rows = await Promise.all(cfg.agents.list.map(async (agent) => {
1820
+ const roster = cfg.agents.list.filter((agent) => !isPhantomMainAgent(agent, projectDir, cfg.agents.list.length));
1821
+ const rows = await Promise.all(roster.map(async (agent) => {
1801
1822
  const identity = await readAgentIdentity(projectDir, agent);
1802
1823
  const meta = await readBotMeta(projectDir, agent, cfg);
1803
1824
  const env = await readProjectEnv(projectDir);
@@ -2391,10 +2412,32 @@ async function startZaloLogin(projectDir, agentId = "") {
2391
2412
  probeCacheClear(`zalohealth:${projectDir || ''}`);
2392
2413
  const cfgPath = join(projectDir, ".openclaw", "openclaw.json");
2393
2414
  if (!existsSync(cfgPath)) throw httpError(404, "openclaw.json not found");
2394
- const cfg = JSON.parse(await fsp.readFile(cfgPath, "utf8"));
2395
- const binding = (cfg.bindings || []).find((b) =>
2415
+ const raw = await fsp.readFile(cfgPath, "utf8");
2416
+ const cfg = ensureConfigShape(parseJsonText(raw));
2417
+ let binding = (cfg.bindings || []).find((b) =>
2396
2418
  (!agentId || b.agentId === agentId) && b.match?.channel === "zalo-connect"
2397
2419
  );
2420
+ // A roster with more than one agent makes OpenClaw ≥2026.8 refuse any channel operation that
2421
+ // cannot name its owner: `AgentSelectionRequiredError — Multiple agents are configured, but
2422
+ // this operation has no explicit owner`. That is exactly what a Docker project looks like once
2423
+ // the gateway has materialised its default `main` agent alongside the real bot, and the QR
2424
+ // login dies with it (measured on vps_tracy-hong, 03/09).
2425
+ //
2426
+ // `openclaw channels login` has no --agent flag (2026.8.1: only --channel/--account/--verbose),
2427
+ // and neither does the channels.start call it makes into the gateway — so the owner can only be
2428
+ // named the way OpenClaw's own error hint says: through a binding. Pin one to the real bot
2429
+ // before the QR starts. Additive: an existing binding is never rewritten, and the phantom
2430
+ // `main` is never the target.
2431
+ if (!binding) {
2432
+ const roster = (cfg.agents.list || []).filter((a) => !isPhantomMainAgent(a, projectDir, (cfg.agents.list || []).length));
2433
+ const target = (agentId && roster.some((a) => a.id === agentId)) ? agentId : roster[0]?.id;
2434
+ if (target) {
2435
+ binding = { agentId: target, match: { channel: 'zalo-connect', accountId: 'default' } };
2436
+ cfg.bindings = [...(cfg.bindings || []), binding];
2437
+ await fsp.writeFile(cfgPath, JSON.stringify(cfg, null, 2) + '\n', 'utf8');
2438
+ sendLog(`[zalo-connect] No zalo-connect binding found — pinned this QR login to agent [${target}] so OpenClaw knows who owns the channel.`);
2439
+ }
2440
+ }
2398
2441
  return startZaloConnectLogin(projectDir, binding?.match?.accountId || "default");
2399
2442
  }
2400
2443
 
@@ -2939,7 +2982,20 @@ function migrationLeaseDeadline(text = '') {
2939
2982
  async function ocDaemon(projectDir, verb, extraArgs = []) {
2940
2983
  const args = ['daemon', verb, ...extraArgs];
2941
2984
  sendLog(`$ openclaw ${args.join(' ')}`);
2942
- const out = await runCapture('openclaw', args, { cwd: projectDir, env: nativeEnv(projectDir), shell: false, timeout: 120000 });
2985
+ // openclaw 2026.8.x refuses EVERY `daemon *` verb (not just install) while OPENCLAW_HOME is
2986
+ // set — "service management skipped: non-default state dir" (measured 03/09/2026: the
2987
+ // post-plugin-install restart failed on a fresh native host). On the 2026.8 layout the
2988
+ // state already lives at ~/.openclaw, so run daemon verbs with the plain account HOME and
2989
+ // no OPENCLAW_* overrides; STOP even suggests --force for the operator gateway, so pass it.
2990
+ let env = nativeEnv(projectDir);
2991
+ if ((await hostOpenclawMajorMinor()) >= 202608) {
2992
+ env = { ...env };
2993
+ delete env.OPENCLAW_HOME;
2994
+ delete env.OPENCLAW_STATE_DIR;
2995
+ env.HOME = os.homedir();
2996
+ }
2997
+ if (verb === 'stop' && !extraArgs.includes('--force')) args.push('--force');
2998
+ const out = await runCapture('openclaw', args, { cwd: projectDir, env, shell: false, timeout: 120000 });
2943
2999
  const text = `${out.stdout || ''}\n${out.stderr || ''}`;
2944
3000
  for (const line of text.split(/\r?\n/).map((l) => l.trimEnd()).filter(Boolean)) sendLog(line);
2945
3001
  return { ...out, text };
@@ -3274,6 +3330,10 @@ async function ensureNativePlugins(projectDir, { restart = false } = {}) {
3274
3330
  // actually declares the channel (mirrors docker-gen's `if (zaloBackend === 'zalo-connect')`).
3275
3331
  const wanted = new Set(['learning-memory']);
3276
3332
  if (cfg?.channels?.[ZALO_CHANNEL_ID] || cfg?.plugins?.entries?.[ZALO_PLUGIN_ID]) wanted.add(ZALO_PLUGIN_ID);
3333
+ // openclaw >=2026.8 unbundled duckduckgo AND refuses to report ready while the config
3334
+ // declares a plugin that lacks capability consent — the docker entrypoint ensures it,
3335
+ // native must too (measured 03/09/2026: fresh install crash-looped on this).
3336
+ if (cfg?.plugins?.entries?.duckduckgo) wanted.add('duckduckgo');
3277
3337
  const installed = [];
3278
3338
  for (const id of wanted) {
3279
3339
  const dir = join(projectDir, '.openclaw', 'extensions', id);
@@ -3492,12 +3552,13 @@ async function startNativeRuntime({ projectDir, osChoice = '', gatewayPort, rout
3492
3552
  // Plugins BEFORE the gateway's first boot — the container entrypoint installs them ahead of the
3493
3553
  // gateway for the same reason: a gateway that boots with its plugins already on disk loads them
3494
3554
  // straight away, needs no follow-up restart, and prints no "plugin not found" warnings.
3495
- await ensureNativePlugins(projectDir).catch((e) => sendLog(`[native] plugin bootstrap skipped: ${e.message}`));
3496
-
3497
- // Config migrations BEFORE the first boot toosame ordering the container entrypoint uses
3498
- // (migrate, then start), so an adopted pre-existing project boots on the upgraded config.
3555
+ // Config migrations FIRST: `openclaw plugins install` validates the config, so a config
3556
+ // still carrying pre-2026.8 keys makes every plugin install fail before migrations ran
3557
+ // (measured on a fresh native install, 03/09/2026learning-memory refused to install).
3499
3558
  await runNativeConfigMigrations(projectDir).catch(() => {});
3500
3559
 
3560
+ await ensureNativePlugins(projectDir).catch((e) => sendLog(`[native] plugin bootstrap skipped: ${e.message}`));
3561
+
3501
3562
  // Managed service = auto-restart (KeepAlive/Restart=always) and start-at-login, the native
3502
3563
  // equivalent of docker's `restart: always`. --force so re-running install updates the port.
3503
3564
  const env = nativeEnv(projectDir);
@@ -3544,6 +3605,13 @@ async function removeNativeRuntime(projectDir) {
3544
3605
  if (!isNativeProject(projectDir)) return false;
3545
3606
  const env = nativeEnv(projectDir);
3546
3607
  await run('openclaw', ['daemon', 'uninstall'], { cwd: projectDir, env }).catch((e) => sendLog(`[native] daemon uninstall: ${e.message}`));
3608
+ // The 9router systemd unit has Restart=always: killing the listener alone brings it (or an
3609
+ // orphaned child) back, the port stays busy, and the NEXT install silently forks off to a
3610
+ // new router port that no ssh tunnel or oc-web table points at (measured 03/09/2026).
3611
+ if (process.platform === 'linux') {
3612
+ await run('systemctl', ['--user', 'disable', '--now', 'openclaw-9router.service'], {}).catch(() => {});
3613
+ await run('systemctl', ['--user', 'disable', '--now', 'openclaw-9router-sync.service'], {}).catch(() => {});
3614
+ }
3547
3615
  const routerPort = (readNativeMeta(projectDir) || {}).routerPort || NATIVE_DEFAULT_ROUTER_PORT;
3548
3616
  await killListenerOnPort(routerPort);
3549
3617
  return true;
@@ -6088,6 +6156,8 @@ const PLUGIN_NPM_SPEC = {
6088
6156
  // learning-memory ships on ClawHub as `openclaw-learning-memory` (manifest id is
6089
6157
  // `learning-memory`, used as the config key). Install by the full package spec.
6090
6158
  'learning-memory': 'clawhub:openclaw-learning-memory',
6159
+ // duckduckgo is openclaw's own external plugin on npm, not a ClawHub package.
6160
+ 'duckduckgo': '@openclaw/duckduckgo-plugin',
6091
6161
  };
6092
6162
  const pluginInstallSpec = (id) => PLUGIN_NPM_SPEC[id] || `clawhub:${id}`;
6093
6163
 
@@ -141,7 +141,9 @@
141
141
  // and poisons the session until a manual reset. 12k chars (~3k tokens) per
142
142
  // result keeps per-source content substantial while making that runaway
143
143
  // impossible. Applies to persisted results + overflow recovery.
144
- contextLimits: { toolResultMaxChars: 12000 },
144
+ // No contextLimits.toolResultMaxChars: openclaw 2026.8.x strict schema rejects the
145
+ // key outright (measured on a fresh native install, 03/09/2026) — the runaway-turn
146
+ // protection it provided is handled by the 2026.8 runtime itself.
145
147
  // Agent-TURN budget (seconds). 120 was too short for multi-step cloud turns (OCR +
146
148
  // file gen + tool calls). 900 = OpenClaw's own native default and the practical max
147
149
  // we use. This is the turn budget — a DIFFERENT layer from 9router's per-request
@@ -194,13 +196,15 @@
194
196
  // arbitrary emoji globally would make those channels reject every ack, so other
195
197
  // channels keep their existing behaviour until someone picks a value valid there.
196
198
  //
197
- // 🦞 is sent as a Zalo *custom* reaction (emoji as rIcon + a hash as rType), which
198
- // needs zalo-connect ≥3.0.15 earlier versions only knew the 55 built-ins and would
199
- // drop it silently. Scope "all" covers DMs and groups; in a mention-gated group the
200
- // plugin still only reacts to messages that address the bot, since non-addressed ones
201
- // are buffered as passive context before the reaction step.
199
+ // `/-heart` is one of Zalo's 55 BUILT-IN reactions, so every zalo-connect version can
200
+ // send it. The previous default (🦞) went out as a Zalo *custom* reaction (emoji as
201
+ // rIcon + a hash as rType), which needs zalo-connect ≥3.0.15 on anything older it was
202
+ // dropped silently and the bot looked unresponsive until the reply landed.
203
+ // Scope "all" covers DMs and groups; in a mention-gated group the plugin still only
204
+ // reacts to messages that address the bot, since non-addressed ones are buffered as
205
+ // passive context before the reaction step.
202
206
  if (isZaloPersonal(channelKey)) {
203
- cfg.messages = { ackReaction: '🦞', ackReactionScope: 'all', removeAckAfterReply: false };
207
+ cfg.messages = { ackReaction: '/-heart', ackReactionScope: 'all', removeAckAfterReply: false };
204
208
  }
205
209
 
206
210
  // ── commands ──────────────────────────────────────────────────────────────
@@ -382,8 +382,11 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
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
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
- const ackReactionScript = `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.messages=c.messages||{};if(c.messages.ackReaction===undefined){c.messages.ackReaction='🦞';ch=true;}if(c.messages.ackReactionScope===undefined){c.messages.ackReactionScope='all';ch=true;}if(ch)fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
385
+ // arbitrary emoji. Absent-only, so an operator's own choice is never overwritten
386
+ // with one exception: the 🦞 this script itself used to seed is rewritten to
387
+ // `/-heart`. 🦞 only ships as a Zalo CUSTOM reaction (needs zalo-connect ≥3.0.15,
388
+ // silently dropped below that); `/-heart` is a built-in every version can send.
389
+ const ackReactionScript = `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.messages=c.messages||{};if(c.messages.ackReaction===undefined||c.messages.ackReaction==='🦞'){c.messages.ackReaction='/-heart';ch=true;}if(c.messages.ackReactionScope===undefined){c.messages.ackReactionScope='all';ch=true;}if(ch)fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
387
390
  runtimeParts.push(`node - <<'NODE'\n${ackReactionScript}\nNODE`);
388
391
  }
389
392
  // Always-on memory context engine for every bot (see bot-config-gen: plugins.slots
@@ -562,6 +565,10 @@ ${indentBlock(docker9RouterEntrypointScript, 8)}
562
565
  - PORT=${routerPort}
563
566
  - HOSTNAME=0.0.0.0
564
567
  - CI=true
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 — without
570
+ # this the user can NEVER log in with the documented default (measured 02/09/2026).
571
+ - INITIAL_PASSWORD=123456
565
572
  volumes:
566
573
  - 9router-data:/root/.9router
567
574
  - ./sync.js:/tmp/sync.js:ro
@@ -656,6 +663,10 @@ ${indentBlock(docker9RouterEntrypointScript, 8)}
656
663
  - PORT=${routerPort}
657
664
  - HOSTNAME=0.0.0.0
658
665
  - CI=true
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 — without
668
+ # this the user can NEVER log in with the documented default (measured 02/09/2026).
669
+ - INITIAL_PASSWORD=123456
659
670
  volumes:
660
671
  - 9router-data:/root/.9router
661
672
  - ./sync.js:/tmp/sync.js:ro
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-openclaw-bot",
3
- "version": "5.16.4",
3
+ "version": "5.16.6",
4
4
  "description": "Interactive CLI installer for OpenClaw Bot",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {