abs-zalo-bot 0.2.0

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/.env.example ADDED
@@ -0,0 +1,48 @@
1
+ # Local only. Never commit real values. Never paste secrets into chat.
2
+ PORT=3871
3
+ HOST=127.0.0.1
4
+ DATA_DIR=./data
5
+ DEFAULT_ACCOUNT_ID=default
6
+ DASHBOARD_TOKEN=change-me
7
+ OWNER_USER_IDS=
8
+ # Optional Hermes analysis webhook (internal only)
9
+ HERMES_WEBHOOK_URL=
10
+ HERMES_WEBHOOK_TOKEN=
11
+ # Hermes Agent brain (OpenAI-compatible API server on :8642)
12
+ HERMES_API_BASE=http://127.0.0.1:8642/v1
13
+ HERMES_API_SERVER_KEY=
14
+ HERMES_API_MODEL=hermes-agent
15
+ # Digest cron minutes; 0 = disabled auto digest
16
+ DIGEST_INTERVAL_MINUTES=0
17
+ # Global kill switch
18
+ BRIDGE_PAUSED=false
19
+ # 24/7 listener + auto-reconnect (no deep-scroll)
20
+ KEEPALIVE_AUTO_CONNECT=true
21
+ KEEPALIVE_TICK_MS=20000
22
+ KEEPALIVE_RECONNECT_BASE_MS=5000
23
+ KEEPALIVE_RECONNECT_MAX_MS=300000
24
+ KEEPALIVE_ALERT_COOLDOWN_MS=900000
25
+ # Operator labels
26
+ ZALO_PHONE_LABEL=
27
+ DESTINATION_GROUP_NAME=
28
+ LISTEN_ALL_GROUPS=false
29
+ # QR onboarding: used only to print safe browser/tunnel instructions.
30
+ # These are not credentials and do not expose the QR image itself.
31
+ QR_LOCAL_PORT=13871
32
+ DASHBOARD_SSH_USER=user
33
+ DASHBOARD_SSH_HOST=your-vps-host
34
+ # Optional: authenticated HTTPS reverse-proxy origin, e.g. https://bridge.example.test
35
+ DASHBOARD_PUBLIC_URL=
36
+
37
+ # ── Brain endpoint cho Zalo OA auto-reply (tuỳ chọn) ───────────────────────────
38
+ # Trỏ tới agent của CHÍNH BẠN: Hermes, n8n, hay bất kỳ API tương thích nào.
39
+ # Bỏ trống = tắt auto-reply. Không có giá trị mặc định để lead không chảy ra ngoài.
40
+ ABS_BRAIN_CHAT_URL=
41
+ ABS_BRAIN_TOKEN=
42
+ # Tên header, chỉ đổi khi backend của bạn yêu cầu khác
43
+ ABS_BRAIN_TOKEN_HEADER=x-abs-token
44
+ ABS_BRAIN_ID_HEADER=x-abs-external-id
45
+
46
+ # ── Telemetry (tuỳ chọn) ──────────────────────────────────────────────────────
47
+ # Đường dẫn tới ledger script của bạn. Bỏ trống = tắt telemetry.
48
+ ABS_LEDGER_PATH=
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zalo Bridge contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,435 @@
1
+ # ABS Zalo Bot
2
+
3
+ **Install once · run from a dashboard button or one command · agents read the repo and know how to work in it**
4
+
5
+ A local/VPS Zalo bridge for Hermes and coding agents:
6
+
7
+ - **Zalo Personal QR**: listens to allowlisted sources, stores data locally, and posts digests to one destination. This is the *unofficial* path — internal/demo use with a dedicated account only.
8
+ - **Zalo OA**: the official adapter, kept separate from Personal QR, and the right choice for a customer-facing bot.
9
+ - **Policy Guard**: fail-closed by default. Nothing is sent until it is configured.
10
+ - **Dashboard**: a non-coder can connect the QR, pick sources, pick a destination, and flip the kill switch.
11
+ - **MCP**: agents can read status, groups, users and corpus, and ask for the destination through a safe contract.
12
+
13
+ > Just want it running for the owner? Read the **[Non-coder quickstart](docs/quickstart-non-coder.md)**.
14
+ >
15
+ > Handing this repo to Claude Code, Codex, Hermes or any other agent? The agent must read **[AGENTS.md](AGENTS.md)** and the **[Agent handoff](docs/agent-handoff.md)** before running any command.
16
+
17
+ ---
18
+
19
+ ## Tóm tắt tiếng Việt
20
+
21
+ Repo này là cầu nối Zalo cho agent. Hai đường tách biệt: **Personal QR** (không chính thức, dùng account riêng, chỉ nội bộ/demo) và **Zalo OA** (chính thức, dùng cho khách hàng). Mặc định **fail-closed** — chưa cấu hình thì không gửi gì cả.
22
+
23
+ Cài nhanh: `bash setup.sh` rồi `npm start`, mở `http://127.0.0.1:3871`. Bắt đầu ở chế độ `listen_only`, kiểm tra dữ liệu đúng rồi mới mở thêm.
24
+
25
+ Ba điều tuyệt đối không làm: không dán secret/OTP/PIN vào chat cho agent, không dùng account Zalo cá nhân chính để automation, không mở port 3871 thẳng ra Internet.
26
+
27
+ Tài liệu còn lại viết bằng tiếng Anh để mọi agent đọc được. Câu lệnh và tên biến giữ nguyên, đọc lướt vẫn theo được.
28
+
29
+ ---
30
+
31
+ ## Documentation map
32
+
33
+ Start here, in this order:
34
+
35
+ | File | What it is |
36
+ |---|---|
37
+ | `README.md` | This file — install, run, and what the project does |
38
+ | `docs/quickstart-non-coder.md` | Fastest path if you do not write code |
39
+ | `AGENTS.md` | Safety boundary every AI agent must follow |
40
+ | `docs/install.md` · `docs/configuration.md` | Setup and environment variables |
41
+ | `docs/personal-qr.md` · `docs/official-oa.md` | The two Zalo adapters |
42
+ | `docs/operations.md` · `docs/troubleshooting.md` | Running it day to day |
43
+ | `SECURITY.md` · `CONTRIBUTING.md` | Reporting issues and sending changes |
44
+ | `docs/internal/` | Design, spec, plan and verification notes kept for maintainers |
45
+
46
+ ## Works with any AI coding tool
47
+
48
+ This repo follows the `AGENTS.md` convention that Codex, Cursor, Zed and other agents already read.
49
+ Each tool has its own entrypoint file; they all point at the same rule set:
50
+
51
+ | Tool | Entrypoint | How to start |
52
+ |---|---|---|
53
+ | Claude Code (Sonnet/Opus) | `CLAUDE.md` | open repo, run `claude` |
54
+ | Codex CLI (GPT) | `CODEX.md` + `AGENTS.md` | open repo, run `codex` |
55
+ | Antigravity / Gemini CLI | `GEMINI.md` | open repo, run the agent |
56
+ | Hermes Agent | `HERMES.md` + `SKILL.md` | `cp -r . ~/.hermes/skills/abs-zalo-bot` or attach via MCP |
57
+ | Cursor | `.cursorrules` | auto-loaded on open |
58
+ | GitHub Copilot | `.github/copilot-instructions.md` | auto-loaded in VS Code |
59
+ | Any other agent | `AGENTS.md` | drop the file into chat |
60
+
61
+ Same bootstrap for every tool:
62
+
63
+ ```bash
64
+ node --version # requires >= 22.5
65
+ npm ci
66
+ npm run doctor
67
+ npm test
68
+ ```
69
+
70
+ ## 1. Pick the right path before installing
71
+
72
+ | What you need | Pick | Notes |
73
+ |---|---|---|
74
+ | Listen to internal groups and digest them into one ops group | Personal QR | Unofficial. Use a dedicated account. No spam, no broadcast |
75
+ | Talk to customers: FAQ, leads, booking, official notices | Zalo OA | The official path. Needs OA credentials and an HTTPS webhook |
76
+ | Not sure yet | Start with Personal QR in `listen_only` | No automatic sending. Inspect the data first |
77
+
78
+ **Do not use your main personal Zalo account for automation.** Never auto-enter OTP/PIN, never bypass login, never broadcast.
79
+
80
+ ---
81
+
82
+ ## 2. Quick install — no coding required
83
+
84
+ ### Requirements
85
+
86
+ - A Linux or macOS machine.
87
+ - Node.js **22.5 or newer**.
88
+ - A dedicated Zalo account if you use Personal QR.
89
+ - No API key is needed to run Personal QR in local listen/digest mode.
90
+
91
+ ### Are a VPS, a model, and Telegram required?
92
+
93
+ - **VPS:** not required to try it or run locally. Only needed for 24/7 operation. For an MVP, start around 1 vCPU / 1 GB RAM / 10 GB disk, and put HTTPS plus auth in front of it if it is reachable from outside. That is a starting point for operations, not a load guarantee.
94
+ - **Model/API key:** not required for `listen_only` or the local fallback. You only need a Hermes API compatible with OpenAI's `/v1/chat/completions` if you want an LLM to analyse or rewrite digests. This repo does not install a model and does not issue keys.
95
+ - **Telegram:** not required for the core bridge. The QR is shown in the dashboard on the local machine or VPS; this version does not forward the QR image over Telegram.
96
+ - **Live QR:** there are real routes — `POST /api/accounts/:id/connect`, the `QRCodeGenerated` callback, `GET /api/accounts/:id/qr` — and the dashboard renders it. Scanning and confirming on the phone stays a manual action by the account owner.
97
+
98
+ If you do not know whether Node.js is installed, hand the agent exactly this:
99
+
100
+ > "Check whether this machine has Node.js 22.5+. If not, walk me through installing it. Do not enter any secret, OTP or PIN on my behalf."
101
+
102
+ ### One install command
103
+
104
+ From the repo directory:
105
+
106
+ ```bash
107
+ bash setup.sh
108
+ ```
109
+
110
+ Setup will:
111
+
112
+ 1. check Node.js;
113
+ 2. create a local `.env` if missing;
114
+ 3. create `config/bots.json` from the example if missing;
115
+ 4. create the data directory with local-only permissions;
116
+ 5. run `npm ci`;
117
+ 6. run tests, config validation, secret scan, syntax check and self-check;
118
+ 7. print the next step.
119
+
120
+ Setup does **not** log into Zalo, scan a QR, send messages, enter OTP/PIN, or touch real credentials.
121
+
122
+ For agents or CI that must run unattended:
123
+
124
+ ```bash
125
+ bash setup.sh --non-interactive
126
+ ```
127
+
128
+ To set up and immediately run in the foreground:
129
+
130
+ ```bash
131
+ bash setup.sh --start
132
+ ```
133
+
134
+ ### Run the dashboard
135
+
136
+ If you did not use `--start`:
137
+
138
+ ```bash
139
+ npm start
140
+ ```
141
+
142
+ Then open:
143
+
144
+ ```text
145
+ http://127.0.0.1:3871
146
+ ```
147
+
148
+ The dashboard binds to localhost by default. On a remote machine or VPS, **do not expose the port directly to the Internet** — use an HTTPS reverse proxy with its own token/auth.
149
+
150
+ ---
151
+
152
+ ## 3. First Personal QR connection
153
+
154
+ 1. Run `npm start`.
155
+ 2. Open the dashboard.
156
+ 3. Click **Connect QR** — the dashboard calls the live route and renders the QR image.
157
+ 4. Scan it from your phone using a **dedicated account**.
158
+ 5. Wait for status `connected`.
159
+ 6. Click **Scan group IDs** if the group list needs refreshing.
160
+ 7. Pick one group as the **destination group**.
161
+ 8. Add sources under **Allowlist source**.
162
+ 9. Start in `listen_only`.
163
+ 10. Only after the stored data looks right, move one source to `digest_only`.
164
+
165
+ What the modes mean:
166
+
167
+ - `off`: source disabled.
168
+ - `listen_only`: store only. No digest, no send.
169
+ - `digest_only`: included in digests on request or on schedule.
170
+ - `alert_only`: only high-priority candidates are considered for alerts.
171
+ - `mention_only`: still blocked from replying while `READ_ONLY_SOURCE=true`.
172
+ - `reply_enabled`: does not override Policy Guard on its own. Use only with a reviewed policy.
173
+
174
+ **Safe defaults:** sources are not replied to, DMs are not replied to, mentions are not replied to, and outbound goes only to the configured destination.
175
+
176
+ On a headless VPS, reach the dashboard over an SSH tunnel or an authenticated HTTPS reverse proxy. Do not open port `3871` to the Internet, and never put a QR or session into logs or chat.
177
+
178
+ ---
179
+
180
+ ## 4. Verify the install
181
+
182
+ None of these send a real message:
183
+
184
+ ```bash
185
+ npm run doctor
186
+ npm run status
187
+ npm test
188
+ npm run validate-config
189
+ npm run secret-scan
190
+ npm run syntax-check
191
+ npm run self-check
192
+ ```
193
+
194
+ What to look for:
195
+
196
+ - `npm test`: everything passes.
197
+ - `npm run doctor`: no public/runtime config errors.
198
+ - `status`: never prints cookies, IMEI, refresh tokens or a raw session.
199
+ - `self-check`: an empty destination/allowlist is a normal fail-closed state.
200
+
201
+ Daemon smoke test:
202
+
203
+ ```bash
204
+ npm run smoke
205
+ ```
206
+
207
+ `npm run smoke` only checks health, MCP and safety. It **does not send a real message** unless `BATTLE_SEND=true` is set.
208
+
209
+ ---
210
+
211
+ ## 5. Official OA
212
+
213
+ Personal QR and OA are two different paths. Never mix a Personal session with OA OAuth.
214
+
215
+ ### Local preparation
216
+
217
+ ```bash
218
+ cp config/bots.example.json config/bots.json
219
+ ```
220
+
221
+ Open `config/bots.json`, keep the bot on `draft_first`, and enable it only once valid credentials exist. That file is git-ignored and must not be committed.
222
+
223
+ Put credentials in `.env` or a local secret manager — **never in chat, issues, the README, or an agent prompt**. Only the variable names declared under `credential` are used:
224
+
225
+ - `ZALO_OA_APP_ID_DEMO_OA`
226
+ - `ZALO_OA_APP_SECRET_DEMO_OA`
227
+ - `ZALO_OA_REFRESH_TOKEN_DEMO_OA`
228
+ - `ZALO_OA_WEBHOOK_SECRET`
229
+
230
+ Real values never live in the public repo.
231
+
232
+ ### Webhook
233
+
234
+ Adapter route:
235
+
236
+ ```text
237
+ POST /webhooks/zalo/oa/:bot_id
238
+ ```
239
+
240
+ The handler validates ingress, normalises text events, and acknowledges quickly. It **does not call an AI and does not send a reply**. Any outbound must go through an external workflow or agent with its own approval and policy.
241
+
242
+ Production needs:
243
+
244
+ - an HTTPS reverse proxy;
245
+ - a signature check or an authenticated edge;
246
+ - a body size limit;
247
+ - logs limited to redacted event IDs/receipts;
248
+ - `draft_first` before enabling any send path.
249
+
250
+ Details: [docs/official-oa.md](docs/official-oa.md).
251
+
252
+ ---
253
+
254
+ ## 6. Repo layout for agents and CLIs
255
+
256
+ ```text
257
+ AGENTS.md non-negotiable rules for every agent
258
+ CLAUDE.md entrypoint for Claude Code
259
+ CODEX.md entrypoint/checklist for Codex CLI
260
+ README.md home page and quickstart
261
+ CONTRIBUTING.md contribution rules
262
+ SECURITY.md how to report a vulnerability
263
+ docs/internal/00-DESIGN.md architecture
264
+ docs/internal/01-SPEC.md I/O contract
265
+ docs/internal/02-PLAN.md build order
266
+ docs/internal/03-HARNESS.md offline test harness
267
+ docs/internal/04-VERIFY.md verification gate
268
+ docs/internal/05-CONTEXT.md runtime constraints
269
+
270
+ setup.sh / install.sh one-command install
271
+ scripts/setup.js setup + doctor + dashboard info
272
+ scripts/public-gate.js validate-config/secret-scan/syntax-check
273
+
274
+ src/ deterministic runtime
275
+ policy.js inbound/outbound guard
276
+ store.js local SQLite
277
+ zalo_runtime.js personal QR listener
278
+ bot_registry.js registry + credential references
279
+ oa_adapter.js official OA OAuth/send boundary
280
+ oa_webhook.js official OA ingress boundary
281
+ server.js dashboard/API/webhook routes
282
+
283
+ config/bots.example.json public example registry
284
+ config/bots.json local registry, git-ignored
285
+ .env.example example environment variables
286
+ .env local, git-ignored
287
+
288
+ data/ SQLite/session/QR, git-ignored
289
+ public/ dashboard static files
290
+ mcp/ MCP stdio facade
291
+ test/ offline tests
292
+ ```
293
+
294
+ ---
295
+
296
+ ## 7. Rules for agents, Claude Code and Codex
297
+
298
+ Agents work in this order:
299
+
300
+ ```text
301
+ 1. read AGENTS.md
302
+ 2. read docs/agent-handoff.md
303
+ 3. run npm run doctor
304
+ 4. open only the relevant files — do not load the whole repo
305
+ 5. make small changes and test immediately
306
+ 6. report real evidence: command, exit code, file, test
307
+ ```
308
+
309
+ An agent must **never**:
310
+
311
+ - ask the owner to paste an API key, refresh token, cookie, IMEI, session, OTP or PIN into chat;
312
+ - enter an OTP/PIN or confirm a third-party login on the owner's behalf;
313
+ - enable public send, broadcast, deploy, systemd or credential changes without approval;
314
+ - treat "code written" as "code ran" — every done claim needs runtime evidence;
315
+ - claim a GitHub publish without real auth and a real receipt;
316
+ - use an LLM to decide deterministic gates such as empty, duplicate, quota, policy or signature.
317
+
318
+ Full instructions: [docs/agent-handoff.md](docs/agent-handoff.md).
319
+
320
+ ---
321
+
322
+ ## 8. Quick troubleshooting
323
+
324
+ ### `Node.js 22.5+ is required`
325
+
326
+ Install a current Node.js LTS, open a new terminal, then:
327
+
328
+ ```bash
329
+ node --version
330
+ bash setup.sh
331
+ ```
332
+
333
+ ### The dashboard will not open
334
+
335
+ ```bash
336
+ npm run doctor
337
+ npm start
338
+ ```
339
+
340
+ If port 3871 is taken, use another one:
341
+
342
+ ```bash
343
+ PORT=3872 npm start
344
+ ```
345
+
346
+ Then open `http://127.0.0.1:3872`.
347
+
348
+ ### The QR does not appear
349
+
350
+ - Check that `npm start` is still running.
351
+ - Click **Connect QR** again.
352
+ - Do not give a PIN/OTP to an agent — do it yourself on the phone/app.
353
+ - Use a dedicated account, not your main personal one.
354
+
355
+ ### `not_connected` on digest/send
356
+
357
+ That is the safety block doing its job. Connect the QR, check the destination, then retry. Do not delete the session unless you intend to log in again.
358
+
359
+ ### `destination_unset`
360
+
361
+ Open the dashboard and pick a destination group. Never set a destination from a guessed ID.
362
+
363
+ ### `npm test` fails
364
+
365
+ Do not skip tests. Hand the agent this:
366
+
367
+ > "Run npm test, read the first failing test, find the cause in the related file/test, make the smallest fix, and run it again. Do not touch secrets or runtime data."
368
+
369
+ ### Stop all outbound immediately
370
+
371
+ Click **Kill switch ON** in the dashboard, or:
372
+
373
+ ```bash
374
+ curl -X POST http://127.0.0.1:3871/api/kill-switch \
375
+ -H 'content-type: application/json' \
376
+ -d '{"paused":true}'
377
+ ```
378
+
379
+ ---
380
+
381
+ ## 9. Stopping, backups and data
382
+
383
+ Stop a foreground run with `Ctrl+C`.
384
+
385
+ Local data lives in `data/` and is never committed. The Personal session is stored with restricted permissions. Never hand the database, session or QR to an agent or a third party without redacting it first.
386
+
387
+ Before a large config change:
388
+
389
+ ```bash
390
+ cp .env .env.backup.local
391
+ cp config/bots.json config/bots.backup.local.json
392
+ ```
393
+
394
+ Those local backups must not be committed either.
395
+
396
+ ---
397
+
398
+ ## 10. Production checklist
399
+
400
+ An open dashboard is not production. You need all of:
401
+
402
+ - clear account/OA ownership;
403
+ - a reviewed allowlist and destination;
404
+ - green tests;
405
+ - secrets in a secret manager or env, never in Git;
406
+ - HTTPS + auth on any public endpoint;
407
+ - a kill switch you have actually tested;
408
+ - logs free of PII and credentials;
409
+ - systemd/Docker enabled only after approval;
410
+ - a live smoke test with real evidence;
411
+ - a tested rollback: pause, disconnect, disable bot.
412
+
413
+ The systemd file in this repo is a template. It does not enable itself.
414
+
415
+ ---
416
+
417
+ ## Next documents
418
+
419
+ - [Non-coder quickstart](docs/quickstart-non-coder.md)
420
+ - [Install guide](docs/install.md)
421
+ - [Agent handoff](docs/agent-handoff.md)
422
+ - [Personal QR](docs/personal-qr.md)
423
+ - [Official OA](docs/official-oa.md)
424
+ - [Commands](docs/commands.md)
425
+ - [Configuration](docs/configuration.md)
426
+ - [Operations](docs/operations.md)
427
+ - [Troubleshooting](docs/troubleshooting.md)
428
+ - [Release checklist](docs/release-checklist.md)
429
+ - [MCP notes](MCP.md)
430
+
431
+ ## License
432
+
433
+ MIT. See [LICENSE](LICENSE).
434
+
435
+ **There is no "100% safe".** Official OA is the path to prefer for customers; Personal QR is unofficial, carries platform risk, and belongs only inside a boundary you have reviewed.
package/SECURITY.md ADDED
@@ -0,0 +1,22 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes target the latest release on the default branch. Older snapshots may be unsupported.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please do not open a public issue for an undisclosed vulnerability.
10
+
11
+ Use GitHub Security Advisories for this repository, or contact the repository maintainers through the private security channel configured by the hosting organization. Include:
12
+
13
+ - a short description and impact;
14
+ - affected version or commit;
15
+ - minimal reproduction steps that do not contain credentials or personal data;
16
+ - a suggested mitigation, if known.
17
+
18
+ Do not attach `.env` files, QR images, session files, cookies, IMEI values, OAuth tokens, database files, or raw Zalo exports. Redact all user IDs, group IDs, phone numbers, and message text before sharing evidence.
19
+
20
+ ## Security boundaries
21
+
22
+ The personal QR adapter uses an unofficial protocol and can be affected by platform changes or account restrictions. It is not a ban-proof or production-safe substitute for the official OA path. Review the policy, rate limits, destination, and account isolation before enabling outbound behavior.
@@ -0,0 +1,33 @@
1
+ {
2
+ "version": 1,
3
+ "bots": [
4
+ {
5
+ "bot_id": "demo-oa",
6
+ "tenant_id": "demo",
7
+ "name": "Demo Zalo OA",
8
+ "adapter": "zalo_oa",
9
+ "enabled": true,
10
+ "credential": {
11
+ "app_id_env": "ZALO_OA_APP_ID_DEMO_OA",
12
+ "app_secret_env": "ZALO_OA_APP_SECRET_DEMO_OA",
13
+ "refresh_token_env": "ZALO_OA_REFRESH_TOKEN_DEMO_OA"
14
+ },
15
+ "policy": {
16
+ "mode": "draft_first",
17
+ "allow_user_ids": []
18
+ }
19
+ },
20
+ {
21
+ "bot_id": "demo-personal",
22
+ "tenant_id": "demo",
23
+ "name": "Demo Personal QR",
24
+ "adapter": "zalo_personal_qr",
25
+ "account_id": "demo-personal",
26
+ "enabled": false,
27
+ "policy": {
28
+ "mode": "draft_first",
29
+ "allow_user_ids": []
30
+ }
31
+ }
32
+ ]
33
+ }
package/config.toml ADDED
@@ -0,0 +1,48 @@
1
+ # ABS-Zalo-Bot demo-safe local configuration.
2
+ # Real destination/group/user IDs belong in runtime data or a private config.
3
+
4
+ default_account_id = "default"
5
+ phone_label = ""
6
+ retention_days = 30
7
+
8
+ # Personal adapter: full capture, absolute silence. No inbound message may
9
+ # invoke a model, skill, MCP workflow, command, digest, alert, or send.
10
+ read_only_source = true
11
+ listen_self = false
12
+ listen_all_groups = true
13
+ listen_dms = true
14
+ listener_only = true
15
+ auto_alert = false
16
+ auto_reply_default = false
17
+
18
+ dashboard_bind = "127.0.0.1"
19
+ dashboard_port = 3871
20
+
21
+ # Leave destination empty until the operator selects one in the private dashboard.
22
+ [destination]
23
+ account_id = "default"
24
+ group_id = ""
25
+ group_name = ""
26
+
27
+ [rate_limit]
28
+ messages_per_hour = 20
29
+ messages_per_day = 120
30
+ ingest_per_hour = 2000
31
+ destination_per_hour = 30
32
+ alert_cooldown_minutes = 30
33
+
34
+ [roles]
35
+ owner = []
36
+ admin = []
37
+ operator = []
38
+ viewer = []
39
+
40
+ [hermes]
41
+ # Optional Hermes Agent/OpenAI-compatible endpoint. Keep keys in environment only.
42
+ api_base = "http://127.0.0.1:8642/v1"
43
+ model = "hermes-agent"
44
+ webhook_url = ""
45
+ timeout_ms = 45000
46
+ auto_analyze = false
47
+
48
+ # Keepalive is env-driven. Use KEEPALIVE_AUTO_CONNECT=false until interactive QR setup is approved.
package/mcp/run.sh ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ # stdio MCP entrypoint for Hermes / Claude / Cursor
3
+ set -euo pipefail
4
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
5
+ export ZALO_BRIDGE_URL="${ZALO_BRIDGE_URL:-http://127.0.0.1:3871}"
6
+ # Never print to stdout except MCP JSON-RPC (handled by node server)
7
+ exec node "$ROOT/mcp/server.js"