zalo-agent-cli 1.0.24 → 1.0.26
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 +77 -1
- package/package.json +1 -1
- package/src/commands/msg.js +105 -3
- package/src/commands/reminder.js +195 -0
- package/src/index.js +2 -0
package/README.md
CHANGED
|
@@ -160,7 +160,7 @@ zalo-agent whoami
|
|
|
160
160
|
|
|
161
161
|
| Command | Description |
|
|
162
162
|
|---------|-------------|
|
|
163
|
-
| `msg send <threadId> <text> [-t 0\|1]` | Send text message |
|
|
163
|
+
| `msg send <threadId> <text> [-t 0\|1] [--md] [--style specs...]` | Send text message (with formatting) |
|
|
164
164
|
| `msg send-image <threadId> <paths...> [-t 0\|1] [-m caption]` | Send images |
|
|
165
165
|
| `msg send-file <threadId> <paths...> [-t 0\|1] [-m caption]` | Send files |
|
|
166
166
|
| `msg send-card <threadId> <userId> [-t 0\|1] [--phone NUM]` | Send contact card |
|
|
@@ -174,6 +174,30 @@ zalo-agent whoami
|
|
|
174
174
|
|
|
175
175
|
> `-t 0` = User (default), `-t 1` = Group
|
|
176
176
|
|
|
177
|
+
**Text formatting with `--md` (markdown mode):**
|
|
178
|
+
```bash
|
|
179
|
+
zalo-agent msg send <threadId> "**Bold** *Italic* __Underline__ ~~Strike~~ {red:Red} {big:BIG}" --md
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
| Syntax | Style |
|
|
183
|
+
|--------|-------|
|
|
184
|
+
| `**text**` | Bold |
|
|
185
|
+
| `*text*` | Italic |
|
|
186
|
+
| `__text__` | Underline |
|
|
187
|
+
| `~~text~~` | Strikethrough |
|
|
188
|
+
| `{red:text}` | Red text |
|
|
189
|
+
| `{orange:text}` | Orange text |
|
|
190
|
+
| `{yellow:text}` | Yellow text |
|
|
191
|
+
| `{green:text}` | Green text |
|
|
192
|
+
| `{big:text}` | Large font |
|
|
193
|
+
| `{small:text}` | Small font |
|
|
194
|
+
|
|
195
|
+
**Manual style with `--style` (for agents/automation):**
|
|
196
|
+
```bash
|
|
197
|
+
# Format: start:len:style — style names: bold, italic, underline, strikethrough, red, orange, yellow, green, big, small
|
|
198
|
+
zalo-agent msg send <threadId> "Hello World" --style 0:5:bold 6:5:italic
|
|
199
|
+
```
|
|
200
|
+
|
|
177
201
|
#### Friends (`friend`)
|
|
178
202
|
|
|
179
203
|
| Command | Description |
|
|
@@ -260,6 +284,37 @@ zalo-agent poll vote <pollId> 123 456
|
|
|
260
284
|
zalo-agent poll lock <pollId>
|
|
261
285
|
```
|
|
262
286
|
|
|
287
|
+
#### Reminders (`reminder`)
|
|
288
|
+
|
|
289
|
+
| Command | Description |
|
|
290
|
+
|---------|-------------|
|
|
291
|
+
| `reminder create <threadId> <title> [-t 0\|1] [--time "YYYY-MM-DD HH:mm"] [--repeat mode] [--emoji]` | Create a reminder |
|
|
292
|
+
| `reminder list <threadId> [-t 0\|1] [-n count]` | List reminders |
|
|
293
|
+
| `reminder info <reminderId>` | View reminder details (group only) |
|
|
294
|
+
| `reminder responses <reminderId>` | View who accepted/rejected (group only) |
|
|
295
|
+
| `reminder edit <reminderId> <threadId> <title> [-t 0\|1] [--time] [--repeat] [--emoji]` | Edit a reminder |
|
|
296
|
+
| `reminder remove <reminderId> <threadId> [-t 0\|1]` | Remove a reminder |
|
|
297
|
+
|
|
298
|
+
**Repeat modes:** `none`, `daily`, `weekly`, `monthly`
|
|
299
|
+
|
|
300
|
+
**Example:**
|
|
301
|
+
```bash
|
|
302
|
+
# Create a daily reminder in a group at 9:00 AM tomorrow
|
|
303
|
+
zalo-agent reminder create <groupId> "Standup meeting" -t 1 --time "2026-03-16 09:00" --repeat daily
|
|
304
|
+
|
|
305
|
+
# List reminders in a group
|
|
306
|
+
zalo-agent reminder list <groupId> -t 1
|
|
307
|
+
|
|
308
|
+
# View who responded
|
|
309
|
+
zalo-agent reminder responses <reminderId>
|
|
310
|
+
|
|
311
|
+
# Edit reminder title and time
|
|
312
|
+
zalo-agent reminder edit <reminderId> <groupId> "New title" -t 1 --time "2026-03-17 10:00"
|
|
313
|
+
|
|
314
|
+
# Remove a reminder
|
|
315
|
+
zalo-agent reminder remove <reminderId> <groupId> -t 1
|
|
316
|
+
```
|
|
317
|
+
|
|
263
318
|
#### Accounts (`account`)
|
|
264
319
|
|
|
265
320
|
| Command | Description |
|
|
@@ -515,6 +570,27 @@ zalo-agent poll vote <pollId> 123 456
|
|
|
515
570
|
zalo-agent poll lock <pollId>
|
|
516
571
|
```
|
|
517
572
|
|
|
573
|
+
#### 7. Nhắc nhở (Reminder)
|
|
574
|
+
|
|
575
|
+
```bash
|
|
576
|
+
# Tạo nhắc nhở hàng ngày trong nhóm lúc 9h sáng
|
|
577
|
+
zalo-agent reminder create <groupId> "Họp standup" -t 1 --time "2026-03-16 09:00" --repeat daily
|
|
578
|
+
|
|
579
|
+
# Xem danh sách nhắc nhở
|
|
580
|
+
zalo-agent reminder list <groupId> -t 1
|
|
581
|
+
|
|
582
|
+
# Xem ai đã chấp nhận/từ chối
|
|
583
|
+
zalo-agent reminder responses <reminderId>
|
|
584
|
+
|
|
585
|
+
# Sửa nhắc nhở
|
|
586
|
+
zalo-agent reminder edit <reminderId> <groupId> "Tiêu đề mới" -t 1 --time "2026-03-17 10:00"
|
|
587
|
+
|
|
588
|
+
# Xóa nhắc nhở
|
|
589
|
+
zalo-agent reminder remove <reminderId> <groupId> -t 1
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
Chế độ lặp: `none` (không lặp), `daily` (hàng ngày), `weekly` (hàng tuần), `monthly` (hàng tháng)
|
|
593
|
+
|
|
518
594
|
### Danh sách lệnh
|
|
519
595
|
|
|
520
596
|
Xem đầy đủ tại [phần tiếng Anh](#command-reference) phía trên. Tất cả lệnh đều giống nhau.
|
package/package.json
CHANGED
package/src/commands/msg.js
CHANGED
|
@@ -7,16 +7,99 @@ import { resolve } from "path";
|
|
|
7
7
|
import { getApi } from "../core/zalo-client.js";
|
|
8
8
|
import { success, error, info, output } from "../utils/output.js";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* TextStyle codes matching zca-js TextStyle enum.
|
|
12
|
+
* Used for --style option and markdown parsing.
|
|
13
|
+
*/
|
|
14
|
+
const TEXT_STYLES = {
|
|
15
|
+
bold: "b",
|
|
16
|
+
b: "b",
|
|
17
|
+
italic: "i",
|
|
18
|
+
i: "i",
|
|
19
|
+
underline: "u",
|
|
20
|
+
u: "u",
|
|
21
|
+
strikethrough: "s",
|
|
22
|
+
s: "s",
|
|
23
|
+
red: "c_db342e",
|
|
24
|
+
orange: "c_f27806",
|
|
25
|
+
yellow: "c_f7b503",
|
|
26
|
+
green: "c_15a85f",
|
|
27
|
+
small: "f_13",
|
|
28
|
+
big: "f_18",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parse markdown-like syntax from message text into plain text + styles array.
|
|
33
|
+
* Supports: **bold**, *italic*, __underline__, ~~strikethrough~~,
|
|
34
|
+
* {red:text}, {orange:text}, {green:text}, {yellow:text},
|
|
35
|
+
* {big:text}, {small:text}
|
|
36
|
+
*/
|
|
37
|
+
function parseMarkdownStyles(input) {
|
|
38
|
+
const styles = [];
|
|
39
|
+
let plain = input;
|
|
40
|
+
|
|
41
|
+
// Process markdown patterns (order matters: ** before *)
|
|
42
|
+
const patterns = [
|
|
43
|
+
{ regex: /\*\*(.+?)\*\*/g, st: "b" },
|
|
44
|
+
{ regex: /\*(.+?)\*/g, st: "i" },
|
|
45
|
+
{ regex: /__(.+?)__/g, st: "u" },
|
|
46
|
+
{ regex: /~~(.+?)~~/g, st: "s" },
|
|
47
|
+
{ regex: /\{(red|orange|yellow|green|big|small):(.+?)\}/g, st: null },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
for (const p of patterns) {
|
|
51
|
+
let match;
|
|
52
|
+
// Re-run from scratch each time since offsets shift
|
|
53
|
+
while ((match = p.regex.exec(plain)) !== null) {
|
|
54
|
+
const fullMatch = match[0];
|
|
55
|
+
const start = match.index;
|
|
56
|
+
let content, st;
|
|
57
|
+
if (p.st === null) {
|
|
58
|
+
// Color/size pattern: {color:text}
|
|
59
|
+
st = TEXT_STYLES[match[1]];
|
|
60
|
+
content = match[2];
|
|
61
|
+
} else {
|
|
62
|
+
st = p.st;
|
|
63
|
+
content = match[1];
|
|
64
|
+
}
|
|
65
|
+
// Replace the markdown syntax with plain content
|
|
66
|
+
plain = plain.slice(0, start) + content + plain.slice(start + fullMatch.length);
|
|
67
|
+
styles.push({ start, len: content.length, st });
|
|
68
|
+
// Reset regex since string changed
|
|
69
|
+
p.regex.lastIndex = start + content.length;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { plain, styles };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Parse manual style specs: "start:len:style" → { start, len, st }
|
|
78
|
+
* Style names: bold, italic, underline, strikethrough, red, orange, yellow, green, big, small
|
|
79
|
+
*/
|
|
80
|
+
function parseStyleSpecs(specs) {
|
|
81
|
+
return specs
|
|
82
|
+
.map((spec) => {
|
|
83
|
+
const [start, len, style] = spec.split(":");
|
|
84
|
+
const st = TEXT_STYLES[style];
|
|
85
|
+
if (!st) return null;
|
|
86
|
+
return { start: Number(start), len: Number(len), st };
|
|
87
|
+
})
|
|
88
|
+
.filter(Boolean);
|
|
89
|
+
}
|
|
90
|
+
|
|
10
91
|
export function registerMsgCommands(program) {
|
|
11
92
|
const msg = program.command("msg").description("Send and manage messages");
|
|
12
93
|
|
|
13
94
|
msg.command("send <threadId> <message>")
|
|
14
|
-
.description("Send a text message")
|
|
95
|
+
.description("Send a text message with optional formatting")
|
|
15
96
|
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
16
97
|
.option(
|
|
17
98
|
"--mention <specs...>",
|
|
18
99
|
"Mention users in group message. Format: pos:userId:len (e.g. 0:USER_ID:5). Use userId=-1 for @All.",
|
|
19
100
|
)
|
|
101
|
+
.option("--style <specs...>", "Text styles. Format: start:len:style (e.g. 0:5:bold 6:5:italic)")
|
|
102
|
+
.option("--md", "Parse markdown-like formatting: **bold** *italic* __underline__ ~~strike~~ {red:text}")
|
|
20
103
|
.option(
|
|
21
104
|
"--react <icon>",
|
|
22
105
|
"Auto-react to sent message. Codes: :> (haha), /-heart (heart), /-strong (like), :o (wow), :-(( (cry), :-h (angry)",
|
|
@@ -29,8 +112,27 @@ export function registerMsgCommands(program) {
|
|
|
29
112
|
return { pos: Number(pos), uid, len: Number(len) };
|
|
30
113
|
});
|
|
31
114
|
|
|
32
|
-
//
|
|
33
|
-
|
|
115
|
+
// Parse text styles
|
|
116
|
+
let styles = [];
|
|
117
|
+
let finalMsg = message;
|
|
118
|
+
|
|
119
|
+
if (opts.md) {
|
|
120
|
+
// Markdown-like parsing: **bold** *italic* __underline__ ~~strike~~
|
|
121
|
+
const parsed = parseMarkdownStyles(message);
|
|
122
|
+
finalMsg = parsed.plain;
|
|
123
|
+
styles = parsed.styles;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (opts.style) {
|
|
127
|
+
// Manual style specs: start:len:style
|
|
128
|
+
styles = styles.concat(parseStyleSpecs(opts.style));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Build message content
|
|
132
|
+
const hasExtras = mentions.length > 0 || styles.length > 0;
|
|
133
|
+
const msgContent = hasExtras
|
|
134
|
+
? { msg: finalMsg, ...(mentions.length > 0 && { mentions }), ...(styles.length > 0 && { styles }) }
|
|
135
|
+
: finalMsg;
|
|
34
136
|
|
|
35
137
|
const cliMsgId = String(Date.now());
|
|
36
138
|
const result = await getApi().sendMessage(msgContent, threadId, Number(opts.type));
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reminder commands — create, list, info, edit, remove reminders in users/groups.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getApi } from "../core/zalo-client.js";
|
|
6
|
+
import { success, error, info, output } from "../utils/output.js";
|
|
7
|
+
|
|
8
|
+
/** Repeat mode labels matching zca-js ReminderRepeatMode enum. */
|
|
9
|
+
const REPEAT_MODES = { none: 0, daily: 1, weekly: 2, monthly: 3 };
|
|
10
|
+
const REPEAT_LABELS = { 0: "None", 1: "Daily", 2: "Weekly", 3: "Monthly" };
|
|
11
|
+
|
|
12
|
+
/** Parse a datetime string into Unix timestamp (ms). Accepts ISO or "YYYY-MM-DD HH:mm". */
|
|
13
|
+
function parseTime(str) {
|
|
14
|
+
// Try "YYYY-MM-DD HH:mm" format
|
|
15
|
+
const match = str.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})$/);
|
|
16
|
+
if (match) {
|
|
17
|
+
const [, y, mo, d, h, mi] = match;
|
|
18
|
+
return new Date(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi)).getTime();
|
|
19
|
+
}
|
|
20
|
+
// Fallback to Date.parse (ISO, etc.)
|
|
21
|
+
const ts = Date.parse(str);
|
|
22
|
+
if (isNaN(ts)) return null;
|
|
23
|
+
return ts;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function registerReminderCommands(program) {
|
|
27
|
+
const reminder = program.command("reminder").description("Create and manage reminders in users/groups");
|
|
28
|
+
|
|
29
|
+
reminder
|
|
30
|
+
.command("create <threadId> <title>")
|
|
31
|
+
.description("Create a reminder")
|
|
32
|
+
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
33
|
+
.option("--time <datetime>", 'Reminder time: "YYYY-MM-DD HH:mm" (default: now)')
|
|
34
|
+
.option("--emoji <emoji>", "Emoji icon", "⏰")
|
|
35
|
+
.option("--repeat <mode>", "Repeat: none, daily, weekly, monthly", "none")
|
|
36
|
+
.action(async (threadId, title, opts) => {
|
|
37
|
+
try {
|
|
38
|
+
const repeatMode = REPEAT_MODES[opts.repeat];
|
|
39
|
+
if (repeatMode === undefined) {
|
|
40
|
+
error(`Invalid repeat mode: "${opts.repeat}". Valid: none, daily, weekly, monthly`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
let startTime = Date.now();
|
|
44
|
+
if (opts.time) {
|
|
45
|
+
startTime = parseTime(opts.time);
|
|
46
|
+
if (!startTime) {
|
|
47
|
+
error(`Invalid time format: "${opts.time}". Use "YYYY-MM-DD HH:mm" or ISO format.`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const result = await getApi().createReminder(
|
|
52
|
+
{ title, emoji: opts.emoji, startTime, repeat: repeatMode },
|
|
53
|
+
threadId,
|
|
54
|
+
Number(opts.type),
|
|
55
|
+
);
|
|
56
|
+
output(result, program.opts().json, () => {
|
|
57
|
+
success(`Reminder created: "${title}"`);
|
|
58
|
+
const id = result.reminderId || result.id || "?";
|
|
59
|
+
info(`Reminder ID: ${id}`);
|
|
60
|
+
info(`Time: ${new Date(startTime).toLocaleString()}`);
|
|
61
|
+
if (repeatMode > 0) info(`Repeat: ${REPEAT_LABELS[repeatMode]}`);
|
|
62
|
+
});
|
|
63
|
+
} catch (e) {
|
|
64
|
+
error(`Create reminder failed: ${e.message}`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
reminder
|
|
69
|
+
.command("list <threadId>")
|
|
70
|
+
.description("List reminders in a thread")
|
|
71
|
+
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
72
|
+
.option("-n, --count <n>", "Max results", "20")
|
|
73
|
+
.action(async (threadId, opts) => {
|
|
74
|
+
try {
|
|
75
|
+
let result;
|
|
76
|
+
try {
|
|
77
|
+
result = await getApi().getListReminder({ count: Number(opts.count) }, threadId, Number(opts.type));
|
|
78
|
+
} catch {
|
|
79
|
+
result = null;
|
|
80
|
+
}
|
|
81
|
+
const items = Array.isArray(result) ? result : [];
|
|
82
|
+
output(items, program.opts().json, () => {
|
|
83
|
+
if (items.length === 0) {
|
|
84
|
+
info("No reminders found.");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
info(`${items.length} reminder(s):`);
|
|
88
|
+
console.log();
|
|
89
|
+
for (const r of items) {
|
|
90
|
+
const id = r.reminderId || r.id || "?";
|
|
91
|
+
const title = r.params?.title || "?";
|
|
92
|
+
const time = new Date(r.startTime).toLocaleString();
|
|
93
|
+
const repeat = REPEAT_LABELS[r.repeat] || "None";
|
|
94
|
+
const emoji = r.emoji || "";
|
|
95
|
+
console.log(` ${emoji} [${id}] ${title}`);
|
|
96
|
+
console.log(` Time: ${time} | Repeat: ${repeat}`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
} catch (e) {
|
|
100
|
+
error(`List reminders failed: ${e.message}`);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
reminder
|
|
105
|
+
.command("info <reminderId>")
|
|
106
|
+
.description("View reminder details (group reminders only)")
|
|
107
|
+
.action(async (reminderId) => {
|
|
108
|
+
try {
|
|
109
|
+
const result = await getApi().getReminder(reminderId);
|
|
110
|
+
output(result, program.opts().json, () => {
|
|
111
|
+
const title = result.params?.title || "?";
|
|
112
|
+
const id = result.id || reminderId;
|
|
113
|
+
info(`Title: ${result.emoji || ""} ${title}`);
|
|
114
|
+
info(`Reminder ID: ${id}`);
|
|
115
|
+
info(`Created: ${new Date(result.createTime).toLocaleString()}`);
|
|
116
|
+
info(`Time: ${new Date(result.startTime).toLocaleString()}`);
|
|
117
|
+
info(`Repeat: ${REPEAT_LABELS[result.repeat] || "None"}`);
|
|
118
|
+
info(`Creator: ${result.creatorId}`);
|
|
119
|
+
if (result.responseMem) {
|
|
120
|
+
info(
|
|
121
|
+
`Responses: ${result.responseMem.acceptMember} accepted, ${result.responseMem.rejectMember} rejected`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
} catch (e) {
|
|
126
|
+
error(`Get reminder failed: ${e.message}`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
reminder
|
|
131
|
+
.command("responses <reminderId>")
|
|
132
|
+
.description("View who accepted/rejected a reminder (group only)")
|
|
133
|
+
.action(async (reminderId) => {
|
|
134
|
+
try {
|
|
135
|
+
const result = await getApi().getReminderResponses(reminderId);
|
|
136
|
+
output(result, program.opts().json, () => {
|
|
137
|
+
const accepted = result.acceptMember || [];
|
|
138
|
+
const rejected = result.rejectMember || [];
|
|
139
|
+
info(`Accepted (${accepted.length}):`);
|
|
140
|
+
accepted.forEach((uid) => console.log(` ✓ ${uid}`));
|
|
141
|
+
info(`Rejected (${rejected.length}):`);
|
|
142
|
+
rejected.forEach((uid) => console.log(` ✗ ${uid}`));
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
error(`Get responses failed: ${e.message}`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
reminder
|
|
150
|
+
.command("edit <reminderId> <threadId> <title>")
|
|
151
|
+
.description("Edit a reminder")
|
|
152
|
+
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
153
|
+
.option("--time <datetime>", 'New time: "YYYY-MM-DD HH:mm"')
|
|
154
|
+
.option("--emoji <emoji>", "New emoji icon")
|
|
155
|
+
.option("--repeat <mode>", "Repeat: none, daily, weekly, monthly")
|
|
156
|
+
.action(async (reminderId, threadId, title, opts) => {
|
|
157
|
+
try {
|
|
158
|
+
const editOpts = { title, topicId: reminderId };
|
|
159
|
+
if (opts.emoji) editOpts.emoji = opts.emoji;
|
|
160
|
+
if (opts.time) {
|
|
161
|
+
const ts = parseTime(opts.time);
|
|
162
|
+
if (!ts) {
|
|
163
|
+
error(`Invalid time format: "${opts.time}". Use "YYYY-MM-DD HH:mm".`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
editOpts.startTime = ts;
|
|
167
|
+
}
|
|
168
|
+
if (opts.repeat) {
|
|
169
|
+
const mode = REPEAT_MODES[opts.repeat];
|
|
170
|
+
if (mode === undefined) {
|
|
171
|
+
error(`Invalid repeat mode: "${opts.repeat}". Valid: none, daily, weekly, monthly`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
editOpts.repeat = mode;
|
|
175
|
+
}
|
|
176
|
+
const result = await getApi().editReminder(editOpts, threadId, Number(opts.type));
|
|
177
|
+
output(result, program.opts().json, () => success(`Reminder ${reminderId} updated`));
|
|
178
|
+
} catch (e) {
|
|
179
|
+
error(`Edit reminder failed: ${e.message}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
reminder
|
|
184
|
+
.command("remove <reminderId> <threadId>")
|
|
185
|
+
.description("Remove a reminder")
|
|
186
|
+
.option("-t, --type <n>", "Thread type: 0=User, 1=Group", "0")
|
|
187
|
+
.action(async (reminderId, threadId, opts) => {
|
|
188
|
+
try {
|
|
189
|
+
const result = await getApi().removeReminder(reminderId, threadId, Number(opts.type));
|
|
190
|
+
output(result, program.opts().json, () => success(`Reminder ${reminderId} removed`));
|
|
191
|
+
} catch (e) {
|
|
192
|
+
error(`Remove reminder failed: ${e.message}`);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
package/src/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import { registerConvCommands } from "./commands/conv.js";
|
|
|
20
20
|
import { registerAccountCommands } from "./commands/account.js";
|
|
21
21
|
import { registerProfileCommands } from "./commands/profile.js";
|
|
22
22
|
import { registerPollCommands } from "./commands/poll.js";
|
|
23
|
+
import { registerReminderCommands } from "./commands/reminder.js";
|
|
23
24
|
import { registerListenCommand } from "./commands/listen.js";
|
|
24
25
|
import { autoLogin } from "./core/zalo-client.js";
|
|
25
26
|
import { checkForUpdates, selfUpdate } from "./utils/update-check.js";
|
|
@@ -74,6 +75,7 @@ registerConvCommands(program);
|
|
|
74
75
|
registerAccountCommands(program);
|
|
75
76
|
registerProfileCommands(program);
|
|
76
77
|
registerPollCommands(program);
|
|
78
|
+
registerReminderCommands(program);
|
|
77
79
|
registerListenCommand(program);
|
|
78
80
|
|
|
79
81
|
program.parse();
|