@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.
- package/README.md +92 -19
- package/dist/bot/auth.d.ts +23 -0
- package/dist/bot/auth.d.ts.map +1 -0
- package/dist/bot/auth.js +36 -0
- package/dist/bot/auth.js.map +1 -0
- package/dist/bot/client.d.ts +20 -0
- package/dist/bot/client.d.ts.map +1 -0
- package/dist/bot/client.js +91 -0
- package/dist/bot/client.js.map +1 -0
- package/dist/bot/generated/manifest.d.ts +3 -0
- package/dist/bot/generated/manifest.d.ts.map +1 -0
- package/dist/bot/generated/manifest.js +1232 -0
- package/dist/bot/generated/manifest.js.map +1 -0
- package/dist/bot/generated/schemas.d.ts +271 -0
- package/dist/bot/generated/schemas.d.ts.map +1 -0
- package/dist/bot/generated/schemas.js +869 -0
- package/dist/bot/generated/schemas.js.map +1 -0
- package/dist/bot/generated/types.d.ts +1088 -0
- package/dist/bot/generated/types.d.ts.map +1 -0
- package/dist/bot/generated/types.js +5 -0
- package/dist/bot/generated/types.js.map +1 -0
- package/dist/bot/input.d.ts +10 -0
- package/dist/bot/input.d.ts.map +1 -0
- package/dist/bot/input.js +88 -0
- package/dist/bot/input.js.map +1 -0
- package/dist/bot/map.d.ts +11 -0
- package/dist/bot/map.d.ts.map +1 -0
- package/dist/bot/map.js +76 -0
- package/dist/bot/map.js.map +1 -0
- package/dist/bot/permissions.d.ts +14 -0
- package/dist/bot/permissions.d.ts.map +1 -0
- package/dist/bot/permissions.js +53 -0
- package/dist/bot/permissions.js.map +1 -0
- package/dist/bot/registry.d.ts +27 -0
- package/dist/bot/registry.d.ts.map +1 -0
- package/dist/bot/registry.js +68 -0
- package/dist/bot/registry.js.map +1 -0
- package/dist/bot/russian-trusted-root.d.ts +8 -0
- package/dist/bot/russian-trusted-root.d.ts.map +1 -0
- package/dist/bot/russian-trusted-root.js +41 -0
- package/dist/bot/russian-trusted-root.js.map +1 -0
- package/dist/bot/transport.d.ts +41 -0
- package/dist/bot/transport.d.ts.map +1 -0
- package/dist/bot/transport.js +200 -0
- package/dist/bot/transport.js.map +1 -0
- package/dist/client.d.ts +32 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +174 -18
- package/dist/client.js.map +1 -1
- package/dist/commands/bot-context.d.ts +21 -0
- package/dist/commands/bot-context.d.ts.map +1 -0
- package/dist/commands/bot-context.js +59 -0
- package/dist/commands/bot-context.js.map +1 -0
- package/dist/commands/bot-reads.d.ts +7 -0
- package/dist/commands/bot-reads.d.ts.map +1 -0
- package/dist/commands/bot-reads.js +103 -0
- package/dist/commands/bot-reads.js.map +1 -0
- package/dist/commands/bot-sends.d.ts +12 -0
- package/dist/commands/bot-sends.d.ts.map +1 -0
- package/dist/commands/bot-sends.js +225 -0
- package/dist/commands/bot-sends.js.map +1 -0
- package/dist/commands/bot.d.ts +3 -0
- package/dist/commands/bot.d.ts.map +1 -0
- package/dist/commands/bot.js +145 -0
- package/dist/commands/bot.js.map +1 -0
- package/dist/commands/chats.d.ts.map +1 -1
- package/dist/commands/chats.js +65 -1
- package/dist/commands/chats.js.map +1 -1
- package/dist/commands/context.d.ts +10 -1
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/doctor.d.ts +6 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +57 -7
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/mcp.d.ts +24 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +80 -14
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/models.d.ts.map +1 -1
- package/dist/commands/models.js +13 -2
- package/dist/commands/models.js.map +1 -1
- package/dist/commands/review.d.ts +8 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +96 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/rules.d.ts +7 -0
- package/dist/commands/rules.d.ts.map +1 -0
- package/dist/commands/rules.js +69 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/diagnose.d.ts +19 -1
- package/dist/diagnose.d.ts.map +1 -1
- package/dist/diagnose.js +37 -1
- package/dist/diagnose.js.map +1 -1
- package/dist/domain/map.d.ts +6 -1
- package/dist/domain/map.d.ts.map +1 -1
- package/dist/domain/map.js +34 -1
- package/dist/domain/map.js.map +1 -1
- package/dist/domain/models.d.ts +79 -0
- package/dist/domain/models.d.ts.map +1 -1
- package/dist/domain/models.js.map +1 -1
- package/dist/generated/operations.generated.d.ts +3 -1
- package/dist/generated/operations.generated.d.ts.map +1 -1
- package/dist/install.d.ts +43 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +142 -0
- package/dist/install.js.map +1 -0
- package/dist/mcp/prompts.d.ts.map +1 -1
- package/dist/mcp/prompts.js +28 -0
- package/dist/mcp/prompts.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +39 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/moderation/rules.d.ts +56 -0
- package/dist/moderation/rules.d.ts.map +1 -0
- package/dist/moderation/rules.js +138 -0
- package/dist/moderation/rules.js.map +1 -0
- package/dist/online.d.ts +23 -0
- package/dist/online.d.ts.map +1 -0
- package/dist/online.js +87 -0
- package/dist/online.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +20 -3
- package/dist/program.js.map +1 -1
- package/dist/protocol/connection.d.ts.map +1 -1
- package/dist/protocol/connection.js +12 -1
- package/dist/protocol/connection.js.map +1 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +13 -2
- package/dist/report.js.map +1 -1
- package/dist/review.d.ts +41 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +111 -0
- package/dist/review.js.map +1 -0
- package/dist/spec/operations/chats.d.ts +4 -1
- package/dist/spec/operations/chats.d.ts.map +1 -1
- package/dist/spec/operations/chats.js +10 -4
- package/dist/spec/operations/chats.js.map +1 -1
- package/dist/transcribe/index.d.ts +1 -0
- package/dist/transcribe/index.d.ts.map +1 -1
- package/dist/transcribe/index.js +8 -4
- package/dist/transcribe/index.js.map +1 -1
- package/dist/transcribe/speech.d.ts.map +1 -1
- package/dist/transcribe/speech.js +2 -0
- package/dist/transcribe/speech.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -6
- package/skills/max-cli/SKILL.md +26 -1
package/README.md
CHANGED
|
@@ -4,13 +4,52 @@
|
|
|
4
4
|
|
|
5
5
|
# max-cli
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Ваши боты [MAX](https://max.ru) и ваш личный аккаунт — в терминале и в ИИ-агентах. `max` —
|
|
8
|
+
программа для терминала и MCP-сервер: пишите от имени бота через официальный Bot API, а в свои
|
|
9
|
+
чаты — сами или руками Claude, Codex, Cursor и других агентов.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
```sh
|
|
12
|
+
max sales bot messages send "Команда продаж" "Сборка готова" # от имени бота
|
|
13
|
+
max messages send "Иван Петров" "Опаздываю на 15 минут" # от вашего имени
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Бот
|
|
17
|
+
|
|
18
|
+
`max bot` работает с ботом через **официальный** [Bot API MAX](https://dev.max.ru/docs-api) по токену
|
|
19
|
+
бота. Ботов может быть несколько: каждый хранится под именем, которое вы выбираете, и это имя —
|
|
20
|
+
первое слово команды.
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
max sales bot auth set # токен — в скрытом вводе, MAX его проверит
|
|
24
|
+
max sales bot me # какой это бот
|
|
25
|
+
max sales bot messages send -72894839451 "Сборка готова"
|
|
26
|
+
max sales bot messages list -72894839451
|
|
27
|
+
max sales bot recipients add -72894839451 # писать только сюда
|
|
28
|
+
max bot list --check # все боты на этом компьютере
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **Сообщения и чаты.** Отправка в чат по номеру, человеку как `user:<номер>` или в чат по
|
|
32
|
+
названию; правка, удаление, чтение, закрепление. `chats list` — чаты, которые бот видел: списка
|
|
33
|
+
чатов бота у MAX нет.
|
|
34
|
+
- **Любая операция API.** Все операции Bot API доступны как `max bot api <операция>` — с флагами
|
|
35
|
+
для параметров и JSON-телом, которое сверяется со схемой до отправки.
|
|
36
|
+
- **Бот не напишет лишнего.** У каждого бота свой список чатов, куда ему можно писать, и журнал
|
|
37
|
+
всего, что он отправил, — без текста. Профиль только для чтения и `allow` действуют и на бота.
|
|
38
|
+
- **Токен не в файле.** Токен бота — в системном хранилище паролей, отдельно от вашего.
|
|
39
|
+
|
|
40
|
+
Бота создают на [business.max.ru](https://business.max.ru/self); MAX выдаёт их подтверждённым
|
|
41
|
+
организациям, ИП и самозанятым. Полностью — [docs/bot.md](docs/bot.md).
|
|
42
|
+
|
|
43
|
+
## Личный аккаунт
|
|
44
|
+
|
|
45
|
+
`max` без слова `bot` работает с вашим личным аккаунтом: как ещё одно ваше устройство, со всеми
|
|
46
|
+
чатами, историей, группами и контактами.
|
|
47
|
+
|
|
48
|
+
> ⚠️ **Для личного аккаунта max-cli использует неофициальный внутренний API MAX.** API может
|
|
49
|
+
> измениться без предупреждения, а использование инструмента может нарушать условия сервиса. Вы
|
|
50
|
+
> используете max-cli на свой риск; авторы и контрибьюторы не несут ответственности за блокировки
|
|
51
|
+
> аккаунтов, потерю данных или другие последствия. Бот работает через официальный API, и к нему
|
|
52
|
+
> это не относится.
|
|
14
53
|
|
|
15
54
|
```sh
|
|
16
55
|
max chats list --limit 5
|
|
@@ -18,6 +57,8 @@ max messages list "Иван Петров"
|
|
|
18
57
|
max messages send "Иван Петров" "Опаздываю на 15 минут"
|
|
19
58
|
```
|
|
20
59
|
|
|
60
|
+
Всё ниже, до раздела «Установка», — про личный аккаунт. Полностью — [docs/usage.md](docs/usage.md).
|
|
61
|
+
|
|
21
62
|
## Как это использовать
|
|
22
63
|
|
|
23
64
|
Самое полезное — поручить переписку агенту: Claude, Codex или другому. Он читает чаты через `max`
|
|
@@ -27,14 +68,34 @@ max messages send "Иван Петров" "Опаздываю на 15 минут
|
|
|
27
68
|
сводку: кто ждёт ответа, что срочно, что можно не читать.
|
|
28
69
|
- **Отчёты.** Итог недели по рабочему чату: что решили, кто что взял на себя, какие вопросы
|
|
29
70
|
остались без ответа.
|
|
30
|
-
- **Кто кому должен.**
|
|
31
|
-
|
|
71
|
+
- **Кто кому должен.** `max review` одним вызовом отдаёт всё, что было в переписке с прошлого
|
|
72
|
+
обзора, — ваши сообщения тоже, голосовые — текстом. Агент раскладывает это на «я должен», «жду от
|
|
73
|
+
других» и «нужно уточнить», а прежде чем назвать что-то просроченным, проверяет рабочие группы:
|
|
74
|
+
может, уже сделано.
|
|
32
75
|
- **Напоминания.** Кому вы обещали ответить и не ответили; чей вопрос висит третий день.
|
|
33
76
|
- **Черновики ответов.** Агент предлагает текст, а отправляете вы — или он сам, если вы разрешили
|
|
34
77
|
писать в этот чат.
|
|
35
78
|
- **Поиск.** «Когда мы договорились о встрече с Иваном?» — ответ с датой и самим сообщением.
|
|
36
79
|
|
|
37
|
-
Как
|
|
80
|
+
Как это выглядит:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
Вы: Что я кому обещал за последние три дня?
|
|
84
|
+
Агент: (вызывает max review: 12 чатов, 3 голосовых расшифровано)
|
|
85
|
+
Я должен
|
|
86
|
+
· Ивану Петрову — прислать счёт до пятницы. «Иван Петров», 24.09
|
|
87
|
+
Жду от других
|
|
88
|
+
· Ольга — макет к 25.09. В группе «Дизайн» его пока нет
|
|
89
|
+
Нужно уточнить
|
|
90
|
+
· «Проект Альфа»: кто везёт образцы — договорились «потом решим», 25.09
|
|
91
|
+
Следующий обзор — с 26.09, 14:05.
|
|
92
|
+
Вы: Напомни Ольге про макет.
|
|
93
|
+
Агент: Черновик: «Ольга, привет! Как там макет?» Отправить?
|
|
94
|
+
Вы: Да.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Агент ничего не отправляет без вашего «да», а чтение не ставит отметку «прочитано». Как настроить
|
|
98
|
+
агента под каждую задачу — готовые запросы, расписание и ограничения:
|
|
38
99
|
[docs/recipes.md](docs/recipes.md).
|
|
39
100
|
|
|
40
101
|
## Как это работает
|
|
@@ -48,9 +109,11 @@ max messages send "Иван Петров" "Опаздываю на 15 минут
|
|
|
48
109
|
- **Агент с терминалом** — Claude Code, Codex, Gemini CLI. Он сам вызывает команды `max`. Дайте
|
|
49
110
|
ему навык (skill) — инструкцию, как работать с `max`: одна команда, см.
|
|
50
111
|
[ниже](#для-скриптов-и-агентов).
|
|
51
|
-
- **Агент без терминала** — Claude Desktop, Cursor и другие клиенты MCP. Подключите `max mcp
|
|
52
|
-
|
|
53
|
-
|
|
112
|
+
- **Агент без терминала** — Claude Desktop, Cursor и другие клиенты MCP. Подключите `max mcp`:
|
|
113
|
+
готовую запись для их настроек печатает `max mcp config`. Там же есть команды `/catch-up` (что
|
|
114
|
+
нового), `/review` (кто кому должен), `/reply` (черновик ответа) и `/find` (поиск). По умолчанию
|
|
115
|
+
агент только читает. Отправку можно разрешить, в том числе с вашим подтверждением каждого
|
|
116
|
+
сообщения.
|
|
54
117
|
|
|
55
118
|
[](https://www.npmjs.com/package/@leemour/max-cli)
|
|
56
119
|
[](https://github.com/leemour/max-cli/actions/workflows/ci.yml)
|
|
@@ -62,7 +125,7 @@ max messages send "Иван Петров" "Опаздываю на 15 минут
|
|
|
62
125
|
## Что умеет
|
|
63
126
|
|
|
64
127
|
- **Читать.** Чаты, история, одно сообщение вместе с соседними, непрочитанное во всех чатах
|
|
65
|
-
сразу (`max inbox`), новые сообщения по мере прихода (`max watch`), скачивание вложений,
|
|
128
|
+
сразу (`max inbox`), вся переписка с прошлого обзора для разбора «кто кому должен» (`max review`), новые сообщения по мере прихода (`max watch`), скачивание вложений,
|
|
66
129
|
расшифровка голосовых в текст на вашем компьютере, выгрузка переписки в JSONL или Markdown.
|
|
67
130
|
- **Искать.** Сообщения — по тексту всего прочитанного, без подключения к MAX. Чаты и контакты —
|
|
68
131
|
по части названия или имени.
|
|
@@ -135,11 +198,13 @@ max messages send "Иван Петров" "Опаздываю на 15 минут
|
|
|
135
198
|
| опросы | — | ✅ | — |
|
|
136
199
|
| пароль и двухфакторный вход, фото профиля | — | ✅ | — |
|
|
137
200
|
|
|
138
|
-
|
|
139
|
-
[
|
|
201
|
+
Для бота есть `max bot` — через официальный Bot API, отдельно от личного аккаунта
|
|
202
|
+
([docs/bot.md](docs/bot.md)). Таблица выше — про личный аккаунт.
|
|
140
203
|
|
|
141
204
|
## Содержание
|
|
142
205
|
|
|
206
|
+
- [Бот](#бот)
|
|
207
|
+
- [Личный аккаунт](#личный-аккаунт)
|
|
143
208
|
- [Установка](#установка)
|
|
144
209
|
- [Вход](#вход)
|
|
145
210
|
- [Использование](#использование)
|
|
@@ -169,8 +234,11 @@ npm install -g @leemour/max-cli
|
|
|
169
234
|
max --version
|
|
170
235
|
```
|
|
171
236
|
|
|
172
|
-
Нужен **Node 22 или новее**, либо **Bun 1.3+**.
|
|
173
|
-
ложатся файлы, — [docs/installation.md](docs/installation.md).
|
|
237
|
+
Нужен **Node 22 или новее**, либо **Bun 1.3+**. Работает на macOS, Linux и Windows. Подробности,
|
|
238
|
+
переменные окружения и то, куда ложатся файлы, — [docs/installation.md](docs/installation.md).
|
|
239
|
+
|
|
240
|
+
Если после установки команда `max` не находится, `npx @leemour/max-cli doctor` скажет почему и
|
|
241
|
+
напечатает команду, которая это исправит.
|
|
174
242
|
|
|
175
243
|
## Вход
|
|
176
244
|
|
|
@@ -257,9 +325,13 @@ Claude Desktop, Cursor и другие клиенты MCP подключаютс
|
|
|
257
325
|
видите чат и текст и отвечаете «да» или «нет». Подробно — [docs/mcp.md](docs/mcp.md).
|
|
258
326
|
|
|
259
327
|
```sh
|
|
260
|
-
claude mcp add max -- max mcp
|
|
328
|
+
claude mcp add max -- max mcp # Claude Code
|
|
329
|
+
max mcp config # запись для Claude Desktop, Cursor и других — с полными путями
|
|
261
330
|
```
|
|
262
331
|
|
|
332
|
+
Команды сервера — `/catch-up`, `/review`, `/reply`, `/find` — готовые просьбы: агент знает, какие
|
|
333
|
+
инструменты вызвать и чего не делать.
|
|
334
|
+
|
|
263
335
|
### Ответы в JSON
|
|
264
336
|
|
|
265
337
|
```sh
|
|
@@ -303,7 +375,8 @@ max chats list --json
|
|
|
303
375
|
## Документация
|
|
304
376
|
|
|
305
377
|
- [docs/installation.md](docs/installation.md) — установка, обновление, куда что ложится
|
|
306
|
-
- [docs/
|
|
378
|
+
- [docs/bot.md](docs/bot.md) — бот: токен, несколько ботов, сообщения, чаты, список получателей, любая операция API
|
|
379
|
+
- [docs/usage.md](docs/usage.md) — личный аккаунт: вход, чтение, отправка, машинный режим
|
|
307
380
|
- [docs/sessions.md](docs/sessions.md) — токен, хранилище паролей, профили
|
|
308
381
|
- [docs/configuration.md](docs/configuration.md) — настройки, переменные, порядок разрешения
|
|
309
382
|
- [docs/mcp.md](docs/mcp.md) — MCP-сервер: подключение, отправка, соединение с MAX
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type CredentialSource, type KeyringStore } from "@leemour/cli-core";
|
|
2
|
+
export interface BotTokenStoreOptions {
|
|
3
|
+
profile: string;
|
|
4
|
+
env?: NodeJS.ProcessEnv;
|
|
5
|
+
keyring?: KeyringStore;
|
|
6
|
+
configDir?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A bot token per profile, beside — never inside — the personal session: keyring account
|
|
10
|
+
* `bot:<profile>`, environment variable `MAX_BOT_TOKEN`, then a 0600 file (`NEED-295`).
|
|
11
|
+
*/
|
|
12
|
+
export declare class BotTokenStore {
|
|
13
|
+
#private;
|
|
14
|
+
readonly profile: string;
|
|
15
|
+
constructor({ profile, env, keyring, configDir }: BotTokenStoreOptions);
|
|
16
|
+
read(): {
|
|
17
|
+
token: string;
|
|
18
|
+
source: CredentialSource;
|
|
19
|
+
} | undefined;
|
|
20
|
+
write(token: string): CredentialSource;
|
|
21
|
+
remove(): CredentialSource[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/bot/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,YAAY,EAGlB,MAAM,mBAAmB,CAAA;AAI1B,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,qBAAa,aAAa;;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IAIxB,YAAY,EAAE,OAAO,EAAE,GAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,oBAAoB,EAanF;IAED,IAAI,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,gBAAgB,CAAA;KAAE,GAAG,SAAS,CAG9D;IAED,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAErC;IAED,MAAM,IAAI,gBAAgB,EAAE,CAE3B;CACF"}
|
package/dist/bot/auth.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Credentials, pathsAreOverridden, resolvePaths, } from "@leemour/cli-core";
|
|
2
|
+
const APP = "max-cli";
|
|
3
|
+
/**
|
|
4
|
+
* A bot token per profile, beside — never inside — the personal session: keyring account
|
|
5
|
+
* `bot:<profile>`, environment variable `MAX_BOT_TOKEN`, then a 0600 file (`NEED-295`).
|
|
6
|
+
*/
|
|
7
|
+
export class BotTokenStore {
|
|
8
|
+
profile;
|
|
9
|
+
#account;
|
|
10
|
+
#credentials;
|
|
11
|
+
constructor({ profile, env = process.env, keyring, configDir }) {
|
|
12
|
+
const paths = resolvePaths({ appName: APP, prefix: "MAX", env });
|
|
13
|
+
this.profile = profile;
|
|
14
|
+
this.#account = `bot:${profile}`;
|
|
15
|
+
this.#credentials = new Credentials({
|
|
16
|
+
configDir: configDir ?? paths.config,
|
|
17
|
+
service: APP,
|
|
18
|
+
envVar: "MAX_BOT_TOKEN",
|
|
19
|
+
isolated: pathsAreOverridden({ appName: APP, prefix: "MAX", env }),
|
|
20
|
+
...(keyring ? { keyring } : {}),
|
|
21
|
+
env,
|
|
22
|
+
warn: (message) => process.stderr.write(`${message}\n`),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
read() {
|
|
26
|
+
const stored = this.#credentials.read(this.#account);
|
|
27
|
+
return stored ? { token: stored.secret, source: stored.source } : undefined;
|
|
28
|
+
}
|
|
29
|
+
write(token) {
|
|
30
|
+
return this.#credentials.write(this.#account, token);
|
|
31
|
+
}
|
|
32
|
+
remove() {
|
|
33
|
+
return this.#credentials.remove(this.#account);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/bot/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EAEX,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAA;AAE1B,MAAM,GAAG,GAAG,SAAS,CAAA;AASrB;;;GAGG;AACH,MAAM,OAAO,aAAa;IACf,OAAO,CAAQ;IACf,QAAQ,CAAQ;IAChB,YAAY,CAAa;IAElC,YAAY,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAwB;QAClF,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;QAChE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,OAAO,OAAO,EAAE,CAAA;QAChC,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC;YAClC,SAAS,EAAE,SAAS,IAAI,KAAK,CAAC,MAAM;YACpC,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE,eAAe;YACvB,QAAQ,EAAE,kBAAkB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YAClE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,GAAG;YACH,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC;SACxD,CAAC,CAAA;IACJ,CAAC;IAED,IAAI;QACF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACpD,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IAC7E,CAAC;IAED,KAAK,CAAC,KAAa;QACjB,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IACtD,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAChD,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ManifestOperation } from "@leemour/cli-core/codegen";
|
|
2
|
+
import type { Chat, Message } from "@leemour/cli-messaging";
|
|
3
|
+
import type { BotInfo as BotInfoType } from "./generated/types.js";
|
|
4
|
+
import { type CallInput, type TransportOptions } from "./transport.js";
|
|
5
|
+
/** Every operation of the committed schema, as the manifest describes it. */
|
|
6
|
+
export declare const botOperations: readonly ManifestOperation[];
|
|
7
|
+
/** The one door to the Bot API: generated operations stay behind it. */
|
|
8
|
+
export declare class BotApiClient {
|
|
9
|
+
#private;
|
|
10
|
+
constructor(options: TransportOptions);
|
|
11
|
+
me(): Promise<BotInfoType>;
|
|
12
|
+
chat(chatId: string): Promise<Chat>;
|
|
13
|
+
message(messageId: string, selfId?: string): Promise<Message>;
|
|
14
|
+
/** Newest last, as MAX returns them. */
|
|
15
|
+
messages(chatId: string, count: number, selfId?: string): Promise<Message[]>;
|
|
16
|
+
/** A message from any answer — a send's result, an update — decoded the same way as a read. */
|
|
17
|
+
decodeMessage(raw: unknown, selfId?: string): Message;
|
|
18
|
+
call(operation: ManifestOperation, input: CallInput): Promise<unknown>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/bot/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAI3D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAyB,MAAM,sBAAsB,CAAA;AAEzF,OAAO,EAAgB,KAAK,SAAS,EAAa,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAE/F,6EAA6E;AAC7E,eAAO,MAAM,aAAa,EAAE,SAAS,iBAAiB,EAAe,CAAA;AAUrE,wEAAwE;AACxE,qBAAa,YAAY;;IAGvB,YAAY,OAAO,EAAE,gBAAgB,EAEpC;IAEK,EAAE,IAAI,OAAO,CAAC,WAAW,CAAC,CAU/B;IAEK,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxC;IAEK,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGlE;IAED,wCAAwC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAKjF;IAED,+FAA+F;IAC/F,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAEpD;IAED,IAAI,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAErE;CAyCF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { CliError } from "@leemour/cli-core";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
import { operations } from "./generated/manifest.js";
|
|
4
|
+
import { BotInfo, Chat as ChatSchema, Message as MessageSchema } from "./generated/schemas.js";
|
|
5
|
+
import { toChat, toMessage } from "./map.js";
|
|
6
|
+
import { BotTransport, plainJson } from "./transport.js";
|
|
7
|
+
/** Every operation of the committed schema, as the manifest describes it. */
|
|
8
|
+
export const botOperations = operations;
|
|
9
|
+
const operationById = new Map(operations.map((operation) => [operation.id, operation]));
|
|
10
|
+
const required = (id) => {
|
|
11
|
+
const operation = operationById.get(id);
|
|
12
|
+
if (!operation)
|
|
13
|
+
throw new CliError("configuration_error", `the generated manifest has no operation ${id}`);
|
|
14
|
+
return operation;
|
|
15
|
+
};
|
|
16
|
+
/** The one door to the Bot API: generated operations stay behind it. */
|
|
17
|
+
export class BotApiClient {
|
|
18
|
+
#transport;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.#transport = new BotTransport(options);
|
|
21
|
+
}
|
|
22
|
+
async me() {
|
|
23
|
+
const answer = await this.#transport.call(required("getMyInfo"));
|
|
24
|
+
const parsed = v.safeParse(BotInfo, answer);
|
|
25
|
+
if (!parsed.success) {
|
|
26
|
+
throw new CliError("invalid_response", "MAX answered getMyInfo in a shape this version does not know", {
|
|
27
|
+
operation: "getMyInfo",
|
|
28
|
+
fields: parsed.issues.map((issue) => v.getDotPath(issue) ?? "(root)"),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return parsed.output;
|
|
32
|
+
}
|
|
33
|
+
async chat(chatId) {
|
|
34
|
+
const answer = await this.#transport.call(required("getChat"), { path: { chatId } });
|
|
35
|
+
return toChat(this.#decode(ChatSchema, answer, "getChat"));
|
|
36
|
+
}
|
|
37
|
+
async message(messageId, selfId) {
|
|
38
|
+
const answer = await this.#transport.call(required("getMessageById"), { path: { messageId } });
|
|
39
|
+
return this.#message(answer, selfId);
|
|
40
|
+
}
|
|
41
|
+
/** Newest last, as MAX returns them. */
|
|
42
|
+
async messages(chatId, count, selfId) {
|
|
43
|
+
const answer = (await this.#transport.call(required("getMessages"), {
|
|
44
|
+
query: { chat_id: chatId, count: String(count) },
|
|
45
|
+
}));
|
|
46
|
+
return (answer?.messages ?? []).map((raw) => this.#message(raw, selfId));
|
|
47
|
+
}
|
|
48
|
+
/** A message from any answer — a send's result, an update — decoded the same way as a read. */
|
|
49
|
+
decodeMessage(raw, selfId) {
|
|
50
|
+
return this.#message(raw, selfId);
|
|
51
|
+
}
|
|
52
|
+
call(operation, input) {
|
|
53
|
+
return this.#transport.call(operation, input);
|
|
54
|
+
}
|
|
55
|
+
#decode(schema, answer, operation) {
|
|
56
|
+
const parsed = v.safeParse(schema, answer);
|
|
57
|
+
if (!parsed.success) {
|
|
58
|
+
throw new CliError("invalid_response", `MAX answered ${operation} in a shape this version does not know`, {
|
|
59
|
+
operation,
|
|
60
|
+
fields: parsed.issues.map((issue) => v.getDotPath(issue) ?? "(root)"),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return parsed.output;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* One message MAX added something new to (an attachment type newer than the schema, `RISK-51`)
|
|
67
|
+
* still shows its text and time rather than failing the whole list.
|
|
68
|
+
*/
|
|
69
|
+
#message(raw, selfId) {
|
|
70
|
+
const parsed = v.safeParse(MessageSchema, raw);
|
|
71
|
+
if (parsed.success)
|
|
72
|
+
return toMessage(parsed.output, selfId);
|
|
73
|
+
const loose = plainJson(raw);
|
|
74
|
+
return {
|
|
75
|
+
id: String(loose.body?.mid ?? "unknown"),
|
|
76
|
+
chatId: String(loose.recipient?.chat_id ?? "unknown"),
|
|
77
|
+
senderId: null,
|
|
78
|
+
senderName: null,
|
|
79
|
+
timestamp: new Date(Number(loose.timestamp ?? 0)).toISOString(),
|
|
80
|
+
editedAt: null,
|
|
81
|
+
text: loose.body?.text ?? "",
|
|
82
|
+
outgoing: null,
|
|
83
|
+
attachments: [],
|
|
84
|
+
replyTo: null,
|
|
85
|
+
forwardedFrom: null,
|
|
86
|
+
reactions: null,
|
|
87
|
+
providerMetadata: { unparsed: parsed.issues.map((issue) => v.getDotPath(issue) ?? "(root)") },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/bot/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/bot/generated/manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAElE,eAAO,MAAM,UAAU,EAAE,SAAS,iBAAiB,EA4tClD,CAAA"}
|