CLI tools

Диагностика: что команда делала

This page is in Russian.

Одно событие на запрос, два места, куда его можно направить. --trace показывает и ничего не хранит, --record хранит и ничего не показывает. По умолчанию ничего не показывается, а сохраняется только запуск, который кончился ошибкой (см. «Неудачный запуск сохраняется всегда»).

Показать

max chats list --trace
→ session.init      op 6   seq 1  432 B
← session.init      op 6   seq 1  89ms  335 B  38 reg-country-code
→ session.login     op 19  seq 2  871 B
← session.login     op 19  seq 2  202ms  48.0 kB  25 chats  6 contacts
→ contacts.info     op 32  seq 3  154 B  3 contacts
← contacts.info     op 32  seq 3  91ms  6.5 kB  10 contacts

→ — что спросили, ← — что пришло, • — ответ, который не уходил в сеть. Дальше по строке: операция, опкод протокола, номер запроса в соединении, названные идентификаторы, длительность, размер кадра и сколько чего вернулось.

Всё это идёт на stderr, поэтому рядом с --json ничего не ломается:

max chats list --json --trace > chats.json    # данные в файл, диагностика на экран

В терминале — строки выше; в трубе — по одному объекту JSON на строку, то же самое правило, что и для данных:

max chats list --json --trace 2>&1 >/dev/null | jq -c 'select(.event == "response")'

--trace сильнее --quiet: флаг, который дописан руками, срабатывает всегда.

Команды бота

У max <имя> bot … одна строка на HTTP-запрос к Bot API: операция, идентификаторы из адреса (чат, сообщение, человек, комментарий), HTTP-код, время, размер ответа.

max shop bot messages list -100 --trace
→ getMyInfo        
← getMyInfo        200  143ms  211 B
→ getMessages      chat -100
← getMessages      200  chat -100  187ms  6.2 kB

Отказ показывает код ошибки и ключ MAX, например 404 not_found not.found, но не текст ответа. Загрузка файла (--file, uploads put) — отдельная пара строк upload.image, upload.video и так далее: размер, HTTP-код, время. Адреса загрузки и имени файла в ней нет: адрес сам работает как пропуск.

Сохранить

max chats list --record
max runs list                 # что делалось, новое сверху
max runs show <id>            # один запуск: чем кончился и куда ходил
max runs path <id>            # каталог, для jq и grep

Каталог запуска:

~/.local/share/max-cli/runs/2026-09-19/20260919T234428Z-chats-list-9df39e/
  run.json       что это было, когда, какой профиль, сколько длилось, чем кончилось
  events.jsonl   по объекту JSON на запрос, без единого управляющего символа

Каталог — 0700, оба файла — 0600. run.json пишется дважды: как только запуск начался, со статусом running, и в конце — с итогом. Каталог с событиями и без метаданных был бы особым случаем, который max runs list носил бы вечно.

Итог записывается на любом пути — в том числе когда команда упала, не успев подключиться:

{ "runId": "…", "command": "chats list", "profile": "default", "status": "failed",
  "requests": 0, "errorCode": "authentication_error", "durationMs": 12 }

Чего в записи нет

Это главное, ради чего страница написана.

ЗаписываетсяНе записывается никогда
операция, опкод, номер запросаназвание чата
идентификатор чата, номер отправки (send), идентификатор сообщенияимя человека
сколько байт ушло и пришлотекст сообщения
сколько миллисекунд занял ответномер телефона
сколько чатов, контактов, сообщений вернулосьтокен
код ошибки, и короткий ключ ошибки MAX вида login.tokenтекст ошибки, пришедший от MAX
предупреждение — кодом, например reactions_unreadтекст предупреждения
при падении — тип ошибки и строки кода, где оно случилосьтекст ошибки при падении
версия, среда (node или bun), системапуть к домашнему каталогу

Ни в обрезанном виде, ни хэшем. Событие собирается из полей, названных по именам, а не фильтрованием копии запроса: поле, которого никто не предвидел, в журнал попасть не может. У session.login есть поле token — и ни одна ветка в коде до него не дотягивается.

Идентификаторы, наоборот, внутри сознательно: идентификатор чата — непрозрачное число, бесполезное без сессии, к которой он относится, и это единственное, что делает диагностику полезной, потому что любая настоящая жалоба — про один конкретный разговор.

Текст ошибки MAX не записывается по той же причине: отказ сервера может цитировать то, что мы послали, а послали мы в том числе сообщение. Записывается только ключ — строчные латинские буквы, цифры, точки и дефисы, как proto.payload. Если MAX ответил чем-то другим, не пишется ничего.

Что можно с этим делать

# сколько времени ушло на вход в последних запусках
for id in $(max runs list --json | jq -r '.items[].runId'); do
  jq -r 'select(.operation=="session.login" and .event=="response") | "\(.durationMs)ms"' \
    "$(max runs path "$id" --json | jq -r .path)/events.jsonl"
done

# какие запуски закончились плохо
max runs list --json | jq '.items[] | select(.status=="failed") | {runId, command, errorCode}'

max runs show печатает то же самое, убрав служебные поля, которые Pino повторяет в каждой строке: без этого таблица уезжает за правый край экрана раньше, чем доходит до длительностей. Файл целиком, со служебными полями, отдаёт max runs path.

Сколько это живёт

30 дней, и удаление старого происходит только в тот момент, когда что-то записывается: инструмент, который ничего не пишет, не имеет причин ходить по этому каталогу. Срок меняется полем keepRunsForDays в настройках.

Удаляется днями целиком, по имени каталога, поэтому ничего не нужно открывать, чтобы решить.

Неудачный запуск сохраняется всегда

Если команда кончилась ошибкой, её запуск сохраняется и без --record — с пометкой "keptBecauseFailed": true в run.json. Это касается любой команды и любой ошибки: неверного флага, неизвестной команды, проверки до начала работы, команд, которые в MAX не ходят (models, server, watch, upgrade). В записи — только слова команды, например messages list, без того, что было написано после них. Удачный запуск без --record не оставляет ничего. Так у отчёта о проблеме есть что приложить, а история того, что вы читали, по-прежнему не копится. --no-record или "record": false в настройках отключают и это.

Когда записывать постоянно

{ "profiles": { "default": { "record": true } } }

Тогда пишется каждый запуск, а --no-record отключает запись для одного вызова. Обратное — то, что по умолчанию: удачный запуск не записывается, пока не попросили; неудачный сохраняется всегда, без текстов, чтобы было что приложить к сообщению об ошибке. Мессенджер, который сам собирает каталог с историей того, кого вы читали и когда, — это чужая жизнь в чужом логе.

Дальше

  • security.md — что вообще попадает на диск
  • troubleshooting.md — как этим пользоваться, когда что-то не работает

On this page