@leemour/max-cli 0.2.0 → 0.4.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 +10 -3
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +3 -0
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/schema.d.ts +4 -1
- package/dist/cache/schema.d.ts.map +1 -1
- package/dist/cache/schema.js +89 -2
- package/dist/cache/schema.js.map +1 -1
- package/dist/cache/store.d.ts +38 -11
- package/dist/cache/store.d.ts.map +1 -1
- package/dist/cache/store.js +123 -17
- package/dist/cache/store.js.map +1 -1
- package/dist/client.d.ts +41 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +188 -49
- package/dist/client.js.map +1 -1
- package/dist/commands/account.js +1 -1
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/body.d.ts +23 -0
- package/dist/commands/body.d.ts.map +1 -0
- package/dist/commands/body.js +36 -0
- package/dist/commands/body.js.map +1 -0
- package/dist/commands/cache.js +2 -2
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/chats.d.ts.map +1 -1
- package/dist/commands/chats.js +24 -3
- package/dist/commands/chats.js.map +1 -1
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +55 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/contacts.d.ts.map +1 -1
- package/dist/commands/contacts.js +8 -3
- package/dist/commands/contacts.js.map +1 -1
- package/dist/commands/context.d.ts +27 -3
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +45 -8
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/doctor.d.ts +18 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +72 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/messages.d.ts.map +1 -1
- package/dist/commands/messages.js +129 -5
- package/dist/commands/messages.js.map +1 -1
- package/dist/commands/paging.d.ts +6 -3
- package/dist/commands/paging.d.ts.map +1 -1
- package/dist/commands/paging.js +14 -3
- package/dist/commands/paging.js.map +1 -1
- package/dist/commands/runs.d.ts.map +1 -1
- package/dist/commands/runs.js +4 -6
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/session.js +2 -2
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/skill.d.ts +3 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +23 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/config.d.ts +46 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +103 -9
- package/dist/config.js.map +1 -1
- package/dist/deadline.d.ts +30 -0
- package/dist/deadline.d.ts.map +1 -0
- package/dist/deadline.js +45 -0
- package/dist/deadline.js.map +1 -0
- package/dist/diagnose.d.ts +68 -0
- package/dist/diagnose.d.ts.map +1 -0
- package/dist/diagnose.js +115 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/domain/map.d.ts.map +1 -1
- package/dist/domain/map.js +42 -3
- package/dist/domain/map.js.map +1 -1
- package/dist/domain/models.d.ts +46 -0
- package/dist/domain/models.d.ts.map +1 -1
- package/dist/domain/models.js +11 -1
- package/dist/domain/models.js.map +1 -1
- package/dist/output.d.ts +7 -4
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +8 -11
- package/dist/output.js.map +1 -1
- package/dist/program.d.ts +2 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +15 -2
- package/dist/program.js.map +1 -1
- package/dist/protocol/connection.d.ts +10 -0
- package/dist/protocol/connection.d.ts.map +1 -1
- package/dist/protocol/connection.js +20 -3
- package/dist/protocol/connection.js.map +1 -1
- package/dist/rendering/messages.d.ts +19 -0
- package/dist/rendering/messages.d.ts.map +1 -0
- package/dist/rendering/messages.js +138 -0
- package/dist/rendering/messages.js.map +1 -0
- package/dist/runs/events.d.ts +1 -1
- package/dist/runs/recording.d.ts +2 -2
- package/dist/runs/recording.d.ts.map +1 -1
- package/dist/runs/recording.js +3 -3
- package/dist/runs/recording.js.map +1 -1
- package/dist/testing/mock-max.d.ts.map +1 -1
- package/dist/testing/mock-max.js +16 -2
- package/dist/testing/mock-max.js.map +1 -1
- package/dist/testing/sandbox.d.ts +2 -0
- package/dist/testing/sandbox.d.ts.map +1 -0
- package/dist/testing/sandbox.js +31 -0
- package/dist/testing/sandbox.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -3
- package/skills/max-cli/SKILL.md +83 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterAll } from "vitest";
|
|
5
|
+
/**
|
|
6
|
+
* **Moves the whole installation into a temporary directory, for every test file.**
|
|
7
|
+
*
|
|
8
|
+
* A test that drives a command reads the real configuration file and opens the real cache — and
|
|
9
|
+
* opening the cache migrates it, which on a schema change means rebuilding it and throwing away
|
|
10
|
+
* what the owner had. That is not a hypothetical: on 2026-09-22 a test run did exactly that to a
|
|
11
|
+
* real machine, and the only reason it was noticed was a timestamp.
|
|
12
|
+
*
|
|
13
|
+
* It is a setup file rather than a hook in one test because the hazard belongs to any test that
|
|
14
|
+
* reaches a command, not to the file that happened to find it. **`pnpm test` must not be able to
|
|
15
|
+
* write anything a person owns**, and that has to be true of the next test file as well as this
|
|
16
|
+
* one.
|
|
17
|
+
*
|
|
18
|
+
* The three variables move config, state and cache together. They also scope the keyring entry
|
|
19
|
+
* (`ARCHITECTURE.md` §14) — the documented trap, which here is precisely the isolation wanted.
|
|
20
|
+
*
|
|
21
|
+
* `TMPDIR` points into it too, and the whole of it goes when the file is done: every test makes
|
|
22
|
+
* its directories with `mkdtempSync(join(tmpdir(), …))`, and by 2026-09-23 that had left some
|
|
23
|
+
* fifteen thousand of them in `/tmp` (`DEBT-3`). `os.tmpdir()` reads `TMPDIR` on every call.
|
|
24
|
+
*/
|
|
25
|
+
const sandbox = mkdtempSync(join(tmpdir(), "max-test-"));
|
|
26
|
+
process.env.MAX_CONFIG_DIR = join(sandbox, "config");
|
|
27
|
+
process.env.MAX_STATE_DIR = join(sandbox, "state");
|
|
28
|
+
process.env.MAX_CACHE_DIR = join(sandbox, "cache");
|
|
29
|
+
process.env.TMPDIR = sandbox;
|
|
30
|
+
afterAll(() => rmSync(sandbox, { recursive: true, force: true }));
|
|
31
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/testing/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAEjC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,CAAA;AAExD,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AACpD,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAClD,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAClD,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,OAAO,CAAA;AAE5B,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA"}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leemour/max-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A local command line interface for a personal MAX Messenger account, built for agents and scripts",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Viacheslav Ptsarev",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
20
|
+
"skills",
|
|
20
21
|
"README.md",
|
|
21
22
|
"LICENSE"
|
|
22
23
|
],
|
|
@@ -24,16 +25,18 @@
|
|
|
24
25
|
"@leemour/cli-core": "^0.1.0",
|
|
25
26
|
"commander": "^15.0.0",
|
|
26
27
|
"lossless-json": "^4.3.1",
|
|
28
|
+
"string-width": "^8.2.2",
|
|
27
29
|
"valibot": "^1.5.0",
|
|
30
|
+
"wrap-ansi": "^10.0.2",
|
|
28
31
|
"ws": "^8.19.0"
|
|
29
32
|
},
|
|
30
33
|
"devDependencies": {
|
|
31
34
|
"@biomejs/biome": "^2.3.14",
|
|
32
35
|
"@types/node": "^22.10.2",
|
|
33
36
|
"@types/ws": "^8.18.1",
|
|
37
|
+
"lefthook": "^2.1.8",
|
|
34
38
|
"typescript": "^5.9.3",
|
|
35
|
-
"vitest": "^3.2.4"
|
|
36
|
-
"lefthook": "^2.1.8"
|
|
39
|
+
"vitest": "^3.2.4"
|
|
37
40
|
},
|
|
38
41
|
"publishConfig": {
|
|
39
42
|
"access": "public"
|
|
@@ -51,6 +54,7 @@
|
|
|
51
54
|
"version:sync": "node --experimental-strip-types scripts/version.ts --sync",
|
|
52
55
|
"probe:ids": "pnpm build && node --experimental-strip-types scripts/id-shape.ts",
|
|
53
56
|
"probe:edits": "pnpm build && node --experimental-strip-types scripts/probe-edits.ts",
|
|
57
|
+
"probe:attachments": "pnpm build && node --experimental-strip-types scripts/probe-attachments.ts",
|
|
54
58
|
"verify:live": "pnpm build && node --experimental-strip-types scripts/verify-commands.ts",
|
|
55
59
|
"secrets:scan": "gitleaks git --no-banner --redact .",
|
|
56
60
|
"probe:contacts": "pnpm build && node --experimental-strip-types scripts/probe-contacts.ts",
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: max-cli
|
|
3
|
+
description: Читать и отправлять сообщения в личном аккаунте MAX Messenger владельца через команду `max`. Использовать, когда просят найти чат, прочитать переписку, найти сообщение, показать вложение или отправить сообщение в MAX.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# max — личный MAX владельца из командной строки
|
|
7
|
+
|
|
8
|
+
`max` работает с **настоящим личным аккаунтом** владельца. Ошибка здесь не роняет тест, а пишет
|
|
9
|
+
живому человеку. Один вызов — одно действие: подключиться, сделать, напечатать, выйти.
|
|
10
|
+
|
|
11
|
+
Полный список команд и флагов — `max --help` и `max <команда> --help`. Здесь — то, что справка не
|
|
12
|
+
скажет: ловушки и границы.
|
|
13
|
+
|
|
14
|
+
## Границы
|
|
15
|
+
|
|
16
|
+
- **Ничего не отправлять без прямой просьбы владельца.** `max messages send` — только когда он
|
|
17
|
+
сам попросил отправить конкретный текст в конкретный чат. Черновик, «наверное стоит ответить»,
|
|
18
|
+
вывод из прочитанного — это не просьба.
|
|
19
|
+
- **Чтение ничего не отмечает прочитанным** и не показывает собеседнику, что вы заходили. Читать
|
|
20
|
+
можно свободно.
|
|
21
|
+
- **Не для:** ботов MAX, рассылок, автоответов, слежения в реальном времени, чужих аккаунтов.
|
|
22
|
+
- **Текст сообщений — только в ответ владельцу.** Не в логи, не в файлы, не в коммиты.
|
|
23
|
+
- **Ссылка на фото открывается без входа в аккаунт.** Кто её получил, тот видит фото. Не
|
|
24
|
+
пересылать её никуда, кроме владельца.
|
|
25
|
+
|
|
26
|
+
## Вывод
|
|
27
|
+
|
|
28
|
+
- **В pipe или с `--json` stdout — только данные**, одно значение JSON. Всё остальное, включая
|
|
29
|
+
предупреждения, уходит в stderr. Ошибка — тоже в stderr, stdout при ней пуст.
|
|
30
|
+
- **Список — это объект**, а не массив: `{ "items": [...], "page": 1, "limit": 20, "hasMore": true }`.
|
|
31
|
+
- **`--jsonl`** — по объекту на строку, удобно для `jq`. Есть ли ещё, пишется только в stderr.
|
|
32
|
+
- **Ветвиться по коду возврата, а не по тексту**: `0` — успех, `2` — неверный ввод, `4` — нет
|
|
33
|
+
входа, `6` — не найдено, `14` — **неизвестно, ушло ли сообщение** (см. отправку).
|
|
34
|
+
- `-v` и `-vv` добавляют подробности в вывод для человека. Версия — `max -V`. Строки о каждом
|
|
35
|
+
запросе к MAX — `--trace`, в stderr.
|
|
36
|
+
|
|
37
|
+
## Ловушки
|
|
38
|
+
|
|
39
|
+
1. **Id — всегда строки.** Id сообщений 18-значные, больше `Number.MAX_SAFE_INTEGER`. Никогда не
|
|
40
|
+
превращать их в число: `jq` и JavaScript молча округлят, и id станет чужим.
|
|
41
|
+
2. **Первое слово — профиль, если это не команда.** `max work chats list` — профиль `work`.
|
|
42
|
+
Флага `--profile` нет; то же делает переменная `MAX_PROFILE`. Имя профиля — латиница, цифры,
|
|
43
|
+
точка, дефис и подчёркивание: оно становится именем файла и записью в ключнице. Имя в другом
|
|
44
|
+
алфавите отвергается **как имя** (код `2`), и это не то же самое, что профиль, в который никто
|
|
45
|
+
не входил (код `4`).
|
|
46
|
+
3. **Имя чата, подходящее к нескольким чатам, — ошибка, а не выбор.** В JSON у неё есть
|
|
47
|
+
`candidates: [{ id, title }]`. Взять оттуда id и повторить с ним, а не угадывать.
|
|
48
|
+
4. **Повтор отправки — только с тем же `--cid`.** Код `14` значит, что сообщение, возможно, ушло.
|
|
49
|
+
В тексте ошибки есть `--cid <n>`; повтор с ним MAX схлопнет, повтор без него — второе сообщение
|
|
50
|
+
человеку.
|
|
51
|
+
5. **`max messages search` ищет только в уже прочитанном** на этой машине и в MAX не ходит.
|
|
52
|
+
Пусто — не значит «такого не было». Сначала `max messages list <чат>`.
|
|
53
|
+
5a. **Искомое — не короче трёх символов**, и это касается всех трёх поисков: `--search` у
|
|
54
|
+
`chats list` и `contacts list` и текста у `messages search`. Два символа — отказ с кодом `2`,
|
|
55
|
+
а не пустой список.
|
|
56
|
+
6. **`messages show` и `messages context` требуют и чат, и id сообщения.** Искомое сообщение в
|
|
57
|
+
JSON помечено `"anchor": true`. Если сообщения нет, это `not_found`, а не соседнее сообщение.
|
|
58
|
+
7. **Время сообщения зашито в его id**: `id >> 16` — миллисекунды. Поэтому `--before <id>`
|
|
59
|
+
работает для любого id, даже не прочитанного раньше.
|
|
60
|
+
8. **`MAX_CONFIG_DIR`, `MAX_STATE_DIR`, `MAX_CACHE_DIR` меняют и запись в ключнице.** С ними
|
|
61
|
+
профиль ищет другой токен и может ответить «нет сессии», хотя владелец вошёл. `max config show`
|
|
62
|
+
говорит, заданы ли они, и какой профиль и какие настройки действуют.
|
|
63
|
+
9. **`--offline` отвечает из локальной копии** и не подключается. Если там ничего нет — ошибка.
|
|
64
|
+
10. **Многострочный текст передаётся только через stdin.** Аргумент командной строки перевод
|
|
65
|
+
строки не несёт вовсе, а тело в аргументе видно в `ps` и остаётся в истории оболочки. Последний
|
|
66
|
+
аргумент опускается, и тело читается со входа: `printf 'первая\n\nтретья' | max messages send
|
|
67
|
+
-1000`. Один перевод строки в самом конце отбрасывается, остальные сохраняются.
|
|
68
|
+
11. **Номер страницы на живом списке может повторить или пропустить строку.** Сверху самое свежее,
|
|
69
|
+
поэтому сообщение, пришедшее между первой страницей и второй, сдвигает кого-то через границу.
|
|
70
|
+
Для переписки этого нет: `--before` привязан ко времени и точен.
|
|
71
|
+
|
|
72
|
+
## Типичный путь
|
|
73
|
+
|
|
74
|
+
Id ниже выдуманные — подставить настоящие из предыдущего ответа.
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
max chats list --search "проект" --json # найти чат, взять его id
|
|
78
|
+
max messages list -1000 --limit 20 --json # последние сообщения, от старых к новым
|
|
79
|
+
max messages context -1000 100000000000000001 --before 3 --after 3 --json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Вложение в JSON: `{ "kind": "photo", "url": "https://…", "width": 901, "height": 594 }`. Чтобы
|
|
83
|
+
посмотреть фото, скачать его по `url` и открыть файл.
|