create-openclaw-bot 5.13.4 → 5.13.5
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.13.
|
|
10
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.13.5-0EA5E9?style=for-the-badge" alt="Version 5.13.5" /></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,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## 🆕 What's New in v5.13.
|
|
40
|
+
## 🆕 What's New in v5.13.5
|
|
41
41
|
|
|
42
42
|
- ⚙️ **New Settings page**: pick your theme (light/dark toggle), language (VI/EN) and timezone right from the dashboard — available in both the sidebar and the mobile nav bar.
|
|
43
43
|
- 🕒 **Schedules & cron run in the correct local time**: newly created bots carry an explicit timezone, so reminders/cron no longer drift a day off around midnight (a UTC-vs-local bug that could schedule into the past). Scheduling guidance was hardened end-to-end (local time + timezone, explicit delivery target, raw group id).
|
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.13.
|
|
10
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.13.5-0EA5E9?style=for-the-badge" alt="Version 5.13.5" /></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,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## 🆕 Có gì mới trong v5.13.
|
|
40
|
+
## 🆕 Có gì mới trong v5.13.5
|
|
41
41
|
|
|
42
42
|
- ⚙️ **Trang Cài đặt mới**: chọn giao diện (nút gạt Sáng/Tối), ngôn ngữ (VI/EN) và múi giờ ngay trong dashboard — có ở cả sidebar lẫn thanh điều hướng mobile.
|
|
43
43
|
- 🕒 **Lịch & cron chạy đúng giờ địa phương**: bot tạo mới nhận múi giờ rõ ràng, nên nhắc hẹn/cron không còn lệch 1 ngày quanh nửa đêm (lỗi UTC-vs-local có thể đặt lịch vào quá khứ). Đã siết hướng dẫn lập lịch toàn diện (giờ local + múi giờ, nơi gửi rõ ràng, ID nhóm dạng thô).
|
|
@@ -3073,7 +3073,12 @@ async function applyFeatureToggle(projectDir, agentId, kind, id, enabled) {
|
|
|
3073
3073
|
|
|
3074
3074
|
const k = `${kind}:${id}`;
|
|
3075
3075
|
|
|
3076
|
-
|
|
3076
|
+
// zalo-connect is required by any Zalo bot — refuse to disable it while a Zalo binding exists
|
|
3077
|
+
// (the UI also locks the toggle; this is the backend guard).
|
|
3078
|
+
if (kind === 'plugin' && (id === 'zalo-connect' || id === 'openclaw-zalo-connect') && !enabled) {
|
|
3079
|
+
const hasZaloBot = (cfg.bindings || []).some((b) => b?.match?.channel === 'zalo-connect');
|
|
3080
|
+
if (hasZaloBot) throw httpError(400, 'Không thể tắt Zalo Connect khi vẫn còn bot Zalo.');
|
|
3081
|
+
}
|
|
3077
3082
|
|
|
3078
3083
|
if (kind === 'skill' && id === 'cron') {
|
|
3079
3084
|
cfg.skills = cfg.skills || { entries: {} };
|
|
@@ -3338,6 +3343,41 @@ async function installFeature(projectDir, agentId, kind, id) {
|
|
|
3338
3343
|
}
|
|
3339
3344
|
|
|
3340
3345
|
if (kind === 'plugin') {
|
|
3346
|
+
// zalo-connect is a GIT-pinned fork (not a ClawHub package) — install/update it by cloning the
|
|
3347
|
+
// pinned tag inside the container (same as first-boot/login). Powers the dashboard "Update"
|
|
3348
|
+
// button so existing Zalo bots can upgrade to the pinned version (bump the pin in common-gen.js).
|
|
3349
|
+
if (id === 'zalo-connect' || id === 'openclaw-zalo-connect') {
|
|
3350
|
+
let composeDir = null;
|
|
3351
|
+
if (existsSync(join(projectDir, 'docker-compose.yml'))) composeDir = projectDir;
|
|
3352
|
+
else if (existsSync(join(projectDir, 'docker', 'openclaw', 'docker-compose.yml'))) composeDir = join(projectDir, 'docker', 'openclaw');
|
|
3353
|
+
const repo = String(ZALO_CONNECT_PLUGIN_SPEC).split('#')[0];
|
|
3354
|
+
const ref = String(ZALO_CONNECT_PLUGIN_SPEC).split('#')[1] || ZALO_CONNECT_VERSION;
|
|
3355
|
+
if (composeDir) {
|
|
3356
|
+
const botContainer = getBotContainerName(projectDir);
|
|
3357
|
+
sendLog(`[zalo-connect] Installing/updating pinned ${ref} inside ${botContainer}...`);
|
|
3358
|
+
const cmd = `tmp=/tmp/openclaw-plugin-zalo-connect-${ref}; rm -rf "$tmp"; git clone --depth 1 --branch "${ref}" "${repo}" "$tmp" && rm -rf "$tmp/.git" && cd /home/node/project && openclaw plugins install "$tmp" --force 2>&1`;
|
|
3359
|
+
const out = await runCapture('docker', ['exec', botContainer, 'sh', '-lc', cmd], { cwd: projectDir, shell: false });
|
|
3360
|
+
if (out) for (const line of `${out.stdout}\n${out.stderr}`.split(/\r?\n/).filter(Boolean)) sendLog(`[zalo-connect] ${line}`);
|
|
3361
|
+
const okDir = existsSync(join(projectDir, '.openclaw', 'extensions', 'zalo-connect'));
|
|
3362
|
+
if (out.code !== 0 && !okDir) throw new Error(out.stderr || out.stdout || 'Failed to install zalo-connect.');
|
|
3363
|
+
}
|
|
3364
|
+
const cfgPath = join(projectDir, '.openclaw', 'openclaw.json');
|
|
3365
|
+
if (existsSync(cfgPath)) {
|
|
3366
|
+
const cfg = ensureConfigShape(JSON.parse(await fsp.readFile(cfgPath, 'utf8')));
|
|
3367
|
+
cfg.plugins = cfg.plugins || { entries: {}, allow: [] };
|
|
3368
|
+
cfg.plugins.entries = cfg.plugins.entries || {};
|
|
3369
|
+
cfg.plugins.entries['zalo-connect'] = cfg.plugins.entries['zalo-connect'] || {};
|
|
3370
|
+
cfg.plugins.entries['zalo-connect'].enabled = true;
|
|
3371
|
+
cfg.plugins.allow = cfg.plugins.allow || [];
|
|
3372
|
+
if (!cfg.plugins.allow.includes('zalo-connect')) cfg.plugins.allow.push('zalo-connect');
|
|
3373
|
+
await fsp.writeFile(cfgPath, JSON.stringify(cfg, null, 2), 'utf8');
|
|
3374
|
+
}
|
|
3375
|
+
if (composeDir) {
|
|
3376
|
+
sendLog('[zalo-connect] Restarting container to apply...');
|
|
3377
|
+
await run('docker', ['restart', getBotContainerName(projectDir)], { shell: false }).catch(() => {});
|
|
3378
|
+
}
|
|
3379
|
+
return { ok: true, id: 'zalo-connect' };
|
|
3380
|
+
}
|
|
3341
3381
|
const installSpec = pluginInstallSpec(id);
|
|
3342
3382
|
const installArgs = ['plugins', 'install', installSpec, '--force'];
|
|
3343
3383
|
if (installSpec.startsWith('clawhub:')) installArgs.push('--acknowledge-clawhub-risk');
|
|
@@ -3640,6 +3680,7 @@ async function getFeatureFlags(projectDir, agentId = '') {
|
|
|
3640
3680
|
poster: ['openclaw-n8n-facebook-poster', 'openclaw-facebook-poster', 'facebook-poster'],
|
|
3641
3681
|
fbMessenger: ['openclaw-fb-messenger', 'fb-messenger'],
|
|
3642
3682
|
tencentMemory: ['memory-tencentdb'],
|
|
3683
|
+
zaloConnect: ['zalo-connect', 'openclaw-zalo-connect'],
|
|
3643
3684
|
};
|
|
3644
3685
|
const flags = {
|
|
3645
3686
|
'skill:browser': browserOn,
|
|
@@ -3653,6 +3694,7 @@ async function getFeatureFlags(projectDir, agentId = '') {
|
|
|
3653
3694
|
'plugin:openclaw-n8n-facebook-poster': isEnabled(aliases.poster),
|
|
3654
3695
|
'plugin:openclaw-fb-messenger': isEnabled(aliases.fbMessenger),
|
|
3655
3696
|
'plugin:memory-tencentdb': isEnabled(aliases.tencentMemory),
|
|
3697
|
+
'plugin:zalo-connect': isEnabled(aliases.zaloConnect),
|
|
3656
3698
|
};
|
|
3657
3699
|
const extensionsDir = join(projectDir || '', '.openclaw', 'extensions');
|
|
3658
3700
|
const extensionDirExists = (aliases = []) =>
|
|
@@ -3671,6 +3713,7 @@ async function getFeatureFlags(projectDir, agentId = '') {
|
|
|
3671
3713
|
'plugin:openclaw-fb-messenger': extensionDirExists(aliases.fbMessenger)
|
|
3672
3714
|
|| aliases.fbMessenger.some((a) => installedKeys.has(a) || Array.from(installedSpecs).some((spec) => spec.includes(a))),
|
|
3673
3715
|
'plugin:memory-tencentdb': isActuallyInstalled(aliases.tencentMemory),
|
|
3716
|
+
'plugin:zalo-connect': isActuallyInstalled(aliases.zaloConnect),
|
|
3674
3717
|
};
|
|
3675
3718
|
const versions = {
|
|
3676
3719
|
'skill:image-gen': await getInstalledSkillVersion(projectDir, aid, 'infographic-generator', cfg),
|
|
@@ -3681,6 +3724,7 @@ async function getFeatureFlags(projectDir, agentId = '') {
|
|
|
3681
3724
|
'plugin:openclaw-n8n-facebook-poster': await getInstalledPluginVersion(projectDir, aliases.poster),
|
|
3682
3725
|
'plugin:openclaw-fb-messenger': await getInstalledPluginVersion(projectDir, aliases.fbMessenger),
|
|
3683
3726
|
'plugin:memory-tencentdb': await getInstalledPluginVersion(projectDir, aliases.tencentMemory),
|
|
3727
|
+
'plugin:zalo-connect': await getInstalledPluginVersion(projectDir, aliases.zaloConnect),
|
|
3684
3728
|
};
|
|
3685
3729
|
// Docker: fill any plugin version still empty from the container's extensions volume
|
|
3686
3730
|
// (e.g. bundled/clawhub plugins like zalo-mod that aren't on the host). One docker exec.
|
|
@@ -3693,9 +3737,14 @@ async function getFeatureFlags(projectDir, agentId = '') {
|
|
|
3693
3737
|
fillVer('plugin:openclaw-n8n-facebook-poster', aliases.poster);
|
|
3694
3738
|
fillVer('plugin:openclaw-fb-messenger', aliases.fbMessenger);
|
|
3695
3739
|
fillVer('plugin:memory-tencentdb', aliases.tencentMemory);
|
|
3740
|
+
fillVer('plugin:zalo-connect', aliases.zaloConnect);
|
|
3696
3741
|
}
|
|
3697
3742
|
const zaloBackend = fresh.channels?.['zalo-connect']?.enabled ? 'zalo-connect' : '';
|
|
3698
|
-
|
|
3743
|
+
// zalo-connect is REQUIRED by any Zalo bot → lock its toggle (checked, can't disable)
|
|
3744
|
+
// whenever a Zalo binding exists.
|
|
3745
|
+
const hasZaloBot = (fresh.bindings || []).some((b) => b?.match?.channel === 'zalo-connect');
|
|
3746
|
+
const locked = { 'plugin:zalo-connect': hasZaloBot };
|
|
3747
|
+
return { flags, installed, versions, zaloBackend, locked };
|
|
3699
3748
|
}
|
|
3700
3749
|
|
|
3701
3750
|
async function serveStatic(req, res) {
|
|
@@ -238,6 +238,8 @@
|
|
|
238
238
|
|
|
239
239
|
// ── skills ───────────────────────────────────────────────────────────────
|
|
240
240
|
const skillEntries = buildSkillsEntries(skills, selectedSkills);
|
|
241
|
+
// NOTE: the "zalo-actions" skill was removed — its guidance now lives in the `zalo-connect`
|
|
242
|
+
// tool description itself (fork ≥ v3.0.2), so no per-bot skill entry is needed anymore.
|
|
241
243
|
if (Object.keys(skillEntries).length > 0) {
|
|
242
244
|
cfg.skills = { entries: skillEntries };
|
|
243
245
|
}
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
// Pin the maintained fork tag so setup never falls back to upstream/ClawHub.
|
|
45
45
|
const ZALO_CHANNEL_ID = 'zalo-connect';
|
|
46
46
|
const ZALO_PLUGIN_ID = 'zalo-connect';
|
|
47
|
-
const ZALO_CONNECT_VERSION = '3.0.
|
|
48
|
-
const ZALO_CONNECT_PLUGIN_SPEC = 'https://github.com/tuanminhhole/openclaw-zalo-connect.git#v3.0.
|
|
47
|
+
const ZALO_CONNECT_VERSION = '3.0.2';
|
|
48
|
+
const ZALO_CONNECT_PLUGIN_SPEC = 'https://github.com/tuanminhhole/openclaw-zalo-connect.git#v3.0.2';
|
|
49
49
|
|
|
50
50
|
function buildRelayPluginInstallCommand(prefix = 'openclaw') {
|
|
51
51
|
return `if [ ! -d "$OPENCLAW_STATE_DIR/extensions/${TELEGRAM_RELAY_PLUGIN_ID}" ]; then ${prefix} plugins install ${TELEGRAM_RELAY_PLUGIN_SPEC} 2>/dev/null || true; fi`;
|
|
@@ -567,15 +567,26 @@ Truyền tham số \`job\` (object) gồm:
|
|
|
567
567
|
- **Một lần:** \`kind: "at"\`, \`at\`: giờ địa phương + \`tz\` (khuyên dùng), ví dụ \`"at": "2026-07-22T00:30:00", "tz": "${tz}"\`. Cũng có thể dùng \`+duration\` (vd \`"+30m"\`). **KHÔNG tự quy đổi & ghi \`...Z\` (UTC)** — dễ sai ngày.
|
|
568
568
|
- 🕒 **XÁC ĐỊNH ĐÚNG NGÀY:** "Current time" trong ngữ cảnh đã theo giờ địa phương (\`${tz}\`). Cứ dùng NGÀY đang thấy để suy "hôm nay / tối nay / sáng mai". (Nếu vô tình thấy giờ dạng \`...Z\` UTC thì phải đổi sang \`${tz}\` trước khi suy ngày.)
|
|
569
569
|
- ✅ Nếu tool báo \`schedule.at is in the past\` → tính sai ngày (thường thiếu 1 ngày). Cộng thêm 1 ngày rồi thử lại; đừng báo lỗi khi chưa tự sửa.
|
|
570
|
-
- **\`payload\`**:
|
|
571
|
-
- \`
|
|
572
|
-
-
|
|
573
|
-
- **\`delivery\`** — 🚨 **BẮT BUỘC
|
|
574
|
-
- \`mode\`: \`"announce"\`.
|
|
570
|
+
- **\`payload\`**: \`{ "kind": "agentTurn", "message": "<chỉ dẫn/nội dung>" }\`.
|
|
571
|
+
- \`message\` là chỉ dẫn để agent **SINH RA nội dung sẽ gửi** — có thể là câu cố định (\`"Chúc cả nhà ngủ ngon 🌙"\`) hoặc yêu cầu tạo mới mỗi lần (\`"Viết một lời chúc buổi sáng mới, tích cực, không lặp lại"\`). **Phần trả lời của agent CHÍNH LÀ tin được gửi.**
|
|
572
|
+
- ⛔ **KHÔNG** viết kiểu mệnh lệnh gửi ("dùng tool ... gửi tới group ...", "gửi tin tới groupId ..."). ⛔ **KHÔNG** để job tự gọi tool gửi tin (message/send/zalo-connect). Việc gửi là do \`delivery.announce\` lo — tự gọi sẽ lỗi \`Unknown target\` / "Cron failed".
|
|
573
|
+
- **\`delivery\`** — 🚨 **BẮT BUỘC** cho tin gửi tới người/nhóm. Isolated job reset routing mỗi lần chạy, nên phải ghi rõ \`channel\` + \`to\`; thiếu → lỗi \`Refusing implicit isolated cron delivery\` (không gửi được):
|
|
574
|
+
- \`mode\`: \`"announce"\`. ⛔ **KHÔNG dùng \`"none"\`** — job vẫn chạy "ok" nhưng KHÔNG gửi gì (đây là bẫy thường gặp).
|
|
575
575
|
- \`channel\`: \`"${zaloDeliveryChannel}"\` (KHÔNG để \`"last"\`).
|
|
576
|
-
- \`to\`:
|
|
576
|
+
- \`to\`: **ID THÔ, KHÔNG tiền tố**. Group Zalo → groupId thẳng (vd \`"1925989252066183028"\`); DM → userId. ⚠️ **KHÔNG thêm \`g:\`** (sẽ lỗi \`Unknown target "g:..."\`).
|
|
577
577
|
|
|
578
|
-
### 📦 Ví dụ
|
|
578
|
+
### 📦 Ví dụ A — LẶP LẠI (chúc buổi sáng 9:05 mỗi ngày cho 1 nhóm):
|
|
579
|
+
\`\`\`json
|
|
580
|
+
{
|
|
581
|
+
"sessionTarget": "isolated",
|
|
582
|
+
"wakeMode": "now",
|
|
583
|
+
"schedule": { "kind": "cron", "expr": "5 9 * * *", "tz": "${tz}" },
|
|
584
|
+
"payload": { "kind": "agentTurn", "message": "Viết MỘT lời chúc buổi sáng MỚI mỗi ngày, tích cực, ấm áp, lịch sự, không lặp lại. Chỉ trả về đúng nội dung lời chúc." },
|
|
585
|
+
"delivery": { "mode": "announce", "channel": "${zaloDeliveryChannel}", "to": "1228185345777623323" }
|
|
586
|
+
}
|
|
587
|
+
\`\`\`
|
|
588
|
+
|
|
589
|
+
### 📦 Ví dụ B — MỘT LẦN (giờ địa phương) — mỗi group 1 job riêng:
|
|
579
590
|
\`\`\`json
|
|
580
591
|
{
|
|
581
592
|
"sessionTarget": "isolated",
|
|
@@ -597,6 +608,54 @@ Truyền tham số \`job\` (object) gồm:
|
|
|
597
608
|
\`openclaw cron run <job_id> --wait\` (hoặc gọi tool \`cron\` với action \`run\` kèm \`id\`).`;
|
|
598
609
|
}
|
|
599
610
|
|
|
611
|
+
// DEPRECATED (unused): guidance moved into the `zalo-connect` tool description (fork ≥ v3.0.2).
|
|
612
|
+
// Kept only for reference; no longer wired into buildWorkspaceFileMap.
|
|
613
|
+
function buildZaloActionsSkillMd(isVi = true, zaloDeliveryChannel = 'zalo-connect') {
|
|
614
|
+
return `---
|
|
615
|
+
name: zalo-actions
|
|
616
|
+
description: Hành động Zalo phong phú qua tool ${zaloDeliveryChannel} — sticker, thả cảm xúc, bình chọn, ghi chú, nhắc hẹn, media, quản trị nhóm.
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
# 💬 Hành động Zalo (tool: \`${zaloDeliveryChannel}\`)
|
|
620
|
+
|
|
621
|
+
Ngoài gửi text, tool \`${zaloDeliveryChannel}\` có ~149 action. Gọi bằng: tool \`${zaloDeliveryChannel}\` với \`{ "action": "<tên>", ... }\`. Cứ chủ động dùng khi phù hợp (user xin sticker, cần bình chọn, nhắc hẹn, ghim ghi chú...).
|
|
622
|
+
|
|
623
|
+
## Quy tắc chung
|
|
624
|
+
- **\`threadId\`** = nơi gửi. Trong GROUP hiện tại → dùng **groupId THÔ** (KHÔNG tiền tố \`g:\`) kèm **\`isGroup: true\`**. DM cá nhân → \`threadId\` = userId, \`isGroup: false\`.
|
|
625
|
+
- Làm xong thì trả lời ngắn gọn cho user, KHÔNG dán JSON/kết quả thô.
|
|
626
|
+
|
|
627
|
+
## 🎨 Sticker — \`send-sticker\`
|
|
628
|
+
- Dễ nhất (theo từ khoá, tool tự tìm & gửi): \`{ "action": "send-sticker", "threadId": "<groupId>", "isGroup": true, "keyword": "chào buổi sáng" }\`.
|
|
629
|
+
- Chỉ định cụ thể: thêm \`"stickerId"\` + \`"stickerCateId"\` (thay cho \`keyword\`).
|
|
630
|
+
|
|
631
|
+
## 😀 Thả cảm xúc — \`add-reaction\`
|
|
632
|
+
- \`{ "action": "add-reaction", "msgId": "<id tin nhắn>", "icon": "heart" }\` — \`icon\`: heart / like / haha / wow / cry / angry.
|
|
633
|
+
|
|
634
|
+
## 📊 Bình chọn — \`create-poll\`
|
|
635
|
+
- \`{ "action": "create-poll", "threadId": "<groupId>", "isGroup": true, "title": "Câu hỏi?", "options": ["A","B"], "allowMultiChoices": false }\`.
|
|
636
|
+
|
|
637
|
+
## 📌 Ghi chú ghim — \`create-note\`
|
|
638
|
+
- \`{ "action": "create-note", "threadId": "<groupId>", "isGroup": true, "title": "Nội dung ghi chú" }\`.
|
|
639
|
+
|
|
640
|
+
## ⏰ Nhắc hẹn nhóm — \`create-reminder\`
|
|
641
|
+
- \`{ "action": "create-reminder", "threadId": "<groupId>", "isGroup": true, "title": "...", "startTime": <epoch ms>, "repeat": 0 }\` (repeat: 0 không lặp / 1 ngày / 2 tuần / 3 tháng). Lịch định kỳ kiểu cron → dùng skill \`cronjob\`.
|
|
642
|
+
|
|
643
|
+
## 🖼️ Media
|
|
644
|
+
- Ảnh: \`send-image\` \`{threadId,isGroup,url}\` · Video: \`send-video\` \`{threadId,isGroup,url,thumbnailUrl?}\` · Voice: \`send-voice\` \`{threadId,isGroup,voiceUrl}\` · File: \`send-file\` \`{threadId,isGroup,filePath}\` · Link preview: \`send-link\` \`{threadId,isGroup,url}\`.
|
|
645
|
+
|
|
646
|
+
## ↪️ Chuyển tiếp / thu hồi / xoá
|
|
647
|
+
- \`forward-message\` \`{msgId, threadIds:["<đích>"]}\` · \`delete-message\` \`{msgId, threadId, onlyMe?}\`.
|
|
648
|
+
- **Thu hồi tin của CHÍNH bot** (\`undo-message\`): khi user bảo "thu hồi/gỡ tin vừa nãy", gọi \`undo-message\` \`{threadId:"<groupId/userId hiện tại>"}\` — **KHÔNG cần msgId**, hệ thống tự lấy tin gần nhất bot đã gửi trong luồng đó. ⏳ Chỉ thu hồi được tin bot gửi **trong 5 phút** gần nhất; tin cũ hơn (hoặc tin của người khác) thì báo lại là không gỡ được. Muốn nhắm tin cụ thể thì truyền thêm \`{msgId}\`.
|
|
649
|
+
|
|
650
|
+
## 🛠️ Quản trị nhóm (bot phải là admin)
|
|
651
|
+
- \`add-group-admin\` / \`remove-group-admin\` \`{groupId,userId}\` · \`rename-group\` \`{groupId,groupName}\` · \`change-group-owner\` \`{groupId,userId}\` · \`invite-to-groups\` \`{userId, groupIds:[...]}\` · \`update-group-settings\` \`{groupId, groupSettings:{...}}\` · link nhóm: \`enable-group-link\`/\`disable-group-link\`/\`get-group-link\` \`{groupId}\`.
|
|
652
|
+
|
|
653
|
+
## 📎 Hội thoại
|
|
654
|
+
- Ghim: \`pin-conversation\` \`{threadId}\` · Tắt báo: \`mute-conversation\` \`{threadId, duration:-1}\` (giây, -1 = mãi) · Đang gõ "…": \`send-typing\` \`{threadId,isGroup}\`.
|
|
655
|
+
|
|
656
|
+
> Còn nhiều action khác (tìm bạn, QR, catalog/sản phẩm, auto-reply, quick message, poll nâng cao, mã hoá tin tự huỷ...). Xem mô tả từng \`action\` + tham số ngay trong schema của tool \`${zaloDeliveryChannel}\`.`;
|
|
657
|
+
}
|
|
658
|
+
|
|
600
659
|
function buildInfographicGeneratorSkillMd(botName = 'Williams') {
|
|
601
660
|
return '';
|
|
602
661
|
}
|
|
@@ -1345,6 +1404,10 @@ Add whatever helps you do your job. This is your cheat sheet.
|
|
|
1345
1404
|
files['skills/cronjob/SKILL.md'] = buildCronjobSkillMd(isVi, 'zalo-connect', userTimezone);
|
|
1346
1405
|
}
|
|
1347
1406
|
|
|
1407
|
+
// NOTE: the old `zalo-actions` agent skill was removed — its guidance (Zalo conventions +
|
|
1408
|
+
// action recipes) now lives directly in the `zalo-connect` tool description (fork ≥ v3.0.2),
|
|
1409
|
+
// so every zalo-connect bot gets it automatically without a generated per-bot skill.
|
|
1410
|
+
|
|
1348
1411
|
if (hasImageGen) {
|
|
1349
1412
|
files['skills/infographic-generator/SKILL.md'] = buildInfographicGeneratorSkillMd(botName);
|
|
1350
1413
|
files['skills/infographic-generator/image-generator.js'] = buildInfographicGeneratorJs();
|
package/dist/web/app.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const $ = (sel) => document.querySelector(sel);
|
|
2
|
-
const state = { tab: 'dashboard', system: null, install: null, files: [], catalog: { skills: [], plugins: [] }, logs: [], zaloLoginOpen: false, zaloLoginLines: [], zaloQrDataUrl: '', lang: localStorage.getItem('openclaw-lang') || 'vi', theme: localStorage.getItem('openclaw-theme') || 'dark', tz: localStorage.getItem('openclaw-tz') || 'Asia/Ho_Chi_Minh', navCollapsed: localStorage.getItem('openclaw-nav')==='1', os: null, mode: null, donateOpen: false, botModalOpen: false, botEditId: '', installModalOpen: false, fbPluginModalOpen: false, installTab: 'docker', installDraft: null, pathModal: null, confirmModal: null, botChannel: 'telegram', botPane: 'list', activeBotId: '', selectedFile: '', botMessage: '', projectConnectMessage: '', pendingProjectDir: '', selectedProjectDir: '', featureFlags: {}, featureInstalled: {}, featureLoading: {}, zaloBackend: '', zaloHealth: null, openDirs: {} };
|
|
2
|
+
const state = { tab: 'dashboard', system: null, install: null, files: [], catalog: { skills: [], plugins: [] }, logs: [], zaloLoginOpen: false, zaloLoginLines: [], zaloQrDataUrl: '', lang: localStorage.getItem('openclaw-lang') || 'vi', theme: localStorage.getItem('openclaw-theme') || 'dark', tz: localStorage.getItem('openclaw-tz') || 'Asia/Ho_Chi_Minh', navCollapsed: localStorage.getItem('openclaw-nav')==='1', os: null, mode: null, donateOpen: false, botModalOpen: false, botEditId: '', installModalOpen: false, fbPluginModalOpen: false, installTab: 'docker', installDraft: null, pathModal: null, confirmModal: null, botChannel: 'telegram', botPane: 'list', activeBotId: '', selectedFile: '', botMessage: '', projectConnectMessage: '', pendingProjectDir: '', selectedProjectDir: '', featureFlags: {}, featureInstalled: {}, featureLoading: {}, featureLocked: {}, zaloBackend: '', zaloHealth: null, openDirs: {} };
|
|
3
3
|
const SVG_CDN = 'https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons';
|
|
4
4
|
const OS_OPTIONS = [
|
|
5
5
|
{ id: 'win', title: 'Windows', subtitle: 'Auto-detected desktop', icon: `${SVG_CDN}/windows/default.svg`, badge: 'Desktop' },
|
|
@@ -1064,6 +1064,7 @@ function botSkillsPanel() {
|
|
|
1064
1064
|
{ id: 'learning-memory', title: 'Siêu Trí Nhớ Dài Hạn (learning-memory)', desc: 'Tự động ghi nhớ bài học vào MEMORY.md, tự đóng gói và tiến hóa kỹ năng mới vào skills/' },
|
|
1065
1065
|
];
|
|
1066
1066
|
const plugins = [
|
|
1067
|
+
{ id: 'zalo-connect', title: 'OpenClaw Zalo Connect', desc: t('Kênh Zalo cá nhân (zca-js) — BẮT BUỘC cho bot Zalo. Tự cài khi tạo bot Zalo đầu tiên; bấm Cập nhật để lên bản mới nhất.', 'Personal Zalo channel (zca-js) — REQUIRED for Zalo bots. Auto-installed with your first Zalo bot; click Update for the latest version.'), channels: ['zalo-personal'] },
|
|
1067
1068
|
{ id: 'memory-tencentdb', title: 'TencentDB Agent Memory', desc: 'Bộ nhớ phân tầng L0–L3 + nén ngữ cảnh: nhớ tốt session dài, tiết kiệm ~61% token (local SQLite, không cần API)' },
|
|
1068
1069
|
{ id: 'openclaw-browser-automation', title: 'openclaw-browser-automation', desc: 'Smart Search + Browser (headless & Chrome thật)' },
|
|
1069
1070
|
{ id: 'openclaw-zalo-mod', title: 'openclaw-zalo-mod', desc: 'Zalo group helpers', channels: ['zalo-personal'], openWebPort: 18790, openWebPath: '/dashboard' },
|
|
@@ -1083,8 +1084,9 @@ function botSkillsPanel() {
|
|
|
1083
1084
|
const row = (item, group) => {
|
|
1084
1085
|
const key = `${group}:${item.id}`;
|
|
1085
1086
|
const loading = !!state.featureLoading[key];
|
|
1087
|
+
const locked = !!state.featureLocked?.[key];
|
|
1086
1088
|
const requiresInstall = group === 'plugin' || (group === 'skill' && (item.id === 'image-gen' || item.id === 'learning-memory'));
|
|
1087
|
-
const isInstalled = !requiresInstall || !!state.featureInstalled?.[key];
|
|
1089
|
+
const isInstalled = !requiresInstall || !!state.featureInstalled?.[key] || locked;
|
|
1088
1090
|
|
|
1089
1091
|
const version = requiresInstall && isInstalled ? (state.featureVersions?.[key] || '') : '';
|
|
1090
1092
|
const versionBadge = version ? `<span class="plugin-version-badge" style="display:inline-block; font-size: 11px; background: rgba(66, 133, 244, 0.15); color: #4285F4; padding: 2px 6px; border-radius: 4px; font-weight: 600; border: 1px solid rgba(66,133,244,0.25); flex:0 0 auto;">v${escapeHtml(version)}</span>` : '';
|
|
@@ -1094,7 +1096,7 @@ function botSkillsPanel() {
|
|
|
1094
1096
|
let toggleHtml = '';
|
|
1095
1097
|
const secs = [];
|
|
1096
1098
|
if (isInstalled) {
|
|
1097
|
-
toggleHtml = `<label class="feature-switch"><input type="checkbox" data-feature-toggle="${key}" ${flags[key] ? 'checked' : ''} ${loading ? 'disabled' : ''}/><span></span></label
|
|
1099
|
+
toggleHtml = `<label class="feature-switch" title="${locked ? t('Bắt buộc cho bot Zalo — không thể tắt','Required for Zalo bots — cannot be disabled') : ''}"><input type="checkbox" data-feature-toggle="${key}" ${(flags[key] || locked) ? 'checked' : ''} ${(loading || locked) ? 'disabled' : ''}/><span></span></label>${locked ? `<span title="${t('Đã khoá','Locked')}" style="margin-left:6px;opacity:.55;font-size:12px;">🔒</span>` : ''}`;
|
|
1098
1100
|
if (item.openWebPort) {
|
|
1099
1101
|
secs.push(`<a class="secondary icon-btn2" href="${sameHostUrl('', item.openWebPort)}${item.openWebPath || ''}" target="_blank" rel="noopener" title="${t('Mở dashboard của plugin','Open the plugin dashboard')}" style="padding: 4px 8px; font-size: 11px; height: 28px; border-width: 1px;">${actionIcon('link')}<span>${t('Mở web','Open')}</span></a>`);
|
|
1100
1102
|
}
|
|
@@ -1607,6 +1609,7 @@ async function loadFeatureFlags(silent=false){
|
|
|
1607
1609
|
state.featureFlags = data.flags || {};
|
|
1608
1610
|
state.featureInstalled = data.installed || {};
|
|
1609
1611
|
state.featureVersions = data.versions || {};
|
|
1612
|
+
state.featureLocked = data.locked || {};
|
|
1610
1613
|
state.zaloBackend = data.zaloBackend || '';
|
|
1611
1614
|
if (state.zaloBackend === 'zalo-connect') await loadZaloHealth(true).catch(() => {});
|
|
1612
1615
|
} catch (_) {
|