Правила фільтрування команд
rtok run (а також rtok filter --stdin і переписування Bash на PreToolUse, яке
викликає rtok run) скорочує вивід команд за правилами для кожного сімейства, перш ніж
його побачить модель. Сирий вивід завжди спершу архівується, тож кожен скорочений
результат можна отримати через rtok expand <id> (типово без втрат, D4).
Правила ніколи нічого не приховують: рядок, що містить помилку, попередження чи секрет, проходить
без змін.
Три рівні об'єднуються в такому порядку; пізніший рівень перемагає для кожного сімейства команд:
- Вбудовані —
rules/default.tomlу репозиторії (grep, rg, sed, cat, make, curl, npm, pnpm, node, а також форматувальники cargo/git/test/tree у коді). - Файл користувача —
[plugins.cmd] rules(типово~/.rtok/rules.toml). - Drop-in-файли — кожен
*.tomlу[plugins.cmd] rules_dir(типово~/.rtok/rules.d/), об'єднані в порядку назв файлів.
Відсутній файл чи каталог — не помилка: цей рівень пропускається. Некоректний
файл пропускається під час виконання (fail open), а rtok config validate повідомляє про нього,
називаючи кожен поганий файл.
Схема
Одна таблиця TOML на сімейство команд. Назва таблиці — перше слово команди
([grep], [pytest]); для невідомих сімейств використовується типове правило
(max_lines = 40, head = 10, tail = 10, дедуплікацію увімкнено). Один виняток: один рядок Bash,
що з'єднує 2+ РІЗНІ програми через &&, ; або новий рядок (T177), — це не вивід одного
сімейства: його зіставляють із [script]. Ланцюжок однієї програми
(cargo build && cargo test або з початковим cd/export) і далі використовує власний
форматувальник/правило цієї програми.
Той самий рушій обрізає результати сторонніх MCP-серверів за rtok mcp -- <server argv> (T59.4):
розділ [mcp] — це правило для текстового блоку tools/call кожного обгорнутого сервера, а якщо його немає — типове
правило. Змінюються лише текстові блоки результату без isError, довші за max_lines;
сирий блок спершу архівується, а обрізаний текст закінчується тим самим рядком
[rtok <id> · N lines · expand: rtok expand <id>], який друкує rtok run. Економія
записується як вимірювання cmd / wrap з ref_id = <server>/<tool>:<id>.
| Поле | Тип | Типово | Значення |
|---|---|---|---|
max_lines | ціле ≥ 0 | 40 | обмеження рядків виводу; решта стає одним рядком … N lines omitted (expand <id>) |
head | ціле ≥ 0 | 10 | рядки, які завжди зберігаються з початку |
tail | ціле ≥ 0 | 10 | рядки, які завжди зберігаються з кінця |
drop | масив рядків | [] | підрядки без урахування регістру, які треба видалити (| розділяє альтернативи) |
keep | масив рядків | [] | підрядки, які ніколи не видаляються й не обрізаються обмеженням; вбудовані keep — error, warning, panic, fail, traceback |
dedupe | bool або "normalized" | true | true згортає сусідні ідентичні рядки в line (×N); "normalized" порівнює рядки із заміненими на заповнювачі мітками часу, id, pid і тривалостями та згортає несусідні збіги в line (×N, also lines k, l, …) |
group | "dir" | "diag" | вимкнено | dir переписує вивід «шлях на рядок» як dir/ (N files): a, b, c …; diag переписує діагностику з кодами як E0308 ×N: first message (file:line, …); виконується до обрізання head/tail (T64.1) |
json_items | ціле ≥ 0 | 20 | масиви JSON зберігають стільки елементів; решта — один … +K more (T65.2) |
json_string | ціле ≥ 0 | 200 | рядки JSON, довші за це, обрізаються із зазначенням їхньої довжини в символах (T65.2) |
Будь-яке інше поле, неправильний тип чи зламаний TOML — це некоректний файл. Ненульовий код виходу
скасовує все це: останні [plugins.cmd] fail_tail_lines рядків (типово
80) друкуються дослівно, бо помилка команди, що впала, — це і є корисні дані.
Розібраний приклад
~/.rtok/rules.d/pytest.toml — зводити тихі запуски pytest до вказівника, але ніколи
не втрачати збій:
[pytest]
max_lines = 30
head = 5
tail = 15
drop = ["PASSED", "passed"]
keep = ["FAILED|failed|ERROR|error"]
dedupe = true
До (212 рядків крапок і пройдених тестів), після (12 рядків):
tests/test_auth.py::test_login PASSED
tests/test_auth.py::test_refresh FAILED
… 200 lines omitted (expand abc123)
E assert False is True
Перевірте, перш ніж на нього покладатися:
rtok config validate # називає файли rules.d/*.toml, які не розбираються
validate перевіряє файл, названий у командному рядку (або конфігурацію користувача),
плюс окремий файл rules і кожен rules.d/*.toml, до якого вона веде.
Файл, про який повідомлено, пропускається під час виконання, доки його не виправлять; усе інше й далі
фільтрується.
Сімейства (T50.1)
Виміряно на golden-фікстурах у tests/cmd_golden/ (rtok filter --stdin, Rule проти
Rule::default() на тому самому тексті; оцінка токенів = байти/4).
| Сімейство | Основне в keep | до, Б | після, Б | оцінка економії |
|---|---|---|---|---|
gh | error, HTTP 4, gh: | 325 | 277 | 12 |
pip | ERROR, Could not | 389 | 341 | 12 |
uv | error, Failed | 292 | 244 | 12 |
python / python3 | Traceback, Error | 367 | 299 | 17 |
go | error, panic, cannot | 290 | 242 | 12 |
aws | An error occurred, AccessDenied | 349 | 301 | 12 |
mvn | BUILD FAILURE, [ERROR] | 419 | 395 | 6 |
gradle | BUILD FAILED, What went wrong | 357 | 302 | 13 |
dotnet | error CS, Build FAILED | 285 | 237 | 12 |
tsc | error TS, Found N error | 373 | 325 | 12 |
eslint | error, warning, problems | 298 | 250 | 12 |
brew | Error:, failed | 310 | 262 | 12 |
apt | ^E:, Unable to | 293 | 245 | 12 |
cmake | CMake Error, FAILED | 317 | 255 | 15 |
Форматувальники (T58.5)
Виміряно на тих самих golden-текстах (formatters::compress, Measurement.kind = formatter
проти Rule::default() на тій самій фікстурі; оцінка токенів = байти/4). Кожен форматувальник зберігає один
рядок на об'єкт і повертає None для нерозпізнаного виводу, тож шлях правил лишається запасним варіантом.
| Сімейство | зберігає | до, Б | після правила, Б | після форматувальника, Б | оцінка економії порівняно з правилом |
|---|---|---|---|---|---|
docker ps | один рядок на контейнер | 3147 | 1311 | 1190 | 30 |
kubectl get | один рядок на об'єкт (NAME READY STATUS IP) | 4542 | 1770 | 1731 | 9 |
ps aux | один рядок на процес | 2341 | 990 | 870 | 30 |
Групування (T64.1)
Виміряно на golden-фікстурах у tests/cmd_golden/ (formatters::compress із
вбудованим правилом проти того самого правила з вимкненим group; оцінка токенів = байти/4). Для сімейства
групування вмикається, лише коли згрупований текст менший. tree, git status, pytest і
python лишаються як є: псевдографіка tree і форматувальники git/pytest — це не потоки «шлях на рядок»
чи діагностики з кодами, а traceback python з T50.1 не стискається у вигляді NameError ×1.
| Сімейство | group | без групування, Б | з групуванням, Б | оцінка економії |
|---|---|---|---|---|
ls | dir | 248 | 49 | 49 |
find | dir | 539 | 83 | 114 |
rg (-l) | dir | 459 | 83 | 94 |
tsc | diag | 1619 | 107 | 378 |
eslint | diag | 749 | 48 | 175 |
cargo (check) | diag | 749 | 34 | 178 |
dotnet | diag | 849 | 71 | 194 |
JSON (T65.2)
Текст, який serde_json розбирає як об'єкт або масив, переписується після групування й
до обрізання head/tail: поля з null / порожнім рядком / порожнім контейнером видаляються, елементи масивів
понад json_items показуються як … +K more, ключі об'єктів зберігаються, рядки, довші за
json_string, обрізаються із зазначенням довжини, один рядок на ключ верхнього рівня. Тексти, що не розбираються,
лишаються недоторканими. Табличні форматувальники (kubectl get, docker ps) поступаються, коли текст — JSON,
тож kubectl get -o json доходить до цього проходу. toon лишається поза шляхом хука. Сирі байти лишаються
в архіві; скорочений результат і далі несе завершальний рядок expand.
Виміряно на tests/cmd_golden/{gh,aws,kubectl}_json.in (formatters::compress проти
обрізання head/tail того самого відформатованого тексту; оцінка токенів = байти/4).
| Джерело | сирий, Б | обрізання рядків, Б | компактний, Б | оцінка економії порівняно із сирим |
|---|---|---|---|---|
gh pr list --json | 10275 | 908 | 4530 | 1436 |
aws ec2 describe-instances | 19516 | 519 | 5890 | 3406 |
kubectl get pods -o json | 26271 | 353 | 8297 | 4493 |