@leemour/max-cli 0.14.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.
Files changed (150) hide show
  1. package/README.md +43 -9
  2. package/dist/bot/client.d.ts +1 -1
  3. package/dist/bot/client.d.ts.map +1 -1
  4. package/dist/bot/client.js +2 -2
  5. package/dist/bot/client.js.map +1 -1
  6. package/dist/bot/keep.d.ts +25 -0
  7. package/dist/bot/keep.d.ts.map +1 -0
  8. package/dist/bot/keep.js +96 -0
  9. package/dist/bot/keep.js.map +1 -0
  10. package/dist/bot/registry.d.ts +3 -0
  11. package/dist/bot/registry.d.ts.map +1 -1
  12. package/dist/bot/registry.js +27 -10
  13. package/dist/bot/registry.js.map +1 -1
  14. package/dist/bot/uploads.d.ts +34 -0
  15. package/dist/bot/uploads.d.ts.map +1 -0
  16. package/dist/bot/uploads.js +122 -0
  17. package/dist/bot/uploads.js.map +1 -0
  18. package/dist/client.d.ts +19 -4
  19. package/dist/client.d.ts.map +1 -1
  20. package/dist/client.js +76 -39
  21. package/dist/client.js.map +1 -1
  22. package/dist/commands/bot-comments.d.ts +4 -0
  23. package/dist/commands/bot-comments.d.ts.map +1 -0
  24. package/dist/commands/bot-comments.js +97 -0
  25. package/dist/commands/bot-comments.js.map +1 -0
  26. package/dist/commands/bot-context.d.ts +9 -3
  27. package/dist/commands/bot-context.d.ts.map +1 -1
  28. package/dist/commands/bot-context.js +38 -15
  29. package/dist/commands/bot-context.js.map +1 -1
  30. package/dist/commands/bot-members.d.ts +12 -0
  31. package/dist/commands/bot-members.d.ts.map +1 -0
  32. package/dist/commands/bot-members.js +136 -0
  33. package/dist/commands/bot-members.js.map +1 -0
  34. package/dist/commands/bot-reads.d.ts.map +1 -1
  35. package/dist/commands/bot-reads.js +50 -8
  36. package/dist/commands/bot-reads.js.map +1 -1
  37. package/dist/commands/bot-sends.d.ts +5 -0
  38. package/dist/commands/bot-sends.d.ts.map +1 -1
  39. package/dist/commands/bot-sends.js +56 -11
  40. package/dist/commands/bot-sends.js.map +1 -1
  41. package/dist/commands/bot-setup.d.ts +5 -0
  42. package/dist/commands/bot-setup.d.ts.map +1 -0
  43. package/dist/commands/bot-setup.js +107 -0
  44. package/dist/commands/bot-setup.js.map +1 -0
  45. package/dist/commands/bot-updates.d.ts +3 -0
  46. package/dist/commands/bot-updates.d.ts.map +1 -0
  47. package/dist/commands/bot-updates.js +182 -0
  48. package/dist/commands/bot-updates.js.map +1 -0
  49. package/dist/commands/bot.d.ts.map +1 -1
  50. package/dist/commands/bot.js +15 -0
  51. package/dist/commands/bot.js.map +1 -1
  52. package/dist/commands/chats.d.ts.map +1 -1
  53. package/dist/commands/chats.js +19 -6
  54. package/dist/commands/chats.js.map +1 -1
  55. package/dist/commands/check.d.ts +8 -0
  56. package/dist/commands/check.d.ts.map +1 -0
  57. package/dist/commands/check.js +64 -0
  58. package/dist/commands/check.js.map +1 -0
  59. package/dist/commands/context.d.ts +5 -0
  60. package/dist/commands/context.d.ts.map +1 -1
  61. package/dist/commands/context.js +5 -1
  62. package/dist/commands/context.js.map +1 -1
  63. package/dist/commands/hearing.d.ts +25 -0
  64. package/dist/commands/hearing.d.ts.map +1 -0
  65. package/dist/commands/hearing.js +41 -0
  66. package/dist/commands/hearing.js.map +1 -0
  67. package/dist/commands/inbox.d.ts.map +1 -1
  68. package/dist/commands/inbox.js +19 -3
  69. package/dist/commands/inbox.js.map +1 -1
  70. package/dist/commands/mcp.d.ts +1 -0
  71. package/dist/commands/mcp.d.ts.map +1 -1
  72. package/dist/commands/mcp.js +7 -4
  73. package/dist/commands/mcp.js.map +1 -1
  74. package/dist/commands/messages.d.ts.map +1 -1
  75. package/dist/commands/messages.js +21 -5
  76. package/dist/commands/messages.js.map +1 -1
  77. package/dist/commands/paging.d.ts +3 -1
  78. package/dist/commands/paging.d.ts.map +1 -1
  79. package/dist/commands/paging.js +4 -1
  80. package/dist/commands/paging.js.map +1 -1
  81. package/dist/commands/review.d.ts.map +1 -1
  82. package/dist/commands/review.js +5 -7
  83. package/dist/commands/review.js.map +1 -1
  84. package/dist/domain/models.d.ts +4 -0
  85. package/dist/domain/models.d.ts.map +1 -1
  86. package/dist/domain/models.js.map +1 -1
  87. package/dist/generated/client.generated.d.ts +1 -0
  88. package/dist/generated/client.generated.d.ts.map +1 -1
  89. package/dist/generated/client.generated.js +1 -0
  90. package/dist/generated/client.generated.js.map +1 -1
  91. package/dist/generated/opcodes.generated.d.ts +1 -0
  92. package/dist/generated/opcodes.generated.d.ts.map +1 -1
  93. package/dist/generated/opcodes.generated.js +1 -0
  94. package/dist/generated/opcodes.generated.js.map +1 -1
  95. package/dist/generated/operations.generated.d.ts +13 -0
  96. package/dist/generated/operations.generated.d.ts.map +1 -1
  97. package/dist/generated/operations.generated.js +2 -1
  98. package/dist/generated/operations.generated.js.map +1 -1
  99. package/dist/mcp/instructions.d.ts +2 -1
  100. package/dist/mcp/instructions.d.ts.map +1 -1
  101. package/dist/mcp/instructions.js +2 -1
  102. package/dist/mcp/instructions.js.map +1 -1
  103. package/dist/mcp/server.d.ts +2 -1
  104. package/dist/mcp/server.d.ts.map +1 -1
  105. package/dist/mcp/server.js +4 -1
  106. package/dist/mcp/server.js.map +1 -1
  107. package/dist/mcp/tools.d.ts +5 -1
  108. package/dist/mcp/tools.d.ts.map +1 -1
  109. package/dist/mcp/tools.js +150 -11
  110. package/dist/mcp/tools.js.map +1 -1
  111. package/dist/moderation/check.d.ts +98 -0
  112. package/dist/moderation/check.d.ts.map +1 -0
  113. package/dist/moderation/check.js +306 -0
  114. package/dist/moderation/check.js.map +1 -0
  115. package/dist/review.d.ts +10 -4
  116. package/dist/review.d.ts.map +1 -1
  117. package/dist/review.js +35 -53
  118. package/dist/review.js.map +1 -1
  119. package/dist/sends/journal.d.ts +1 -1
  120. package/dist/sends/journal.d.ts.map +1 -1
  121. package/dist/session/store.d.ts +2 -0
  122. package/dist/session/store.d.ts.map +1 -1
  123. package/dist/session/store.js +2 -0
  124. package/dist/session/store.js.map +1 -1
  125. package/dist/spec/index.d.ts.map +1 -1
  126. package/dist/spec/index.js +2 -1
  127. package/dist/spec/index.js.map +1 -1
  128. package/dist/spec/operations/messages.d.ts.map +1 -1
  129. package/dist/spec/operations/messages.js +9 -4
  130. package/dist/spec/operations/messages.js.map +1 -1
  131. package/dist/spec/operations/uploads.d.ts +13 -0
  132. package/dist/spec/operations/uploads.d.ts.map +1 -1
  133. package/dist/spec/operations/uploads.js +21 -0
  134. package/dist/spec/operations/uploads.js.map +1 -1
  135. package/dist/transcribe/index.d.ts +36 -1
  136. package/dist/transcribe/index.d.ts.map +1 -1
  137. package/dist/transcribe/index.js +91 -14
  138. package/dist/transcribe/index.js.map +1 -1
  139. package/dist/upload.d.ts +3 -0
  140. package/dist/upload.d.ts.map +1 -1
  141. package/dist/upload.js +13 -7
  142. package/dist/upload.js.map +1 -1
  143. package/dist/version.d.ts +1 -1
  144. package/dist/version.js +1 -1
  145. package/dist/voice.d.ts +9 -0
  146. package/dist/voice.d.ts.map +1 -0
  147. package/dist/voice.js +36 -0
  148. package/dist/voice.js.map +1 -0
  149. package/package.json +5 -2
  150. package/skills/max-cli/SKILL.md +10 -3
@@ -3,16 +3,20 @@ import { BotTokenStore } from "../bot/auth.js";
3
3
  import { BotApiClient } from "../bot/client.js";
4
4
  import { BOT_PERMISSIONS } from "../bot/permissions.js";
5
5
  import { ChatRegistry } from "../bot/registry.js";
6
+ import { botFetch } from "../bot/transport.js";
6
7
  import { resolveSettings } from "../config.js";
7
8
  import { resolveOutput } from "../output.js";
8
9
  import { asFirstWord } from "../profile.js";
9
10
  import { readSecret } from "../session/prompt.js";
10
11
  import { environmentOf } from "./context.js";
11
- export const botContext = (command) => {
12
+ /** `offline` is for the reads the local copy can answer; every other command still refuses the flag. */
13
+ export const botContext = (command, { offline: answersOffline = false } = {}) => {
12
14
  const environment = environmentOf(command);
13
15
  const flags = command.optsWithGlobals();
14
- if (flags.offline)
15
- throw new CliError("validation_error", "max bot always asks MAX; --offline cannot apply to it");
16
+ const offline = flags.offline === true;
17
+ if (offline && !answersOffline) {
18
+ throw new CliError("validation_error", `--offline reads the local copy; \`${command.name()}\` has to ask MAX`);
19
+ }
16
20
  const settings = resolveSettings(flags);
17
21
  const { renderer, streams, format, color } = resolveOutput({
18
22
  ...settings,
@@ -20,25 +24,44 @@ export const botContext = (command) => {
20
24
  ...(environment.tty === undefined ? {} : { tty: environment.tty }),
21
25
  });
22
26
  const store = environment.botStore?.(settings.profile) ?? new BotTokenStore({ profile: settings.profile });
23
- const signal = settings.commandTimeoutMs === undefined ? undefined : AbortSignal.timeout(settings.commandTimeoutMs);
24
- const client = (token) => new BotApiClient({
25
- token,
26
- ...(environment.botFetch ? { fetch: environment.botFetch } : {}),
27
- ...(environment.botUrl ? { baseUrl: environment.botUrl } : {}),
28
- ...(settings.timeoutMs === undefined ? {} : { timeoutMs: settings.timeoutMs }),
29
- ...(environment.botRetry ? { retry: environment.botRetry } : {}),
30
- ...(signal ? { signal } : {}),
31
- });
27
+ const deadline = settings.commandTimeoutMs === undefined ? undefined : AbortSignal.timeout(settings.commandTimeoutMs);
28
+ const client = (token, stop) => {
29
+ const signal = deadline && stop ? AbortSignal.any([deadline, stop]) : (deadline ?? stop);
30
+ return new BotApiClient({
31
+ token,
32
+ ...(environment.botFetch ? { fetch: environment.botFetch } : {}),
33
+ ...(environment.botUrl ? { baseUrl: environment.botUrl } : {}),
34
+ ...(settings.timeoutMs === undefined ? {} : { timeoutMs: settings.timeoutMs }),
35
+ ...(environment.botRetry ? { retry: environment.botRetry } : {}),
36
+ ...(signal ? { signal } : {}),
37
+ });
38
+ };
32
39
  const ask = environment.ask ?? ((prompt) => readSecret(prompt, { echo: false }));
33
- const authenticated = () => {
40
+ /** `stop` is for a command that runs until told to — `updates watch` — and ends its request in flight. */
41
+ const authenticated = (stop) => {
34
42
  const stored = store.read();
35
43
  if (!stored) {
36
44
  throw new CliError("authentication_error", `no bot token for profile "${settings.profile}" — run \`max ${asFirstWord(settings.profile)}bot auth set\``);
37
45
  }
38
- return client(stored.token);
46
+ return client(stored.token, stop);
39
47
  };
40
48
  const registry = environment.botRegistry?.(settings.profile) ?? new ChatRegistry(settings.profile);
41
- return { settings, renderer, streams, format, color, store, registry, client, ask, authenticated };
49
+ const uploadFetch = () => environment.botFetch ?? botFetch();
50
+ return {
51
+ settings,
52
+ renderer,
53
+ streams,
54
+ format,
55
+ color,
56
+ store,
57
+ registry,
58
+ client,
59
+ ask,
60
+ authenticated,
61
+ signal: deadline,
62
+ uploadFetch,
63
+ offline,
64
+ };
42
65
  };
43
66
  /** The personal account's `readOnly` and `allow` hold for the bot too; a prompt was waived (`NEED-304`), a refusal was not. */
44
67
  export const assertAllowed = (operation, settings) => {
@@ -1 +1 @@
1
- {"version":3,"file":"bot-context.js","sourceRoot":"","sources":["../../src/commands/bot-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bot-context.js","sourceRoot":"","sources":["../../src/commands/bot-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * User ids as JSON numbers with exactly the digits typed: the schema says int64, and `Number`
4
+ * would turn an id above 2^53 into somebody else's.
5
+ */
6
+ export declare const userIdsJson: (ids: readonly string[]) => string;
7
+ /** A friendly command's body meets the same schema check as one given to `max bot api`. */
8
+ export declare const checked: (id: string, text: string) => string;
9
+ export declare const membersCommand: () => Command;
10
+ export declare const ADMIN_PERMISSIONS: readonly ["read_all_messages", "add_remove_members", "add_admins", "change_chat_info", "pin_message", "edit_link", "write", "edit", "delete", "can_call", "view_stats"];
11
+ export declare const adminsCommand: () => Command;
12
+ //# sourceMappingURL=bot-members.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-members.d.ts","sourceRoot":"","sources":["../../src/commands/bot-members.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AASnC;;;GAGG;AACH,eAAO,MAAM,WAAW,QAAS,SAAS,MAAM,EAAE,KAAG,MAKpD,CAAA;AAED,2FAA2F;AAC3F,eAAO,MAAM,OAAO,OAAQ,MAAM,QAAQ,MAAM,KAAG,MAAgD,CAAA;AAYnG,eAAO,MAAM,cAAc,QAAO,OA4CjC,CAAA;AAED,eAAO,MAAM,iBAAiB,YAC5B,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,OAAO,EACP,MAAM,EACN,QAAQ,EACR,UAAU,EACV,YAAY,CACJ,CAAA;AAkBV,eAAO,MAAM,aAAa,QAAO,OA2ChC,CAAA"}
@@ -0,0 +1,136 @@
1
+ import { CliError } from "@leemour/cli-core";
2
+ import { annotate } from "@leemour/cli-core/commands";
3
+ import { Command } from "commander";
4
+ import { checkBody } from "../bot/input.js";
5
+ import { plainJson } from "../bot/transport.js";
6
+ import { botContext } from "./bot-context.js";
7
+ import { chatIdOf } from "./bot-reads.js";
8
+ import { guardedCall, operation } from "./bot-sends.js";
9
+ const USER_ID = /^\d+$/;
10
+ /**
11
+ * User ids as JSON numbers with exactly the digits typed: the schema says int64, and `Number`
12
+ * would turn an id above 2^53 into somebody else's.
13
+ */
14
+ export const userIdsJson = (ids) => {
15
+ for (const id of ids) {
16
+ if (!USER_ID.test(id))
17
+ throw new CliError("validation_error", `a user id is digits only, not ${id}`);
18
+ }
19
+ return `[${ids.join(",")}]`;
20
+ };
21
+ /** A friendly command's body meets the same schema check as one given to `max bot api`. */
22
+ export const checked = (id, text) => checkBody(operation(id), text) ?? text;
23
+ const limitOf = (limit) => {
24
+ if (limit > 100)
25
+ throw new CliError("validation_error", "MAX gives at most 100 at a time — --limit 100");
26
+ return String(limit);
27
+ };
28
+ const listOf = (answer) => {
29
+ const { members, marker } = plainJson(answer);
30
+ return { members: members ?? [], marker: marker ?? null };
31
+ };
32
+ export const membersCommand = () => {
33
+ const command = new Command("members").description("the people in a group chat or channel the bot is in");
34
+ command
35
+ .command("list <chat>")
36
+ .description("members of a chat, a page at a time — --marker takes the `marker` the last page gave")
37
+ .option("--limit <n>", "how many, up to 100", (value) => Number.parseInt(value, 10))
38
+ .option("--marker <marker>", "continue from here")
39
+ .action(async function (chat) {
40
+ const context = botContext(this);
41
+ const marker = this.opts().marker;
42
+ const answer = await context.authenticated().call(operation("getMembers"), {
43
+ path: { chatId: chatIdOf(chat, context.registry) },
44
+ query: { count: limitOf(context.settings.limit), ...(marker ? { marker } : {}) },
45
+ });
46
+ context.renderer.result(listOf(answer));
47
+ });
48
+ annotate(command.command("add <chat> <users...>"), { mutates: true })
49
+ .description("add people to a chat by user id; the bot must be an admin that may add members")
50
+ .action(async function (chat, users) {
51
+ const context = botContext(this);
52
+ const answer = await guardedCall(context, operation("addMembers"), {
53
+ path: { chatId: chatIdOf(chat, context.registry) },
54
+ body: checked("addMembers", `{"user_ids": ${userIdsJson(users)}}`),
55
+ });
56
+ context.renderer.result(plainJson(answer) ?? { success: true });
57
+ });
58
+ annotate(command.command("remove <chat> <user>"), { mutates: true })
59
+ .description("remove a person from a chat")
60
+ .option("--block", "also block them from coming back by the chat's link")
61
+ .action(async function (chat, user) {
62
+ const context = botContext(this);
63
+ userIdsJson([user]);
64
+ const block = this.opts().block === true;
65
+ const answer = await guardedCall(context, operation("removeMember"), {
66
+ path: { chatId: chatIdOf(chat, context.registry) },
67
+ query: { user_id: user, ...(block ? { block: "true" } : {}) },
68
+ });
69
+ context.renderer.result(plainJson(answer) ?? { success: true });
70
+ });
71
+ return command;
72
+ };
73
+ export const ADMIN_PERMISSIONS = [
74
+ "read_all_messages",
75
+ "add_remove_members",
76
+ "add_admins",
77
+ "change_chat_info",
78
+ "pin_message",
79
+ "edit_link",
80
+ "write",
81
+ "edit",
82
+ "delete",
83
+ "can_call",
84
+ "view_stats",
85
+ ];
86
+ const permissionsOf = (list) => {
87
+ const permissions = list
88
+ .split(",")
89
+ .map((one) => one.trim())
90
+ .filter(Boolean);
91
+ const unknown = permissions.filter((one) => !ADMIN_PERMISSIONS.includes(one));
92
+ if (permissions.length === 0 || unknown.length > 0) {
93
+ throw new CliError("validation_error", `--permissions takes a comma list of: ${ADMIN_PERMISSIONS.join(", ")}` +
94
+ (unknown.length > 0 ? ` — not ${unknown.join(", ")}` : ""));
95
+ }
96
+ return permissions;
97
+ };
98
+ export const adminsCommand = () => {
99
+ const command = new Command("admins").description("the admins of a group chat or channel the bot is an admin in");
100
+ command
101
+ .command("list <chat>")
102
+ .description("the admins of a chat and what each may do")
103
+ .action(async function (chat) {
104
+ const context = botContext(this);
105
+ const answer = await context.authenticated().call(operation("getAdmins"), {
106
+ path: { chatId: chatIdOf(chat, context.registry) },
107
+ });
108
+ context.renderer.result(listOf(answer));
109
+ });
110
+ annotate(command.command("add <chat> <user>"), { mutates: true })
111
+ .description("make a person an admin with the permissions named")
112
+ .requiredOption("--permissions <list>", `a comma list: ${ADMIN_PERMISSIONS.join(", ")}`)
113
+ .option("--alias <title>", "the title shown beside their name")
114
+ .action(async function (chat, user) {
115
+ const context = botContext(this);
116
+ const options = this.opts();
117
+ const admin = `{"user_id": ${userIdsJson([user]).slice(1, -1)}, "permissions": ${JSON.stringify(permissionsOf(options.permissions))}${options.alias === undefined ? "" : `, "alias": ${JSON.stringify(options.alias)}`}}`;
118
+ const answer = await guardedCall(context, operation("postAdmins"), {
119
+ path: { chatId: chatIdOf(chat, context.registry) },
120
+ body: checked("postAdmins", `{"admins": [${admin}]}`),
121
+ });
122
+ context.renderer.result(plainJson(answer) ?? { success: true });
123
+ });
124
+ annotate(command.command("remove <chat> <user>"), { mutates: true })
125
+ .description("take a person's admin rights away; they stay in the chat")
126
+ .action(async function (chat, user) {
127
+ const context = botContext(this);
128
+ userIdsJson([user]);
129
+ const answer = await guardedCall(context, operation("deleteAdmins"), {
130
+ path: { chatId: chatIdOf(chat, context.registry), userId: user },
131
+ });
132
+ context.renderer.result(plainJson(answer) ?? { success: true });
133
+ });
134
+ return command;
135
+ };
136
+ //# sourceMappingURL=bot-members.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-members.js","sourceRoot":"","sources":["../../src/commands/bot-members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAEvD,MAAM,OAAO,GAAG,OAAO,CAAA;AAEvB;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAsB,EAAU,EAAE;IAC5D,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,iCAAiC,EAAE,EAAE,CAAC,CAAA;IACtG,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA;AAC7B,CAAC,CAAA;AAED,2FAA2F;AAC3F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EAAU,EAAE,IAAY,EAAU,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,CAAA;AAEnG,MAAM,OAAO,GAAG,CAAC,KAAa,EAAU,EAAE;IACxC,IAAI,KAAK,GAAG,GAAG;QAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,+CAA+C,CAAC,CAAA;IACxG,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;AACtB,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,MAAe,EAAE,EAAE;IACjC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAA8C,CAAA;IAC1F,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAE,CAAA;AAC3D,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,GAAY,EAAE;IAC1C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,qDAAqD,CAAC,CAAA;IAEzG,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,sFAAsF,CAAC;SACnG,MAAM,CAAC,aAAa,EAAE,qBAAqB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;SACnF,MAAM,CAAC,mBAAmB,EAAE,oBAAoB,CAAC;SACjD,MAAM,CAAC,KAAK,WAA0B,IAAY;QACjD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAuB,CAAC,MAAM,CAAA;QACtD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE;YACzE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAClD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;SACjF,CAAC,CAAA;QACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;IAEJ,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;SAClE,WAAW,CAAC,gFAAgF,CAAC;SAC7F,MAAM,CAAC,KAAK,WAA0B,IAAY,EAAE,KAAe;QAClE,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,YAAY,CAAC,EAAE;YACjE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAClD,IAAI,EAAE,OAAO,CAAC,YAAY,EAAE,gBAAgB,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC;SACnE,CAAC,CAAA;QACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACjE,CAAC,CAAC,CAAA;IAEJ,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;SACjE,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,SAAS,EAAE,qDAAqD,CAAC;SACxE,MAAM,CAAC,KAAK,WAA0B,IAAY,EAAE,IAAY;QAC/D,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;QAChC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAuB,CAAC,KAAK,KAAK,IAAI,CAAA;QAC7D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,cAAc,CAAC,EAAE;YACnE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAClD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;SAC9D,CAAC,CAAA;QACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACjE,CAAC,CAAC,CAAA;IAEJ,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,mBAAmB;IACnB,oBAAoB;IACpB,YAAY;IACZ,kBAAkB;IAClB,aAAa;IACb,WAAW;IACX,OAAO;IACP,MAAM;IACN,QAAQ;IACR,UAAU;IACV,YAAY;CACJ,CAAA;AAEV,MAAM,aAAa,GAAG,CAAC,IAAY,EAAY,EAAE;IAC/C,MAAM,WAAW,GAAG,IAAI;SACrB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,OAAO,CAAC,CAAA;IAClB,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAE,iBAAuC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;IACpG,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,QAAQ,CAChB,kBAAkB,EAClB,wCAAwC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACpE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC7D,CAAA;IACH,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,GAAY,EAAE;IACzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,8DAA8D,CAAC,CAAA;IAEjH,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,KAAK,WAA0B,IAAY;QACjD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE;YACxE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;SACnD,CAAC,CAAA;QACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;IAEJ,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;SAC9D,WAAW,CAAC,mDAAmD,CAAC;SAChE,cAAc,CAAC,sBAAsB,EAAE,iBAAiB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SACvF,MAAM,CAAC,iBAAiB,EAAE,mCAAmC,CAAC;SAC9D,MAAM,CAAC,KAAK,WAA0B,IAAY,EAAE,IAAY;QAC/D,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAA2C,CAAA;QACpE,MAAM,KAAK,GAAG,eAAe,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAC7F,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,CACnC,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAA;QACvF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,YAAY,CAAC,EAAE;YACjE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAClD,IAAI,EAAE,OAAO,CAAC,YAAY,EAAE,eAAe,KAAK,IAAI,CAAC;SACtD,CAAC,CAAA;QACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACjE,CAAC,CAAC,CAAA;IAEJ,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;SACjE,WAAW,CAAC,0DAA0D,CAAC;SACvE,MAAM,CAAC,KAAK,WAA0B,IAAY,EAAE,IAAY;QAC/D,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;QAChC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QACnB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,cAAc,CAAC,EAAE;YACnE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;SACjE,CAAC,CAAA;QACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACjE,CAAC,CAAC,CAAA;IAEJ,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"bot-reads.d.ts","sourceRoot":"","sources":["../../src/commands/bot-reads.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAMtD,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,cAAe,MAAM,YAAY,YAAY,KAAG,MAMpE,CAAA;AAQD,eAAO,MAAM,eAAe,QAAO,OAkClC,CAAA;AAiBD,eAAO,MAAM,YAAY,QAAO,OAmD/B,CAAA"}
1
+ {"version":3,"file":"bot-reads.d.ts","sourceRoot":"","sources":["../../src/commands/bot-reads.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAStD,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,cAAe,MAAM,YAAY,YAAY,KAAG,MAMpE,CAAA;AAQD,eAAO,MAAM,eAAe,QAAO,OA0ElC,CAAA;AA0BD,eAAO,MAAM,YAAY,QAAO,OAoD/B,CAAA"}
@@ -3,6 +3,8 @@ import { annotate } from "@leemour/cli-core/commands";
3
3
  import { pickChat, renderMessages } from "@leemour/cli-messaging";
4
4
  import { Command } from "commander";
5
5
  import { botOperations } from "../bot/client.js";
6
+ import { accountOf, fromStore, keep, keepChat, PROVIDER } from "../bot/keep.js";
7
+ import { asFirstWord } from "../profile.js";
6
8
  import { botContext } from "./bot-context.js";
7
9
  import { guardedCall, sendCommands } from "./bot-sends.js";
8
10
  const CHAT_ID = /^-?\d+$/;
@@ -26,16 +28,28 @@ export const messagesCommand = () => {
26
28
  command
27
29
  .command("list <chat>")
28
30
  .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")
31
+ .description("the latest messages in a chat (--limit, up to 100) — its id, or the title of a chat this bot has seen; " +
32
+ "--offline answers from the local copy")
30
33
  .action(async function (chat) {
31
- const context = botContext(this);
34
+ const context = botContext(this, { offline: true });
32
35
  const limit = context.settings.limit;
33
36
  if (limit > 100)
34
37
  throw new CliError("validation_error", "a bot reads at most 100 messages at a time — --limit 100");
35
- const client = context.authenticated();
36
38
  const chatId = chatIdOf(chat, context.registry);
39
+ if (context.offline) {
40
+ const botId = storedBotId(context);
41
+ const page = await fromStore((store) => store.messages(accountOf(botId), chatId, { limit }));
42
+ if (page.items.length === 0) {
43
+ throw new CliError("not_found", `nothing is recorded for chat ${chatId} on this machine — run it once without --offline`);
44
+ }
45
+ show(context, page.items);
46
+ return;
47
+ }
48
+ const client = context.authenticated();
37
49
  const self = (await client.me()).user_id;
50
+ context.registry.rememberBot(self);
38
51
  const messages = await client.messages(chatId, limit, self);
52
+ await keep(self, messages, "history", context.streams.diagnostic);
39
53
  context.registry.observe([{ id: chatId }]);
40
54
  show(context, messages);
41
55
  });
@@ -43,14 +57,41 @@ export const messagesCommand = () => {
43
57
  .command("get <message>")
44
58
  .description("one message by its id (mid.…)")
45
59
  .action(async function (message) {
46
- const context = botContext(this);
60
+ const context = botContext(this, { offline: true });
61
+ if (context.offline) {
62
+ const botId = storedBotId(context);
63
+ const kept = await fromStore((store) => store.message(accountOf(botId), message));
64
+ if (!kept)
65
+ throw new CliError("not_found", `message ${message} is not in the local copy`);
66
+ show(context, [kept]);
67
+ return;
68
+ }
47
69
  const client = context.authenticated();
48
70
  const self = (await client.me()).user_id;
49
- show(context, [await client.message(message, self)]);
71
+ context.registry.rememberBot(self);
72
+ const found = await client.message(message, self);
73
+ await keep(self, [found], "history", context.streams.diagnostic);
74
+ show(context, [found]);
75
+ });
76
+ command
77
+ .command("search <text>")
78
+ .option("--limit <n>", "how many", (value) => Number.parseInt(value, 10))
79
+ .description("search the messages this bot has read, sent or received on this machine — the local copy only, newest first")
80
+ .action(async function (text) {
81
+ const context = botContext(this, { offline: true });
82
+ const botId = storedBotId(context);
83
+ const page = await fromStore((store) => store.search(text, { limit: context.settings.limit, account: accountOf(botId) }));
84
+ show(context, page.items);
50
85
  });
51
86
  sendCommands(command);
52
87
  return command;
53
88
  };
89
+ const storedBotId = (context) => {
90
+ const botId = context.registry.botId();
91
+ if (botId)
92
+ return botId;
93
+ throw new CliError("not_found", `nothing is recorded for this bot on this machine — run \`max ${asFirstWord(context.settings.profile)}bot messages list <chat>\` once`);
94
+ };
54
95
  const show = (context, messages) => {
55
96
  if (context.format !== "pretty") {
56
97
  context.renderer.result(messages);
@@ -60,7 +101,7 @@ const show = (context, messages) => {
60
101
  verbosity: context.settings.detail,
61
102
  color: context.color,
62
103
  profile: context.settings.profile,
63
- provider: "max-bot",
104
+ provider: PROVIDER,
64
105
  }));
65
106
  };
66
107
  export const chatsCommand = () => {
@@ -69,16 +110,17 @@ export const chatsCommand = () => {
69
110
  .command("list")
70
111
  .description("chats this bot has seen on this machine — not a complete list from MAX")
71
112
  .action(function () {
72
- const { renderer, registry } = botContext(this);
113
+ const { renderer, registry } = botContext(this, { offline: true });
73
114
  renderer.result(registry.list());
74
115
  });
75
116
  command
76
117
  .command("get <chat>")
77
118
  .description("one chat from MAX, and remember it")
78
119
  .action(async function (chat) {
79
- const { renderer, registry, authenticated } = botContext(this);
120
+ const { renderer, registry, authenticated, streams } = botContext(this);
80
121
  const found = await authenticated().chat(chatIdOf(chat, registry));
81
122
  registry.observe([found]);
123
+ await keepChat(registry.botId(), found, streams.diagnostic);
82
124
  renderer.result(found);
83
125
  });
84
126
  const write = (name, operationId, description, body) => annotate(command.command(name), { mutates: true })
@@ -1 +1 @@
1
- {"version":3,"file":"bot-reads.js","sourceRoot":"","sources":["../../src/commands/bot-reads.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bot-reads.js","sourceRoot":"","sources":["../../src/commands/bot-reads.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,13 @@
1
1
  import type { ManifestOperation } from "@leemour/cli-core/codegen";
2
2
  import { Command } from "commander";
3
3
  import { type CallInput } from "../bot/transport.js";
4
+ import { type UploadType } from "../bot/uploads.js";
4
5
  import { botContext } from "./bot-context.js";
5
6
  type Context = ReturnType<typeof botContext>;
7
+ export declare const operation: (id: string) => ManifestOperation;
8
+ /** Step one through the client, step two to the upload host; the attachment a body carries. */
9
+ export declare const uploaded: (context: Context, path: string, type?: UploadType, call?: (target: ManifestOperation, input: CallInput) => Promise<unknown>) => Promise<import("../bot/uploads.js").Attachment>;
10
+ export declare const textOf: (text: string) => string;
6
11
  /** Every bot write, from any command: readOnly and allow, then the recipient list and the journal. */
7
12
  export declare const guardedCall: (context: Context, target: ManifestOperation, input: CallInput) => Promise<unknown>;
8
13
  export declare const sendCommands: (messages: Command) => void;
@@ -1 +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"}
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;AAM3C,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAGL,KAAK,UAAU,EAIhB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAiB,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE5D,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;AAE5C,eAAO,MAAM,SAAS,OAAQ,MAAM,sBAInC,CAAA;AA2DD,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,YACV,OAAO,QACV,MAAM,SACN,UAAU,SACV,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,oDAYxE,CAAA;AAED,eAAO,MAAM,MAAM,SAAU,MAAM,KAAG,MAA4E,CAAA;AAgElH,sGAAsG;AACtG,eAAO,MAAM,WAAW,YAAmB,OAAO,UAAU,iBAAiB,SAAS,SAAS,KAAG,OAAO,CAAC,OAAO,CAUhH,CAAA;AAED,eAAO,MAAM,YAAY,aAAc,OAAO,KAAG,IAyGhD,CAAA;AAED,eAAO,MAAM,iBAAiB,QAAO,OAoCpC,CAAA;AAED,eAAO,MAAM,YAAY,QAAO,OAQ3B,CAAA"}
@@ -7,12 +7,14 @@ import { newSendId, RecipientList, SendJournal, sendGuard } from "@leemour/cli-m
7
7
  import { Command, Option } from "commander";
8
8
  import { botOperations } from "../bot/client.js";
9
9
  import { checkBody } from "../bot/input.js";
10
+ import { forget, keepSent } from "../bot/keep.js";
10
11
  import { BOT_JOURNAL_KINDS } from "../bot/permissions.js";
11
12
  import { botsDirectory } from "../bot/registry.js";
12
13
  import { plainJson } from "../bot/transport.js";
14
+ import { endpointOf, UPLOAD_TYPES, uploadFile, uploadTypeOf, whenAttachmentReady, } from "../bot/uploads.js";
13
15
  import { asFirstWord } from "../profile.js";
14
16
  import { assertAllowed, botContext } from "./bot-context.js";
15
- const operation = (id) => {
17
+ export const operation = (id) => {
16
18
  const found = botOperations.find((candidate) => candidate.id === id);
17
19
  if (!found)
18
20
  throw new CliError("configuration_error", `the generated manifest has no operation ${id}`);
@@ -49,12 +51,40 @@ const targetOf = (reference, context) => {
49
51
  const id = pickChat(reference, context.registry.list()).id;
50
52
  return { key: id, query: { chat_id: id } };
51
53
  };
52
- const textOf = (text) => (text === "-" ? readFileSync(0, "utf8").replace(/\n$/, "") : text);
54
+ /**
55
+ * `UX-14`: a positive number is a person far more often than a chat — group chats are negative —
56
+ * yet a dialog's chat id is positive too, so this is a hint and never a refusal.
57
+ */
58
+ const withPersonHint = (error, reference) => {
59
+ const failure = error;
60
+ if (!/^\d+$/.test(reference) || failure.details?.maxCode !== "chat.not.found" || !failure.code)
61
+ return error;
62
+ return new CliError(failure.code, `${failure.message} — a positive number is usually a person, not a chat: to write to them, use user:${reference}`, failure.details);
63
+ };
64
+ /** Step one through the client, step two to the upload host; the attachment a body carries. */
65
+ export const uploaded = async (context, path, type = uploadTypeOf(path), call = (target, input) => context.authenticated().call(target, input)) => {
66
+ const answer = await call(operation("getUploadUrl"), { query: { type } });
67
+ return uploadFile({
68
+ path,
69
+ type,
70
+ endpoint: endpointOf(answer),
71
+ fetch: context.uploadFetch(),
72
+ ...(context.signal ? { signal: context.signal } : {}),
73
+ ...(context.settings.timeoutMs === undefined ? {} : { timeoutMs: context.settings.timeoutMs }),
74
+ });
75
+ };
76
+ export const textOf = (text) => (text === "-" ? readFileSync(0, "utf8").replace(/\n$/, "") : text);
53
77
  /** Runs one write through the guard and the journal, on every outcome. */
54
78
  const guarded = async (context, request, body, length) => {
55
79
  const guard = guardOf(context);
56
80
  const sendId = newSendId();
57
- const base = { chatId: request.chatId, kind: request.kind, sendId, ...(length === undefined ? {} : { length }) };
81
+ const base = {
82
+ chatId: request.chatId,
83
+ kind: request.kind,
84
+ sendId,
85
+ ...(request.action ? { action: request.action } : {}),
86
+ ...(length === undefined ? {} : { length }),
87
+ };
58
88
  try {
59
89
  guard.check(request);
60
90
  }
@@ -113,38 +143,50 @@ export const guardedCall = async (context, target, input) => {
113
143
  if (!kind)
114
144
  return client.call(target, input);
115
145
  const chatId = await chatOfCall(context, input);
116
- return guarded(context, { chatId, kind }, async () => ({ result: await client.call(target, input) }));
146
+ // The guard names every account change; the bot's own `allow` check has already run in assertAllowed.
147
+ const action = kind === "account" ? { action: "profile" } : {};
148
+ return guarded(context, { chatId, kind, ...action }, async () => ({ result: await client.call(target, input) }));
117
149
  };
118
150
  export const sendCommands = (messages) => {
119
151
  annotate(messages.command("send"), { mutates: true })
120
152
  .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
153
  .argument("<chat>")
122
- .argument("<text>")
154
+ .argument("[text]", "may be left out with --file")
123
155
  .addOption(new Option("--format <format>", "how the text is marked up").choices(["markdown", "html"]))
124
156
  .option("--reply-to <message>", "answer this message")
125
157
  .option("--silent", "no notification for the people in the chat")
158
+ .option("--file <path>", "attach a file from disk: an image, video or audio by its extension, else a file")
159
+ .addOption(new Option("--type <type>", "send --file as this kind instead of guessing").choices(UPLOAD_TYPES))
126
160
  .action(async function (chat, text) {
127
161
  const context = botContext(this);
128
162
  const options = this.opts();
163
+ if (text === undefined && !options.file)
164
+ throw new CliError("validation_error", "nothing to send: give a text or --file");
129
165
  const send = operation("sendMessage");
130
166
  assertAllowed(send, context.settings);
131
167
  const target = targetOf(chat, context);
132
- const content = textOf(text);
133
- const body = checkBody(send, JSON.stringify({
134
- text: content,
168
+ const content = text === undefined ? "" : textOf(text);
169
+ const bodyWith = (attachments) => checkBody(send, JSON.stringify({
170
+ ...(content ? { text: content } : {}),
171
+ ...(attachments ? { attachments } : {}),
135
172
  ...(options.format ? { format: options.format } : {}),
136
173
  ...(options.silent ? { notify: false } : {}),
137
174
  ...(options.replyTo ? { link: { type: "reply", mid: options.replyTo } } : {}),
138
175
  }));
139
176
  const client = context.authenticated();
140
177
  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;
178
+ const attachment = options.file ? await uploaded(context, options.file, options.type) : undefined;
179
+ const body = bodyWith(attachment ? [attachment] : undefined);
180
+ const answer = (await whenAttachmentReady(() => client.call(send, { query: target.query, ...(body ? { body } : {}) }), context.signal));
181
+ const message = answer?.message ? { ...client.decodeMessage(answer.message), outgoing: true } : undefined;
143
182
  return { result: message ?? plainJson(answer), ...(message ? { messageId: message.id } : {}) };
144
- }, content.length);
183
+ }, content.length).catch((error) => {
184
+ throw withPersonHint(error, chat);
185
+ });
145
186
  const recipientChat = sent.chatId;
146
187
  if (recipientChat && DIGITS.test(recipientChat))
147
188
  context.registry.observe([{ id: recipientChat }]);
189
+ await keepSent(context.registry, sent, context.streams.diagnostic);
148
190
  context.renderer.result(sent);
149
191
  });
150
192
  annotate(messages.command("edit"), { mutates: true })
@@ -178,6 +220,9 @@ export const sendCommands = (messages) => {
178
220
  result: plainJson(await context.authenticated().call(remove, { query: { message_id: messageId } })),
179
221
  messageId,
180
222
  }));
223
+ const botId = context.registry.botId();
224
+ if (botId)
225
+ await forget(botId, [{ chatId, messageId }], context.streams.diagnostic);
181
226
  context.renderer.result(answer ?? { success: true });
182
227
  });
183
228
  };