@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.
- package/README.md +43 -9
- package/dist/bot/client.d.ts +1 -1
- package/dist/bot/client.d.ts.map +1 -1
- package/dist/bot/client.js +2 -2
- package/dist/bot/client.js.map +1 -1
- 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/registry.d.ts +3 -0
- package/dist/bot/registry.d.ts.map +1 -1
- package/dist/bot/registry.js +27 -10
- package/dist/bot/registry.js.map +1 -1
- 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 +19 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +76 -39
- 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 +9 -3
- package/dist/commands/bot-context.d.ts.map +1 -1
- package/dist/commands/bot-context.js +38 -15
- package/dist/commands/bot-context.js.map +1 -1
- 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.map +1 -1
- package/dist/commands/bot-reads.js +50 -8
- package/dist/commands/bot-reads.js.map +1 -1
- package/dist/commands/bot-sends.d.ts +5 -0
- package/dist/commands/bot-sends.d.ts.map +1 -1
- package/dist/commands/bot-sends.js +56 -11
- package/dist/commands/bot-sends.js.map +1 -1
- 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.map +1 -1
- package/dist/commands/bot.js +15 -0
- package/dist/commands/bot.js.map +1 -1
- package/dist/commands/chats.d.ts.map +1 -1
- package/dist/commands/chats.js +19 -6
- 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 +5 -0
- 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 +5 -7
- package/dist/commands/review.js.map +1 -1
- package/dist/domain/models.d.ts +4 -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 +13 -0
- 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 +150 -11
- 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/review.d.ts +10 -4
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +35 -53
- 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/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 +5 -2
- 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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
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
|
|
24
|
-
const client = (token) =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAG5C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAoB,eAAe,EAAiB,MAAM,cAAc,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAgB,EAAE,EAAE;
|
|
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":"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"}
|
|
@@ -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;
|
|
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
|
-
|
|
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:
|
|
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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AACrD,OAAO,EAAgB,QAAQ,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;
|
|
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;
|
|
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
|
-
|
|
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 = {
|
|
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
|
-
|
|
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("
|
|
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
|
|
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
|
|
142
|
-
const
|
|
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
|
};
|