zalo-agent-cli 1.0.6 → 1.0.8
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/package.json +1 -1
- package/src/commands/msg.js +61 -7
package/package.json
CHANGED
package/src/commands/msg.js
CHANGED
|
@@ -13,10 +13,29 @@ export function registerMsgCommands(program) {
|
|
|
13
13
|
msg.command("send <threadId> <message>")
|
|
14
14
|
.description("Send a text message")
|
|
15
15
|
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
16
|
+
.option(
|
|
17
|
+
"--react <icon>",
|
|
18
|
+
"Auto-react to sent message. Codes: :> (haha), /-heart (heart), /-strong (like), :o (wow), :-(( (cry), :-h (angry)",
|
|
19
|
+
)
|
|
16
20
|
.action(async (threadId, message, opts) => {
|
|
17
21
|
try {
|
|
22
|
+
// Capture clientId before send — zca-js uses Date.now() internally
|
|
23
|
+
const cliMsgId = String(Date.now());
|
|
18
24
|
const result = await getApi().sendMessage(message, threadId, Number(opts.type));
|
|
25
|
+
// Include cliMsgId in output for later use with react command
|
|
26
|
+
result.cliMsgId = cliMsgId;
|
|
19
27
|
output(result, program.opts().json, () => success("Message sent"));
|
|
28
|
+
|
|
29
|
+
// Auto-react if --react flag provided
|
|
30
|
+
if (opts.react && result.message?.msgId) {
|
|
31
|
+
const dest = {
|
|
32
|
+
data: { msgId: String(result.message.msgId), cliMsgId },
|
|
33
|
+
threadId,
|
|
34
|
+
type: Number(opts.type),
|
|
35
|
+
};
|
|
36
|
+
await getApi().addReaction(opts.react, dest);
|
|
37
|
+
success(`Auto-reacted with '${opts.react}'`);
|
|
38
|
+
}
|
|
20
39
|
} catch (e) {
|
|
21
40
|
error(e.message);
|
|
22
41
|
}
|
|
@@ -188,9 +207,14 @@ export function registerMsgCommands(program) {
|
|
|
188
207
|
});
|
|
189
208
|
|
|
190
209
|
msg.command("react <msgId> <threadId> <reaction>")
|
|
191
|
-
.description(
|
|
210
|
+
.description(
|
|
211
|
+
"React to a message. Reaction codes: :> (haha), /-heart (heart), /-strong (like), :o (wow), :-(( (cry), :-h (angry)",
|
|
212
|
+
)
|
|
192
213
|
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
193
|
-
.option(
|
|
214
|
+
.option(
|
|
215
|
+
"-c, --cli-msg-id <id>",
|
|
216
|
+
"Client message ID (required for reaction to appear, get from msg listen --json)",
|
|
217
|
+
)
|
|
194
218
|
.action(async (msgId, threadId, reaction, opts) => {
|
|
195
219
|
try {
|
|
196
220
|
// zca-js addReaction(icon, dest) — dest needs msgId + cliMsgId
|
|
@@ -207,14 +231,28 @@ export function registerMsgCommands(program) {
|
|
|
207
231
|
});
|
|
208
232
|
|
|
209
233
|
msg.command("listen")
|
|
210
|
-
.description(
|
|
211
|
-
|
|
234
|
+
.description(
|
|
235
|
+
"Listen for incoming messages in real-time via WebSocket. Outputs msgId + cliMsgId needed for react. Use --json for machine parsing.",
|
|
236
|
+
)
|
|
237
|
+
.option("-f, --filter <type>", "Filter messages: user (DM only), group (groups only), all (default)", "all")
|
|
238
|
+
.option("-w, --webhook <url>", "POST each message as JSON to this URL (for n8n, Make, etc.)")
|
|
239
|
+
.option("--no-self", "Exclude messages sent by this account")
|
|
240
|
+
.action(async (opts) => {
|
|
212
241
|
try {
|
|
213
242
|
const api = getApi();
|
|
243
|
+
const jsonMode = program.opts().json;
|
|
214
244
|
info("Listening for messages... Press Ctrl+C to stop.");
|
|
215
245
|
info("Note: Only one web listener per account. Browser Zalo will disconnect.");
|
|
246
|
+
if (opts.filter !== "all") info(`Filter: ${opts.filter} messages only`);
|
|
247
|
+
if (opts.webhook) info(`Webhook: POST to ${opts.webhook}`);
|
|
248
|
+
|
|
249
|
+
api.listener.on("message", async (msg) => {
|
|
250
|
+
// Filter by type: 0=User, 1=Group
|
|
251
|
+
if (opts.filter === "user" && msg.type !== 0) return;
|
|
252
|
+
if (opts.filter === "group" && msg.type !== 1) return;
|
|
253
|
+
// Filter self messages
|
|
254
|
+
if (!opts.self && msg.isSelf) return;
|
|
216
255
|
|
|
217
|
-
api.listener.on("message", (msg) => {
|
|
218
256
|
const content = typeof msg.data.content === "string" ? msg.data.content : "[non-text]";
|
|
219
257
|
const data = {
|
|
220
258
|
msgId: msg.data.msgId,
|
|
@@ -224,11 +262,27 @@ export function registerMsgCommands(program) {
|
|
|
224
262
|
isSelf: msg.isSelf,
|
|
225
263
|
content,
|
|
226
264
|
};
|
|
227
|
-
|
|
265
|
+
|
|
266
|
+
// Output to stdout
|
|
267
|
+
if (jsonMode) {
|
|
228
268
|
console.log(JSON.stringify(data));
|
|
229
269
|
} else {
|
|
230
270
|
const dir = msg.isSelf ? "→" : "←";
|
|
231
|
-
|
|
271
|
+
const typeLabel = msg.type === 0 ? "DM" : "GR";
|
|
272
|
+
console.log(` ${dir} [${typeLabel}] [${msg.threadId}] ${content} (msgId: ${msg.data.msgId})`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// POST to webhook if configured
|
|
276
|
+
if (opts.webhook) {
|
|
277
|
+
try {
|
|
278
|
+
await fetch(opts.webhook, {
|
|
279
|
+
method: "POST",
|
|
280
|
+
headers: { "Content-Type": "application/json" },
|
|
281
|
+
body: JSON.stringify(data),
|
|
282
|
+
});
|
|
283
|
+
} catch {
|
|
284
|
+
// Silent webhook failure — don't block listener
|
|
285
|
+
}
|
|
232
286
|
}
|
|
233
287
|
});
|
|
234
288
|
|