@leemour/max-cli 0.12.0 → 0.14.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.
Files changed (149) hide show
  1. package/README.md +92 -19
  2. package/dist/bot/auth.d.ts +23 -0
  3. package/dist/bot/auth.d.ts.map +1 -0
  4. package/dist/bot/auth.js +36 -0
  5. package/dist/bot/auth.js.map +1 -0
  6. package/dist/bot/client.d.ts +20 -0
  7. package/dist/bot/client.d.ts.map +1 -0
  8. package/dist/bot/client.js +91 -0
  9. package/dist/bot/client.js.map +1 -0
  10. package/dist/bot/generated/manifest.d.ts +3 -0
  11. package/dist/bot/generated/manifest.d.ts.map +1 -0
  12. package/dist/bot/generated/manifest.js +1232 -0
  13. package/dist/bot/generated/manifest.js.map +1 -0
  14. package/dist/bot/generated/schemas.d.ts +271 -0
  15. package/dist/bot/generated/schemas.d.ts.map +1 -0
  16. package/dist/bot/generated/schemas.js +869 -0
  17. package/dist/bot/generated/schemas.js.map +1 -0
  18. package/dist/bot/generated/types.d.ts +1088 -0
  19. package/dist/bot/generated/types.d.ts.map +1 -0
  20. package/dist/bot/generated/types.js +5 -0
  21. package/dist/bot/generated/types.js.map +1 -0
  22. package/dist/bot/input.d.ts +10 -0
  23. package/dist/bot/input.d.ts.map +1 -0
  24. package/dist/bot/input.js +88 -0
  25. package/dist/bot/input.js.map +1 -0
  26. package/dist/bot/map.d.ts +11 -0
  27. package/dist/bot/map.d.ts.map +1 -0
  28. package/dist/bot/map.js +76 -0
  29. package/dist/bot/map.js.map +1 -0
  30. package/dist/bot/permissions.d.ts +14 -0
  31. package/dist/bot/permissions.d.ts.map +1 -0
  32. package/dist/bot/permissions.js +53 -0
  33. package/dist/bot/permissions.js.map +1 -0
  34. package/dist/bot/registry.d.ts +27 -0
  35. package/dist/bot/registry.d.ts.map +1 -0
  36. package/dist/bot/registry.js +68 -0
  37. package/dist/bot/registry.js.map +1 -0
  38. package/dist/bot/russian-trusted-root.d.ts +8 -0
  39. package/dist/bot/russian-trusted-root.d.ts.map +1 -0
  40. package/dist/bot/russian-trusted-root.js +41 -0
  41. package/dist/bot/russian-trusted-root.js.map +1 -0
  42. package/dist/bot/transport.d.ts +41 -0
  43. package/dist/bot/transport.d.ts.map +1 -0
  44. package/dist/bot/transport.js +200 -0
  45. package/dist/bot/transport.js.map +1 -0
  46. package/dist/client.d.ts +32 -1
  47. package/dist/client.d.ts.map +1 -1
  48. package/dist/client.js +174 -18
  49. package/dist/client.js.map +1 -1
  50. package/dist/commands/bot-context.d.ts +21 -0
  51. package/dist/commands/bot-context.d.ts.map +1 -0
  52. package/dist/commands/bot-context.js +59 -0
  53. package/dist/commands/bot-context.js.map +1 -0
  54. package/dist/commands/bot-reads.d.ts +7 -0
  55. package/dist/commands/bot-reads.d.ts.map +1 -0
  56. package/dist/commands/bot-reads.js +103 -0
  57. package/dist/commands/bot-reads.js.map +1 -0
  58. package/dist/commands/bot-sends.d.ts +12 -0
  59. package/dist/commands/bot-sends.d.ts.map +1 -0
  60. package/dist/commands/bot-sends.js +225 -0
  61. package/dist/commands/bot-sends.js.map +1 -0
  62. package/dist/commands/bot.d.ts +3 -0
  63. package/dist/commands/bot.d.ts.map +1 -0
  64. package/dist/commands/bot.js +145 -0
  65. package/dist/commands/bot.js.map +1 -0
  66. package/dist/commands/chats.d.ts.map +1 -1
  67. package/dist/commands/chats.js +65 -1
  68. package/dist/commands/chats.js.map +1 -1
  69. package/dist/commands/context.d.ts +10 -1
  70. package/dist/commands/context.d.ts.map +1 -1
  71. package/dist/commands/context.js.map +1 -1
  72. package/dist/commands/doctor.d.ts +6 -0
  73. package/dist/commands/doctor.d.ts.map +1 -1
  74. package/dist/commands/doctor.js +57 -7
  75. package/dist/commands/doctor.js.map +1 -1
  76. package/dist/commands/mcp.d.ts +24 -0
  77. package/dist/commands/mcp.d.ts.map +1 -1
  78. package/dist/commands/mcp.js +80 -14
  79. package/dist/commands/mcp.js.map +1 -1
  80. package/dist/commands/models.d.ts.map +1 -1
  81. package/dist/commands/models.js +13 -2
  82. package/dist/commands/models.js.map +1 -1
  83. package/dist/commands/review.d.ts +8 -0
  84. package/dist/commands/review.d.ts.map +1 -0
  85. package/dist/commands/review.js +96 -0
  86. package/dist/commands/review.js.map +1 -0
  87. package/dist/commands/rules.d.ts +7 -0
  88. package/dist/commands/rules.d.ts.map +1 -0
  89. package/dist/commands/rules.js +69 -0
  90. package/dist/commands/rules.js.map +1 -0
  91. package/dist/diagnose.d.ts +19 -1
  92. package/dist/diagnose.d.ts.map +1 -1
  93. package/dist/diagnose.js +37 -1
  94. package/dist/diagnose.js.map +1 -1
  95. package/dist/domain/map.d.ts +6 -1
  96. package/dist/domain/map.d.ts.map +1 -1
  97. package/dist/domain/map.js +34 -1
  98. package/dist/domain/map.js.map +1 -1
  99. package/dist/domain/models.d.ts +79 -0
  100. package/dist/domain/models.d.ts.map +1 -1
  101. package/dist/domain/models.js.map +1 -1
  102. package/dist/generated/operations.generated.d.ts +3 -1
  103. package/dist/generated/operations.generated.d.ts.map +1 -1
  104. package/dist/install.d.ts +43 -0
  105. package/dist/install.d.ts.map +1 -0
  106. package/dist/install.js +142 -0
  107. package/dist/install.js.map +1 -0
  108. package/dist/mcp/prompts.d.ts.map +1 -1
  109. package/dist/mcp/prompts.js +28 -0
  110. package/dist/mcp/prompts.js.map +1 -1
  111. package/dist/mcp/tools.d.ts.map +1 -1
  112. package/dist/mcp/tools.js +39 -1
  113. package/dist/mcp/tools.js.map +1 -1
  114. package/dist/moderation/rules.d.ts +56 -0
  115. package/dist/moderation/rules.d.ts.map +1 -0
  116. package/dist/moderation/rules.js +138 -0
  117. package/dist/moderation/rules.js.map +1 -0
  118. package/dist/online.d.ts +23 -0
  119. package/dist/online.d.ts.map +1 -0
  120. package/dist/online.js +87 -0
  121. package/dist/online.js.map +1 -0
  122. package/dist/program.d.ts.map +1 -1
  123. package/dist/program.js +20 -3
  124. package/dist/program.js.map +1 -1
  125. package/dist/protocol/connection.d.ts.map +1 -1
  126. package/dist/protocol/connection.js +12 -1
  127. package/dist/protocol/connection.js.map +1 -1
  128. package/dist/report.d.ts.map +1 -1
  129. package/dist/report.js +13 -2
  130. package/dist/report.js.map +1 -1
  131. package/dist/review.d.ts +41 -0
  132. package/dist/review.d.ts.map +1 -0
  133. package/dist/review.js +111 -0
  134. package/dist/review.js.map +1 -0
  135. package/dist/spec/operations/chats.d.ts +4 -1
  136. package/dist/spec/operations/chats.d.ts.map +1 -1
  137. package/dist/spec/operations/chats.js +10 -4
  138. package/dist/spec/operations/chats.js.map +1 -1
  139. package/dist/transcribe/index.d.ts +1 -0
  140. package/dist/transcribe/index.d.ts.map +1 -1
  141. package/dist/transcribe/index.js +8 -4
  142. package/dist/transcribe/index.js.map +1 -1
  143. package/dist/transcribe/speech.d.ts.map +1 -1
  144. package/dist/transcribe/speech.js +2 -0
  145. package/dist/transcribe/speech.js.map +1 -1
  146. package/dist/version.d.ts +1 -1
  147. package/dist/version.js +1 -1
  148. package/package.json +14 -6
  149. package/skills/max-cli/SKILL.md +26 -1
@@ -0,0 +1,103 @@
1
+ import { CliError } from "@leemour/cli-core";
2
+ import { annotate } from "@leemour/cli-core/commands";
3
+ import { pickChat, renderMessages } from "@leemour/cli-messaging";
4
+ import { Command } from "commander";
5
+ import { botOperations } from "../bot/client.js";
6
+ import { botContext } from "./bot-context.js";
7
+ import { guardedCall, sendCommands } from "./bot-sends.js";
8
+ const CHAT_ID = /^-?\d+$/;
9
+ /** An id as it is, or a title this bot has already seen — never a guess (ARCHITECTURE §9). */
10
+ export const chatIdOf = (reference, registry) => {
11
+ if (CHAT_ID.test(reference))
12
+ return reference;
13
+ if (reference.startsWith("user:")) {
14
+ throw new CliError("validation_error", "a direct chat is read by its chat id; `user:<id>` is only for sending");
15
+ }
16
+ return pickChat(reference, registry.list()).id;
17
+ };
18
+ const operation = (id) => {
19
+ const found = botOperations.find((candidate) => candidate.id === id);
20
+ if (!found)
21
+ throw new CliError("configuration_error", `the generated manifest has no operation ${id}`);
22
+ return found;
23
+ };
24
+ export const messagesCommand = () => {
25
+ const command = new Command("messages").description("messages in the chats this bot is in");
26
+ command
27
+ .command("list <chat>")
28
+ .option("--limit <n>", "how many, up to 100", (value) => Number.parseInt(value, 10))
29
+ .description("the latest messages in a chat (--limit, up to 100) — its id, or the title of a chat this bot has seen")
30
+ .action(async function (chat) {
31
+ const context = botContext(this);
32
+ const limit = context.settings.limit;
33
+ if (limit > 100)
34
+ throw new CliError("validation_error", "a bot reads at most 100 messages at a time — --limit 100");
35
+ const client = context.authenticated();
36
+ const chatId = chatIdOf(chat, context.registry);
37
+ const self = (await client.me()).user_id;
38
+ const messages = await client.messages(chatId, limit, self);
39
+ context.registry.observe([{ id: chatId }]);
40
+ show(context, messages);
41
+ });
42
+ command
43
+ .command("get <message>")
44
+ .description("one message by its id (mid.…)")
45
+ .action(async function (message) {
46
+ const context = botContext(this);
47
+ const client = context.authenticated();
48
+ const self = (await client.me()).user_id;
49
+ show(context, [await client.message(message, self)]);
50
+ });
51
+ sendCommands(command);
52
+ return command;
53
+ };
54
+ const show = (context, messages) => {
55
+ if (context.format !== "pretty") {
56
+ context.renderer.result(messages);
57
+ return;
58
+ }
59
+ context.streams.data(renderMessages(messages, {
60
+ verbosity: context.settings.detail,
61
+ color: context.color,
62
+ profile: context.settings.profile,
63
+ provider: "max-bot",
64
+ }));
65
+ };
66
+ export const chatsCommand = () => {
67
+ const command = new Command("chats").description("the chats this bot is in — MAX gives a bot no list of them, so `list` shows the ones it has seen");
68
+ command
69
+ .command("list")
70
+ .description("chats this bot has seen on this machine — not a complete list from MAX")
71
+ .action(function () {
72
+ const { renderer, registry } = botContext(this);
73
+ renderer.result(registry.list());
74
+ });
75
+ command
76
+ .command("get <chat>")
77
+ .description("one chat from MAX, and remember it")
78
+ .action(async function (chat) {
79
+ const { renderer, registry, authenticated } = botContext(this);
80
+ const found = await authenticated().chat(chatIdOf(chat, registry));
81
+ registry.observe([found]);
82
+ renderer.result(found);
83
+ });
84
+ const write = (name, operationId, description, body) => annotate(command.command(name), { mutates: true })
85
+ .description(description)
86
+ .action(async function (chat, argument) {
87
+ const context = botContext(this);
88
+ const { renderer, registry } = context;
89
+ const chatId = chatIdOf(chat, registry);
90
+ const answer = await guardedCall(context, operation(operationId), {
91
+ path: { chatId },
92
+ ...(body ? { body: body(argument) } : {}),
93
+ });
94
+ registry.observe([{ id: chatId }]);
95
+ renderer.result(answer ?? { success: true });
96
+ });
97
+ write("pin <chat> <message>", "pinMessage", "pin a message in a chat", (message) => JSON.stringify({ message_id: message, notify: false }));
98
+ write("unpin <chat>", "unpinMessage", "unpin whatever is pinned in a chat");
99
+ write("leave <chat>", "leaveChat", "the bot leaves the chat; only an admin can bring it back");
100
+ write("action <chat> <action>", "sendAction", "show an action to the chat: typing_on, sending_photo, sending_video, sending_audio, sending_file, mark_seen", (action) => JSON.stringify({ action }));
101
+ return command;
102
+ };
103
+ //# sourceMappingURL=bot-reads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-reads.js","sourceRoot":"","sources":["../../src/commands/bot-reads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ManifestOperation } from "@leemour/cli-core/codegen";
2
+ import { Command } from "commander";
3
+ import { type CallInput } from "../bot/transport.js";
4
+ import { botContext } from "./bot-context.js";
5
+ type Context = ReturnType<typeof botContext>;
6
+ /** Every bot write, from any command: readOnly and allow, then the recipient list and the journal. */
7
+ export declare const guardedCall: (context: Context, target: ManifestOperation, input: CallInput) => Promise<unknown>;
8
+ export declare const sendCommands: (messages: Command) => void;
9
+ export declare const recipientsCommand: () => Command;
10
+ export declare const sendsCommand: () => Command;
11
+ export {};
12
+ //# sourceMappingURL=bot-sends.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-sends.d.ts","sourceRoot":"","sources":["../../src/commands/bot-sends.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAIlE,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAK3C,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,qBAAqB,CAAA;AAE/D,OAAO,EAAiB,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE5D,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;AA6G5C,sGAAsG;AACtG,eAAO,MAAM,WAAW,YAAmB,OAAO,UAAU,iBAAiB,SAAS,SAAS,KAAG,OAAO,CAAC,OAAO,CAQhH,CAAA;AAED,eAAO,MAAM,YAAY,aAAc,OAAO,KAAG,IAqFhD,CAAA;AAED,eAAO,MAAM,iBAAiB,QAAO,OAoCpC,CAAA;AAED,eAAO,MAAM,YAAY,QAAO,OAQ3B,CAAA"}
@@ -0,0 +1,225 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { CliError } from "@leemour/cli-core";
4
+ import { annotate } from "@leemour/cli-core/commands";
5
+ import { pickChat } from "@leemour/cli-messaging";
6
+ import { newSendId, RecipientList, SendJournal, sendGuard } from "@leemour/cli-messaging/sends";
7
+ import { Command, Option } from "commander";
8
+ import { botOperations } from "../bot/client.js";
9
+ import { checkBody } from "../bot/input.js";
10
+ import { BOT_JOURNAL_KINDS } from "../bot/permissions.js";
11
+ import { botsDirectory } from "../bot/registry.js";
12
+ import { plainJson } from "../bot/transport.js";
13
+ import { asFirstWord } from "../profile.js";
14
+ import { assertAllowed, botContext } from "./bot-context.js";
15
+ const operation = (id) => {
16
+ const found = botOperations.find((candidate) => candidate.id === id);
17
+ if (!found)
18
+ throw new CliError("configuration_error", `the generated manifest has no operation ${id}`);
19
+ return found;
20
+ };
21
+ /** How the owner types this bot, so every refusal names the command that fixes it. */
22
+ const botWords = (profile) => `${asFirstWord(profile)}bot`;
23
+ const files = (profile) => ({
24
+ journal: join(botsDirectory(), "sends", `${profile}.jsonl`),
25
+ recipients: join(botsDirectory(), "recipients", `${profile}.json`),
26
+ });
27
+ const recipientsOf = (context) => new RecipientList(files(context.settings.profile).recipients, `max ${botWords(context.settings.profile)}`);
28
+ /**
29
+ * cli-messaging's guard with the bot's own recipient list and journal. `readOnly` and `allow` are
30
+ * checked before it, with the bot's permission names; a bot has no hourly limit (owner, `NEED-305`).
31
+ */
32
+ const guardOf = (context) => sendGuard({
33
+ profile: botWords(context.settings.profile),
34
+ command: "max",
35
+ readOnly: false,
36
+ readOnlyFrom: "default",
37
+ sendsPerHour: Number.POSITIVE_INFINITY,
38
+ journal: new SendJournal(files(context.settings.profile).journal),
39
+ recipients: recipientsOf(context),
40
+ warn: (message) => context.streams.diagnostic(message),
41
+ });
42
+ const DIGITS = /^-?\d+$/;
43
+ const targetOf = (reference, context) => {
44
+ if (DIGITS.test(reference))
45
+ return { key: reference, query: { chat_id: reference } };
46
+ const user = /^user:(\d+)$/.exec(reference);
47
+ if (user?.[1])
48
+ return { key: reference, query: { user_id: user[1] } };
49
+ const id = pickChat(reference, context.registry.list()).id;
50
+ return { key: id, query: { chat_id: id } };
51
+ };
52
+ const textOf = (text) => (text === "-" ? readFileSync(0, "utf8").replace(/\n$/, "") : text);
53
+ /** Runs one write through the guard and the journal, on every outcome. */
54
+ const guarded = async (context, request, body, length) => {
55
+ const guard = guardOf(context);
56
+ const sendId = newSendId();
57
+ const base = { chatId: request.chatId, kind: request.kind, sendId, ...(length === undefined ? {} : { length }) };
58
+ try {
59
+ guard.check(request);
60
+ }
61
+ catch (error) {
62
+ const code = error.code;
63
+ guard.record({ ...base, outcome: "refused", ...(code ? { errorCode: code } : {}) });
64
+ throw error;
65
+ }
66
+ try {
67
+ const { result, messageId } = await body(sendId);
68
+ guard.record({
69
+ ...base,
70
+ outcome: "sent",
71
+ ...(messageId ? { messageId } : {}),
72
+ ...(request.count ? { count: request.count } : {}),
73
+ });
74
+ return result;
75
+ }
76
+ catch (error) {
77
+ const code = error.code;
78
+ guard.record({
79
+ ...base,
80
+ outcome: code === "outcome_unknown" ? "outcome_unknown" : "failed",
81
+ ...(code ? { errorCode: code } : {}),
82
+ });
83
+ throw error;
84
+ }
85
+ };
86
+ const chatOfMessage = async (context, messageId) => {
87
+ const message = await context.authenticated().message(messageId);
88
+ return message.chatId;
89
+ };
90
+ /**
91
+ * Which chat a write reaches, from its own parameters — the recipient list must hold for
92
+ * `max bot api` as much as for `messages send`, or the raw command is the way around it.
93
+ */
94
+ const chatOfCall = async (context, input) => {
95
+ const chat = input.path?.chatId ?? input.query?.chat_id;
96
+ if (typeof chat === "string")
97
+ return chat;
98
+ const user = input.query?.user_id;
99
+ if (typeof user === "string")
100
+ return `user:${user}`;
101
+ const message = input.path?.messageId ?? input.query?.message_id;
102
+ if (typeof message === "string")
103
+ return chatOfMessage(context, message);
104
+ return null;
105
+ };
106
+ /** Every bot write, from any command: readOnly and allow, then the recipient list and the journal. */
107
+ export const guardedCall = async (context, target, input) => {
108
+ const client = context.authenticated();
109
+ if (target.effect === "read")
110
+ return client.call(target, input);
111
+ assertAllowed(target, context.settings);
112
+ const kind = BOT_JOURNAL_KINDS[target.id];
113
+ if (!kind)
114
+ return client.call(target, input);
115
+ const chatId = await chatOfCall(context, input);
116
+ return guarded(context, { chatId, kind }, async () => ({ result: await client.call(target, input) }));
117
+ };
118
+ export const sendCommands = (messages) => {
119
+ annotate(messages.command("send"), { mutates: true })
120
+ .description("send a message as the bot — to a chat id, `user:<id>`, or the title of a chat it has seen; - reads stdin")
121
+ .argument("<chat>")
122
+ .argument("<text>")
123
+ .addOption(new Option("--format <format>", "how the text is marked up").choices(["markdown", "html"]))
124
+ .option("--reply-to <message>", "answer this message")
125
+ .option("--silent", "no notification for the people in the chat")
126
+ .action(async function (chat, text) {
127
+ const context = botContext(this);
128
+ const options = this.opts();
129
+ const send = operation("sendMessage");
130
+ assertAllowed(send, context.settings);
131
+ const target = targetOf(chat, context);
132
+ const content = textOf(text);
133
+ const body = checkBody(send, JSON.stringify({
134
+ text: content,
135
+ ...(options.format ? { format: options.format } : {}),
136
+ ...(options.silent ? { notify: false } : {}),
137
+ ...(options.replyTo ? { link: { type: "reply", mid: options.replyTo } } : {}),
138
+ }));
139
+ const client = context.authenticated();
140
+ const sent = await guarded(context, { chatId: target.key, kind: "message" }, async () => {
141
+ const answer = (await client.call(send, { query: target.query, ...(body ? { body } : {}) }));
142
+ const message = answer?.message ? client.decodeMessage(answer.message) : undefined;
143
+ return { result: message ?? plainJson(answer), ...(message ? { messageId: message.id } : {}) };
144
+ }, content.length);
145
+ const recipientChat = sent.chatId;
146
+ if (recipientChat && DIGITS.test(recipientChat))
147
+ context.registry.observe([{ id: recipientChat }]);
148
+ context.renderer.result(sent);
149
+ });
150
+ annotate(messages.command("edit"), { mutates: true })
151
+ .description("replace the text of a message the bot sent; - reads stdin")
152
+ .argument("<message>")
153
+ .argument("<text>")
154
+ .addOption(new Option("--format <format>", "how the text is marked up").choices(["markdown", "html"]))
155
+ .action(async function (messageId, text) {
156
+ const context = botContext(this);
157
+ const edit = operation("editMessage");
158
+ assertAllowed(edit, context.settings);
159
+ const content = textOf(text);
160
+ const format = this.opts().format;
161
+ const body = checkBody(edit, JSON.stringify({ text: content, ...(format ? { format } : {}) }));
162
+ const chatId = await chatOfMessage(context, messageId);
163
+ const answer = await guarded(context, { chatId, kind: "edit" }, async () => ({
164
+ result: plainJson(await context.authenticated().call(edit, { query: { message_id: messageId }, ...(body ? { body } : {}) })),
165
+ messageId,
166
+ }), content.length);
167
+ context.renderer.result(answer ?? { success: true });
168
+ });
169
+ annotate(messages.command("delete"), { mutates: true })
170
+ .description("delete a message in a chat the bot can delete in")
171
+ .argument("<message>")
172
+ .action(async function (messageId) {
173
+ const context = botContext(this);
174
+ const remove = operation("deleteMessage");
175
+ assertAllowed(remove, context.settings);
176
+ const chatId = await chatOfMessage(context, messageId);
177
+ const answer = await guarded(context, { chatId, kind: "delete", count: 1 }, async () => ({
178
+ result: plainJson(await context.authenticated().call(remove, { query: { message_id: messageId } })),
179
+ messageId,
180
+ }));
181
+ context.renderer.result(answer ?? { success: true });
182
+ });
183
+ };
184
+ export const recipientsCommand = () => {
185
+ const command = new Command("recipients").description("the chats this bot may write to; with no list, every chat — `off` removes the list");
186
+ command
187
+ .command("list")
188
+ .description("the chats on the list, or nothing when there is no list")
189
+ .action(function () {
190
+ const context = botContext(this);
191
+ context.renderer.result(recipientsOf(context).read() ?? []);
192
+ });
193
+ command
194
+ .command("add <chat>")
195
+ .description("allow a chat: its id, `user:<id>`, or the title of a chat this bot has seen")
196
+ .action(function (chat) {
197
+ const context = botContext(this);
198
+ const target = targetOf(chat, context);
199
+ const title = context.registry.list().find((seen) => seen.id === target.key)?.title ?? null;
200
+ recipientsOf(context).add({ id: target.key, title, addedAt: new Date().toISOString() });
201
+ context.renderer.result(recipientsOf(context).read() ?? []);
202
+ });
203
+ command
204
+ .command("remove <chat>")
205
+ .description("take a chat off the list")
206
+ .action(function (chat) {
207
+ const context = botContext(this);
208
+ context.renderer.result({ removed: recipientsOf(context).remove(chat) ?? null });
209
+ });
210
+ command
211
+ .command("off")
212
+ .description("remove the list: the bot may write to any chat again")
213
+ .action(function () {
214
+ const context = botContext(this);
215
+ context.renderer.result({ removed: recipientsOf(context).off() });
216
+ });
217
+ return command;
218
+ };
219
+ export const sendsCommand = () => new Command("sends")
220
+ .description("what this bot sent, edited and deleted from this machine — ids and outcomes, never text")
221
+ .addCommand(new Command("list").action(function () {
222
+ const context = botContext(this);
223
+ context.renderer.result(new SendJournal(files(context.settings.profile).journal).entries());
224
+ }));
225
+ //# sourceMappingURL=bot-sends.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-sends.js","sourceRoot":"","sources":["../../src/commands/bot-sends.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const botCommand: () => Command;
3
+ //# sourceMappingURL=bot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../src/commands/bot.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAiD3C,eAAO,MAAM,UAAU,QAAO,OAwG7B,CAAA"}
@@ -0,0 +1,145 @@
1
+ import { CliError } from "@leemour/cli-core";
2
+ import { annotate } from "@leemour/cli-core/commands";
3
+ import { Command, Option } from "commander";
4
+ import { BotTokenStore } from "../bot/auth.js";
5
+ import { botOperations } from "../bot/client.js";
6
+ import { checkBody, checkParameter, flagOf, optionKey, readBody } from "../bot/input.js";
7
+ import { registryProfiles } from "../bot/registry.js";
8
+ import { plainJson } from "../bot/transport.js";
9
+ import { configuredProfiles } from "../config.js";
10
+ import { assertAllowed, botContext } from "./bot-context.js";
11
+ import { chatsCommand, messagesCommand } from "./bot-reads.js";
12
+ import { guardedCall, recipientsCommand, sendsCommand } from "./bot-sends.js";
13
+ import { environmentOf } from "./context.js";
14
+ const apiCommand = (operation) => {
15
+ const binding = operation.binding.kind === "http" ? `${operation.binding.method} ${operation.binding.path}` : operation.id;
16
+ const command = new Command(operation.command).description(`${operation.summary ?? operation.id} — ${operation.effect} (${binding})`);
17
+ for (const parameter of operation.parameters) {
18
+ const option = new Option(`--${flagOf(parameter.name)} <value>`, parameter.description?.split("\n")[0] ?? parameter.name);
19
+ command.addOption(parameter.required ? option.makeOptionMandatory() : option);
20
+ }
21
+ if (operation.request) {
22
+ command.option("--body <json>", "the request body as JSON; - reads it from stdin");
23
+ command.option("--body-file <path>", "the request body from a JSON file; - is stdin");
24
+ }
25
+ annotate(command, { origin: "generated", operationId: operation.id, mutates: operation.effect !== "read" });
26
+ return command.action(async function () {
27
+ const options = this.opts();
28
+ const input = { path: {}, query: {} };
29
+ for (const parameter of operation.parameters) {
30
+ const raw = options[optionKey(parameter.name)];
31
+ if (raw === undefined)
32
+ continue;
33
+ const problem = checkParameter(parameter.name, parameter.schema, raw);
34
+ if (problem)
35
+ throw new CliError("validation_error", problem);
36
+ if (parameter.in === "path")
37
+ input.path[parameter.name] = raw;
38
+ else if (parameter.in === "query")
39
+ input.query[parameter.name] = raw;
40
+ }
41
+ const context = botContext(this);
42
+ if (operation.effect !== "read")
43
+ assertAllowed(operation, context.settings);
44
+ const body = checkBody(operation, readBody(options));
45
+ const call = body === undefined ? input : { ...input, body };
46
+ context.renderer.result(plainJson(await guardedCall(context, operation, call)));
47
+ });
48
+ };
49
+ export const botCommand = () => {
50
+ const command = new Command("bot").description("a MAX bot, through the official Bot API and a bot token — not your personal account");
51
+ const auth = new Command("auth").description("the bot token this profile uses");
52
+ auth
53
+ .command("set")
54
+ .description("check a bot token with MAX, then keep it — typed at a hidden prompt or piped on stdin")
55
+ .action(async function () {
56
+ const { store, client, ask, renderer, settings, streams } = botContext(this);
57
+ const token = (await ask("Bot token: ", { secret: true })).trim();
58
+ if (!token)
59
+ throw new CliError("validation_error", "no token given");
60
+ const bot = await client(token).me();
61
+ const source = store.write(token);
62
+ botContext(this).registry.touch();
63
+ if (process.env.MAX_BOT_TOKEN) {
64
+ streams.diagnostic("MAX_BOT_TOKEN is set, and it wins over the token just kept until it is unset");
65
+ }
66
+ renderer.result({
67
+ profile: settings.profile,
68
+ stored: source,
69
+ bot: bot.first_name,
70
+ id: bot.user_id,
71
+ username: bot.username,
72
+ });
73
+ });
74
+ auth
75
+ .command("show")
76
+ .description("where this profile's bot token comes from, and which bot it is")
77
+ .action(async function () {
78
+ const { store, authenticated, renderer, settings } = botContext(this);
79
+ const source = store.read()?.source;
80
+ const bot = await authenticated().me();
81
+ renderer.result({
82
+ profile: settings.profile,
83
+ source,
84
+ bot: bot.first_name,
85
+ id: bot.user_id,
86
+ username: bot.username,
87
+ });
88
+ });
89
+ auth
90
+ .command("remove")
91
+ .description("forget this profile's bot token")
92
+ .action(function () {
93
+ const { store, renderer, settings } = botContext(this);
94
+ renderer.result({ profile: settings.profile, removed: store.remove() });
95
+ });
96
+ command.addCommand(auth);
97
+ command
98
+ .command("me")
99
+ .description("the bot this profile's token belongs to: name, id, description, commands")
100
+ .action(async function () {
101
+ const { authenticated, renderer } = botContext(this);
102
+ renderer.result(await authenticated().me());
103
+ });
104
+ command
105
+ .command("list")
106
+ .description("every name on this machine that has a bot token; --check asks MAX which bot each is")
107
+ .option("--check", "ask MAX who each bot is")
108
+ .action(async function () {
109
+ const { renderer, streams } = botContext(this);
110
+ const check = this.opts().check === true;
111
+ const environment = environmentOf(this);
112
+ const names = [...new Set(["default", ...configuredProfiles(), ...registryProfiles()])].sort();
113
+ if (process.env.MAX_BOT_TOKEN)
114
+ streams.diagnostic("MAX_BOT_TOKEN is set, so every name uses that one token");
115
+ const rows = [];
116
+ for (const name of names) {
117
+ const store = environment.botStore?.(name) ?? new BotTokenStore({ profile: name });
118
+ const stored = store.read();
119
+ if (!stored)
120
+ continue;
121
+ const row = { name, token: stored.source };
122
+ if (check) {
123
+ try {
124
+ const bot = await botContext(this).client(stored.token).me();
125
+ Object.assign(row, { bot: bot.username ?? bot.first_name, id: bot.user_id });
126
+ }
127
+ catch (error) {
128
+ row.problem = error.code ?? "failed";
129
+ }
130
+ }
131
+ rows.push(row);
132
+ }
133
+ renderer.result(rows);
134
+ });
135
+ command.addCommand(messagesCommand());
136
+ command.addCommand(chatsCommand());
137
+ command.addCommand(recipientsCommand());
138
+ command.addCommand(sendsCommand());
139
+ const api = new Command("api").description("every operation of the official Bot API, generated from its schema — docs/dev/bot-api-coverage.md");
140
+ for (const operation of botOperations)
141
+ api.addCommand(apiCommand(operation));
142
+ command.addCommand(api);
143
+ return command;
144
+ };
145
+ //# sourceMappingURL=bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../src/commands/bot.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/commands/chats.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAQnC,eAAO,MAAM,YAAY,QAAO,OA4L/B,CAAA"}
1
+ {"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/commands/chats.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,YAAY,QAAO,OA8P/B,CAAA"}
@@ -6,6 +6,8 @@ import { ADMIN_RIGHTS } from "../client.js";
6
6
  import { forCommand } from "./context.js";
7
7
  import { foldersCommand } from "./folders.js";
8
8
  import { renderPage, window, withPaging } from "./paging.js";
9
+ import { rulesCommand } from "./rules.js";
10
+ const EVENTS_DAYS = 7;
9
11
  export const chatsCommand = () => {
10
12
  const command = new Command("chats").description("the chats this account is in");
11
13
  withPaging(command.command("list").description("the chats this account is in"))
@@ -51,6 +53,48 @@ export const chatsCommand = () => {
51
53
  }
52
54
  });
53
55
  });
56
+ command
57
+ .command("events")
58
+ .argument("<chat>", "chat id, or part of a chat name")
59
+ .option("--since <id-or-time>", `from this message id or ISO 8601 time; ${EVENTS_DAYS} days ago if not given`)
60
+ .option("--event <names>", "only these, comma-separated, as MAX names them: new, add, remove, pin…")
61
+ .description("who joined, left, was added or removed, and by whom — from the chat's service messages")
62
+ .action(async function (chat) {
63
+ const options = this.optsWithGlobals();
64
+ const { renderer, settings, format, createClient, run } = forCommand(this);
65
+ const cache = await openProfileCache(settings.profile, { onProblem: (message) => renderer.note(message) });
66
+ const only = options.event === undefined
67
+ ? undefined
68
+ : new Set(String(options.event)
69
+ .split(",")
70
+ .map((e) => e.trim()));
71
+ await run("chats events", async (events) => {
72
+ const client = createClient({ events, ...(cache ? { cache } : {}) });
73
+ try {
74
+ const since = options.since === undefined
75
+ ? Date.now() - EVENTS_DAYS * 86_400_000
76
+ : client.messages.moment(String(options.since), "--since");
77
+ const found = await client.chats.events(chat, { since });
78
+ const kept = only ? { ...found, events: found.events.filter((one) => only.has(one.event)) } : found;
79
+ if (format !== "pretty")
80
+ renderer.result(kept);
81
+ else {
82
+ renderer.stream(kept.events.map((one) => ({
83
+ time: one.timestamp,
84
+ event: one.event,
85
+ by: one.by.name ?? one.by.id,
86
+ people: one.people.map((person) => person.name ?? person.id).join(", "),
87
+ })));
88
+ }
89
+ if (kept.more)
90
+ renderer.note(`more history than one run reads — run again with --since after the last one`);
91
+ }
92
+ finally {
93
+ await client.close();
94
+ cache?.close();
95
+ }
96
+ });
97
+ });
54
98
  command
55
99
  .command("inspect")
56
100
  .argument("<link>", "an invite link, https://max.ru/join/…, or a public one, https://max.ru/<name>")
@@ -85,7 +129,26 @@ export const chatsCommand = () => {
85
129
  .action(async function (title, people) {
86
130
  await withClient(this, "chats create", (client) => client.chats.create(title, people));
87
131
  });
88
- const members = command.command("members").description("add people to a group or channel, or remove them");
132
+ const members = command.command("members").description("who is in a group or channel; add or remove people");
133
+ members
134
+ .command("list")
135
+ .argument("<chat>", "chat id, or part of a chat name")
136
+ .description("everyone in a group or channel, from MAX: when their account was made and when they were last seen")
137
+ .action(async function (chat) {
138
+ const { renderer, createClient, run } = forCommand(this);
139
+ await run("chats members list", async (events) => {
140
+ const client = createClient({ events });
141
+ try {
142
+ const found = await client.chats.members.list(chat);
143
+ renderer.stream(found.members);
144
+ if (!found.complete)
145
+ renderer.note(`only the first ${found.members.length} members were read`);
146
+ }
147
+ finally {
148
+ await client.close();
149
+ }
150
+ });
151
+ });
89
152
  annotate(members.command("add"), { mutates: true })
90
153
  .argument("<chat>", "chat id, or part of a chat name")
91
154
  .argument("<person...>", "an id, or part of a name")
@@ -170,6 +233,7 @@ export const chatsCommand = () => {
170
233
  await withClient(this, "chats link reset", (client) => client.chats.resetLink(chat));
171
234
  });
172
235
  command.addCommand(foldersCommand());
236
+ command.addCommand(rulesCommand());
173
237
  return command;
174
238
  };
175
239
  const withClient = async (command, label, act) => {