zalo-agent-cli 1.0.18 → 1.0.19
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 +44 -4
- package/package.json +1 -1
- package/src/commands/conv.js +85 -1
- package/src/commands/friend.js +33 -0
package/README.md
CHANGED
|
@@ -80,13 +80,32 @@ A QR code PNG will be saved and a local HTTP server starts automatically. Open t
|
|
|
80
80
|
|
|
81
81
|
> **Important:** Use Zalo's built-in QR scanner (not regular phone camera). The QR expires in ~60 seconds.
|
|
82
82
|
|
|
83
|
-
#### 2.
|
|
83
|
+
#### 2. Find a thread ID
|
|
84
|
+
|
|
85
|
+
A `thread_id` is a user ID (for DMs) or group ID (for group chats). You need it for most messaging commands.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Search friends by name → get their thread_id
|
|
89
|
+
zalo-agent friend search "Phúc"
|
|
90
|
+
|
|
91
|
+
# List recent conversations (friends + groups) with thread_id
|
|
92
|
+
zalo-agent conv recent
|
|
93
|
+
|
|
94
|
+
# List only groups
|
|
95
|
+
zalo-agent conv recent --groups-only
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### 3. Send a message
|
|
84
99
|
|
|
85
100
|
```bash
|
|
101
|
+
# Send to a user (type 0, default)
|
|
86
102
|
zalo-agent msg send <THREAD_ID> "Hello from zalo-agent!"
|
|
103
|
+
|
|
104
|
+
# Send to a group (type 1)
|
|
105
|
+
zalo-agent msg send <THREAD_ID> "Hello group!" -t 1
|
|
87
106
|
```
|
|
88
107
|
|
|
89
|
-
####
|
|
108
|
+
#### 4. List friends
|
|
90
109
|
|
|
91
110
|
```bash
|
|
92
111
|
zalo-agent friend list
|
|
@@ -140,6 +159,7 @@ zalo-agent whoami
|
|
|
140
159
|
| Command | Description |
|
|
141
160
|
|---------|-------------|
|
|
142
161
|
| `friend list` | List all friends |
|
|
162
|
+
| `friend search <name>` | Search friends by name (get thread_id) |
|
|
143
163
|
| `friend online` | List online friends |
|
|
144
164
|
| `friend find <query>` | Find by phone or ID |
|
|
145
165
|
| `friend info <userId>` | Get user profile |
|
|
@@ -168,6 +188,7 @@ zalo-agent whoami
|
|
|
168
188
|
|
|
169
189
|
| Command | Description |
|
|
170
190
|
|---------|-------------|
|
|
191
|
+
| `conv recent [-n limit] [--friends-only] [--groups-only]` | List recent conversations with thread_id |
|
|
171
192
|
| `conv pinned` | List pinned |
|
|
172
193
|
| `conv archived` | List archived |
|
|
173
194
|
| `conv mute <threadId> [-t 0\|1] [-d secs]` | Mute (-1 = forever) |
|
|
@@ -365,13 +386,32 @@ zalo-agent login
|
|
|
365
386
|
|
|
366
387
|
HTTP server tự khởi động và hiện URL (ví dụ `http://ip:18927/qr`). Mở URL trên trình duyệt, quét bằng **Zalo app > Quét mã QR** (không dùng camera thường). Thông tin đăng nhập tự động lưu tại `~/.zalo-agent-cli/`.
|
|
367
388
|
|
|
368
|
-
#### 2.
|
|
389
|
+
#### 2. Tìm thread ID
|
|
390
|
+
|
|
391
|
+
`thread_id` là ID của người dùng (tin nhắn riêng) hoặc ID nhóm (nhóm chat). Bạn cần nó cho hầu hết các lệnh gửi tin.
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
# Tìm bạn bè theo tên → lấy thread_id
|
|
395
|
+
zalo-agent friend search "Phúc"
|
|
396
|
+
|
|
397
|
+
# Xem danh sách hội thoại gần đây (bạn bè + nhóm) kèm thread_id
|
|
398
|
+
zalo-agent conv recent
|
|
399
|
+
|
|
400
|
+
# Chỉ xem nhóm
|
|
401
|
+
zalo-agent conv recent --groups-only
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### 3. Gửi tin nhắn
|
|
369
405
|
|
|
370
406
|
```bash
|
|
407
|
+
# Gửi cho cá nhân (type 0, mặc định)
|
|
371
408
|
zalo-agent msg send <THREAD_ID> "Xin chào!"
|
|
409
|
+
|
|
410
|
+
# Gửi vào nhóm (type 1)
|
|
411
|
+
zalo-agent msg send <THREAD_ID> "Xin chào nhóm!" -t 1
|
|
372
412
|
```
|
|
373
413
|
|
|
374
|
-
####
|
|
414
|
+
#### 4. Xem danh sách bạn bè
|
|
375
415
|
|
|
376
416
|
```bash
|
|
377
417
|
zalo-agent friend list
|
package/package.json
CHANGED
package/src/commands/conv.js
CHANGED
|
@@ -3,11 +3,95 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { getApi } from "../core/zalo-client.js";
|
|
6
|
-
import { success, error, output } from "../utils/output.js";
|
|
6
|
+
import { success, error, info, output } from "../utils/output.js";
|
|
7
7
|
|
|
8
8
|
export function registerConvCommands(program) {
|
|
9
9
|
const conv = program.command("conv").description("Manage conversations");
|
|
10
10
|
|
|
11
|
+
conv.command("recent")
|
|
12
|
+
.description("List recent conversations with thread_id (friends + groups)")
|
|
13
|
+
.option("-n, --limit <n>", "Max results per type", "20")
|
|
14
|
+
.option("--friends-only", "Show only friend conversations")
|
|
15
|
+
.option("--groups-only", "Show only group conversations")
|
|
16
|
+
.action(async (opts) => {
|
|
17
|
+
try {
|
|
18
|
+
const api = getApi();
|
|
19
|
+
const limit = Number(opts.limit);
|
|
20
|
+
const conversations = [];
|
|
21
|
+
|
|
22
|
+
// Fetch friends (sorted by lastActionTime = most recent interaction)
|
|
23
|
+
if (!opts.groupsOnly) {
|
|
24
|
+
const friends = await api.getAllFriends();
|
|
25
|
+
const list = Array.isArray(friends) ? friends : [];
|
|
26
|
+
const sorted = list
|
|
27
|
+
.filter((f) => f.lastActionTime > 0)
|
|
28
|
+
.sort((a, b) => b.lastActionTime - a.lastActionTime)
|
|
29
|
+
.slice(0, limit);
|
|
30
|
+
for (const f of sorted) {
|
|
31
|
+
conversations.push({
|
|
32
|
+
threadId: f.userId,
|
|
33
|
+
name: f.displayName || f.zaloName || "?",
|
|
34
|
+
type: "User",
|
|
35
|
+
typeFlag: 0,
|
|
36
|
+
lastActive: new Date(f.lastActionTime * 1000).toLocaleString(),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Fetch groups
|
|
42
|
+
if (!opts.friendsOnly) {
|
|
43
|
+
const groupsResult = await api.getAllGroups();
|
|
44
|
+
const groupIds = Object.keys(groupsResult?.gridVerMap || {});
|
|
45
|
+
if (groupIds.length > 0) {
|
|
46
|
+
const batchSize = 50;
|
|
47
|
+
const batches = [];
|
|
48
|
+
for (let i = 0; i < Math.min(groupIds.length, limit); i += batchSize) {
|
|
49
|
+
batches.push(groupIds.slice(i, i + batchSize));
|
|
50
|
+
}
|
|
51
|
+
for (const batch of batches) {
|
|
52
|
+
try {
|
|
53
|
+
const groupInfo = await api.getGroupInfo(batch);
|
|
54
|
+
const map = groupInfo?.gridInfoMap || {};
|
|
55
|
+
for (const [gid, g] of Object.entries(map)) {
|
|
56
|
+
conversations.push({
|
|
57
|
+
threadId: gid,
|
|
58
|
+
name: g.name || "?",
|
|
59
|
+
type: "Group",
|
|
60
|
+
typeFlag: 1,
|
|
61
|
+
memberCount: g.totalMember || 0,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
// Skip failed batch
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
output(conversations, program.opts().json, () => {
|
|
72
|
+
if (conversations.length === 0) {
|
|
73
|
+
error("No conversations found.");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
info(`${conversations.length} conversation(s):`);
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(" THREAD_ID TYPE NAME");
|
|
79
|
+
console.log(" " + "-".repeat(60));
|
|
80
|
+
for (const c of conversations) {
|
|
81
|
+
const typeLabel = c.type === "Group" ? `Group(${c.memberCount})` : "User";
|
|
82
|
+
const id = c.threadId.padEnd(22);
|
|
83
|
+
console.log(` ${id} ${typeLabel.padEnd(12)} ${c.name}`);
|
|
84
|
+
}
|
|
85
|
+
console.log();
|
|
86
|
+
info("Use thread_id with messaging commands:");
|
|
87
|
+
info(' zalo-agent msg send <thread_id> "Hello" (User)');
|
|
88
|
+
info(' zalo-agent msg send <thread_id> "Hello" -t 1 (Group)');
|
|
89
|
+
});
|
|
90
|
+
} catch (e) {
|
|
91
|
+
error(e.message);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
11
95
|
conv.command("pinned")
|
|
12
96
|
.description("List pinned conversations")
|
|
13
97
|
.action(async () => {
|
package/src/commands/friend.js
CHANGED
|
@@ -45,6 +45,39 @@ export function registerFriendCommands(program) {
|
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
+
friend
|
|
49
|
+
.command("search <name>")
|
|
50
|
+
.description("Search friends by name (returns thread_id for messaging)")
|
|
51
|
+
.action(async (name) => {
|
|
52
|
+
try {
|
|
53
|
+
const result = await getApi().getAllFriends();
|
|
54
|
+
const friends = Array.isArray(result) ? result : [];
|
|
55
|
+
const query = name.toLowerCase();
|
|
56
|
+
const matches = friends.filter((f) => {
|
|
57
|
+
const dn = (f.displayName || "").toLowerCase();
|
|
58
|
+
const zn = (f.zaloName || "").toLowerCase();
|
|
59
|
+
return dn.includes(query) || zn.includes(query);
|
|
60
|
+
});
|
|
61
|
+
output(matches, program.opts().json, () => {
|
|
62
|
+
if (matches.length === 0) {
|
|
63
|
+
error(`No friends matching "${name}". Use "friend list" to see all.`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
info(`${matches.length} friend(s) matching "${name}":`);
|
|
67
|
+
console.log();
|
|
68
|
+
for (const f of matches) {
|
|
69
|
+
const display = f.displayName || f.zaloName || "?";
|
|
70
|
+
console.log(` ${f.userId} ${display}`);
|
|
71
|
+
}
|
|
72
|
+
console.log();
|
|
73
|
+
info("Use the ID above as thread_id for messaging commands.");
|
|
74
|
+
info('Example: zalo-agent msg send <thread_id> "Hello"');
|
|
75
|
+
});
|
|
76
|
+
} catch (e) {
|
|
77
|
+
error(e.message);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
48
81
|
friend
|
|
49
82
|
.command("find <query>")
|
|
50
83
|
.description("Find user by phone number or Zalo ID")
|