@ardennguyen/zalo-agent-cli 2.1.1 → 2.2.1

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 CHANGED
@@ -21,10 +21,15 @@
21
21
  # ZALO_OA_DIR=
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
- # Runtime & Protocol Options (Optional)
24
+ # Runtime & Account Options (Optional)
25
25
  # ----------------------------------------------------------------------------
26
+ # Pin a default registered account ID for this environment without changing
27
+ # the global active entry in accounts.json (equivalent to --account <ID>):
28
+ # ZALO_ACCOUNT=
29
+
26
30
  # Set to any value (e.g. 1) to disable the background npm update check:
27
31
  # ZALO_AGENT_NO_UPDATE_CHECK=1
28
32
 
29
33
  # Protocol version announced to Zalo (default: 691; set 685 to roll back):
30
34
  # ZALO_API_VERSION=691
35
+
package/README.md CHANGED
@@ -47,12 +47,13 @@ Xây dựng trên [zca-js](https://github.com/RFS-ADRENO/zca-js).
47
47
  > **MCP Server (AI Agent Integration)** — Model Context Protocol cho Claude Code và các MCP client:
48
48
  > ```bash
49
49
  > zalo-agent mcp start # stdio (local Claude Code)
50
+ > zalo-agent mcp start --account <ID> # Ghim tài khoản (chạy nhiều tài khoản live cùng lúc)
50
51
  > zalo-agent mcp start --http 3847 --auth your-secret # HTTP (VPS)
51
52
  > ```
52
- > 14 tools: `zalo_get_messages` · `zalo_send_message` · `zalo_list_threads` · `zalo_search_threads` · `zalo_mark_read` · `zalo_get_history` · `zalo_view_media` · `zalo_react` · `zalo_undo` · `zalo_get_group_members` · `zalo_list_conversations` · `zalo_coverage` · `zalo_sync` · `zalo_sync_status`
53
+ > 21 tools: `zalo_get_messages` · `zalo_send_message` · `zalo_list_threads` · `zalo_search_threads` · `zalo_mark_read` · `zalo_get_history` · `zalo_view_media` · `zalo_react` · `zalo_undo` · `zalo_get_group_members` · `zalo_list_conversations` · `zalo_coverage` · `zalo_sync` · `zalo_sync_status` · `zalo_search_messages` · `zalo_lookup_user` · `zalo_forward_message` · `zalo_delete_message` · `zalo_reminder` · `zalo_note` · `zalo_poll`
53
54
 
54
- [Sync qua MCP và điều kiện phát hành](docs/mcp-sync.vi.md).
55
- > Auto-reconnect · thread filter · noise reduction · tự tải media · thông báo qua nhóm Zalo
55
+ [Sync qua MCP](docs/mcp-sync.vi.md) · [Ghim đa tài khoản live](docs/account-pinning.vi.md).
56
+ > Auto-reconnect · thread filter · noise reduction · tự tải media · thông báo qua nhóm Zalo · chạy song song nhiều tài khoản (`--account <ID>`)
56
57
  > Xem [MCP Guide](skill/references/mcp-guide.md) · [INSTALLATION.md](INSTALLATION.md)
57
58
 
58
59
  ---
@@ -123,7 +124,7 @@ Tất cả lệnh hỗ trợ `--json`. Tài liệu đầy đủ: **[Wiki](https:
123
124
  | `label` | 2 | Nhãn hội thoại | [Nhãn](https://github.com/ardennguyen/zalo-agent-cli/wiki/Nh%C3%A3n) |
124
125
  | `catalog` | 9 | zBusiness — danh mục sản phẩm | [zBusiness](https://github.com/ardennguyen/zalo-agent-cli/wiki/zBusiness) |
125
126
  | `listen` | 1 | Lắng nghe real-time, webhook, JSONL, ghi vào cache cục bộ | [Lắng nghe](https://github.com/ardennguyen/zalo-agent-cli/wiki/L%E1%BA%AFng-Nghe) |
126
- | `mcp` | 1 | MCP server (stdio/HTTP) — 14 tools cho AI agent | [MCP Server](https://github.com/ardennguyen/zalo-agent-cli/wiki/MCP-Server-(VN)) |
127
+ | `mcp` | 1 | MCP server (stdio/HTTP) — 21 tools cho AI agent | [MCP Server](https://github.com/ardennguyen/zalo-agent-cli/wiki/MCP-Server-(VN)) |
127
128
  | **`oa`** | **32** | **Zalo Official Account API v3.0 — OAuth, tin nhắn, follower, tag, bài viết, cửa hàng, webhook** | **[Official Account](https://github.com/ardennguyen/zalo-agent-cli/wiki/Official-Account-(VN))** |
128
129
 
129
130
  Xem thêm: [Đa tài khoản & Proxy](https://github.com/ardennguyen/zalo-agent-cli/wiki/%C4%90a-T%C3%A0i-Kho%E1%BA%A3n-&-Proxy) · [Cài đặt VPS](https://github.com/ardennguyen/zalo-agent-cli/wiki/C%C3%A0i-%C4%90%E1%BA%B7t-VPS) · [Thẻ chuyển khoản & QR](https://github.com/ardennguyen/zalo-agent-cli/wiki/Th%E1%BA%BB-Chuy%E1%BB%83n-Kho%E1%BA%A3n-&-QR) · [Bộ nhớ đệm & Đồng bộ](https://github.com/ardennguyen/zalo-agent-cli/wiki/B%E1%BB%99-Nh%E1%BB%9B-%C4%90%E1%BB%87m-&-%C4%90%E1%BB%93ng-B%E1%BB%99) · [Bảo mật](https://github.com/ardennguyen/zalo-agent-cli/wiki/B%E1%BA%A3o-M%E1%BA%ADt)
@@ -133,10 +134,10 @@ Xem thêm: [Đa tài khoản & Proxy](https://github.com/ardennguyen/zalo-agent-
133
134
  ## Tính năng
134
135
 
135
136
  - Đăng nhập QR qua HTTP server tự động (browser + terminal), báo ngay khi bị **từ chối trên điện thoại** thay vì treo tới hết 60s
136
- - Đa tài khoản với proxy riêng biệt (1:1), device fingerprint riêng cho từng tài khoản
137
+ - Đa tài khoản với proxy riêng biệt (1:1), device fingerprint riêng cho từng tài khoản; chạy **nhiều tài khoản live đồng thời** (mỗi tài khoản một tiến trình `mcp start` hoặc `listen` kèm `--account <ID>`, và truyền `--account <ID>` / `ZALO_ACCOUNT` trên mọi lệnh CLI mà không ghi đè `accounts.json`)
137
138
  - **190 lệnh** phủ hết tính năng Zalo cá nhân
138
139
  - **Zalo Official Account (OA) API v3.0** — OAuth login, gửi tin nhắn, follower, tag, bài viết, cửa hàng, webhook listener, multi-OA
139
- - **MCP server** (stdio + HTTP) — 14 tools cho Claude Code và các MCP client: đọc, gửi (kể cả vào My Documents, đánh dấu Quan trọng/Khẩn cấp), thả cảm xúc, thu hồi tin, xem thành viên nhóm, liệt kê hội thoại gần đây và kiểm tra độ đầy đủ của cache
140
+ - **MCP server** (stdio + HTTP) — 21 tools cho Claude Code và các MCP client: đọc, gửi (văn bản, link preview, danh thiếp, vào My Documents, đánh dấu Quan trọng/Khẩn cấp), tìm kiếm tin nhắn trong cache, tra cứu người dùng, thả cảm xúc, thu hồi, chuyển tiếp, xóa tin, nhắc hẹn, ghi chú/ghim tin, bình chọn, xem thành viên nhóm, liệt kê hội thoại gần đây và kiểm tra độ đầy đủ của cache
140
141
  - **Bộ nhớ đệm cục bộ (SQLite)** — `listen` ghi mọi tin nhắn vào `zalo.db`, `msg history` đọc từ cache, `sync` (hoặc `sync-mobile`) khôi phục toàn bộ lịch sử từ điện thoại vào `zalo.db` (giải mã transfer-sync-v2; xác nhận một lần trên điện thoại), mặc định lấy **toàn bộ** lịch sử (không còn mốc chặn 2024-01-01); thêm `--days <n>` hoặc `--from <YYYY-MM-DD>` nếu chỉ cần một khoảng. Dọn dẹp: `sync-media --prune <days|all>` giải phóng dung lượng nhưng giữ nguyên nội dung tin nhắn, `--prune-orphans` nhắm vào hội thoại tài khoản không còn, và `conv forget` xoá hẳn bản sao cục bộ của một hội thoại — không cái nào gửi gì tới Zalo. Luồng đồng bộ chỉ mang **liên kết** media chứ không mang file, nên sau khi lưu tin nhắn, `sync-mobile` **tự động tải media về** (thêm `--messages-only` nếu chỉ muốn tin nhắn); `sync-media` chạy lại/tiếp tục bước tải này, không cần xác nhận trên điện thoại. Ghi chú, tin ghim, bình chọn và nhắc hẹn nằm ngoài luồng tin nhắn — dùng `sync-boards`
141
142
  - Tự động tải media (ảnh/audio/video) — một downloader duy nhất cho `listen`, `msg history`, `mcp start` và các lệnh sync, lưu vào `~/.zalo-agent-cli/accounts/<id>/media/<threadId>/` (hoặc tách riêng credentials, database `zalo.db`, media và OA sang các ổ đĩa/mount khác nhau qua `--credentials-dir`, `--data-dir`, `--media-dir`, `--oa-dir` / biến môi trường `ZALO_*_DIR` trong `~/.zalo-agent-cli/.env`; nếu dùng kèm `zalo-mcp`, chỉ nên giữ cấu hình PORT trong `zalo-mcp/.env` và đặt toàn bộ đường dẫn lưu trữ vào `<CONFIG_DIR>/.env`)
142
143
  - Thẻ chuyển khoản (55+ ngân hàng VN) & QR VietQR
@@ -211,12 +212,13 @@ CLI tool for Zalo automation — multi-account, proxy support, bank transfers, Q
211
212
  > **MCP Server (AI Agent Integration)** — Model Context Protocol support for Claude Code and MCP clients:
212
213
  > ```bash
213
214
  > zalo-agent mcp start # stdio (local Claude Code)
215
+ > zalo-agent mcp start --account <ID> # Pin account (run multiple live accounts at once)
214
216
  > zalo-agent mcp start --http 3847 --auth your-secret # HTTP (VPS)
215
217
  > ```
216
- > 14 tools: `zalo_get_messages` · `zalo_send_message` · `zalo_list_threads` · `zalo_search_threads` · `zalo_mark_read` · `zalo_get_history` · `zalo_view_media` · `zalo_react` · `zalo_undo` · `zalo_get_group_members` · `zalo_list_conversations` · `zalo_coverage` · `zalo_sync` · `zalo_sync_status`
218
+ > 21 tools: `zalo_get_messages` · `zalo_send_message` · `zalo_list_threads` · `zalo_search_threads` · `zalo_mark_read` · `zalo_get_history` · `zalo_view_media` · `zalo_react` · `zalo_undo` · `zalo_get_group_members` · `zalo_list_conversations` · `zalo_coverage` · `zalo_sync` · `zalo_sync_status` · `zalo_search_messages` · `zalo_lookup_user` · `zalo_forward_message` · `zalo_delete_message` · `zalo_reminder` · `zalo_note` · `zalo_poll`
217
219
 
218
- [MCP sync and release prerequisites](docs/mcp-sync.md).
219
- > Auto-reconnect · thread filter · noise reduction · media auto-download · Zalo-group notifications
220
+ [MCP sync](docs/mcp-sync.md) · [Multi-account pinning](docs/account-pinning.md).
221
+ > Auto-reconnect · thread filter · noise reduction · media auto-download · Zalo-group notifications · concurrent multi-account (`--account <ID>`)
220
222
  > See [MCP Guide](skill/references/mcp-guide.md) · [INSTALLATION.md](INSTALLATION.md)
221
223
 
222
224
  ### Quick Start
@@ -253,7 +255,7 @@ Full docs: **[Wiki](https://github.com/ardennguyen/zalo-agent-cli/wiki)** · [Fu
253
255
  | `label` | 2 | Conversation labels | [Labels](https://github.com/ardennguyen/zalo-agent-cli/wiki/Labels) |
254
256
  | `catalog` | 9 | zBusiness catalogs & products | [Catalog](https://github.com/ardennguyen/zalo-agent-cli/wiki/Catalog) |
255
257
  | `listen` | 1 | Real-time listener, webhook, JSONL, local cache writes | [Listener](https://github.com/ardennguyen/zalo-agent-cli/wiki/Listener) |
256
- | `mcp` | 1 | MCP server (stdio/HTTP) — 14 tools for AI agents | [MCP Server](https://github.com/ardennguyen/zalo-agent-cli/wiki/MCP-Server) |
258
+ | `mcp` | 1 | MCP server (stdio/HTTP) — 21 tools for AI agents | [MCP Server](https://github.com/ardennguyen/zalo-agent-cli/wiki/MCP-Server) |
257
259
  | **`oa`** | **32** | **Zalo Official Account API v3.0 — OAuth, messaging, followers, tags, articles, store, webhook** | **[Official Account](https://github.com/ardennguyen/zalo-agent-cli/wiki/Official-Account)** |
258
260
 
259
261
  See also: [Multi-Account & Proxy](https://github.com/ardennguyen/zalo-agent-cli/wiki/Multi-Account-&-Proxy) · [VPS Setup](https://github.com/ardennguyen/zalo-agent-cli/wiki/VPS-Setup) · [Bank Card & QR Payments](https://github.com/ardennguyen/zalo-agent-cli/wiki/Bank-Card-&-QR-Payments) · [Local Cache & Sync](https://github.com/ardennguyen/zalo-agent-cli/wiki/Local-Cache-&-Sync) · [Security](https://github.com/ardennguyen/zalo-agent-cli/wiki/Security)
@@ -261,10 +263,10 @@ See also: [Multi-Account & Proxy](https://github.com/ardennguyen/zalo-agent-cli/
261
263
  ### Features
262
264
 
263
265
  - QR login over an auto-started HTTP server (browser + terminal), reporting a **decline on the phone** immediately instead of hanging until the 60s timeout
264
- - Multi-account with a dedicated proxy (1:1) and a per-account device fingerprint
266
+ - Multi-account with a dedicated proxy (1:1) and a per-account device fingerprint; run **multiple live accounts simultaneously** (one `mcp start` or `listen` process per account with `--account <ID>`, plus `--account <ID>` / `ZALO_ACCOUNT` on any CLI command without mutating `accounts.json`)
265
267
  - **190 commands** covering the personal-account Zalo surface
266
268
  - **Zalo Official Account (OA) API v3.0** — OAuth login, messaging, followers, tags, articles, store, webhook listener, multi-OA
267
- - **MCP server** (stdio + HTTP) — 14 tools for Claude Code and other MCP clients: read, send (to My Documents too, marked Important/Urgent), react, recall, list a group's members, list recent conversations, and check how complete the cache is
269
+ - **MCP server** (stdio + HTTP) — 21 tools for Claude Code and other MCP clients: read, send (text, link previews, contact cards, to My Documents too, marked Important/Urgent), search cached messages, look up users, react, recall, forward, delete, reminders, group notes/pins, group polls, list a group's members, list recent conversations, and check how complete the cache is
268
270
  - **Local SQLite cache** — `listen` writes every message to `zalo.db`, `msg history` reads from it, and `sync` (or `sync-mobile`) restores full history from the phone into `zalo.db` (transfer-sync-v2 decrypt; one confirmation on the phone), defaulting to **all** history (the old 2024-01-01 floor is gone), with `--days <n>` or `--from <YYYY-MM-DD>` to narrow it. Housekeeping: `sync-media --prune <days|all>` reclaims disk while keeping message text, `--prune-orphans` targets conversations the account no longer has, and `conv forget` removes a conversation's local copy entirely — none of which contact Zalo. The sync stream carries media **links**, not files, so a `sync-mobile` run **downloads its attachments automatically** once the messages are stored (`--messages-only` skips it); `sync-media` re-runs or resumes that fetch on its own, with no phone confirmation. Notes, pinned messages, polls and reminders live outside the message stream — `sync-boards` fetches those
269
271
  - Automatic media download — one downloader shared by `listen`, `msg history`, `mcp start` and the sync commands, saving to `~/.zalo-agent-cli/accounts/<id>/media/<threadId>/` (or separate credentials, `zalo.db`, media, and OA credentials onto independent volumes/mounts via `--credentials-dir`, `--data-dir`, `--media-dir`, `--oa-dir` / `ZALO_*_DIR` in `~/.zalo-agent-cli/.env`; when using `zalo-mcp`, keep `zalo-mcp/.env` for PORT settings only and place all storage/engine settings in `<CONFIG_DIR>/.env`)
270
272
  - Bank cards (55+ VN banks) and VietQR payment images
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ardennguyen/zalo-agent-cli",
3
- "version": "2.1.1",
3
+ "version": "2.2.1",
4
4
  "description": "CLI tool for Zalo automation — multi-account, proxy, bank transfers, QR payments, Official Account API v3.0",
5
5
  "type": "module",
6
6
  "bin": {
@@ -77,6 +77,6 @@
77
77
  },
78
78
  "allowScripts": {
79
79
  "better-sqlite3@13.0.3": true,
80
- "@ardennguyen/zalo-agent-cli@2.1.1": true
80
+ "@ardennguyen/zalo-agent-cli@2.2.1": true
81
81
  }
82
82
  }
@@ -84,7 +84,9 @@ export function registerListenCommand(program) {
84
84
  .action(async (opts) => {
85
85
  let activeAcc;
86
86
  try {
87
- activeAcc = selectDaemonAccount(opts.account);
87
+ const requestedAccount =
88
+ opts.account ?? program.opts().account ?? (process.env.ZALO_ACCOUNT?.trim() || undefined);
89
+ activeAcc = selectDaemonAccount(requestedAccount);
88
90
  } catch (e) {
89
91
  error(e.message);
90
92
  process.exit(1);
@@ -143,7 +143,9 @@ export function registerMCPCommands(program) {
143
143
  // Select once; acquire the selected account's lock before authentication.
144
144
  let activeAcc;
145
145
  try {
146
- activeAcc = selectDaemonAccount(opts.account);
146
+ const requestedAccount =
147
+ opts.account ?? program.opts().account ?? (process.env.ZALO_ACCOUNT?.trim() || undefined);
148
+ activeAcc = selectDaemonAccount(requestedAccount);
147
149
  } catch (e) {
148
150
  console.error("[mcp] Account selection failed:", e.message);
149
151
  process.exit(1);
@@ -33,14 +33,37 @@ function save(accounts) {
33
33
  chmodSync(file, 0o600);
34
34
  }
35
35
 
36
+ let _pinnedAccountId = null;
37
+
38
+ /**
39
+ * Pin this process's target account ID without modifying accounts.json on disk.
40
+ * Used when `--account <id>` or `ZALO_ACCOUNT` is passed to a CLI command.
41
+ * @param {string|null|undefined} ownId
42
+ */
43
+ export function setPinnedAccount(ownId) {
44
+ _pinnedAccountId = ownId ? String(ownId) : null;
45
+ }
46
+
47
+ /**
48
+ * Return the process-pinned account ID if set, or null.
49
+ * @returns {string|null}
50
+ */
51
+ export function getPinnedAccountId() {
52
+ return _pinnedAccountId;
53
+ }
54
+
36
55
  /** List all registered accounts. */
37
56
  export function listAccounts() {
38
57
  return load();
39
58
  }
40
59
 
41
- /** Get currently active account or null. */
60
+ /** Get currently active (or process-pinned) account or null. */
42
61
  export function getActive() {
43
- return load().find((a) => a.active) || null;
62
+ const accounts = load();
63
+ if (_pinnedAccountId !== null) {
64
+ return accounts.find((a) => a.ownId === _pinnedAccountId) || null;
65
+ }
66
+ return accounts.find((a) => a.active) || null;
44
67
  }
45
68
 
46
69
  /** Set an account as active (deactivates others). Returns false if not found. */
package/src/core/db.js CHANGED
@@ -621,6 +621,50 @@ export function getMessageById(msgId) {
621
621
  return db.prepare("SELECT * FROM messages WHERE msgId = ?").get(String(msgId)) || null;
622
622
  }
623
623
 
624
+ /**
625
+ * Search cached messages by text substring across one or all conversations, newest first.
626
+ *
627
+ * Purely local SQLite query — never touches the Zalo network. Excludes recalled/deleted
628
+ * tombstones (`type = 'deleted'`) and escapes SQLite LIKE wildcards (`%`, `_`, `\`) so literal
629
+ * characters in `query` match as literals.
630
+ *
631
+ * @param {object} opts
632
+ * @param {string} opts.query - Substring to match in message text (case-insensitive for ASCII)
633
+ * @param {string} [opts.threadId] - Restrict to one conversation
634
+ * @param {string} [opts.senderId] - Restrict to one sender UID
635
+ * @param {number} [opts.since] - Only messages at or after this epoch-ms timestamp
636
+ * @param {number} [opts.until] - Only messages at or before this epoch-ms timestamp
637
+ * @param {number} [opts.limit=50] - Max messages to return
638
+ * @returns {Array<object>}
639
+ */
640
+ export function searchMessages(opts = {}) {
641
+ if (!db) throw new Error("Database not initialized");
642
+ const { query, threadId, senderId, since, until, limit = 50 } = opts;
643
+ const escaped = String(query ?? "").replace(/[\\%_]/g, "\\$&");
644
+ const where = ["COALESCE(type, '') != 'deleted'", "text IS NOT NULL", "text LIKE ? ESCAPE '\\'"];
645
+ const params = [`%${escaped}%`];
646
+ if (threadId) {
647
+ where.push("threadId = ?");
648
+ params.push(String(threadId));
649
+ }
650
+ if (senderId) {
651
+ where.push("senderId = ?");
652
+ params.push(String(senderId));
653
+ }
654
+ if (Number.isFinite(since)) {
655
+ where.push("timestamp >= ?");
656
+ params.push(Number(since));
657
+ }
658
+ if (Number.isFinite(until)) {
659
+ where.push("timestamp <= ?");
660
+ params.push(Number(until));
661
+ }
662
+ params.push(limit);
663
+ return db
664
+ .prepare(`SELECT * FROM messages WHERE ${where.join(" AND ")} ORDER BY timestamp DESC LIMIT ?`)
665
+ .all(...params);
666
+ }
667
+
624
668
  /**
625
669
  * Most recently active threads, newest first.
626
670
  *
package/src/index.js CHANGED
@@ -30,7 +30,8 @@ import { registerOACommands } from "./commands/oa.js";
30
30
  import { registerMCPCommands } from "./commands/mcp.js";
31
31
  import { registerSyncCommands } from "./commands/sync.js";
32
32
  import { autoLogin } from "./core/zalo-client.js";
33
- import { getActive } from "./core/accounts.js";
33
+ import { getActive, setPinnedAccount } from "./core/accounts.js";
34
+ import { parseAccountId, selectDaemonAccount } from "./core/daemon-account.js";
34
35
  import { configureStoragePaths } from "./core/credentials.js";
35
36
  import { logoutNeedsSession } from "./core/logout.js";
36
37
  import { checkForUpdates, selfUpdate } from "./utils/update-check.js";
@@ -47,6 +48,11 @@ program
47
48
  .description("CLI tool for Zalo automation — multi-account, proxy, bank transfers, QR payments")
48
49
  .version(pkg.version)
49
50
  .option("--json", "Output results as JSON (machine-readable)")
51
+ .option(
52
+ "--account <id>",
53
+ "Pin this command to an exact registered account ID without changing the active account (env: ZALO_ACCOUNT)",
54
+ parseAccountId,
55
+ )
50
56
  .option("--env-file <path>", "Load environment variables from a .env file (env: ZALO_ENV_FILE)")
51
57
  .option("--config-dir <dir>", "Config directory (default: ~/.zalo-agent-cli, env: ZALO_CONFIG_DIR)")
52
58
  .option(
@@ -79,6 +85,23 @@ program
79
85
  warning(DISCLAIMER);
80
86
  console.log();
81
87
  }
88
+ // Pin the target account for this invocation when --account or ZALO_ACCOUNT is set,
89
+ // without changing the global active entry in accounts.json. Daemons (`listen`, `mcp`)
90
+ // perform their own selection and lock acquisition inside their command actions.
91
+ const envAccount = process.env.ZALO_ACCOUNT?.trim() || undefined;
92
+ const requestedAccount = actionCommand.opts()?.account ?? globalOpts.account ?? envAccount;
93
+ if (
94
+ requestedAccount !== undefined &&
95
+ !["mcp", "listen", "oa", "update", "help", "version", "login"].includes(cmdName)
96
+ ) {
97
+ try {
98
+ const pinned = selectDaemonAccount(requestedAccount);
99
+ setPinnedAccount(pinned.ownId);
100
+ } catch (e) {
101
+ error(e.message);
102
+ process.exit(1);
103
+ }
104
+ }
82
105
  // Auto-login before any command that needs it (skip for login/account/oa
83
106
  // commands, and for a logout that will not call Zalo at all).
84
107
  // Daemons authenticate their pinned identity after acquiring its lock.