zalo-agent-cli 1.0.30 → 1.0.31
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 +62 -2
- package/package.json +1 -1
- package/src/commands/auto-reply.js +83 -0
- package/src/commands/catalog.js +143 -0
- package/src/commands/conv.js +86 -0
- package/src/commands/label.js +39 -0
- package/src/commands/msg.js +38 -0
- package/src/commands/profile.js +64 -0
- package/src/commands/quick-msg.js +55 -0
- package/src/index.js +8 -0
package/README.md
CHANGED
|
@@ -37,7 +37,8 @@ Built on top of [zca-js](https://github.com/AKAspanion/zca-js), the unofficial Z
|
|
|
37
37
|
- Generate and send VietQR transfer images via qr.sepay.vn
|
|
38
38
|
- Friend management (list, find, add, remove, block, alias, recommendations)
|
|
39
39
|
- Group management (create, rename, members, settings, links, notes, invites)
|
|
40
|
-
- Conversation management (mute, pin, archive,
|
|
40
|
+
- Conversation management (mute, pin, archive, hidden, auto-delete)
|
|
41
|
+
- Auto-reply, quick messages, labels, Zalo Shop catalogs
|
|
41
42
|
- Export/import credentials for headless server deployment
|
|
42
43
|
- Local HTTP server for QR display on VPS (via SSH tunnel)
|
|
43
44
|
- `--json` output on all commands for scripting and coding agents
|
|
@@ -170,6 +171,9 @@ zalo-agent whoami
|
|
|
170
171
|
| `msg send-link <threadId> <url> [-m caption] [-t 0\|1]` | Send link with auto-preview |
|
|
171
172
|
| `msg send-video <threadId> <videoUrl> --thumb <thumbUrl> [-m caption] [-d ms] [-W px] [-H px]` | Send video from URL |
|
|
172
173
|
| `msg sticker <threadId> <keyword> [-t 0\|1]` | Search and send sticker |
|
|
174
|
+
| `msg sticker-list <keyword>` | Search stickers (returns IDs) |
|
|
175
|
+
| `msg sticker-detail <stickerIds...>` | Get sticker details by IDs |
|
|
176
|
+
| `msg sticker-category <categoryId>` | Get sticker category details |
|
|
173
177
|
| `msg react <msgId> <threadId> <emoji> [-t 0\|1]` | React to a message |
|
|
174
178
|
| `msg delete <msgId> <threadId> [-t 0\|1]` | Delete a message |
|
|
175
179
|
| `msg forward <msgId> <threadId> [-t 0\|1]` | Forward a message |
|
|
@@ -274,6 +278,13 @@ zalo-agent msg send <threadId> "Hello World" --style 0:5:bold 6:5:italic
|
|
|
274
278
|
| `conv unmute <threadId> [-t 0\|1]` | Unmute |
|
|
275
279
|
| `conv read <threadId> [-t 0\|1]` | Mark as read |
|
|
276
280
|
| `conv unread <threadId> [-t 0\|1]` | Mark as unread |
|
|
281
|
+
| `conv hidden` | List hidden conversations |
|
|
282
|
+
| `conv hide <threadIds...> [-t 0\|1]` | Hide conversation(s) |
|
|
283
|
+
| `conv unhide <threadIds...> [-t 0\|1]` | Unhide conversation(s) |
|
|
284
|
+
| `conv hidden-pin <pin>` | Set PIN for hidden conversations |
|
|
285
|
+
| `conv hidden-pin-reset` | Reset hidden conversations PIN |
|
|
286
|
+
| `conv auto-delete-status` | View auto-delete chat settings |
|
|
287
|
+
| `conv auto-delete <threadId> <ttl> [-t 0\|1]` | Set auto-delete (off, 1d, 7d, 14d) |
|
|
277
288
|
| `conv delete <threadId> [-t 0\|1]` | Delete conversation |
|
|
278
289
|
|
|
279
290
|
#### Profile (`profile`)
|
|
@@ -284,6 +295,11 @@ zalo-agent msg send <threadId> "Hello World" --style 0:5:bold 6:5:italic
|
|
|
284
295
|
| `profile avatar <imagePath>` | Change profile avatar |
|
|
285
296
|
| `profile bio [text]` | View or update bio/status |
|
|
286
297
|
| `profile update [-n name] [-d YYYY-MM-DD] [-g 0\|1]` | Update name, birthday, gender |
|
|
298
|
+
| `profile avatars [-c count] [-p page]` | List avatar gallery |
|
|
299
|
+
| `profile full-avatar <friendId>` | Get full-size avatar URL |
|
|
300
|
+
| `profile avatar-url <friendIds...>` | Get avatar URLs for users |
|
|
301
|
+
| `profile delete-avatar <photoIds...>` | Delete avatar(s) from gallery |
|
|
302
|
+
| `profile reuse-avatar <photoId>` | Reuse a previous avatar |
|
|
287
303
|
| `profile settings` | View privacy settings |
|
|
288
304
|
| `profile set <setting> <value>` | Update a privacy setting |
|
|
289
305
|
|
|
@@ -351,6 +367,49 @@ zalo-agent reminder edit <reminderId> <groupId> "New title" -t 1 --time "2026-03
|
|
|
351
367
|
zalo-agent reminder remove <reminderId> <groupId> -t 1
|
|
352
368
|
```
|
|
353
369
|
|
|
370
|
+
#### Auto-Reply (`auto-reply`)
|
|
371
|
+
|
|
372
|
+
| Command | Description |
|
|
373
|
+
| --------------------------------------------------------------------------------- | ------------------------- |
|
|
374
|
+
| `auto-reply list` | List all auto-reply rules |
|
|
375
|
+
| `auto-reply create <content> [--enable] [--start ms] [--end ms] [--scope n]` | Create auto-reply |
|
|
376
|
+
| `auto-reply update <id> <content> [--enable] [--start ms] [--end ms] [--scope n]` | Update auto-reply |
|
|
377
|
+
| `auto-reply delete <id>` | Delete auto-reply |
|
|
378
|
+
|
|
379
|
+
**Scope:** `0`=all, `1`=friends, `2`=strangers
|
|
380
|
+
|
|
381
|
+
#### Quick Messages (`quick-msg`)
|
|
382
|
+
|
|
383
|
+
| Command | Description |
|
|
384
|
+
| --------------------------------------------- | ------------------------- |
|
|
385
|
+
| `quick-msg list` | List saved quick messages |
|
|
386
|
+
| `quick-msg add <keyword> <title>` | Add a quick message |
|
|
387
|
+
| `quick-msg update <itemId> <keyword> <title>` | Update a quick message |
|
|
388
|
+
| `quick-msg remove <itemIds...>` | Remove quick message(s) |
|
|
389
|
+
|
|
390
|
+
#### Labels (`label`)
|
|
391
|
+
|
|
392
|
+
| Command | Description |
|
|
393
|
+
| --------------------- | -------------------------------- |
|
|
394
|
+
| `label list` | List all conversation labels |
|
|
395
|
+
| `label update <json>` | Update labels (raw JSON payload) |
|
|
396
|
+
|
|
397
|
+
#### Catalog / Shop (`catalog`)
|
|
398
|
+
|
|
399
|
+
| Command | Description |
|
|
400
|
+
| ----------------------------------------------------------------------------------------- | ---------------------------------- |
|
|
401
|
+
| `catalog list [-l limit] [-p page]` | List all catalogs |
|
|
402
|
+
| `catalog create <name>` | Create a catalog |
|
|
403
|
+
| `catalog rename <catalogId> <name>` | Rename a catalog |
|
|
404
|
+
| `catalog delete <catalogId>` | Delete a catalog |
|
|
405
|
+
| `catalog products <catalogId> [-l limit] [-p page]` | List products in a catalog |
|
|
406
|
+
| `catalog add-product <catalogId> <name> <price> <desc> [--photos urls...]` | Add product |
|
|
407
|
+
| `catalog update-product <catalogId> <productId> <name> <price> <desc> [--photos urls...]` | Update product |
|
|
408
|
+
| `catalog delete-product <catalogId> <productIds...>` | Delete product(s) |
|
|
409
|
+
| `catalog upload-photo <filePath>` | Upload product photo (returns URL) |
|
|
410
|
+
|
|
411
|
+
> Catalog/Shop APIs require a Zalo Business account.
|
|
412
|
+
|
|
354
413
|
#### Accounts (`account`)
|
|
355
414
|
|
|
356
415
|
| Command | Description |
|
|
@@ -523,7 +582,8 @@ This is an **unofficial** project and is **not affiliated with, endorsed by, or
|
|
|
523
582
|
- Tạo và gửi ảnh QR chuyển khoản qua qr.sepay.vn
|
|
524
583
|
- Quản lý bạn bè (danh sách, tìm kiếm, thêm, xóa, chặn, biệt danh, gợi ý)
|
|
525
584
|
- Quản lý nhóm (tạo, đổi tên, thành viên, cài đặt, link, ghi chú, lời mời)
|
|
526
|
-
- Quản lý hội thoại (tắt thông báo, ghim, lưu
|
|
585
|
+
- Quản lý hội thoại (tắt thông báo, ghim, lưu trữ, ẩn, tự xóa)
|
|
586
|
+
- Trả lời tự động, tin nhắn nhanh, nhãn, cửa hàng Zalo Shop
|
|
527
587
|
- Xuất/nhập credentials cho triển khai trên server
|
|
528
588
|
- HTTP server local hiển thị QR cho VPS (qua SSH tunnel)
|
|
529
589
|
- Output `--json` cho mọi lệnh, phục vụ scripting và coding agent
|
package/package.json
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-reply commands — list, create, update, delete auto-reply messages.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getApi } from "../core/zalo-client.js";
|
|
6
|
+
import { success, error, output } from "../utils/output.js";
|
|
7
|
+
|
|
8
|
+
export function registerAutoReplyCommands(program) {
|
|
9
|
+
const ar = program.command("auto-reply").description("Manage auto-reply messages");
|
|
10
|
+
|
|
11
|
+
ar.command("list")
|
|
12
|
+
.description("List all auto-reply rules")
|
|
13
|
+
.action(async () => {
|
|
14
|
+
try {
|
|
15
|
+
const result = await getApi().getAutoReplyList();
|
|
16
|
+
output(result, program.opts().json);
|
|
17
|
+
} catch (e) {
|
|
18
|
+
error(`Get auto-reply list failed: ${e.message}`);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
ar.command("create <content>")
|
|
23
|
+
.description("Create an auto-reply rule")
|
|
24
|
+
.option("--enable", "Enable the rule (default: true)", true)
|
|
25
|
+
.option("--no-enable", "Create disabled")
|
|
26
|
+
.option("--start <ms>", "Start time (epoch ms)", parseInt, 0)
|
|
27
|
+
.option("--end <ms>", "End time (epoch ms)", parseInt, 0)
|
|
28
|
+
.option("--scope <n>", "Scope: 0=all, 1=friends, 2=strangers", parseInt, 0)
|
|
29
|
+
.option("--uids <ids...>", "Specific user IDs to auto-reply to")
|
|
30
|
+
.action(async (content, opts) => {
|
|
31
|
+
try {
|
|
32
|
+
const payload = {
|
|
33
|
+
content,
|
|
34
|
+
isEnable: opts.enable,
|
|
35
|
+
startTime: opts.start,
|
|
36
|
+
endTime: opts.end,
|
|
37
|
+
scope: opts.scope,
|
|
38
|
+
};
|
|
39
|
+
if (opts.uids) payload.uids = opts.uids;
|
|
40
|
+
const result = await getApi().createAutoReply(payload);
|
|
41
|
+
output(result, program.opts().json, () => success("Auto-reply created"));
|
|
42
|
+
} catch (e) {
|
|
43
|
+
error(`Create auto-reply failed: ${e.message}`);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
ar.command("update <id> <content>")
|
|
48
|
+
.description("Update an auto-reply rule")
|
|
49
|
+
.option("--enable", "Enable the rule")
|
|
50
|
+
.option("--no-enable", "Disable the rule")
|
|
51
|
+
.option("--start <ms>", "Start time (epoch ms)", parseInt, 0)
|
|
52
|
+
.option("--end <ms>", "End time (epoch ms)", parseInt, 0)
|
|
53
|
+
.option("--scope <n>", "Scope: 0=all, 1=friends, 2=strangers", parseInt, 0)
|
|
54
|
+
.option("--uids <ids...>", "Specific user IDs")
|
|
55
|
+
.action(async (id, content, opts) => {
|
|
56
|
+
try {
|
|
57
|
+
const payload = {
|
|
58
|
+
id: Number(id),
|
|
59
|
+
content,
|
|
60
|
+
isEnable: opts.enable ?? true,
|
|
61
|
+
startTime: opts.start,
|
|
62
|
+
endTime: opts.end,
|
|
63
|
+
scope: opts.scope,
|
|
64
|
+
};
|
|
65
|
+
if (opts.uids) payload.uids = opts.uids;
|
|
66
|
+
const result = await getApi().updateAutoReply(payload);
|
|
67
|
+
output(result, program.opts().json, () => success(`Auto-reply ${id} updated`));
|
|
68
|
+
} catch (e) {
|
|
69
|
+
error(`Update auto-reply failed: ${e.message}`);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
ar.command("delete <id>")
|
|
74
|
+
.description("Delete an auto-reply rule")
|
|
75
|
+
.action(async (id) => {
|
|
76
|
+
try {
|
|
77
|
+
const result = await getApi().deleteAutoReply(Number(id));
|
|
78
|
+
output(result, program.opts().json, () => success(`Auto-reply ${id} deleted`));
|
|
79
|
+
} catch (e) {
|
|
80
|
+
error(`Delete auto-reply failed: ${e.message}`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog commands — manage Zalo Shop catalogs and products.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { resolve } from "path";
|
|
6
|
+
import { getApi } from "../core/zalo-client.js";
|
|
7
|
+
import { success, error, info, output } from "../utils/output.js";
|
|
8
|
+
|
|
9
|
+
export function registerCatalogCommands(program) {
|
|
10
|
+
const catalog = program.command("catalog").description("Manage Zalo Shop catalogs and products");
|
|
11
|
+
|
|
12
|
+
catalog
|
|
13
|
+
.command("list")
|
|
14
|
+
.description("List all catalogs")
|
|
15
|
+
.option("-l, --limit <n>", "Items per page", parseInt, 20)
|
|
16
|
+
.option("-p, --page <n>", "Page number", parseInt, 0)
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
try {
|
|
19
|
+
const result = await getApi().getCatalogList({ limit: opts.limit, page: opts.page });
|
|
20
|
+
output(result, program.opts().json);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
error(`Get catalogs failed: ${e.message}`);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
catalog
|
|
27
|
+
.command("create <name>")
|
|
28
|
+
.description("Create a new catalog")
|
|
29
|
+
.action(async (name) => {
|
|
30
|
+
try {
|
|
31
|
+
const result = await getApi().createCatalog(name);
|
|
32
|
+
output(result, program.opts().json, () => success(`Catalog "${name}" created`));
|
|
33
|
+
} catch (e) {
|
|
34
|
+
error(`Create catalog failed: ${e.message}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
catalog
|
|
39
|
+
.command("rename <catalogId> <name>")
|
|
40
|
+
.description("Rename a catalog")
|
|
41
|
+
.action(async (catalogId, name) => {
|
|
42
|
+
try {
|
|
43
|
+
const result = await getApi().updateCatalog({ catalogId, catalogName: name });
|
|
44
|
+
output(result, program.opts().json, () => success(`Catalog renamed to "${name}"`));
|
|
45
|
+
} catch (e) {
|
|
46
|
+
error(`Rename catalog failed: ${e.message}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
catalog
|
|
51
|
+
.command("delete <catalogId>")
|
|
52
|
+
.description("Delete a catalog")
|
|
53
|
+
.action(async (catalogId) => {
|
|
54
|
+
try {
|
|
55
|
+
const result = await getApi().deleteCatalog(catalogId);
|
|
56
|
+
output(result, program.opts().json, () => success(`Catalog ${catalogId} deleted`));
|
|
57
|
+
} catch (e) {
|
|
58
|
+
error(`Delete catalog failed: ${e.message}`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
catalog
|
|
63
|
+
.command("products <catalogId>")
|
|
64
|
+
.description("List products in a catalog")
|
|
65
|
+
.option("-l, --limit <n>", "Items per page", parseInt, 100)
|
|
66
|
+
.option("-p, --page <n>", "Page number", parseInt, 0)
|
|
67
|
+
.action(async (catalogId, opts) => {
|
|
68
|
+
try {
|
|
69
|
+
const result = await getApi().getProductCatalogList({
|
|
70
|
+
catalogId,
|
|
71
|
+
limit: opts.limit,
|
|
72
|
+
page: opts.page,
|
|
73
|
+
});
|
|
74
|
+
output(result, program.opts().json);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
error(`Get products failed: ${e.message}`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
catalog
|
|
81
|
+
.command("add-product <catalogId> <name> <price> <description>")
|
|
82
|
+
.description("Add a product to a catalog")
|
|
83
|
+
.option("--photos <urls...>", "Product photo URLs (up to 5)")
|
|
84
|
+
.action(async (catalogId, name, price, description, opts) => {
|
|
85
|
+
try {
|
|
86
|
+
const payload = { catalogId, productName: name, price, description };
|
|
87
|
+
if (opts.photos) payload.product_photos = opts.photos;
|
|
88
|
+
const result = await getApi().createProductCatalog(payload);
|
|
89
|
+
output(result, program.opts().json, () => success(`Product "${name}" added to catalog`));
|
|
90
|
+
} catch (e) {
|
|
91
|
+
error(`Add product failed: ${e.message}`);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
catalog
|
|
96
|
+
.command("update-product <catalogId> <productId> <name> <price> <description>")
|
|
97
|
+
.description("Update a product in a catalog")
|
|
98
|
+
.option("--photos <urls...>", "Product photo URLs (up to 5)")
|
|
99
|
+
.action(async (catalogId, productId, name, price, description, opts) => {
|
|
100
|
+
try {
|
|
101
|
+
const payload = {
|
|
102
|
+
catalogId,
|
|
103
|
+
productId,
|
|
104
|
+
productName: name,
|
|
105
|
+
price,
|
|
106
|
+
description,
|
|
107
|
+
createTime: Date.now(),
|
|
108
|
+
};
|
|
109
|
+
if (opts.photos) payload.product_photos = opts.photos;
|
|
110
|
+
const result = await getApi().updateProductCatalog(payload);
|
|
111
|
+
output(result, program.opts().json, () => success(`Product ${productId} updated`));
|
|
112
|
+
} catch (e) {
|
|
113
|
+
error(`Update product failed: ${e.message}`);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
catalog
|
|
118
|
+
.command("delete-product <catalogId> <productIds...>")
|
|
119
|
+
.description("Delete product(s) from a catalog")
|
|
120
|
+
.action(async (catalogId, productIds) => {
|
|
121
|
+
try {
|
|
122
|
+
const result = await getApi().deleteProductCatalog({ catalogId, productIds });
|
|
123
|
+
output(result, program.opts().json, () => success(`Deleted ${productIds.length} product(s)`));
|
|
124
|
+
} catch (e) {
|
|
125
|
+
error(`Delete product failed: ${e.message}`);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
catalog
|
|
130
|
+
.command("upload-photo <filePath>")
|
|
131
|
+
.description("Upload a product photo (returns URL for use with add-product --photos)")
|
|
132
|
+
.action(async (filePath) => {
|
|
133
|
+
try {
|
|
134
|
+
const absPath = resolve(filePath);
|
|
135
|
+
const result = await getApi().uploadProductPhoto({ file: absPath });
|
|
136
|
+
output(result, program.opts().json, () => {
|
|
137
|
+
info("Photo uploaded. Use the URL with: catalog add-product --photos <url>");
|
|
138
|
+
});
|
|
139
|
+
} catch (e) {
|
|
140
|
+
error(`Upload photo failed: ${e.message}`);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
package/src/commands/conv.js
CHANGED
|
@@ -163,6 +163,92 @@ export function registerConvCommands(program) {
|
|
|
163
163
|
}
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
+
conv.command("hidden")
|
|
167
|
+
.description("List hidden conversations")
|
|
168
|
+
.action(async () => {
|
|
169
|
+
try {
|
|
170
|
+
const result = await getApi().getHiddenConversations();
|
|
171
|
+
output(result, program.opts().json);
|
|
172
|
+
} catch (e) {
|
|
173
|
+
error(`Get hidden conversations failed: ${e.message}`);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
conv.command("hide <threadIds...>")
|
|
178
|
+
.description("Hide conversation(s)")
|
|
179
|
+
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
180
|
+
.action(async (threadIds, opts) => {
|
|
181
|
+
try {
|
|
182
|
+
const result = await getApi().setHiddenConversations(true, threadIds, Number(opts.type));
|
|
183
|
+
output(result, program.opts().json, () => success(`Hidden ${threadIds.length} conversation(s)`));
|
|
184
|
+
} catch (e) {
|
|
185
|
+
error(`Hide failed: ${e.message}`);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
conv.command("unhide <threadIds...>")
|
|
190
|
+
.description("Unhide conversation(s)")
|
|
191
|
+
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
192
|
+
.action(async (threadIds, opts) => {
|
|
193
|
+
try {
|
|
194
|
+
const result = await getApi().setHiddenConversations(false, threadIds, Number(opts.type));
|
|
195
|
+
output(result, program.opts().json, () => success(`Unhidden ${threadIds.length} conversation(s)`));
|
|
196
|
+
} catch (e) {
|
|
197
|
+
error(`Unhide failed: ${e.message}`);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
conv.command("hidden-pin <pin>")
|
|
202
|
+
.description("Set or update PIN for hidden conversations (4 digits)")
|
|
203
|
+
.action(async (pin) => {
|
|
204
|
+
try {
|
|
205
|
+
const result = await getApi().updateHiddenConversPin(pin);
|
|
206
|
+
output(result, program.opts().json, () => success("Hidden conversation PIN updated"));
|
|
207
|
+
} catch (e) {
|
|
208
|
+
error(`Update PIN failed: ${e.message}`);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
conv.command("hidden-pin-reset")
|
|
213
|
+
.description("Reset hidden conversations PIN")
|
|
214
|
+
.action(async () => {
|
|
215
|
+
try {
|
|
216
|
+
const result = await getApi().resetHiddenConversPin();
|
|
217
|
+
output(result, program.opts().json, () => success("Hidden conversation PIN reset"));
|
|
218
|
+
} catch (e) {
|
|
219
|
+
error(`Reset PIN failed: ${e.message}`);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
conv.command("auto-delete-status")
|
|
224
|
+
.description("View auto-delete chat settings")
|
|
225
|
+
.action(async () => {
|
|
226
|
+
try {
|
|
227
|
+
const result = await getApi().getAutoDeleteChat();
|
|
228
|
+
output(result, program.opts().json);
|
|
229
|
+
} catch (e) {
|
|
230
|
+
error(`Get auto-delete status failed: ${e.message}`);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
conv.command("auto-delete <threadId> <ttl>")
|
|
235
|
+
.description("Set auto-delete for a conversation (off, 1d, 7d, 14d)")
|
|
236
|
+
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
237
|
+
.action(async (threadId, ttl, opts) => {
|
|
238
|
+
try {
|
|
239
|
+
const ttlMap = { off: 0, "1d": 86400000, "7d": 604800000, "14d": 1209600000 };
|
|
240
|
+
const ttlValue = ttlMap[ttl];
|
|
241
|
+
if (ttlValue === undefined) {
|
|
242
|
+
error(`Invalid TTL "${ttl}". Valid: off, 1d, 7d, 14d`);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const result = await getApi().updateAutoDeleteChat(ttlValue, threadId, Number(opts.type));
|
|
246
|
+
output(result, program.opts().json, () => success(`Auto-delete set to ${ttl} for ${threadId}`));
|
|
247
|
+
} catch (e) {
|
|
248
|
+
error(`Set auto-delete failed: ${e.message}`);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
166
252
|
conv.command("delete <threadId>")
|
|
167
253
|
.description("Delete conversation history")
|
|
168
254
|
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label commands — list and update conversation/contact labels.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getApi } from "../core/zalo-client.js";
|
|
6
|
+
import { success, error, output } from "../utils/output.js";
|
|
7
|
+
|
|
8
|
+
export function registerLabelCommands(program) {
|
|
9
|
+
const label = program.command("label").description("Manage conversation labels");
|
|
10
|
+
|
|
11
|
+
label
|
|
12
|
+
.command("list")
|
|
13
|
+
.description("List all labels")
|
|
14
|
+
.action(async () => {
|
|
15
|
+
try {
|
|
16
|
+
const result = await getApi().getLabels();
|
|
17
|
+
output(result, program.opts().json);
|
|
18
|
+
} catch (e) {
|
|
19
|
+
error(`Get labels failed: ${e.message}`);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
label
|
|
24
|
+
.command("update <json>")
|
|
25
|
+
.description('Update labels (JSON payload: {"labelData":[...],"version":N})')
|
|
26
|
+
.action(async (json) => {
|
|
27
|
+
try {
|
|
28
|
+
const payload = JSON.parse(json);
|
|
29
|
+
const result = await getApi().updateLabels(payload);
|
|
30
|
+
output(result, program.opts().json, () => success("Labels updated"));
|
|
31
|
+
} catch (e) {
|
|
32
|
+
if (e instanceof SyntaxError) {
|
|
33
|
+
error(`Invalid JSON: ${e.message}`);
|
|
34
|
+
} else {
|
|
35
|
+
error(`Update labels failed: ${e.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
package/src/commands/msg.js
CHANGED
|
@@ -376,6 +376,44 @@ export function registerMsgCommands(program) {
|
|
|
376
376
|
}
|
|
377
377
|
});
|
|
378
378
|
|
|
379
|
+
msg.command("sticker-list <keyword>")
|
|
380
|
+
.description("Search stickers by keyword (returns sticker IDs)")
|
|
381
|
+
.action(async (keyword) => {
|
|
382
|
+
try {
|
|
383
|
+
const result = await getApi().getStickers(keyword);
|
|
384
|
+
output(result, program.opts().json, () => {
|
|
385
|
+
const ids = Array.isArray(result) ? result : [];
|
|
386
|
+
info(`${ids.length} sticker(s) found for "${keyword}"`);
|
|
387
|
+
for (const id of ids) console.log(` ${id}`);
|
|
388
|
+
});
|
|
389
|
+
} catch (e) {
|
|
390
|
+
error(`Sticker search failed: ${e.message}`);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
msg.command("sticker-detail <stickerIds...>")
|
|
395
|
+
.description("Get sticker details by IDs")
|
|
396
|
+
.action(async (stickerIds) => {
|
|
397
|
+
try {
|
|
398
|
+
const ids = stickerIds.map(Number);
|
|
399
|
+
const result = await getApi().getStickersDetail(ids);
|
|
400
|
+
output(result, program.opts().json);
|
|
401
|
+
} catch (e) {
|
|
402
|
+
error(`Sticker detail failed: ${e.message}`);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
msg.command("sticker-category <categoryId>")
|
|
407
|
+
.description("Get sticker category details")
|
|
408
|
+
.action(async (categoryId) => {
|
|
409
|
+
try {
|
|
410
|
+
const result = await getApi().getStickerCategoryDetail(Number(categoryId));
|
|
411
|
+
output(result, program.opts().json);
|
|
412
|
+
} catch (e) {
|
|
413
|
+
error(`Sticker category failed: ${e.message}`);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
379
417
|
msg.command("react <msgId> <threadId> <reaction>")
|
|
380
418
|
.description(
|
|
381
419
|
"React to a message. Reaction codes: :> (haha), /-heart (heart), /-strong (like), :o (wow), :-(( (cry), :-h (angry)",
|
package/src/commands/profile.js
CHANGED
|
@@ -182,6 +182,70 @@ export function registerProfileCommands(program) {
|
|
|
182
182
|
}
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
+
profile
|
|
186
|
+
.command("avatars")
|
|
187
|
+
.description("List your avatar gallery")
|
|
188
|
+
.option("-c, --count <n>", "Page size", parseInt, 50)
|
|
189
|
+
.option("-p, --page <n>", "Page number", parseInt, 1)
|
|
190
|
+
.action(async (opts) => {
|
|
191
|
+
try {
|
|
192
|
+
const result = await getApi().getAvatarList(opts.count, opts.page);
|
|
193
|
+
output(result, program.opts().json);
|
|
194
|
+
} catch (e) {
|
|
195
|
+
error(`Get avatars failed: ${e.message}`);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
profile
|
|
200
|
+
.command("full-avatar <friendId>")
|
|
201
|
+
.description("Get full-size avatar URL for a user")
|
|
202
|
+
.action(async (friendId) => {
|
|
203
|
+
try {
|
|
204
|
+
const result = await getApi().getFullAvatar(friendId);
|
|
205
|
+
output(result, program.opts().json, () => {
|
|
206
|
+
info(`Avatar: ${result?.avatar || "?"}`);
|
|
207
|
+
});
|
|
208
|
+
} catch (e) {
|
|
209
|
+
error(`Get full avatar failed: ${e.message}`);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
profile
|
|
214
|
+
.command("avatar-url <friendIds...>")
|
|
215
|
+
.description("Get avatar URLs for one or more users")
|
|
216
|
+
.action(async (friendIds) => {
|
|
217
|
+
try {
|
|
218
|
+
const result = await getApi().getAvatarUrlProfile(friendIds);
|
|
219
|
+
output(result, program.opts().json);
|
|
220
|
+
} catch (e) {
|
|
221
|
+
error(`Get avatar URLs failed: ${e.message}`);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
profile
|
|
226
|
+
.command("delete-avatar <photoIds...>")
|
|
227
|
+
.description("Delete avatar(s) from your gallery")
|
|
228
|
+
.action(async (photoIds) => {
|
|
229
|
+
try {
|
|
230
|
+
const result = await getApi().deleteAvatar(photoIds);
|
|
231
|
+
output(result, program.opts().json, () => success(`Deleted ${photoIds.length} avatar(s)`));
|
|
232
|
+
} catch (e) {
|
|
233
|
+
error(`Delete avatar failed: ${e.message}`);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
profile
|
|
238
|
+
.command("reuse-avatar <photoId>")
|
|
239
|
+
.description("Reuse a previous avatar from your gallery")
|
|
240
|
+
.action(async (photoId) => {
|
|
241
|
+
try {
|
|
242
|
+
const result = await getApi().reuseAvatar(photoId);
|
|
243
|
+
output(result, program.opts().json, () => success("Avatar reused"));
|
|
244
|
+
} catch (e) {
|
|
245
|
+
error(`Reuse avatar failed: ${e.message}`);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
185
249
|
profile
|
|
186
250
|
.command("set <setting> <value>")
|
|
187
251
|
.description("Update a privacy setting (use 'profile settings' to see options)")
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quick message commands — list, add, update, remove saved quick messages.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getApi } from "../core/zalo-client.js";
|
|
6
|
+
import { success, error, output } from "../utils/output.js";
|
|
7
|
+
|
|
8
|
+
export function registerQuickMsgCommands(program) {
|
|
9
|
+
const qm = program.command("quick-msg").description("Manage quick/saved messages");
|
|
10
|
+
|
|
11
|
+
qm.command("list")
|
|
12
|
+
.description("List all quick messages")
|
|
13
|
+
.action(async () => {
|
|
14
|
+
try {
|
|
15
|
+
const result = await getApi().getQuickMessageList();
|
|
16
|
+
output(result, program.opts().json);
|
|
17
|
+
} catch (e) {
|
|
18
|
+
error(`Get quick messages failed: ${e.message}`);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
qm.command("add <keyword> <title>")
|
|
23
|
+
.description("Add a quick message")
|
|
24
|
+
.action(async (keyword, title) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = await getApi().addQuickMessage({ keyword, title });
|
|
27
|
+
output(result, program.opts().json, () => success(`Quick message added: "${keyword}" → "${title}"`));
|
|
28
|
+
} catch (e) {
|
|
29
|
+
error(`Add quick message failed: ${e.message}`);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
qm.command("update <itemId> <keyword> <title>")
|
|
34
|
+
.description("Update a quick message")
|
|
35
|
+
.action(async (itemId, keyword, title) => {
|
|
36
|
+
try {
|
|
37
|
+
const result = await getApi().updateQuickMessage({ keyword, title }, Number(itemId));
|
|
38
|
+
output(result, program.opts().json, () => success(`Quick message ${itemId} updated`));
|
|
39
|
+
} catch (e) {
|
|
40
|
+
error(`Update quick message failed: ${e.message}`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
qm.command("remove <itemIds...>")
|
|
45
|
+
.description("Remove quick message(s)")
|
|
46
|
+
.action(async (itemIds) => {
|
|
47
|
+
try {
|
|
48
|
+
const ids = itemIds.map(Number);
|
|
49
|
+
const result = await getApi().removeQuickMessage(ids);
|
|
50
|
+
output(result, program.opts().json, () => success(`Removed ${ids.length} quick message(s)`));
|
|
51
|
+
} catch (e) {
|
|
52
|
+
error(`Remove quick message failed: ${e.message}`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
package/src/index.js
CHANGED
|
@@ -21,6 +21,10 @@ import { registerAccountCommands } from "./commands/account.js";
|
|
|
21
21
|
import { registerProfileCommands } from "./commands/profile.js";
|
|
22
22
|
import { registerPollCommands } from "./commands/poll.js";
|
|
23
23
|
import { registerReminderCommands } from "./commands/reminder.js";
|
|
24
|
+
import { registerAutoReplyCommands } from "./commands/auto-reply.js";
|
|
25
|
+
import { registerQuickMsgCommands } from "./commands/quick-msg.js";
|
|
26
|
+
import { registerLabelCommands } from "./commands/label.js";
|
|
27
|
+
import { registerCatalogCommands } from "./commands/catalog.js";
|
|
24
28
|
import { registerListenCommand } from "./commands/listen.js";
|
|
25
29
|
import { autoLogin } from "./core/zalo-client.js";
|
|
26
30
|
import { checkForUpdates, selfUpdate } from "./utils/update-check.js";
|
|
@@ -76,6 +80,10 @@ registerAccountCommands(program);
|
|
|
76
80
|
registerProfileCommands(program);
|
|
77
81
|
registerPollCommands(program);
|
|
78
82
|
registerReminderCommands(program);
|
|
83
|
+
registerAutoReplyCommands(program);
|
|
84
|
+
registerQuickMsgCommands(program);
|
|
85
|
+
registerLabelCommands(program);
|
|
86
|
+
registerCatalogCommands(program);
|
|
79
87
|
registerListenCommand(program);
|
|
80
88
|
|
|
81
89
|
program.parse();
|