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 +17 -7
- package/README.vi.md +17 -7
- package/dist/server/local-server.js +79 -9
- package/dist/setup/shared/bot-config-gen.js +11 -7
- package/dist/setup/shared/docker-gen.js +13 -2
- package/package.json +1 -1
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.
|
|
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.
|
|
40
|
+
## 🆕 What's New in v5.16.6
|
|
41
41
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
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.
|
|
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.
|
|
40
|
+
## 🆕 Có gì mới trong v5.16.6
|
|
41
41
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
42
|
+
- 🩹 **Cài native trên OpenClaw 2026.8 mượt từ phát đầu** - đợt này vá 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ự, và 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" - mà 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ũ 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 mà không ai hay - giờ xoá là 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 vì 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
|
-
|
|
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
|
|
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
|
|
2395
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
3496
|
-
|
|
3497
|
-
//
|
|
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/2026 — learning-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
|
-
|
|
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
|
-
//
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
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: '
|
|
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
|
-
|
|
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
|