@leemour/max-cli 0.13.0 → 0.15.0
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 +92 -14
- package/dist/bot/auth.d.ts +23 -0
- package/dist/bot/auth.d.ts.map +1 -0
- package/dist/bot/auth.js +36 -0
- package/dist/bot/auth.js.map +1 -0
- package/dist/bot/client.d.ts +20 -0
- package/dist/bot/client.d.ts.map +1 -0
- package/dist/bot/client.js +91 -0
- package/dist/bot/client.js.map +1 -0
- package/dist/bot/generated/manifest.d.ts +3 -0
- package/dist/bot/generated/manifest.d.ts.map +1 -0
- package/dist/bot/generated/manifest.js +1232 -0
- package/dist/bot/generated/manifest.js.map +1 -0
- package/dist/bot/generated/schemas.d.ts +271 -0
- package/dist/bot/generated/schemas.d.ts.map +1 -0
- package/dist/bot/generated/schemas.js +869 -0
- package/dist/bot/generated/schemas.js.map +1 -0
- package/dist/bot/generated/types.d.ts +1088 -0
- package/dist/bot/generated/types.d.ts.map +1 -0
- package/dist/bot/generated/types.js +5 -0
- package/dist/bot/generated/types.js.map +1 -0
- package/dist/bot/input.d.ts +10 -0
- package/dist/bot/input.d.ts.map +1 -0
- package/dist/bot/input.js +88 -0
- package/dist/bot/input.js.map +1 -0
- package/dist/bot/keep.d.ts +25 -0
- package/dist/bot/keep.d.ts.map +1 -0
- package/dist/bot/keep.js +96 -0
- package/dist/bot/keep.js.map +1 -0
- package/dist/bot/map.d.ts +11 -0
- package/dist/bot/map.d.ts.map +1 -0
- package/dist/bot/map.js +76 -0
- package/dist/bot/map.js.map +1 -0
- package/dist/bot/permissions.d.ts +14 -0
- package/dist/bot/permissions.d.ts.map +1 -0
- package/dist/bot/permissions.js +53 -0
- package/dist/bot/permissions.js.map +1 -0
- package/dist/bot/registry.d.ts +30 -0
- package/dist/bot/registry.d.ts.map +1 -0
- package/dist/bot/registry.js +85 -0
- package/dist/bot/registry.js.map +1 -0
- package/dist/bot/russian-trusted-root.d.ts +8 -0
- package/dist/bot/russian-trusted-root.d.ts.map +1 -0
- package/dist/bot/russian-trusted-root.js +41 -0
- package/dist/bot/russian-trusted-root.js.map +1 -0
- package/dist/bot/transport.d.ts +41 -0
- package/dist/bot/transport.d.ts.map +1 -0
- package/dist/bot/transport.js +200 -0
- package/dist/bot/transport.js.map +1 -0
- package/dist/bot/uploads.d.ts +34 -0
- package/dist/bot/uploads.d.ts.map +1 -0
- package/dist/bot/uploads.js +122 -0
- package/dist/bot/uploads.js.map +1 -0
- package/dist/client.d.ts +39 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +168 -23
- package/dist/client.js.map +1 -1
- package/dist/commands/bot-comments.d.ts +4 -0
- package/dist/commands/bot-comments.d.ts.map +1 -0
- package/dist/commands/bot-comments.js +97 -0
- package/dist/commands/bot-comments.js.map +1 -0
- package/dist/commands/bot-context.d.ts +27 -0
- package/dist/commands/bot-context.d.ts.map +1 -0
- package/dist/commands/bot-context.js +82 -0
- package/dist/commands/bot-context.js.map +1 -0
- package/dist/commands/bot-members.d.ts +12 -0
- package/dist/commands/bot-members.d.ts.map +1 -0
- package/dist/commands/bot-members.js +136 -0
- package/dist/commands/bot-members.js.map +1 -0
- package/dist/commands/bot-reads.d.ts +7 -0
- package/dist/commands/bot-reads.d.ts.map +1 -0
- package/dist/commands/bot-reads.js +145 -0
- package/dist/commands/bot-reads.js.map +1 -0
- package/dist/commands/bot-sends.d.ts +17 -0
- package/dist/commands/bot-sends.d.ts.map +1 -0
- package/dist/commands/bot-sends.js +270 -0
- package/dist/commands/bot-sends.js.map +1 -0
- package/dist/commands/bot-setup.d.ts +5 -0
- package/dist/commands/bot-setup.d.ts.map +1 -0
- package/dist/commands/bot-setup.js +107 -0
- package/dist/commands/bot-setup.js.map +1 -0
- package/dist/commands/bot-updates.d.ts +3 -0
- package/dist/commands/bot-updates.d.ts.map +1 -0
- package/dist/commands/bot-updates.js +182 -0
- package/dist/commands/bot-updates.js.map +1 -0
- package/dist/commands/bot.d.ts +3 -0
- package/dist/commands/bot.d.ts.map +1 -0
- package/dist/commands/bot.js +160 -0
- package/dist/commands/bot.js.map +1 -0
- package/dist/commands/chats.d.ts.map +1 -1
- package/dist/commands/chats.js +79 -2
- package/dist/commands/chats.js.map +1 -1
- package/dist/commands/check.d.ts +8 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +64 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/context.d.ts +15 -1
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +5 -1
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/hearing.d.ts +25 -0
- package/dist/commands/hearing.d.ts.map +1 -0
- package/dist/commands/hearing.js +41 -0
- package/dist/commands/hearing.js.map +1 -0
- package/dist/commands/inbox.d.ts.map +1 -1
- package/dist/commands/inbox.js +19 -3
- package/dist/commands/inbox.js.map +1 -1
- package/dist/commands/mcp.d.ts +1 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +7 -4
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/messages.d.ts.map +1 -1
- package/dist/commands/messages.js +21 -5
- package/dist/commands/messages.js.map +1 -1
- package/dist/commands/paging.d.ts +3 -1
- package/dist/commands/paging.d.ts.map +1 -1
- package/dist/commands/paging.js +4 -1
- package/dist/commands/paging.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +22 -8
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/rules.d.ts +7 -0
- package/dist/commands/rules.d.ts.map +1 -0
- package/dist/commands/rules.js +69 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/domain/map.d.ts +6 -1
- package/dist/domain/map.d.ts.map +1 -1
- package/dist/domain/map.js +34 -1
- package/dist/domain/map.js.map +1 -1
- package/dist/domain/models.d.ts +55 -0
- package/dist/domain/models.d.ts.map +1 -1
- package/dist/domain/models.js.map +1 -1
- package/dist/generated/client.generated.d.ts +1 -0
- package/dist/generated/client.generated.d.ts.map +1 -1
- package/dist/generated/client.generated.js +1 -0
- package/dist/generated/client.generated.js.map +1 -1
- package/dist/generated/opcodes.generated.d.ts +1 -0
- package/dist/generated/opcodes.generated.d.ts.map +1 -1
- package/dist/generated/opcodes.generated.js +1 -0
- package/dist/generated/opcodes.generated.js.map +1 -1
- package/dist/generated/operations.generated.d.ts +16 -1
- package/dist/generated/operations.generated.d.ts.map +1 -1
- package/dist/generated/operations.generated.js +2 -1
- package/dist/generated/operations.generated.js.map +1 -1
- package/dist/mcp/instructions.d.ts +2 -1
- package/dist/mcp/instructions.d.ts.map +1 -1
- package/dist/mcp/instructions.js +2 -1
- package/dist/mcp/instructions.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +4 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +5 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +160 -13
- package/dist/mcp/tools.js.map +1 -1
- package/dist/moderation/check.d.ts +98 -0
- package/dist/moderation/check.d.ts.map +1 -0
- package/dist/moderation/check.js +306 -0
- package/dist/moderation/check.js.map +1 -0
- package/dist/moderation/rules.d.ts +56 -0
- package/dist/moderation/rules.d.ts.map +1 -0
- package/dist/moderation/rules.js +138 -0
- package/dist/moderation/rules.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +18 -3
- package/dist/program.js.map +1 -1
- package/dist/protocol/connection.d.ts.map +1 -1
- package/dist/protocol/connection.js +12 -1
- package/dist/protocol/connection.js.map +1 -1
- package/dist/review.d.ts +32 -5
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +82 -45
- package/dist/review.js.map +1 -1
- package/dist/sends/journal.d.ts +1 -1
- package/dist/sends/journal.d.ts.map +1 -1
- package/dist/session/store.d.ts +2 -0
- package/dist/session/store.d.ts.map +1 -1
- package/dist/session/store.js +2 -0
- package/dist/session/store.js.map +1 -1
- package/dist/spec/index.d.ts.map +1 -1
- package/dist/spec/index.js +2 -1
- package/dist/spec/index.js.map +1 -1
- package/dist/spec/operations/chats.d.ts +4 -1
- package/dist/spec/operations/chats.d.ts.map +1 -1
- package/dist/spec/operations/chats.js +10 -4
- package/dist/spec/operations/chats.js.map +1 -1
- package/dist/spec/operations/messages.d.ts.map +1 -1
- package/dist/spec/operations/messages.js +9 -4
- package/dist/spec/operations/messages.js.map +1 -1
- package/dist/spec/operations/uploads.d.ts +13 -0
- package/dist/spec/operations/uploads.d.ts.map +1 -1
- package/dist/spec/operations/uploads.js +21 -0
- package/dist/spec/operations/uploads.js.map +1 -1
- package/dist/transcribe/index.d.ts +36 -1
- package/dist/transcribe/index.d.ts.map +1 -1
- package/dist/transcribe/index.js +91 -14
- package/dist/transcribe/index.js.map +1 -1
- package/dist/upload.d.ts +3 -0
- package/dist/upload.d.ts.map +1 -1
- package/dist/upload.js +13 -7
- package/dist/upload.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/voice.d.ts +9 -0
- package/dist/voice.d.ts.map +1 -0
- package/dist/voice.js +36 -0
- package/dist/voice.js.map +1 -0
- package/package.json +17 -6
- package/skills/max-cli/SKILL.md +23 -2
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { CliError } from "@leemour/cli-core";
|
|
2
|
+
import { defaultRules, ModerationRules, moderationPathFor } from "./rules.js";
|
|
3
|
+
const INVITE = /max\.ru\/join\//i;
|
|
4
|
+
const LINK = /https?:\/\/\S+/i;
|
|
5
|
+
/** Which action wins when a message breaks several rules; the first rule listed breaks a tie. */
|
|
6
|
+
const STRENGTH = { report: 0, delete: 1, remove: 2 };
|
|
7
|
+
/**
|
|
8
|
+
* What the rules say about what is new. Pure: nothing here talks to MAX. One finding per message —
|
|
9
|
+
* the rule with the strongest action — and one removal per person, whatever else they did.
|
|
10
|
+
*/
|
|
11
|
+
export const judge = ({ rules, messages, joined, requests, answerers, now }) => {
|
|
12
|
+
const trusted = new Set(rules.trusted);
|
|
13
|
+
const blocked = (id, name) => (id !== null && rules.blocked.includes(id)) ||
|
|
14
|
+
(name !== null && rules.blockedNames.some((part) => name.toLocaleLowerCase().includes(part.toLocaleLowerCase())));
|
|
15
|
+
const young = (member) => rules.newAccount.days > 0 &&
|
|
16
|
+
member.registeredAt !== null &&
|
|
17
|
+
now - Date.parse(member.registeredAt) < rules.newAccount.days * 86_400_000;
|
|
18
|
+
const found = [];
|
|
19
|
+
const add = (finding) => {
|
|
20
|
+
if (finding.action === "remove" && found.some((f) => f.action === "remove" && f.personId === finding.personId)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
found.push(finding);
|
|
24
|
+
};
|
|
25
|
+
for (const request of requests) {
|
|
26
|
+
const person = { kind: "request", personId: request.id, personName: request.name };
|
|
27
|
+
const policy = rules.requests;
|
|
28
|
+
if (trusted.has(request.id) && (policy === "accept-trusted" || policy === "both")) {
|
|
29
|
+
add({ ...person, rule: "trusted", action: "accept" });
|
|
30
|
+
}
|
|
31
|
+
else if (blocked(request.id, request.name)) {
|
|
32
|
+
add({
|
|
33
|
+
...person,
|
|
34
|
+
rule: "blocked",
|
|
35
|
+
action: policy === "decline-blocked" || policy === "both" ? "decline" : "report",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else if (young(request)) {
|
|
39
|
+
add({ ...person, rule: "newAccount", action: rules.newAccount.action === "remove" ? "decline" : "report" });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
add({ ...person, rule: "request", action: "report" });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const member of joined) {
|
|
46
|
+
if (trusted.has(member.id) || answerers.has(member.id))
|
|
47
|
+
continue;
|
|
48
|
+
const person = { kind: "member", personId: member.id, personName: member.name };
|
|
49
|
+
if (blocked(member.id, member.name)) {
|
|
50
|
+
add({ ...person, rule: "blocked", action: rules.blockedPeople === "remove" ? "remove" : "report" });
|
|
51
|
+
}
|
|
52
|
+
else if (young(member)) {
|
|
53
|
+
add({ ...person, rule: "newAccount", action: rules.newAccount.action });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const flooding = floodOf(messages, rules.flood);
|
|
57
|
+
for (const message of messages) {
|
|
58
|
+
const id = message.senderId;
|
|
59
|
+
if (id === null || message.outgoing === true || answerers.has(id) || trusted.has(id))
|
|
60
|
+
continue;
|
|
61
|
+
if (message.attachments.some((attachment) => attachment.kind === "control"))
|
|
62
|
+
continue;
|
|
63
|
+
const base = { kind: "message", personId: id, personName: message.senderName, messageId: message.id };
|
|
64
|
+
const text = message.text;
|
|
65
|
+
const broken = [];
|
|
66
|
+
if (blocked(id, message.senderName))
|
|
67
|
+
broken.push(["blocked", rules.blockedPeople]);
|
|
68
|
+
if (INVITE.test(text))
|
|
69
|
+
broken.push(["invites", rules.invites]);
|
|
70
|
+
if (LINK.test(text) || message.attachments.some((attachment) => attachment.kind === "share")) {
|
|
71
|
+
broken.push(["links", rules.links]);
|
|
72
|
+
}
|
|
73
|
+
if (message.forwardedFrom !== null)
|
|
74
|
+
broken.push(["forwards", rules.forwards]);
|
|
75
|
+
if (flooding.has(message.id))
|
|
76
|
+
broken.push(["flood", rules.flood.action]);
|
|
77
|
+
const strongest = broken.reduce((best, rule) => (best === undefined || STRENGTH[rule[1]] > STRENGTH[best[1]] ? rule : best), undefined);
|
|
78
|
+
if (strongest)
|
|
79
|
+
add({ ...base, rule: strongest[0], action: strongest[1] });
|
|
80
|
+
}
|
|
81
|
+
return found;
|
|
82
|
+
};
|
|
83
|
+
/** Messages past the limit: more than `messages` from one person within `minutes`. */
|
|
84
|
+
const floodOf = (messages, flood) => {
|
|
85
|
+
const window = flood.minutes * 60_000;
|
|
86
|
+
const over = new Set();
|
|
87
|
+
const bySender = new Map();
|
|
88
|
+
for (const message of messages) {
|
|
89
|
+
if (message.senderId === null)
|
|
90
|
+
continue;
|
|
91
|
+
const times = bySender.get(message.senderId) ?? [];
|
|
92
|
+
const at = Date.parse(message.timestamp);
|
|
93
|
+
times.push(at);
|
|
94
|
+
bySender.set(message.senderId, times);
|
|
95
|
+
if (times.filter((time) => at - time < window).length > flood.messages)
|
|
96
|
+
over.add(message.id);
|
|
97
|
+
}
|
|
98
|
+
return over;
|
|
99
|
+
};
|
|
100
|
+
const CONSENT = {
|
|
101
|
+
delete: "delete",
|
|
102
|
+
remove: "remove",
|
|
103
|
+
accept: "accept",
|
|
104
|
+
decline: "decline",
|
|
105
|
+
};
|
|
106
|
+
/** The personal account: deleting is for everyone, removing leaves messages and cannot ban. */
|
|
107
|
+
export const personal = (client) => ({
|
|
108
|
+
deleteMessage: async (chatId, messageId) => {
|
|
109
|
+
await client.messages.delete(chatId, [messageId], { forEveryone: true });
|
|
110
|
+
},
|
|
111
|
+
removePerson: async (chatId, personId) => {
|
|
112
|
+
await client.chats.members.remove(chatId, [personId]);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
export const act = async (moderator, findings, options) => {
|
|
116
|
+
const { chatId, rules, allowDangerous, dryRun, maxActions, confirm } = options;
|
|
117
|
+
const rows = [];
|
|
118
|
+
let acted = 0;
|
|
119
|
+
let stopped;
|
|
120
|
+
for (const finding of findings) {
|
|
121
|
+
if (finding.action === "report") {
|
|
122
|
+
rows.push({ ...finding, outcome: "reported" });
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const command = commandFor(chatId, finding);
|
|
126
|
+
const level = rules.consent[CONSENT[finding.action]];
|
|
127
|
+
const row = (outcome, reason) => ({
|
|
128
|
+
...finding,
|
|
129
|
+
outcome,
|
|
130
|
+
...(reason ? { reason } : {}),
|
|
131
|
+
...(outcome === "done" ? {} : { command }),
|
|
132
|
+
});
|
|
133
|
+
if (level === "forbid") {
|
|
134
|
+
rows.push(row("forbidden", `consent.${CONSENT[finding.action]} is forbid`));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (finding.action === "accept" || finding.action === "decline") {
|
|
138
|
+
rows.push(row("planned", "accepting and declining are not measured against MAX yet (MAX-41)"));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (dryRun) {
|
|
142
|
+
rows.push(row("planned", "--dry-run"));
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (level === "flag" && !allowDangerous) {
|
|
146
|
+
rows.push(row("planned", `consent.${CONSENT[finding.action]} is flag — run with --allow-dangerous`));
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (stopped || acted >= maxActions) {
|
|
150
|
+
rows.push(row("skipped", stopped ?? `over the limit of ${maxActions} actions per check`));
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (level === "confirm") {
|
|
154
|
+
if (!confirm) {
|
|
155
|
+
rows.push(row("planned", `consent.${CONSENT[finding.action]} is confirm, and nobody is there to ask`));
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (!(await confirm(finding))) {
|
|
159
|
+
rows.push(row("declined", "not confirmed"));
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
acted += 1;
|
|
164
|
+
try {
|
|
165
|
+
if (finding.action === "delete" && finding.messageId) {
|
|
166
|
+
await moderator.deleteMessage(chatId, finding.messageId);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
await moderator.removePerson(chatId, finding.personId);
|
|
170
|
+
}
|
|
171
|
+
rows.push(row("done"));
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
const failure = asCliError(error);
|
|
175
|
+
if (failure.code === "rate_limited")
|
|
176
|
+
stopped = failure.message;
|
|
177
|
+
const refused = ["rate_limited", "permission_error", "confirmation_required"].includes(failure.code);
|
|
178
|
+
rows.push(row(refused ? "refused" : "failed", failure.message));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return rows;
|
|
182
|
+
};
|
|
183
|
+
const asCliError = (error) => error instanceof CliError
|
|
184
|
+
? error
|
|
185
|
+
: new CliError("provider_error", error instanceof Error ? error.message : String(error));
|
|
186
|
+
const who = (finding) => finding.personName ?? finding.personId;
|
|
187
|
+
/** One action in words, for a prompt or a confirmation form. */
|
|
188
|
+
export const describe = (finding) => finding.action === "delete"
|
|
189
|
+
? `delete message ${finding.messageId} from ${who(finding)} for everyone (${finding.rule})`
|
|
190
|
+
: `remove ${who(finding)} from the group (${finding.rule})`;
|
|
191
|
+
/** Whether acting on it waits for the owner's yes. */
|
|
192
|
+
export const needsConfirm = (rules, finding) => (finding.action === "delete" || finding.action === "remove") && rules.consent[finding.action] === "confirm";
|
|
193
|
+
const commandFor = (chatId, finding) => {
|
|
194
|
+
switch (finding.action) {
|
|
195
|
+
case "delete":
|
|
196
|
+
return `max messages delete ${chatId} ${finding.messageId} --for-everyone --allow-dangerous`;
|
|
197
|
+
case "remove":
|
|
198
|
+
return `max chats members remove ${chatId} ${finding.personId}`;
|
|
199
|
+
case "accept":
|
|
200
|
+
return `max chats requests accept ${chatId} ${finding.personId}`;
|
|
201
|
+
case "decline":
|
|
202
|
+
return `max chats requests decline ${chatId} ${finding.personId}`;
|
|
203
|
+
default:
|
|
204
|
+
return "";
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* What is new in the group since `since`: its messages, who joined (from the service messages —
|
|
209
|
+
* `add` measured, `joinByLink` assumed to name the joiner or be sent by them), who asks to join,
|
|
210
|
+
* and who the admins are.
|
|
211
|
+
*/
|
|
212
|
+
export const gather = async (client, chatId, since) => {
|
|
213
|
+
const notes = [];
|
|
214
|
+
const { messages, more } = await client.chats.since(chatId, since);
|
|
215
|
+
const joinedIds = new Set(messages.flatMap((message) => message.attachments.flatMap((attachment) => {
|
|
216
|
+
if (attachment.event === "add")
|
|
217
|
+
return attachment.userIds ?? [];
|
|
218
|
+
if (attachment.event === "joinByLink") {
|
|
219
|
+
return attachment.userIds?.length ? attachment.userIds : message.senderId ? [message.senderId] : [];
|
|
220
|
+
}
|
|
221
|
+
return [];
|
|
222
|
+
})));
|
|
223
|
+
const joined = joinedIds.size === 0
|
|
224
|
+
? []
|
|
225
|
+
: (await client.chats.members.list(chatId)).members.filter((member) => joinedIds.has(member.id));
|
|
226
|
+
let requests = [];
|
|
227
|
+
try {
|
|
228
|
+
requests = await client.chats.requests.list(chatId);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
notes.push(`join requests not read: ${asCliError(error).message}`);
|
|
232
|
+
}
|
|
233
|
+
const admins = await client.chats.adminIds(chatId);
|
|
234
|
+
if (admins === undefined)
|
|
235
|
+
notes.push("the group's admins are not known, so only your own messages are exempt");
|
|
236
|
+
return {
|
|
237
|
+
messages,
|
|
238
|
+
joined,
|
|
239
|
+
requests,
|
|
240
|
+
answerers: new Set(admins ?? []),
|
|
241
|
+
until: messages.at(-1)?.timestamp ?? null,
|
|
242
|
+
more,
|
|
243
|
+
notes,
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
export const MAX_ACTIONS = 10;
|
|
247
|
+
/** A group never checked before is looked at this far back. */
|
|
248
|
+
const FIRST_LOOK_MS = 24 * 3_600_000;
|
|
249
|
+
/** Reads and judges; changes nothing. `since` overrides the group's saved point. */
|
|
250
|
+
export const prepare = async (client, { store, profile, chat, since }) => {
|
|
251
|
+
const group = await client.chats.show(chat);
|
|
252
|
+
const saved = new ModerationRules(moderationPathFor(profile)).read(group.id);
|
|
253
|
+
const rules = saved ?? defaultRules(group.title);
|
|
254
|
+
const point = store.readState().checkedUntil?.[group.id];
|
|
255
|
+
const from = since ?? (point === undefined ? Date.now() - FIRST_LOOK_MS : Date.parse(point));
|
|
256
|
+
const found = await gather(client, group.id, from);
|
|
257
|
+
return {
|
|
258
|
+
chatId: group.id,
|
|
259
|
+
title: group.title,
|
|
260
|
+
rules,
|
|
261
|
+
found,
|
|
262
|
+
findings: judge({ ...found, rules, now: Date.now() }),
|
|
263
|
+
explicit: since !== undefined,
|
|
264
|
+
notes: [
|
|
265
|
+
...(saved ? [] : [`${group.title ?? group.id} has no rules yet — the defaults only report`]),
|
|
266
|
+
...found.notes,
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
/** Acts on what `prepare` found, moves the group's saved point, and says what is left. */
|
|
271
|
+
export const finish = async (moderator, store, prepared, options) => {
|
|
272
|
+
const { chatId, rules, found, findings, explicit } = prepared;
|
|
273
|
+
const rows = await act(moderator, findings, { ...options, chatId, rules });
|
|
274
|
+
const notes = [...prepared.notes];
|
|
275
|
+
const next = nextPoint(rows, found);
|
|
276
|
+
if (!explicit && !options.dryRun && next !== null) {
|
|
277
|
+
const state = store.readState();
|
|
278
|
+
store.writeState({ ...state, checkedUntil: { ...state.checkedUntil, [chatId]: next } });
|
|
279
|
+
}
|
|
280
|
+
if (next !== found.until && rows.some(undone)) {
|
|
281
|
+
notes.push("some actions are not done — the next check starts at the first of them");
|
|
282
|
+
}
|
|
283
|
+
else if (found.more) {
|
|
284
|
+
notes.push("more history than one check reads — the next check goes on from here");
|
|
285
|
+
}
|
|
286
|
+
return { rows, notes };
|
|
287
|
+
};
|
|
288
|
+
const undone = (row) => ["planned", "skipped", "failed"].includes(row.outcome) && row.kind !== "request";
|
|
289
|
+
/**
|
|
290
|
+
* Where the next check starts: after the newest message read, or just before the first message whose
|
|
291
|
+
* action is still undone — so it is judged again, and what came after it is still read. A person
|
|
292
|
+
* who joined and is still undone keeps the point where it was, since the join is not a row's message.
|
|
293
|
+
*/
|
|
294
|
+
const nextPoint = (rows, found) => {
|
|
295
|
+
const waiting = rows.filter(undone);
|
|
296
|
+
if (waiting.some((row) => row.messageId === undefined))
|
|
297
|
+
return null;
|
|
298
|
+
const times = waiting
|
|
299
|
+
.map((row) => found.messages.find((message) => message.id === row.messageId)?.timestamp)
|
|
300
|
+
.filter((time) => time !== undefined)
|
|
301
|
+
.map(Date.parse);
|
|
302
|
+
if (times.length === 0)
|
|
303
|
+
return found.until;
|
|
304
|
+
return new Date(Math.min(...times) - 1).toISOString();
|
|
305
|
+
};
|
|
306
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/moderation/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import type { Id } from "../domain/models.js";
|
|
3
|
+
/** How much say the owner keeps over one kind of action (`NEED-308`). */
|
|
4
|
+
export declare const CONSENT_LEVELS: readonly ["forbid", "flag", "confirm", "allow"];
|
|
5
|
+
/** What a rule does with what it finds; nothing but `report` acts until consent lets it. */
|
|
6
|
+
export declare const RULE_ACTIONS: readonly ["report", "delete", "remove"];
|
|
7
|
+
export declare const REQUEST_POLICIES: readonly ["report", "accept-trusted", "decline-blocked", "both"];
|
|
8
|
+
declare const groupRules: v.StrictObjectSchema<{
|
|
9
|
+
readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
10
|
+
readonly trusted: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a person id is digits">]>, undefined>;
|
|
11
|
+
readonly blocked: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a person id is digits">]>, undefined>;
|
|
12
|
+
readonly blockedNames: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
13
|
+
readonly links: v.PicklistSchema<readonly ["report", "delete", "remove"], undefined>;
|
|
14
|
+
readonly invites: v.PicklistSchema<readonly ["report", "delete", "remove"], undefined>;
|
|
15
|
+
readonly forwards: v.PicklistSchema<readonly ["report", "delete", "remove"], undefined>;
|
|
16
|
+
readonly blockedPeople: v.PicklistSchema<readonly ["report", "delete", "remove"], undefined>;
|
|
17
|
+
readonly flood: v.StrictObjectSchema<{
|
|
18
|
+
readonly messages: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, number, undefined>]>;
|
|
19
|
+
readonly minutes: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, number, undefined>]>;
|
|
20
|
+
readonly action: v.PicklistSchema<readonly ["report", "delete", "remove"], undefined>;
|
|
21
|
+
}, undefined>;
|
|
22
|
+
/** `remove` declines a join request and removes a member. 0 days turns the rule off. */
|
|
23
|
+
readonly newAccount: v.StrictObjectSchema<{
|
|
24
|
+
readonly days: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, number, undefined>]>;
|
|
25
|
+
readonly action: v.PicklistSchema<["report", "remove"], undefined>;
|
|
26
|
+
}, undefined>;
|
|
27
|
+
readonly requests: v.PicklistSchema<readonly ["report", "accept-trusted", "decline-blocked", "both"], undefined>;
|
|
28
|
+
readonly consent: v.StrictObjectSchema<{
|
|
29
|
+
readonly delete: v.PicklistSchema<readonly ["forbid", "flag", "confirm", "allow"], undefined>;
|
|
30
|
+
readonly remove: v.PicklistSchema<readonly ["forbid", "flag", "confirm", "allow"], undefined>;
|
|
31
|
+
readonly accept: v.PicklistSchema<readonly ["forbid", "flag", "confirm", "allow"], undefined>;
|
|
32
|
+
readonly decline: v.PicklistSchema<readonly ["forbid", "flag", "confirm", "allow"], undefined>;
|
|
33
|
+
}, undefined>;
|
|
34
|
+
}, undefined>;
|
|
35
|
+
export type GroupRules = v.InferOutput<typeof groupRules>;
|
|
36
|
+
/** Every key written out, so the file shows all there is to set (`NEED-314`). Nothing here acts. */
|
|
37
|
+
export declare const defaultRules: (title: string | null) => GroupRules;
|
|
38
|
+
export declare const RULE_KEYS: string[];
|
|
39
|
+
export declare const moderationPathFor: (profile: string, env?: NodeJS.ProcessEnv) => string;
|
|
40
|
+
/**
|
|
41
|
+
* The rules of each group this profile moderates, one state file per profile beside the recipient
|
|
42
|
+
* list. May be edited by hand; a file that does not check out refuses rather than being guessed at.
|
|
43
|
+
*/
|
|
44
|
+
export declare class ModerationRules {
|
|
45
|
+
#private;
|
|
46
|
+
readonly path: string;
|
|
47
|
+
constructor(path: string);
|
|
48
|
+
/** `undefined` when this group has no section yet. */
|
|
49
|
+
read(chatId: Id): GroupRules | undefined;
|
|
50
|
+
/** Writes the group's whole section — the defaults first, if it had none — with one key changed. */
|
|
51
|
+
set(chatId: Id, title: string | null, key: string, value: string): GroupRules;
|
|
52
|
+
/** Puts one key back to its default. */
|
|
53
|
+
unset(chatId: Id, title: string | null, key: string): GroupRules;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/moderation/rules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAA;AAE7C,yEAAyE;AACzE,eAAO,MAAM,cAAc,YAAI,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAU,CAAA;AAC7E,4FAA4F;AAC5F,eAAO,MAAM,YAAY,YAAI,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAA;AACnE,eAAO,MAAM,gBAAgB,YAAI,QAAQ,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,CAAU,CAAA;AAOhG,QAAA,MAAM,UAAU;;;;;;;;;;;;;;IAUd,wFAAwF;;;;;;;;;;;;aAIxF,CAAA;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,UAAU,CAAC,CAAA;AAIzD,oGAAoG;AACpG,eAAO,MAAM,YAAY,UAAW,MAAM,GAAG,IAAI,KAAG,UAalD,CAAA;AA+BF,eAAO,MAAM,SAAS,UAAoB,CAAA;AAE1C,eAAO,MAAM,iBAAiB,YAAa,MAAM,QAAO,MAAM,CAAC,UAAU,KAAiB,MACsB,CAAA;AAEhH;;;GAGG;AACH,qBAAa,eAAe;;IACd,QAAQ,CAAC,IAAI,EAAE,MAAM;IAAjC,YAAqB,IAAI,EAAE,MAAM,EAAI;IAErC,sDAAsD;IACtD,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,UAAU,GAAG,SAAS,CAEvC;IAED,oGAAoG;IACpG,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAS5E;IAED,wCAAwC;IACxC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAO/D;CAqBF"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { CliError, resolvePaths, writeSecurely } from "@leemour/cli-core";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
/** How much say the owner keeps over one kind of action (`NEED-308`). */
|
|
6
|
+
export const CONSENT_LEVELS = ["forbid", "flag", "confirm", "allow"];
|
|
7
|
+
/** What a rule does with what it finds; nothing but `report` acts until consent lets it. */
|
|
8
|
+
export const RULE_ACTIONS = ["report", "delete", "remove"];
|
|
9
|
+
export const REQUEST_POLICIES = ["report", "accept-trusted", "decline-blocked", "both"];
|
|
10
|
+
const level = v.picklist(CONSENT_LEVELS);
|
|
11
|
+
const action = v.picklist(RULE_ACTIONS);
|
|
12
|
+
const personIds = v.array(v.pipe(v.string(), v.regex(/^\d+$/, "a person id is digits")));
|
|
13
|
+
const atLeast = (min) => v.pipe(v.number(), v.integer(), v.minValue(min));
|
|
14
|
+
const groupRules = v.strictObject({
|
|
15
|
+
title: v.nullable(v.string()),
|
|
16
|
+
trusted: personIds,
|
|
17
|
+
blocked: personIds,
|
|
18
|
+
blockedNames: v.array(v.pipe(v.string(), v.minLength(1))),
|
|
19
|
+
links: action,
|
|
20
|
+
invites: action,
|
|
21
|
+
forwards: action,
|
|
22
|
+
blockedPeople: action,
|
|
23
|
+
flood: v.strictObject({ messages: atLeast(1), minutes: atLeast(1), action }),
|
|
24
|
+
/** `remove` declines a join request and removes a member. 0 days turns the rule off. */
|
|
25
|
+
newAccount: v.strictObject({ days: atLeast(0), action: v.picklist(["report", "remove"]) }),
|
|
26
|
+
requests: v.picklist(REQUEST_POLICIES),
|
|
27
|
+
consent: v.strictObject({ delete: level, remove: level, accept: level, decline: level }),
|
|
28
|
+
});
|
|
29
|
+
const file = v.strictObject({ groups: v.record(v.string(), groupRules) });
|
|
30
|
+
/** Every key written out, so the file shows all there is to set (`NEED-314`). Nothing here acts. */
|
|
31
|
+
export const defaultRules = (title) => ({
|
|
32
|
+
title,
|
|
33
|
+
trusted: [],
|
|
34
|
+
blocked: [],
|
|
35
|
+
blockedNames: [],
|
|
36
|
+
links: "report",
|
|
37
|
+
invites: "report",
|
|
38
|
+
forwards: "report",
|
|
39
|
+
blockedPeople: "report",
|
|
40
|
+
flood: { messages: 5, minutes: 1, action: "report" },
|
|
41
|
+
newAccount: { days: 7, action: "report" },
|
|
42
|
+
requests: "report",
|
|
43
|
+
consent: { delete: "flag", remove: "flag", accept: "flag", decline: "flag" },
|
|
44
|
+
});
|
|
45
|
+
const list = (value) => value
|
|
46
|
+
.split(",")
|
|
47
|
+
.map((item) => item.trim())
|
|
48
|
+
.filter(Boolean);
|
|
49
|
+
const whole = (value) => (/^\d+$/.test(value.trim()) ? Number(value) : Number.NaN);
|
|
50
|
+
/** What `rules set` accepts, and how its text becomes the stored value. */
|
|
51
|
+
const KEYS = {
|
|
52
|
+
trusted: { help: "person ids, comma-separated; never acted on", parse: list },
|
|
53
|
+
blocked: { help: "person ids, comma-separated", parse: list },
|
|
54
|
+
blockedNames: { help: "parts of a name, comma-separated, any case", parse: list },
|
|
55
|
+
links: { help: RULE_ACTIONS.join("|"), parse: String },
|
|
56
|
+
invites: { help: RULE_ACTIONS.join("|"), parse: String },
|
|
57
|
+
forwards: { help: RULE_ACTIONS.join("|"), parse: String },
|
|
58
|
+
blockedPeople: { help: RULE_ACTIONS.join("|"), parse: String },
|
|
59
|
+
"flood.messages": { help: "a whole number, 1 or more", parse: whole },
|
|
60
|
+
"flood.minutes": { help: "a whole number, 1 or more", parse: whole },
|
|
61
|
+
"flood.action": { help: RULE_ACTIONS.join("|"), parse: String },
|
|
62
|
+
"newAccount.days": { help: "a whole number; 0 turns it off", parse: whole },
|
|
63
|
+
"newAccount.action": { help: "report|remove", parse: String },
|
|
64
|
+
requests: { help: REQUEST_POLICIES.join("|"), parse: String },
|
|
65
|
+
"consent.delete": { help: CONSENT_LEVELS.join("|"), parse: String },
|
|
66
|
+
"consent.remove": { help: CONSENT_LEVELS.join("|"), parse: String },
|
|
67
|
+
"consent.accept": { help: CONSENT_LEVELS.join("|"), parse: String },
|
|
68
|
+
"consent.decline": { help: CONSENT_LEVELS.join("|"), parse: String },
|
|
69
|
+
};
|
|
70
|
+
export const RULE_KEYS = Object.keys(KEYS);
|
|
71
|
+
export const moderationPathFor = (profile, env = process.env) => join(resolvePaths({ appName: "max-cli", prefix: "MAX", env }).state, "profiles", `${profile}.moderation.json`);
|
|
72
|
+
/**
|
|
73
|
+
* The rules of each group this profile moderates, one state file per profile beside the recipient
|
|
74
|
+
* list. May be edited by hand; a file that does not check out refuses rather than being guessed at.
|
|
75
|
+
*/
|
|
76
|
+
export class ModerationRules {
|
|
77
|
+
path;
|
|
78
|
+
constructor(path) {
|
|
79
|
+
this.path = path;
|
|
80
|
+
}
|
|
81
|
+
/** `undefined` when this group has no section yet. */
|
|
82
|
+
read(chatId) {
|
|
83
|
+
return this.#all()[chatId];
|
|
84
|
+
}
|
|
85
|
+
/** Writes the group's whole section — the defaults first, if it had none — with one key changed. */
|
|
86
|
+
set(chatId, title, key, value) {
|
|
87
|
+
const known = KEYS[key];
|
|
88
|
+
if (!known)
|
|
89
|
+
throw invalid(`no rule ${key} — one of: ${RULE_KEYS.join(", ")}`);
|
|
90
|
+
const current = this.read(chatId) ?? defaultRules(title);
|
|
91
|
+
const changed = assign(current, key, known.parse(value));
|
|
92
|
+
const checked = v.safeParse(groupRules, changed);
|
|
93
|
+
if (!checked.success)
|
|
94
|
+
throw invalid(`${key} ${JSON.stringify(value)} is not valid — ${known.help}`);
|
|
95
|
+
this.#write({ ...this.#all(), [chatId]: checked.output });
|
|
96
|
+
return checked.output;
|
|
97
|
+
}
|
|
98
|
+
/** Puts one key back to its default. */
|
|
99
|
+
unset(chatId, title, key) {
|
|
100
|
+
if (!KEYS[key])
|
|
101
|
+
throw invalid(`no rule ${key} — one of: ${RULE_KEYS.join(", ")}`);
|
|
102
|
+
const fallback = lookup(defaultRules(title), key);
|
|
103
|
+
const current = this.read(chatId) ?? defaultRules(title);
|
|
104
|
+
const changed = assign(current, key, fallback);
|
|
105
|
+
this.#write({ ...this.#all(), [chatId]: changed });
|
|
106
|
+
return changed;
|
|
107
|
+
}
|
|
108
|
+
#all() {
|
|
109
|
+
if (!existsSync(this.path))
|
|
110
|
+
return {};
|
|
111
|
+
let parsed;
|
|
112
|
+
try {
|
|
113
|
+
parsed = JSON.parse(readFileSync(this.path, "utf8"));
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw broken(this.path, error instanceof Error ? error.message : String(error));
|
|
117
|
+
}
|
|
118
|
+
const checked = v.safeParse(file, parsed);
|
|
119
|
+
if (!checked.success) {
|
|
120
|
+
const problems = checked.issues.map((issue) => `${v.getDotPath(issue) ?? "file"}: ${issue.message}`);
|
|
121
|
+
throw broken(this.path, problems.join("; "));
|
|
122
|
+
}
|
|
123
|
+
return checked.output.groups;
|
|
124
|
+
}
|
|
125
|
+
#write(groups) {
|
|
126
|
+
writeSecurely(this.path, `${JSON.stringify({ groups }, null, 2)}\n`, 0o600);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const invalid = (message) => new CliError("validation_error", message);
|
|
130
|
+
const broken = (path, why) => new CliError("configuration_error", `the moderation rules ${path} cannot be read (${why}) — fix the file`);
|
|
131
|
+
const lookup = (rules, key) => key.split(".").reduce((value, part) => value[part], rules);
|
|
132
|
+
const assign = (rules, key, value) => {
|
|
133
|
+
const [head, tail] = key.split(".");
|
|
134
|
+
if (tail === undefined)
|
|
135
|
+
return { ...rules, [head]: value };
|
|
136
|
+
return { ...rules, [head]: { ...rules[head], [tail]: value } };
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/moderation/rules.ts"],"names":[],"mappings":"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"}
|
package/dist/program.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,OAAO,EAEb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAA;AAUnD,OAAO,EAAE,KAAK,WAAW,EAAW,MAAM,uBAAuB,CAAA;AAwBjE,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6EAA6E;IAC7E,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,mGAAmG;IACnG,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5B,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,kBAAkB,cAAc,KAAQ,OAyEjE,CAAA;AAOD;;;;;;GAMG;AACH,eAAO,MAAM,GAAG,SAAgB,MAAM,EAAE,YAAW,UAAU,KAAQ,OAAO,CAAC,MAAM,CAwElF,CAAA"}
|
package/dist/program.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { CliError, exitCodeFor, GENERIC_FAILURE, processStreams, visibleControls, } from "@leemour/cli-core";
|
|
1
|
+
import { CliError, errorCodes, exitCodeFor, GENERIC_FAILURE, processStreams, visibleControls, } from "@leemour/cli-core";
|
|
2
2
|
import { Command, CommanderError } from "commander";
|
|
3
3
|
import { accountCommand } from "./commands/account.js";
|
|
4
4
|
import { backupCommand } from "./commands/backup.js";
|
|
5
|
+
import { botCommand } from "./commands/bot.js";
|
|
5
6
|
import { cacheCommand } from "./commands/cache.js";
|
|
6
7
|
import { chatsCommand } from "./commands/chats.js";
|
|
7
8
|
import { commandsCommand } from "./commands/commands.js";
|
|
@@ -43,7 +44,7 @@ export const createProgram = ({ out, err } = {}) => {
|
|
|
43
44
|
program
|
|
44
45
|
.name("max")
|
|
45
46
|
.usage("[profile] [options] <command>")
|
|
46
|
-
.description("
|
|
47
|
+
.description("MAX Messenger from the terminal: bots through the official Bot API (`max bot …`), and your personal account\n\n" +
|
|
47
48
|
"The first word is the profile whenever it is not a command — `max personal chats list`.\n" +
|
|
48
49
|
"`MAX_PROFILE` says the same thing for a whole shell session; without either it is `default`.")
|
|
49
50
|
.version(VERSION, "-V, --version")
|
|
@@ -87,6 +88,7 @@ export const createProgram = ({ out, err } = {}) => {
|
|
|
87
88
|
program.addCommand(selfUpdateCommand());
|
|
88
89
|
program.addCommand(completeCommand(), { hidden: true });
|
|
89
90
|
program.addCommand(mcpCommand());
|
|
91
|
+
program.addCommand(botCommand());
|
|
90
92
|
// Depth-first: Commander does not pass `configureOutput` down to a command added with
|
|
91
93
|
// `addCommand`, so `max messages --help` would write to the real terminal while the top level
|
|
92
94
|
// wrote to the injected streams — and a test reading stdout would see nothing at all.
|
|
@@ -149,7 +151,8 @@ export const run = async (argv, options = {}) => {
|
|
|
149
151
|
streams.diagnostic(line);
|
|
150
152
|
return process.exitCode === undefined ? 0 : Number(process.exitCode);
|
|
151
153
|
}
|
|
152
|
-
catch (
|
|
154
|
+
catch (thrown) {
|
|
155
|
+
const error = ownCliError(thrown);
|
|
153
156
|
if (!(error instanceof CommanderError) || error.exitCode !== 0) {
|
|
154
157
|
const failure = error instanceof CommanderError ? new CliError("validation_error", error.message) : error;
|
|
155
158
|
await keepFailure(failure, program, rest, profile, streams);
|
|
@@ -178,6 +181,18 @@ export const run = async (argv, options = {}) => {
|
|
|
178
181
|
* command that never opens one — through the same recorder, unless recording was turned off by
|
|
179
182
|
* name (`OPS-15`). Only the command's words are named, never its arguments: those can be a message.
|
|
180
183
|
*/
|
|
184
|
+
/**
|
|
185
|
+
* cli-messaging brings its own copy of cli-core, and its `CliError` is not an `instanceof` ours —
|
|
186
|
+
* a recipient-list refusal would otherwise leave with exit 1 and `generic_failure`.
|
|
187
|
+
*/
|
|
188
|
+
const ownCliError = (error) => {
|
|
189
|
+
if (error instanceof CliError || !(error instanceof Error) || error.name !== "CliError")
|
|
190
|
+
return error;
|
|
191
|
+
const { code, details } = error;
|
|
192
|
+
if (typeof code !== "string" || !errorCodes.includes(code))
|
|
193
|
+
return error;
|
|
194
|
+
return new CliError(code, error.message, details ?? {});
|
|
195
|
+
};
|
|
181
196
|
const keepFailure = async (error, program, rest, profile, streams) => {
|
|
182
197
|
if (wasSettled(error))
|
|
183
198
|
return;
|