cubest 0.1.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.
Files changed (46) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +27 -0
  3. package/README.ar.md +110 -0
  4. package/README.bn.md +111 -0
  5. package/README.es.md +110 -0
  6. package/README.hi.md +110 -0
  7. package/README.ja.md +113 -0
  8. package/README.md +469 -0
  9. package/README.pa.md +114 -0
  10. package/README.pt.md +113 -0
  11. package/README.ru.md +1174 -0
  12. package/README.zh-CN.md +233 -0
  13. package/bin/cubest.js +28 -0
  14. package/cubest.py +1862 -0
  15. package/package.json +28 -0
  16. package/profiles/agents_inventory.yaml +15 -0
  17. package/profiles/api_routes.yaml +20 -0
  18. package/profiles/call_graph.yaml +19 -0
  19. package/profiles/code_atlas.yaml +33 -0
  20. package/profiles/code_stats.yaml +15 -0
  21. package/profiles/csv_analytics.yaml +31 -0
  22. package/profiles/disk_usage.yaml +29 -0
  23. package/profiles/doc_structure.yaml +16 -0
  24. package/profiles/file_tree.yaml +27 -0
  25. package/profiles/frontend_geoip.yaml +49 -0
  26. package/profiles/git_log_activity.yaml +29 -0
  27. package/profiles/imports.yaml +16 -0
  28. package/profiles/jsonl_events.yaml +19 -0
  29. package/profiles/k8s_resources.yaml +25 -0
  30. package/profiles/loc_counter.yaml +51 -0
  31. package/profiles/mr_impact.yaml +19 -0
  32. package/profiles/nginx_access.yaml +33 -0
  33. package/profiles/nginx_cdn_covers.yaml +32 -0
  34. package/profiles/openapi_endpoints.yaml +19 -0
  35. package/profiles/react_components.yaml +15 -0
  36. package/profiles/sdd_checklist.yaml +17 -0
  37. package/profiles/sdd_specs.yaml +19 -0
  38. package/profiles/seo_audit.yaml +31 -0
  39. package/profiles/seo_semantic_tree.yaml +17 -0
  40. package/profiles/sitemap_map.yaml +20 -0
  41. package/profiles/skills_inventory.yaml +17 -0
  42. package/profiles/spec_status.yaml +18 -0
  43. package/profiles/sql_functions.yaml +31 -0
  44. package/profiles/tech_debt.yaml +16 -0
  45. package/profiles/xml_tags.yaml +21 -0
  46. package/profiles/yaml_keys.yaml +19 -0
package/README.ru.md ADDED
@@ -0,0 +1,1174 @@
1
+ # cubest — универсальный single-pass OLAP-индексатор
2
+
3
+ [English](README.md) · [简体中文](README.zh-CN.md) · [Español](README.es.md) · [हिन्दी](README.hi.md) · [العربية](README.ar.md) · [বাংলা](README.bn.md) · [Português](README.pt.md) · **Русский** · [日本語](README.ja.md) · [ਪੰਜਾਬੀ](README.pa.md)
4
+
5
+ > **7–22× меньше токенов на запрос AI-агенту.** Single-pass OLAP-агрегатор
6
+ > для любого текстового потока — код, логи, CSV, JSONL, XML, HTML,
7
+ > SDD-артефакты. Для **Claude Code, Cursor, Codex, Aider, Windsurf, Cline,
8
+ > Continue.dev** и любого AI-агента, платящего за input-токены.
9
+ > Измеренные результаты — в [`examples/`](examples/) (воспроизводимо через
10
+ > `./run_all.sh`).
11
+
12
+ ---
13
+
14
+ Один Python-файл. Читает поток текстовых записей (файлы кода, логи, TSV/CSV,
15
+ JSONL, экспорты аналитики, дампы колоночных БД) за **один проход**, строит
16
+ в памяти иерархический OLAP-куб по указанным измерениям (dimensions) и
17
+ считает меры (measures: count / sum / avg / min / max), затем печатает
18
+ компактное дерево, breadcrumb-строки, CSV или JSON.
19
+
20
+ Проектная цель — **не тянуть содержимое исходников в контекст LLM**.
21
+ Вместо десятков `cat`+`grep` — один запуск с готовым агрегатом на выходе,
22
+ десятки-сотни строк вместо десятков тысяч.
23
+
24
+ ## Ключевые свойства
25
+
26
+ - Один файл, только `pyyaml` из зависимостей (JSON-профили работают и без него).
27
+ - Поддержка gzip: `.gz` → авто-streaming построчно.
28
+ - Автопереключение в streaming-режим на файлах > 10 MiB.
29
+ - Gitignore-подобные фильтры: `*.py`, `docs/**/*.md`, `node_modules/`,
30
+ `/README.md`, `!keep.me` (negation).
31
+ - Пресеты: `paths` (метаданные путей, не читая файл), `funcs`, `headers`, `lines`.
32
+ - Форматы вывода: `tree`, `flat` (breadcrumb), `compact`, `csv`, `json`.
33
+ - Экономия токенов: `top_n`, `min_count`, `max_lines`, `max_depth`,
34
+ `human_bytes`.
35
+
36
+ ## Value proposition — что здесь самое ценное
37
+
38
+ Приоритизировано по трём осям: **Impact** (насколько меняет workflow),
39
+ **Uniqueness** (насколько отсутствует у альтернатив), **Frequency** (как
40
+ часто пригождается). Максимум по оси = 5. Суммарный score из 15.
41
+
42
+ | # | Что даёт | Impact | Uniq | Freq | Total | Кому важнее всего |
43
+ |---|-------------------------------------------------------------|:------:|:----:|:----:|:-----:|----------------------------------------------|
44
+ | 1 | **Экономия токенов LLM** через свёртку потока в агрегат | 5 | 5 | 5 | **15** | AI-агенты (Claude Code, Cursor, Codex) |
45
+ | 2 | **Динамическая гибкость** — inline JSON/YAML профиль полностью параметризует вход/обработку/выход | 5 | 5 | 4 | **14** | AI-агенты, автоматизация в CI |
46
+ | 3 | **Универсальность формата** — 15+ типов данных одним tool (код/логи/csv/xml/html/json/sdd/k8s/openapi) | 4 | 5 | 5 | **14** | Все роли; заменяет 10+ CLI-утилит |
47
+ | 4 | **Работа с терабайтными файлами** через streaming .gz + reservoir sampling (O(k) память) | 5 | 4 | 4 | **13** | SRE, data-инженер |
48
+ | 5 | **12 форматов вывода** — от tree/csv/md до dot/mermaid/plantuml/drawio/echarts | 4 | 5 | 4 | **13** | Team leads, PR-workflow, LLM-агенты |
49
+ | 6 | **Zero-install** — один Python-файл, только stdlib для JSON-профилей | 4 | 4 | 4 | **12** | Container/CI, air-gapped envs, quick ad-hoc |
50
+ | 7 | **Percentile из коробки** (p50/p90/p95/p99 через reservoir) без t-digest / HDR-hist deps | 4 | 5 | 3 | **12** | SRE, performance-инженер |
51
+ | 8 | **Скорость** — 200k rec/s insert, 43k lines/s gzip stream (CPython 3.8) | 3 | 3 | 5 | **11** | Все роли |
52
+ | 9 | **Готовая визуализация без спина инфры** — интерактивный ECharts HTML в один файл | 4 | 4 | 3 | **11** | Обмен результатами с не-техн. командой |
53
+ | 10| **Composability** — stdin, pipe, `-F -` для файловых списков (MR-workflow) | 3 | 3 | 4 | **10** | DevOps, CI-скрипты |
54
+ | 11| **Reproducibility** — YAML-профиль в git → одинаковый результат в CI и локально | 3 | 3 | 4 | **10** | Team leads, аудит, приёмка |
55
+ | 12| **Approximate call-graph** без tree-sitter/AST-setup | 3 | 4 | 2 | 9 | Разработчик при onboarding |
56
+ | 13| **Air-gapped безопасность** — работает без интернета (echarts CDN vendorable) | 3 | 4 | 2 | 9 | On-prem, enterprise, регулируемые среды |
57
+
58
+ ### Top-3 ключевых свойств (что здесь по-настоящему уникально)
59
+
60
+ **🥇 #1 — Экономия токенов LLM-агентов.** Это главный value для 2026-эпохи.
61
+ Один запуск сворачивает содержимое сотен файлов в 20-100 строк агрегата
62
+ (вместо 30-60k input-токенов при обычном read/grep). При $3-15/M токенов
63
+ (Opus/Sonnet) на LLM-heavy workflow экономия — **20-50× за операцию**,
64
+ переводит длинные сессии из «упирается в контекст» в «делает больше».
65
+
66
+ **🥇 #2 — Динамическая гибкость.** Агент сам генерирует профиль inline
67
+ (dimensions, measures, filters, format) под каждый конкретный вопрос
68
+ пользователя. Не нужно писать код или добавлять шаблоны — вся логика
69
+ в одном JSON, который агент собирает на лету. Никакие awk/jq/sql/du/wc
70
+ такого не дают: там для каждой задачи нужен свой синтаксис.
71
+
72
+ **🥇 #3 — Универсальность на 15+ типов данных.** Один инструмент вместо
73
+ `scc + tokei + cloc + GoAccess + jq-агрегаты + yq-инвентарь + pyan + awk
74
+ + Graphviz + du + Screaming Frog`. Уменьшает cognitive load, не требует
75
+ переключения контекста между 10 разными CLI.
76
+
77
+ ### Что отличает cubest от «универсальных» альтернатив
78
+
79
+ - **vs DuckDB/dsq/q (SQL-on-files)**: SQL требует полноценного
80
+ парсера входа (для nginx — регулярка через `regexp_matches`),
81
+ выгрузка идёт в таблицу. cubest работает regex-first,
82
+ сохраняет иерархию OLAP-cube нативно, отдаёт диаграммы из коробки.
83
+ - **vs визуализатор (Grafana / Kibana)**: требуют развёрнутого стека,
84
+ индексов, retention. cubest — one-shot, self-contained HTML.
85
+ - **vs AIOps (Datadog / New Relic)**: SaaS с оплатой per host/GB.
86
+ cubest — 0$, работает над архивом на локальном диске.
87
+ - **vs Graphify (AST + LLM knowledge graph)**: тяжёлый setup + LLM
88
+ инференс. cubest — быстрая эвристика без LLM, дополняет Graphify
89
+ на слое OLAP-агрегатов для не-code данных.
90
+
91
+ ## Роли и типовые задачи
92
+
93
+ ### Разработчик
94
+ - **Onboarding в незнакомый монорепо**: `file_tree` даёт карту за 30 строк
95
+ вместо 3k строк листингов
96
+ - **Инвентарь**: `api_routes` (все HTTP endpoints), `code_atlas` (функции
97
+ по 15 языкам), `react_components`, `imports`, `tech_debt` (TODO/FIXME)
98
+ - **Автодокументация**: file → class → method → nested function в один
99
+ запуск (`code_atlas` с `parent`/`depth` для Python)
100
+ - **Approx call-graph**: `call_graph` + `format: dot|mermaid|echarts` —
101
+ быстрый скетч архитектуры без tree-sitter
102
+ - **PR-preflight**: `mr_impact` по `git diff --name-only` — увидеть
103
+ распределение изменений до отправки на ревью
104
+
105
+ ### SRE / on-call
106
+ - **Расследование инцидента**: агрегат `nginx_access.log.gz` за минуты
107
+ вместо часов ручного `grep|awk|sort|uniq` — сокращение investigation
108
+ phase (обычно 60-80% MTTR) через готовый OLAP-cut
109
+ - **Latency-профиль**: `p50/p90/p95/p99` над длительностями запросов из
110
+ логов, с memory O(k) — прогонится над терабайтом gzip без OOM
111
+ - **Blast-radius для deployment**: изменённые сервисы × кластеры ×
112
+ количество вызовов через `mr_impact`
113
+ - **CDN-аудит**: `nginx_cdn_covers` — топ форматов/размеров/устройств
114
+ за окно
115
+ - **Kubernetes-inventory**: `k8s_resources` по helm-chart / kustomize
116
+ - **Disk-clean**: `disk_usage` до глубины 2-3 с `content_match` для
117
+ таргетинга (например, только логи старше X)
118
+
119
+ ### DevOps
120
+ - **CI-отчёты**: junit/allure XML → agg по suite × status × avg(duration)
121
+ - **API-инвентарь**: `openapi_endpoints` — счёт `method × path` по всем
122
+ спекам репо
123
+ - **Config-audit**: `yaml_keys` — что вообще есть в куче YAML/JSON
124
+ манифестов (docker-compose, GHA, GitLab CI, Terraform yaml, Ansible)
125
+ - **Git-активность**: `git_log_activity` — MD-таблица авторов и вкладов
126
+ для quarterly review
127
+
128
+ ### Data-инженер
129
+ - **Второй OLAP-проход** после ClickHouse/DuckDB/Athena экспорта: SQL
130
+ выдаёт данные в TSV → cubest делает финальный cut без запроса на
131
+ кластер (экономия compute)
132
+ - **Ad/analytics rollup**: `csv_analytics` — GA4/AdWords/Metrica-выгрузки
133
+ сводятся в 30-100 строк вместо десятков тысяч
134
+ - **JSONL-поток**: `jsonl_events` — event × source × schema-версия
135
+ - **Sample-based percentile**: `p95/p99` над метриками без t-digest-
136
+ зависимости
137
+
138
+ ### AI-специалист / prompt-engineer
139
+ - **SDD-каталог**: `spec_status` — MD-таблица `phase × status × owner`
140
+ для дашборда фаз в PR
141
+ - **Прогресс приёмки**: `sdd_checklist` — done vs todo per file
142
+ - **Каталог агентов и скиллов**: `agents_inventory`, `skills_inventory`
143
+ для аудита длины descriptions, модели, обязательных полей
144
+
145
+ ### AI-агент (Claude Code / Cursor / Codex)
146
+ - **Компактная карта репо** вместо 30k токенов листингов — один tool
147
+ call сворачивает содержимое в 30 строк tree/flat
148
+ - **Machine-readable**: JSON/YAML/CSV/DOT для последующих tool-цепочек
149
+ - **Экономия контекста в длинных сессиях**: сотни kb → сотни байт
150
+ - **Prescan гипотез**: «есть ли X в проекте, где, сколько» — одним
151
+ запуском, вместо десятков read/grep
152
+
153
+ ## Замена популярных инструментов (drop-in для многих задач)
154
+
155
+ Не полная замена, но покрывает 80% типовых сценариев одним скриптом
156
+ без установки массы CLI:
157
+
158
+ | Инструмент | Что заменяет cubest | Профиль / рецепт |
159
+ |---------------------|----------------------------------------------------------------------|-------------------------------------------|
160
+ | **scc / tokei / cloc** | LOC-каунт по языкам с делением на code / blanks / comments | `loc_counter` |
161
+ | **cloc --by-file** | LOC по файлам | `--profile loc_counter --dimensions [file]` (inline) |
162
+ | **du -sh */** | disk-usage до N-й глубины + подсчёт файлов | `disk_usage` |
163
+ | **find + wc -l** | inventory файлов по типу/пути без запуска wc | `file_tree` |
164
+ | **GoAccess** | базовые агрегаты nginx-логов (URL × status × avg duration + HTML) | `nginx_access` + `format: echarts` |
165
+ | **grep -c PAT** | счётчик вхождений с группировкой по файлу/каталогу | inline-regex + count |
166
+ | **ripgrep + xargs** | «найти все места + сгруппировать» одной командой | inline-regex + dimensions |
167
+ | **jq \| sort \| uniq -c** | агрегат по полю JSONL | `jsonl_events` |
168
+ | **yq / kubectl get**| инвентарь K8s-манифестов в файлах чарта | `k8s_resources` |
169
+ | **swagger-cli** | инвентарь endpoints в OpenAPI/Swagger | `openapi_endpoints` |
170
+ | **git log --stat \| awk** | активность авторов по месяцам с added/removed | `git_log_activity` |
171
+ | **git diff --stat \| wc** | размер MR/PR по каталогам и языкам | `mr_impact --files-from -` |
172
+ | **ctags + grep** | быстрый инвентарь символов кода (без AST-точности) | `code_atlas` |
173
+ | **rga / grep --include** | код-поиск с фильтром по типу файла и агрегатом | inline + `content_match` |
174
+ | **allure/junit-xml summary** | rollup по suite × status × avg duration | inline regex по XML |
175
+ | **awk histogram** | histogram, percentile, распределение метрик из логов | `p50/p90/p95/p99` measure |
176
+ | **treemap.py / sqlite-utils** | визуализация иерархии | `format: echarts` (treemap/sunburst) |
177
+ | **graphviz-ast** | approximate call-graph → SVG/PNG | `call_graph` + `format: dot` |
178
+
179
+ Плюс — три преимущества, которые дают drop-in-replacement:
180
+
181
+ - **Один Python-файл**, ставится в контейнер за 1 команду, не тянет
182
+ ni tree-sitter, ни SQLite, ни LSP;
183
+ - **Единый формат конфига** (yaml/JSON profile) для всех задач — вместо
184
+ запоминания флагов 15 разных утилит;
185
+ - **Автоматически подходит агентам** — machine-readable выход в JSON/CSV/
186
+ YAML/DOT для tool-цепочек.
187
+
188
+ ## Классические cookbook-задачи: было → стало
189
+
190
+ Один и тот же результат, разное количество тыкания.
191
+
192
+ ### 1. LOC-каунт по языкам в репозитории
193
+
194
+ **Было** (`scc` не установлен, `cloc` тоже):
195
+ ```bash
196
+ find . -name "*.py" -not -path "./venv/*" | xargs wc -l | tail -1
197
+ find . -name "*.js" -not -path "./node_modules/*" | xargs wc -l | tail -1
198
+ find . -name "*.go" -not -path "./vendor/*" | xargs wc -l | tail -1
199
+ # ...повторить для каждого языка
200
+ ```
201
+
202
+ **Стало:**
203
+ ```bash
204
+ python .claude/skills/cubest/cubest.py --profile loc_counter .
205
+ ```
206
+
207
+ Выводит:
208
+ ```
209
+ py>src 12503 lines=12503, blanks=1240.0, comments=812.0, bytes=421.3KiB
210
+ ts>web 8942 lines=8942, blanks=1105.0, comments=610.0, bytes=298.1KiB
211
+ go>cmd 3210 lines=3210, blanks=298.0, comments=140.0, bytes=112.6KiB
212
+ ...
213
+ ```
214
+
215
+ ### 2. Топ URL по количеству 5xx-ошибок за сутки из nginx-логов
216
+
217
+ **Было:**
218
+ ```bash
219
+ zcat access.log.gz | awk '$9 ~ /^5/' | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
220
+ ```
221
+
222
+ **Стало:**
223
+ ```bash
224
+ python .claude/skills/cubest/cubest.py -p '{
225
+ "dimensions":["path_root","status"],
226
+ "measures":[{"name":"hits","type":"count"}],
227
+ "extract":[{"type":"regex","pattern":"\"(?P<method>GET|POST|PUT|DELETE) /(?P<path_root>[^/? ]+)[^ ]* HTTP/[\\\\d.]+\" (?P<status>5\\\\d\\\\d)"}],
228
+ "output":{"format":"flat","top_n":20}
229
+ }' access.log.gz
230
+ ```
231
+
232
+ Дополнительно получаем: gzip-стриминг из коробки, sub-percentile-latency
233
+ через `p95/p99`, ECharts-визуализацию с `format: echarts`.
234
+
235
+ ### 3. Disk-usage до 2-й глубины директорий
236
+
237
+ **Было:**
238
+ ```bash
239
+ du -sh */ | sort -rh | head -20 # только 1 уровень
240
+ du -h --max-depth=2 . | sort -rh | head -20 # шумно, много служебки
241
+ ```
242
+
243
+ **Стало:**
244
+ ```bash
245
+ python .claude/skills/cubest/cubest.py --profile disk_usage .
246
+ ```
247
+
248
+ Выводит с человеческими размерами + счёт файлов + max_file per каталог.
249
+
250
+ ### 4. Все TODO/FIXME в проекте с группировкой
251
+
252
+ **Было:**
253
+ ```bash
254
+ grep -rn --include='*.py' --include='*.js' -E 'TODO|FIXME|HACK' . | wc -l
255
+ grep -rn --include='*.py' 'TODO' . | awk -F: '{print $1}' | sort | uniq -c | sort -rn | head
256
+ ```
257
+
258
+ **Стало:**
259
+ ```bash
260
+ python .claude/skills/cubest/cubest.py --profile tech_debt .
261
+ ```
262
+
263
+ ### 5. Активность коммиттеров за 6 месяцев
264
+
265
+ **Было:**
266
+ ```bash
267
+ git log --format='%an' --since=6.months | sort | uniq -c | sort -rn
268
+ git log --numstat --format='COMMIT|%an' --since=6.months | \
269
+ awk '/^COMMIT/{a=$2}/^[0-9]/{c[a]+=$1+$2}END{for(k in c)print c[k],k}' | sort -rn
270
+ ```
271
+
272
+ **Стало:**
273
+ ```bash
274
+ git log --numstat --format='COMMIT|%an|%ai' --since=6.months > /tmp/gitlog.txt
275
+ python .claude/skills/cubest/cubest.py --profile git_log_activity /tmp/gitlog.txt
276
+ ```
277
+
278
+ Готовая MD-таблица `author × month → commits, added, removed`.
279
+
280
+ ### 6. Percentile латентности из access-log
281
+
282
+ **Было:**
283
+ ```bash
284
+ # для этого обычно ставят GoAccess или пишут awk-скрипт
285
+ zcat access.log.gz | awk '{print $NF}' | sort -n | \
286
+ awk 'BEGIN{c=0}{arr[c++]=$1}END{print arr[int(c*0.95)]}'
287
+ # и это ест всю память, потому что sort -n
288
+ ```
289
+
290
+ **Стало:**
291
+ ```bash
292
+ python .claude/skills/cubest/cubest.py -p '{
293
+ "dimensions":["path_root"],
294
+ "measures":[
295
+ {"name":"hits","type":"count"},
296
+ {"name":"p50","type":"p50","field":"duration"},
297
+ {"name":"p95","type":"p95","field":"duration"},
298
+ {"name":"p99","type":"p99","field":"duration"}
299
+ ],
300
+ "extract":[{"type":"regex","pattern":" /(?P<path_root>[^/? ]+)[^ ]* HTTP.* (?P<duration>[0-9.]+)$"}],
301
+ "scan":{"stream":true},
302
+ "output":{"format":"flat","top_n":20}
303
+ }' access.log.gz
304
+ ```
305
+
306
+ Reservoir sampling → **O(k) память** независимо от размера файла.
307
+
308
+ ### 7. Inventory K8s-манифестов в helm-chart
309
+
310
+ **Было:**
311
+ ```bash
312
+ find . -name '*.yaml' -exec grep -l '^apiVersion:' {} \; | \
313
+ xargs -I {} yq eval '.kind + " " + .metadata.namespace + " " + .metadata.name' {} | \
314
+ sort | uniq -c
315
+ ```
316
+
317
+ **Стало:**
318
+ ```bash
319
+ python .claude/skills/cubest/cubest.py --profile k8s_resources ./chart/
320
+ ```
321
+
322
+ ### 8. Approximate call-graph в SVG
323
+
324
+ **Было:**
325
+ ```bash
326
+ # либо большой pyan / snakefood / pyreverse setup
327
+ # либо ручной grep + Graphviz-разметка
328
+ pyan3 src/*.py --uses --colored --grouped --annotated --dot | dot -Tsvg > graph.svg
329
+ ```
330
+
331
+ **Стало:**
332
+ ```bash
333
+ python .claude/skills/cubest/cubest.py --profile call_graph src/ | dot -Tsvg > graph.svg
334
+ ```
335
+
336
+ Или сразу интерактивный HTML:
337
+ ```bash
338
+ python .claude/skills/cubest/cubest.py --profile call_graph src/ \
339
+ -p '{"output":{"format":"echarts","chart_type":"graph"}}' > graph.html
340
+ ```
341
+
342
+ ### 9. Отчёт по MR/PR без клонирования локально
343
+
344
+ **Было:**
345
+ ```bash
346
+ # либо custom CI-скрипт на bash с find/xargs/awk
347
+ # либо тяжёлый инструмент вроде Danger.js
348
+ ```
349
+
350
+ **Стало (в 2 строки в GitHub Actions):**
351
+ ```bash
352
+ git diff --name-only origin/main...HEAD | \
353
+ python .claude/skills/cubest/cubest.py -F - --profile mr_impact . \
354
+ -p '{"output":{"format":"md_table"}}' > /tmp/impact.md
355
+ gh pr comment ${{ github.event.number }} --body-file /tmp/impact.md
356
+ ```
357
+
358
+ ### 10. SEO: семантическое дерево и аудит сайта
359
+
360
+ Три преcета для работы с HTML/XML сайтов без внешних SEO-краулеров:
361
+
362
+ - **`html_meta`** — один record на страницу с полями `title`, `title_len`,
363
+ `description`, `desc_len`, `keywords`, `canonical`, `robots`,
364
+ `og_title`, `og_description`, `twitter_card`, `lang`, `h1_count`,
365
+ `h1_first`, `h2_count`, `h3_count`, `has_schema` (JSON-LD).
366
+ - **`html_headings`** — один record на каждый heading: `level` (1-6),
367
+ `title`. Даёт семантическое дерево страницы.
368
+ - **`sitemap`** — один record на `<url>` из sitemap.xml: `url`, `path`,
369
+ `host`, `priority`, `lastmod`, `changefreq`, `depth`, `section_1`,
370
+ `section_2`, `section_3` (первые 3 сегмента URL).
371
+
372
+ Готовые профили:
373
+
374
+ ```bash
375
+ # 1) Общий SEO-аудит: длины title/description, дубли, наличие schema
376
+ python .claude/skills/cubest/cubest.py --profile seo_audit ./crawl/
377
+ # → md_table: pages | title_avg | title_max | desc_avg | h1_total | schema_pages
378
+
379
+ # 2) Семантическое дерево: file × level × title как interactive sunburst
380
+ python .claude/skills/cubest/cubest.py --profile seo_semantic_tree ./crawl/ > tree.html
381
+
382
+ # 3) URL-таксономия из sitemap.xml как treemap
383
+ python .claude/skills/cubest/cubest.py --profile sitemap_map sitemap.xml > urls.html
384
+ ```
385
+
386
+ **Как раньше** делали то же самое:
387
+ ```bash
388
+ # Screaming Frog GUI, лицензия $259/год; либо
389
+ # сmartupdate + jq для каждой страницы; либо
390
+ # python + BeautifulSoup + lxml + custom-скрипт
391
+ ```
392
+
393
+ **Как теперь** — 3 команды на терминале, готовый ECharts HTML для команды.
394
+
395
+ Прицельные вопросы, на которые отвечают эти профили:
396
+
397
+ - «Какие страницы без H1?» → `filters: ["h1_count == 0"]` в `seo_audit`
398
+ - «Где title > 60 символов?» → `filters: ["title_len > 60"]`
399
+ - «Где отсутствует canonical?» → `filters: ["canonical == ''"]`
400
+ - «Какой раздел сайта самый крупный?» → `sitemap_map` treemap
401
+ - «Дубликаты title через страницы» → `dimensions: [title]` + count > 1
402
+ - «Страницы без JSON-LD schema» → `filters: ["has_schema == 0"]`
403
+
404
+ Inline-пример «топ H1-заголовков сайта» под ключевые слова:
405
+
406
+ ```bash
407
+ python .claude/skills/cubest/cubest.py -p '{
408
+ "dimensions": ["title"],
409
+ "measures": [{"name":"pages","type":"count"}],
410
+ "extract": [{"type":"preset","preset":"html_headings"}],
411
+ "filters": ["level == 1"],
412
+ "output": {"format":"md_table","top_n":30}
413
+ }' ./crawl/ >> KEYWORD_AUDIT.md
414
+ ```
415
+
416
+ Комбинируется с `content_match` для фильтра по content-nature: «H1 только
417
+ на страницах, где встречается upgrade-CTA» и т.п.
418
+
419
+ ### 11. CSV/TSV на входе → OLAP-агрегат → ECharts HTML
420
+
421
+ Native CSV/TSV-парсер stdlib с header row: имена колонок автоматически
422
+ нормализуются (`Campaign Name` → `campaign_name`), становятся полями
423
+ record'а. Дальше — обычные dimensions/measures + любой формат вывода,
424
+ включая интерактивный ECharts HTML.
425
+
426
+ ```bash
427
+ # GA4/AdWords/Metrica/Facebook Ads CSV → готовая диаграмма
428
+ python .claude/skills/cubest/cubest.py --profile csv_analytics \
429
+ ~/downloads/ads_report.csv > /tmp/ads.html
430
+ open /tmp/ads.html # интерактивный sankey/treemap/bar в браузере
431
+ ```
432
+
433
+ Свой профиль под конкретный CSV-экспорт — inline JSON, без создания файла:
434
+
435
+ ```bash
436
+ python .claude/skills/cubest/cubest.py -p '{
437
+ "dimensions": ["campaign", "device"],
438
+ "measures": [
439
+ {"name":"impressions","type":"sum","field":"impressions"},
440
+ {"name":"clicks","type":"sum","field":"clicks"},
441
+ {"name":"cpm","type":"avg","field":"cost"},
442
+ {"name":"cost_p95","type":"p95","field":"cost"}
443
+ ],
444
+ "extract": [{"type":"preset","preset":"csv"}],
445
+ "output": {"format":"echarts","chart_type":"sankey","title":"Campaign → Device"}
446
+ }' /path/to/report.csv > /tmp/report.html
447
+ ```
448
+
449
+ Опции preset:
450
+
451
+ | Опция | Что делает |
452
+ |-------------|---------------------------------------------------------------------|
453
+ | `sep` | Разделитель: `","` для csv (default), `"\t"` для tsv, `";"` для EU CSV |
454
+ | `header` | `true` (default), `false` (использует `col_0..col_N`) или явный список имён |
455
+ | `skip` | Сколько строк выкинуть перед header (GA4 иногда пишет метаданные) |
456
+ | `quotechar` | Символ кавычек, default `"` |
457
+
458
+ Тот же CSV можно выдать в разных форматах — `md_table` для PR, `csv` для
459
+ пайпа в дальнейшую обработку, `json` для программного потребления,
460
+ `mermaid` для встраивания в GitHub markdown:
461
+
462
+ ```bash
463
+ python cubest.py -p '{"dimensions":["campaign"],"extract":[{"type":"preset","preset":"csv"}],"measures":[{"name":"impressions","type":"sum","field":"impressions"}],"output":{"format":"md_table"}}' report.csv >> PR_DESCRIPTION.md
464
+ ```
465
+
466
+ ### 12. Frontend/CDN log с GeoIP: мобильный Chrome из US/CA по /pub/covers/*
467
+
468
+ Задача: посчитать нагрузку по расширениям картинок (webp/jpg/png/avif) с
469
+ метриками `hits`, `p90(duration)`, `avg(size)`, отфильтровав по стране
470
+ (US/CA), UA (Mobile Chrome), эндпоинту (`/pub/covers/*`) и статусу 200.
471
+
472
+ **Как раньше** (набор шагов на awk/sort/uniq):
473
+ ```bash
474
+ zcat access.log.gz \
475
+ | awk '$9==200 && $7 ~ /^\/pub\/covers\// { print $1, $7, $10, $NF }' \
476
+ | while read ip url dur bytes; do
477
+ cc=$(geoiplookup "$ip" | awk -F: '{print $2}' | awk '{print $1}')
478
+ # ... тут ещё нужен ручной extract UA, ext, дальше sort/awk по ext
479
+ done | ...
480
+ ```
481
+ и это без p90 (для перцентиля обычно нужен GoAccess или отдельный скрипт).
482
+
483
+ **Как теперь**:
484
+
485
+ Шаг 1 — предпочтительно, добавляем GeoIP в log_format nginx (см.
486
+ `tools/geoip_enrich.sh` для полного примера конфига):
487
+ ```nginx
488
+ load_module modules/ngx_http_geoip2_module.so;
489
+ http {
490
+ geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
491
+ $geoip2_country_code default=XX country iso_code;
492
+ $geoip2_subdivision default=XX subdivisions 0 iso_code;
493
+ }
494
+ log_format main_geoip
495
+ '$remote_addr - $remote_user [$time_local] '
496
+ '"$request" $status $body_bytes_sent '
497
+ '"$http_referer" "$http_user_agent" $request_time '
498
+ '$geoip2_country_code $geoip2_subdivision';
499
+ access_log /var/log/nginx/access.log main_geoip;
500
+ }
501
+ ```
502
+
503
+ Если тронуть nginx нельзя — fallback через bash-скрипт (медленнее в 20-100
504
+ раз, но работает на архивных логах):
505
+ ```bash
506
+ zcat access.log.gz | tools/geoip_enrich.sh > enriched.log
507
+ ```
508
+
509
+ Шаг 2 — один запуск cubest:
510
+ ```bash
511
+ python .claude/skills/cubest/cubest.py \
512
+ --profile frontend_geoip enriched.log.gz
513
+ ```
514
+
515
+ Профиль встроен и делает всё разом:
516
+ - **regex-парсер** вынимает `ip, datetime, method, path, status, bytes,
517
+ ua, duration, country, region, ext`
518
+ - **filters** оставляют только `status==200`, `country in {US, CA}`,
519
+ `Mobile in ua and Chrome in ua`, `ext in {webp, jpg, png, avif, gif}`
520
+ - **dimensions=[ext]**, measures: `hits`, `p50_ms`, `p90_ms`, `p99_ms`,
521
+ `avg_size`, `bytes_total`
522
+ - **output** — интерактивный ECharts HTML с bar-графиком (можно
523
+ переключить на treemap/pie в UI), либо flat/csv/md_table для CI
524
+
525
+ Пример вывода `format: flat`:
526
+ ```
527
+ webp 128432 hits=128432, p50_ms=0.041, p90_ms=0.180, p99_ms=0.520, avg_size=18234.2, bytes_total=2.2GiB
528
+ jpg 54210 hits=54210, p50_ms=0.055, p90_ms=0.240, p99_ms=0.780, avg_size=32188.4, bytes_total=1.6GiB
529
+ avif 3212 hits=3212, p50_ms=0.038, p90_ms=0.150, p99_ms=0.410, avg_size=9420.1, bytes_total=28.9MiB
530
+ ```
531
+
532
+ Быстрое расширение: добавить второе измерение (`dimensions: [country, ext]`)
533
+ или сгруппировать по региону штата/провинции (`dimensions: [country, region, ext]`).
534
+ Всё в том же профиле, изменение одной строки — не переписывая regex/фильтры.
535
+
536
+ ### 13. Быстрый LOC на изменённых файлах MR
537
+
538
+ **Было:** отдельная утилита + фильтр.
539
+ **Стало:**
540
+ ```bash
541
+ git diff --name-only origin/main...HEAD | \
542
+ python .claude/skills/cubest/cubest.py -F - --profile loc_counter .
543
+ ```
544
+
545
+ ## Использование в MR/PR-хуках
546
+
547
+ Флаг `--files-from -` принимает список путей из stdin (обычно от `git
548
+ diff --name-only`):
549
+
550
+ ```bash
551
+ # Что затрагивает этот MR — карта каталогов и языков
552
+ git diff --name-only origin/main...HEAD | \
553
+ python .claude/skills/cubest/cubest.py -F - --profile mr_impact .
554
+
555
+ # Быстрый LOC-каунт только по изменённым файлам
556
+ git diff --name-only origin/main...HEAD | \
557
+ python .claude/skills/cubest/cubest.py -F - --profile loc_counter .
558
+
559
+ # Не пропустили ли TODO в изменённых файлах?
560
+ git diff --name-only origin/main...HEAD | \
561
+ python .claude/skills/cubest/cubest.py -F - --profile tech_debt .
562
+
563
+ # Активность за 6 месяцев в MD-таблицу для PR/статуса
564
+ git log --numstat --format='COMMIT|%an|%ai' --since=6.months > /tmp/gitlog.txt
565
+ python .claude/skills/cubest/cubest.py --profile git_log_activity /tmp/gitlog.txt
566
+ ```
567
+
568
+ Интеграция в GitLab CI / GitHub Actions: в 3 строки — прогнать профиль,
569
+ сохранить `format: md_table` вывод, запостить в комментарий MR через `gh
570
+ pr comment` / `glab mr note`.
571
+
572
+ ## Латентность и SRE-метрики: percentile из коробки
573
+
574
+ Меры `p50`, `p90`, `p95`, `p99`, `percentile` (с параметром `q: 0.75`)
575
+ считаются через **reservoir sampling** (Vitter Algorithm R). Память —
576
+ O(k) на leaf-узел (default k=128 семплов = ~1 KB), независимо от объёма
577
+ входных данных. Точность ~5% для p95 при 1000+ observations; для точных
578
+ квантилей используй t-digest / HDR-hist.
579
+
580
+ ```yaml
581
+ measures:
582
+ - {name: dur_p50, type: p50, field: duration}
583
+ - {name: dur_p95, type: p95, field: duration}
584
+ - {name: dur_p99, type: p99, field: duration, sample_size: 512}
585
+ - {name: dur_p75, type: percentile, field: duration, q: 0.75}
586
+ ```
587
+
588
+ ## Когда применять (агностично)
589
+
590
+ Общее правило: **есть большой набор строчно-структурированных данных, и
591
+ нужен агрегат / карта, а не сами строки.**
592
+
593
+ ### 1. Код и репозитории
594
+
595
+ - Карта дерева: расширения × топ-каталоги, размер, глубина.
596
+ - Инвентаризация: сколько функций/классов на файл, распределение по модулям.
597
+ - API-инвентарь: все HTTP-роуты по методу и файлу (FastAPI/Flask/Django,
598
+ Express, Spring MVC — regex по декоратору).
599
+ - Технический долг: TODO/FIXME/HACK по типам и локациям.
600
+ - React/Vue-компоненты, страницы Next.js, exported symbols.
601
+ - Оглавление markdown-документации (заголовки × уровень × файл).
602
+ - Импорты: карта зависимостей по модулям.
603
+
604
+ Хорошее место в цикле: **первый шаг onboarding'а в незнакомый монорепо** —
605
+ дать LLM 30-строчную карту вместо 3000 строк листингов.
606
+
607
+ ### 2. Логи веб-серверов и приложений
608
+
609
+ - **nginx / apache / envoy access-log**: URL-раздел × статус × метод
610
+ с avg(request_time), sum(bytes), max(request_time). Работает прямо с
611
+ `.log.gz`, потоково, без распаковки на диск.
612
+ - **CDN-логи** (Cloudflare/Fastly/CloudFront TSV): формат-файла × размер ×
613
+ устройство × регион с avg upstream_response_time.
614
+ - **Application logs** (JSON, syslog): уровень × сервис × endpoint,
615
+ распределение ошибок за окно времени.
616
+ - **Kubernetes / Docker**: pod × container × log-level, top причины падений.
617
+ - **Access reviews**: user × action × resource из audit-log.
618
+
619
+ ### 3. Реклама и веб-аналитика (табличные экспорты)
620
+
621
+ - **Google Analytics 4 / Universal Analytics export CSV**: source/medium ×
622
+ device с sum(sessions), sum(revenue).
623
+ - **Google Ads / AdWords Report** (CSV): campaign × ad_group × device с
624
+ sum(impressions/clicks/cost), avg(ctr).
625
+ - **Yandex Metrica logs API export** (TSV): visit-page × utm_source ×
626
+ browser, распределение конверсий.
627
+ - **Yandex Direct reports**: keyword × placement × device.
628
+ - **Facebook/Meta Ads insights CSV**: campaign × placement × age×gender.
629
+ - **TikTok Ads / VK Ads export**: creative × audience.
630
+
631
+ Ключевой сценарий: **быстро свести отчёт до 30–100 строк**, вместо
632
+ загрузки полного CSV на десятки тысяч строк в контекст.
633
+
634
+ ### 4. Колоночные БД и озёра данных (через экспорт)
635
+
636
+ Сам по себе cubest — не БД. Но идеально комбинируется с колонками:
637
+
638
+ - **ClickHouse**: `SELECT ... FORMAT TSV` (или `JSONEachRow`) → пайпом в
639
+ `cubest --profile - -` — вторичная агрегация локально, без нагрузки
640
+ на кластер, с фильтрами и rollup за секунды.
641
+ - **DuckDB / SQLite**: `duckdb -c "COPY ... TO STDOUT (FORMAT CSV)"` →
642
+ cubest для быстрого exploratory-среза без лишних join'ов.
643
+ - **AWS Athena / BigQuery / Snowflake**: экспортированный CSV/Parquet →
644
+ parquet-tools → CSV → cubest.
645
+ - **Kafka dump** (jsonl): event × source × schema-версия.
646
+ - **Prometheus / VictoriaMetrics** экспорт: метрика × label-set.
647
+ - **Elasticsearch scroll dump** (jsonl): index × source_type × severity.
648
+
649
+ Логика: колоночная БД возвращает уже подготовленные строки, cubest
650
+ делает финальный OLAP-cut и печатает в token-эффективном виде.
651
+
652
+ ### 5. Файловые архивы, бэкапы, каталоги
653
+
654
+ - Инвентаризация огромного диска: тип × top-каталог × размер (`file_tree`).
655
+ - Аудит бэкапов: расширение × возраст файла × размер.
656
+ - Обзор клиентских выгрузок: сколько файлов какого типа пришло.
657
+ - Дедуп: distinct(basename) с count по каталогам.
658
+
659
+ ### 6. Диагностика CI/CD и test reports
660
+
661
+ - Junit/Allure XML dump: suite × test × status с avg(duration).
662
+ - Build-логи: stage × status × длительность.
663
+ - Coverage-отчёт: файл × процент × количество непокрытых строк.
664
+
665
+ ### 7. SDD-артефакты и generated-by-methodology коллекции
666
+
667
+ Когда любая методология (SDD, ADR-first, PRD-driven, RFC-workflow, Design Doc
668
+ templates) выпускает файлы по стандартному шаблону с YAML-фронтматтером и
669
+ чеклистами, cubest за один запуск сводит весь этот корпус в дашборд.
670
+
671
+ - **SDD spec catalog** (профиль `spec_status`): `type × status × phase × owner`
672
+ сводится в md-таблицу — видно, сколько спек в draft/approved/deprecated,
673
+ где висят «сироты» без владельца.
674
+ - **Каталог агентов** (`agents_inventory`): распределение сабагентов по модели
675
+ (haiku/sonnet/opus), длина description'ов, наличие обязательных полей.
676
+ - **Каталог скиллов** (`skills_inventory`): обзор `**/SKILL.md` — фронтматтер
677
+ каждого скилла + top-каталог.
678
+ - **Прогресс приёмки** (`sdd_checklist`): пересчёт `- [x]` vs `- [ ]` в
679
+ чеклистах Phase Gates / capability-preflight. Одна строка = один файл =
680
+ «сколько закрыто из скольких».
681
+ - **ADR/RFC/Design-Doc lifecycle**: те же frontmatter-поля (`status`,
682
+ `decision`, `supersedes`) → срез по актуальности.
683
+ - **Any templated-artefact rollup**: у любой методологии, где артефакты имеют
684
+ общую голову с полями (`sdd-applicability.md`, `capability-profiles.yaml`,
685
+ `artefacts-manifest.yaml`), — тот же паттерн `md_frontmatter` даст
686
+ инвентарь без чтения тел файлов.
687
+
688
+ Идея: если ты **сам генерируешь** файлы по методологии, добавь пару полей во
689
+ frontmatter (`status`, `phase`, `owner`) — и получишь готовый дашборд одним
690
+ запуском cubest.
691
+
692
+ ### 8. XML / YAML / structured configs
693
+
694
+ Скилл читает эти форматы «из коробки» через regex-пресеты — YAML/JSON парсеры
695
+ не нужны, если задача сводится к инвентарю ключей или тегов:
696
+
697
+ - **XML/HTML/SVG/POM/AndroidManifest/OPML/RSS/Atom** (`xml_tags`) — топ-теги
698
+ по документу и файлу. Работает на любом XML-диалекте, потому что это
699
+ regex по `<tag>`.
700
+ - **YAML/JSON top-level keys** (`yaml_keys`) — `key × file`. Хорошо для
701
+ быстрого «что вообще есть в этой куче конфигов»: k8s-манифесты, docker-
702
+ compose, GitHub Actions, GitLab CI, Ansible playbooks, Terraform *.yaml.
703
+ - **Kubernetes** (`k8s_resources`) — `kind × namespace × name` по helm-chart
704
+ или kustomize-дереву; content_match отсеивает не-манифестные YAML.
705
+ - **OpenAPI / Swagger** (`openapi_endpoints`) — `method × path`, работает
706
+ и на YAML, и на JSON-спеках.
707
+ - **Docker-compose services** — быстро через inline-профиль:
708
+ ```yaml
709
+ extract: [{type: regex, multiline: true, pattern: '^\s{2}(?P<service>[\w-]+):\s*\n\s+image:\s*(?P<image>\S+)'}]
710
+ dimensions: [service, image]
711
+ ```
712
+ - **GitHub Actions workflows** — распределение `uses:` action'ов, matrix-
713
+ комбинации; тем же inline-регексом.
714
+ - **Terraform** — `resource "kind" "name" {` через regex.
715
+ - **Ansible** — модули по вхождению `- name:` / `<module_name>:`.
716
+ - **XLIFF/PO/TS** (переводы) — теги `<trans-unit>` для аудита локалей.
717
+ - **CSV/TSV с шапкой** — inline-профиль с регексом по колонкам.
718
+
719
+ Идея: если формат текстовый и структурированный, дальше вопрос двух
720
+ сроок regex. Полный YAML-парсинг с nested keys — вне scope (нужен yq/jq);
721
+ cubest закрывает 80% inventory-задач.
722
+
723
+ ### 9. Автодокументация кода и топ-язык
724
+
725
+ Профиль `code_atlas` строит карту символов на 15 языках (`.py .js .ts .jsx
726
+ .tsx .go .rs .java .rb .php .kt .swift .c .cpp .sh`). Для Python определяет
727
+ вложенность через indent-stack — в каждом record есть `parent` и `depth`,
728
+ можно строить дерево `file → class → method → nested_function`. Для
729
+ остальных языков — плоский список символов.
730
+
731
+ - `code_atlas` — атлас функций и классов по языку × файлу × родителю.
732
+ - `sql_functions` — все функции в файлах, где есть raw SQL (SELECT/INSERT/
733
+ UPDATE/DELETE/CREATE TABLE/WITH). Использует `content_match` для
734
+ префильтра, чтобы не парсить все файлы репо, а только те, где SQL.
735
+ - Комбинация с `content_match` даёт быстрый ответ на «какие функции
736
+ трогают Redis», «какие модули используют pandas», «в каких сервисах
737
+ есть отсылки к legacy-таблице `t_users`».
738
+
739
+ ### 10. Call-graph и рекурсивные проходы + GraphViz
740
+
741
+ Скилл может вывести граф вызовов в формате GraphViz DOT: пресет `calls`
742
+ эмитит пары `(caller, callee)`, формат `dot` собирает `digraph`. Точность
743
+ эвристическая (indent-stack + `\bname\(` — без AST), для 100% AST-точности
744
+ используй tree-sitter-based инструменты типа Graphify. Но для быстрого
745
+ скетча «кто кого зовёт в этом модуле» — один запуск и всё.
746
+
747
+ Готовый профиль:
748
+
749
+ ```bash
750
+ python .claude/skills/cubest/cubest.py --profile call_graph src/ \
751
+ > /tmp/calls.dot
752
+ dot -Tsvg /tmp/calls.dot > /tmp/calls.svg
753
+ ```
754
+
755
+ #### Рекомендация агенту: как собрать полный граф за 2–3 запуска
756
+
757
+ Когда одного прохода мало (например, `callee` определён в другом модуле,
758
+ и агенту нужно достроить недостающие ноды), используй такой рецепт:
759
+
760
+ 1. **Собрать рёбра** по модулям — можно параллельно:
761
+ ```bash
762
+ for M in src/api src/core src/util; do
763
+ python .claude/skills/cubest/cubest.py -p '{
764
+ "dimensions":["caller","callee"],
765
+ "extract":[{"type":"preset","preset":"calls"}],
766
+ "filters":["caller != callee"],
767
+ "output":{"format":"json"}
768
+ }' "$M" > /tmp/edges_$(basename $M).json
769
+ done
770
+ ```
771
+
772
+ 2. **Собрать все определённые символы** (чтобы автодоставить ноды-листья,
773
+ которые никто не вызывает, но которые важно показать):
774
+ ```bash
775
+ python .claude/skills/cubest/cubest.py -p '{
776
+ "dimensions":["name"],
777
+ "extract":[{"type":"preset","preset":"funcs"}],
778
+ "output":{"format":"json"}
779
+ }' src/ > /tmp/defs.json
780
+ ```
781
+
782
+ 3. **Слить в один DOT** с автоподключением нод, подсветкой хабов и
783
+ sink'ов:
784
+ ```bash
785
+ python .claude/skills/cubest/tools/callgraph_merge.py \
786
+ --calls /tmp/edges_*.json \
787
+ --defs /tmp/defs.json \
788
+ --out /tmp/callgraph.dot
789
+ dot -Tsvg /tmp/callgraph.dot > /tmp/callgraph.svg
790
+ ```
791
+
792
+ Merger сам:
793
+
794
+ - объединяет веса рёбер (сколько раз функция A зовёт B);
795
+ - декларирует **все** узлы, включая те, которые пришли только из `--defs`
796
+ (уединённые функции не теряются);
797
+ - красит **хабы** (топ по in+out degree) жёлтым, **entrypoints** (только
798
+ исходящие) синим, **sinks** (только входящие) зелёным.
799
+
800
+ Рекурсивное разрастание графа за N шагов реализуется в цикле: сохранил
801
+ DOT → распарсил ноды с out-degree=0 → запустил cubest на других модулях
802
+ с `content_match: ["\\bНАЗВАНИЕ\\("]` → домержил рёбра. Скилл при этом
803
+ сам ничего не помнит, но за счёт единого JSON-выхода легко компонуется в
804
+ пайплайн любой глубины.
805
+
806
+ ### 11. Уборка диска / disk-usage аудит
807
+
808
+ Профиль `disk_usage` использует `paths`-preset + `path_1..path_5` для
809
+ агрегации по N-й глубине директорий с `sum(size)` и `count(files)`:
810
+
811
+ ```bash
812
+ # «Что жрёт место на диске в /mnt/drive до глубины 2?»
813
+ python .claude/skills/cubest/cubest.py --profile disk_usage /mnt/drive
814
+
815
+ # только те подкаталоги, где есть файлы, содержащие TODO
816
+ python .claude/skills/cubest/cubest.py -p '{
817
+ "dimensions":["path_1","path_2"],
818
+ "measures":[{"name":"files","type":"count"},{"name":"bytes","type":"sum","field":"size"}],
819
+ "extract":[{"type":"preset","preset":"paths"}],
820
+ "scan":{"content_match":["TODO"],"content_scan_bytes":65536},
821
+ "output":{"format":"flat","human_bytes":true,"top_n":15}
822
+ }' /mnt/drive
823
+ ```
824
+
825
+ Комбинация `content_match` + `paths` позволяет отвечать на нетривиальные
826
+ вопросы: «сколько места занимают старые кампании» (регекс по маркеру
827
+ устаревания в файле), «где хранятся notebook'и с BigQuery-запросами»
828
+ (regex по SQL-паттерну), «в каких папках дампы содержат кириллицу».
829
+
830
+ ## Когда **не** применять
831
+
832
+ - Одиночный поиск в конкретном файле → `Grep`/`Read`.
833
+ - Нужен исходный текст строки, не агрегат → `Grep`.
834
+ - Данных < 100 строк / <10 файлов → быстрее прочитать напрямую.
835
+ - Требуется семантический граф зависимостей между функциями/файлами (кто
836
+ что вызывает, blast radius) → это задача **Graphify** / code-review-graph /
837
+ ast-grep, не cubest.
838
+
839
+ ## Сравнение с Graphify и другими инструментами
840
+
841
+ | Аспект | cubest | Graphify | grep -c / awk |
842
+ |---------------------------|-----------------------------------------|------------------------------------------------|----------------------------------|
843
+ | Тип | Aggregator (OLAP-cube) | Knowledge graph (AST + LLM) | Простой счётчик |
844
+ | Backend | regex + presets | tree-sitter (20 языков) + LLM inference | regex |
845
+ | LLM требуется | нет | да, для inferred edges и multimodal | нет |
846
+ | Персистентность | stateless | graph.json на диске + PreToolUse-хуки | stateless |
847
+ | Тип запросов | «сколько чего где», группировка | «какая функция вызывает что», blast radius | сколько совпадений |
848
+ | Логи / CSV / метрики | подходит | нет (только код + docs + media) | подходит для одного среза |
849
+ | Многоуровневая аггрегация | да (иерархия dimensions) | косвенно (обход графа) | нет |
850
+ | Multimodal (PDF/images) | нет | да (Claude Vision) | нет |
851
+ | Скорость | миллисекунды/файл, single-pass | секунды/файл при первом проходе (LLM-инференс) | миллисекунды/файл |
852
+ | Инсталляция | один py-файл + `pyyaml` | пакет + tree-sitter grammars + LLM | встроено в POSIX |
853
+ | Sweet spot | быстрая карта, agg-срезы, потоки данных | глубокая семантика, cross-file навигация | ad-hoc подсчёт в одном каталоге |
854
+ | Экономия токенов | тысячи → десятки строк за один запуск | заявлено ×71.5 за счёт графа | зависит от запроса |
855
+
856
+ **cubest и Graphify — не конкуренты**. Graphify отвечает на вопросы
857
+ типа «какие компоненты зависят от `AuthService.verify`?» — там нужен
858
+ семантический AST-граф. cubest отвечает на «сколько 5xx по эндпоинтам
859
+ за последний час», «какие 20 самых больших папок в бэкапе», «топ
860
+ кампаний по CTR из CSV» — для этого граф-БД избыточен, достаточно
861
+ regex + агрегата. Они хорошо комбинируются в одном проекте.
862
+
863
+ ## Профили из коробки
864
+
865
+ | Профиль | Что делает |
866
+ |---------------------|---------------------------------------------------------------|
867
+ | `file_tree` | Дерево проекта: top-каталог × расширение, размер файлов |
868
+ | `disk_usage` | Аудит диска: `path_1 × path_2` → sum(size) + count(files) |
869
+ | `code_stats` | Функции/классы по файлам |
870
+ | `api_routes` | FastAPI/Flask/Django HTTP-эндпоинты |
871
+ | `tech_debt` | TODO/FIXME/HACK по типу и файлу |
872
+ | `react_components` | React/Vue-компоненты по типу декларации |
873
+ | `imports` | Python-импорты по модулям |
874
+ | `doc_structure` | Заголовки Markdown ≤ h3 |
875
+ | `nginx_access` | Combined access-log → URL-раздел × статус × метод |
876
+ | `nginx_cdn_covers` | CDN TSV-логи → size × format × device (порт cdn_stat.pl) |
877
+ | `frontend_geoip` | Frontend log + GeoIP: фильтр по стране/UA/эндпоинту → ext × p90 |
878
+ | `loc_counter` | LOC-каунт по языкам (drop-in для scc/tokei/cloc) |
879
+ | `mr_impact` | Impact-map MR/PR по `git diff --name-only` через `-F -` |
880
+ | `git_log_activity` | Author × month активность из `git log --numstat` |
881
+ | `seo_audit` | SEO-аудит HTML-краула: title/desc/H1/canonical/schema (md-таблица) |
882
+ | `seo_semantic_tree` | Семантическое дерево заголовков H1-H6 → sunburst ECharts |
883
+ | `sitemap_map` | Инвентарь URL из sitemap.xml → treemap |
884
+ | `csv_analytics` | GA4/AdWords/Metrica CSV → campaign × device |
885
+ | `jsonl_events` | JSONL/NDJSON события → event × source |
886
+ | `sdd_specs` | Каталог спек: `type × status × name` из md-фронтматтера |
887
+ | `sdd_checklist` | Прогресс чеклистов: done vs todo per file |
888
+ | `spec_status` | SDD lifecycle: `phase × status × owner` → md-таблица |
889
+ | `agents_inventory` | Каталог Claude subagents (model × name) |
890
+ | `skills_inventory` | Каталог Claude skills: `**/SKILL.md` из фронтматтера |
891
+ | `code_atlas` | Атлас функций/классов для 15 языков (parent+depth для Python) |
892
+ | `sql_functions` | Функции в файлах с raw SQL |
893
+ | `call_graph` | Approximate call graph → DOT (для рендера в SVG/PNG) |
894
+ | `xml_tags` | XML/HTML/SVG/POM/AndroidManifest inventory |
895
+ | `yaml_keys` | Top-level keys для YAML/JSON конфигов |
896
+ | `k8s_resources` | Kubernetes manifests: kind × namespace × name |
897
+ | `openapi_endpoints` | OpenAPI/Swagger: method × path |
898
+
899
+ ## Форматы вывода
900
+
901
+ Текстовые / табличные:
902
+
903
+ | Формат | Когда выбирать |
904
+ |-----------------|-------------------------------------------------------|
905
+ | `tree` (default)| Иерархия с отступами, читаемо человеку |
906
+ | `flat` | `a>b>c\tN` — компактно, ~30% меньше токенов чем tree |
907
+ | `compact` | `k: N` — только верхний уровень, сортировка по счёту |
908
+ | `csv` | Импорт в таблицу, парсинг, пайп |
909
+ | `md_table` | Готовый отчёт в Markdown (для PR/Confluence/README) |
910
+ | `yaml` | Дальнейшая обработка YAML-инструментами |
911
+ | `json` | Полный дамп куба для программной обработки |
912
+ | `xml` | Общий XML-дамп куба (integration с XML-пайплайнами) |
913
+
914
+ Диаграммы (требуют dimensions=[src, dst] или больше):
915
+
916
+ | Формат | Что выдаёт |
917
+ |---------------------|----------------------------------------------------------------|
918
+ | `dot` / `graphviz` | GraphViz DOT (`dot -Tsvg` → SVG/PDF) |
919
+ | `mermaid` / `mmd` | Mermaid `flowchart LR` — рендерит GitHub, GitLab, Notion |
920
+ | `plantuml` / `puml` | PlantUML `@startuml` component-диаграмма |
921
+ | `drawio` / `diagrams` | draw.io / diagrams.net XML (`File → Import` в приложении) |
922
+ | `echarts` / `html` | Интерактивный HTML с Apache ECharts (CDN, данные inline) |
923
+
924
+ ### ECharts HTML
925
+
926
+ `echarts` (`html`) выдаёт **один автономный HTML-файл**, который открывается
927
+ в браузере и работает без сети (после первой загрузки CDN echarts.min.js).
928
+ Все данные встроены inline. В хедере есть переключатель между 6 типами
929
+ диаграмм — cubest подбирает совместимые под форму данных автоматически,
930
+ несовместимые кнопки disabled:
931
+
932
+ | Тип | Хорош для |
933
+ |-----------|------------------------------------------------------------------------|
934
+ | Sunburst | Иерархии ≥3 dimensions (пример: `lang × file × parent × name`) |
935
+ | Tree | Глубокие иерархии с раскрытием узлов (call-tree, файловые деревья) |
936
+ | Treemap | Пропорции размеров (disk_usage, code_atlas, file_tree) |
937
+ | Sankey | 2 dimensions как поток (API-роуты `method → path_root`, call_graph) |
938
+ | Graph | Force-directed граф связей (call_graph, dependency-graph) |
939
+ | Bar | Одномерный топ-N (`compact` в интерактиве) |
940
+
941
+ Autodetect (`chart_type: auto` — дефолт):
942
+
943
+ - 1 dim → **bar**
944
+ - 2 dims с малым fan-out → **treemap**, с большим → **sankey**
945
+ - ≥3 dims → **sunburst**, для очень глубоких (>4) → **tree**
946
+
947
+ Явный выбор через `output.chart_type`:
948
+
949
+ ```yaml
950
+ output:
951
+ format: echarts
952
+ chart_type: sankey # или sunburst | tree | treemap | graph | bar | auto
953
+ top_n: 100
954
+ min_count: 2
955
+ title: "API traffic by section"
956
+ ```
957
+
958
+ CDN зафиксирован на `echarts@5.5.1` (jsDelivr). HTML полностью standalone —
959
+ можно сохранить в артефакт CI, приложить к PR, открыть в браузере без
960
+ локального сервера.
961
+
962
+ ## Установка
963
+
964
+ ```bash
965
+ pip install -r requirements.txt # с pip
966
+ uv pip install -r requirements.txt # с uv
967
+ uv run --with pyyaml cubest.py -p file_tree . # ad-hoc через uv без венва
968
+ ```
969
+
970
+ Единственная опциональная зависимость — `PyYAML`. Только-JSON-профили работают
971
+ без неё, стандартной библиотеки Python 3.8+ достаточно.
972
+
973
+ ## Быстрый старт
974
+
975
+ ```bash
976
+ # карта репо (без чтения содержимого)
977
+ python .claude/skills/cubest/cubest.py --profile file_tree .
978
+
979
+ # nginx access-log прямо с .gz
980
+ python .claude/skills/cubest/cubest.py \
981
+ --profile nginx_access /var/log/nginx/access.log.gz
982
+
983
+ # ClickHouse → cubest по пайпу
984
+ clickhouse-client -q "SELECT event, source, cnt FROM ... FORMAT TSV" > /tmp/e.tsv
985
+ python .claude/skills/cubest/cubest.py --profile jsonl_events /tmp/e.tsv
986
+
987
+ # Inline-профиль под свой формат
988
+ cat <<'EOF' | python .claude/skills/cubest/cubest.py --profile - ./data
989
+ dimensions: [dir, ext]
990
+ measures: [{name: files, type: count}, {name: bytes, type: sum, field: size}]
991
+ extract: [{type: preset, preset: paths}]
992
+ scan: {exclude: ["node_modules/", "*.tmp"]}
993
+ output: {format: flat, top_n: 20, human_bytes: true, max_lines: 40}
994
+ EOF
995
+ ```
996
+
997
+ ## Экономия токенов в выводе
998
+
999
+ - `output.format: flat` — breadcrumb-строки короче tree-иерархии на ~30%.
1000
+ - `output.top_n: N` — оставить только N веток на каждом уровне.
1001
+ - `output.min_count: N` — не показывать хвосты <N.
1002
+ - `output.max_lines: N` — жёсткий cap с суффиксом `… (+K more)`.
1003
+ - `output.max_depth: N` — обрезать глубину дерева.
1004
+ - `output.human_bytes: true` — `2.1MiB` вместо `2202009.0`.
1005
+ - `output.format: csv` — минимум «водянки», удобно для последующей вставки
1006
+ в таблицу или markdown.
1007
+
1008
+ ## Тесты
1009
+
1010
+ ```bash
1011
+ python3 .claude/skills/cubest/tests/run_tests.py # 38 unit-тестов
1012
+ python3 .claude/skills/cubest/tests/bench.py # быстрый нагрузочный
1013
+ HEAVY=1 python3 .claude/skills/cubest/tests/bench.py # 5M records, 200k файлов
1014
+ ```
1015
+
1016
+ Unit-тесты (38 шт.) покрывают: pattern-matching, scan/prune, OLAP-rollup
1017
+ (count/sum/avg/min/max), форматы (tree/flat/compact/csv/md_table/yaml/json),
1018
+ `max_lines` cap, все presets (paths/funcs/headers/md_checklist/md_frontmatter),
1019
+ stream-режим, gzip, `content_match`/`content_not`, filter-eval sandbox
1020
+ (builtins-leak protection).
1021
+
1022
+ Bench-цели (light-mode на CPython 3.8):
1023
+
1024
+ | Сценарий | Метрика |
1025
+ |---------------------------------|-----------------------------------------------|
1026
+ | Cube insert | ~200k записей/сек, RSS ~25 MiB на 500k |
1027
+ | Scan 10k мелких файлов | ~14k файлов/сек (paths preset, без чтения) |
1028
+ | Streaming gzip access-log | ~43k строк/сек, **ΔRSS <200 KiB на 500k** |
1029
+ | Format flat из 50k ячеек | ~1 мс |
1030
+
1031
+ Streaming держит константную память — так что 10 ТБ логов обрабатываются
1032
+ за счёт I/O, а не памяти. `HEAVY=1` — 5 M записей / 200k файлов, требует
1033
+ ~30 с и ~500 MiB RSS.
1034
+
1035
+ ## Похожие open-source проекты (для честности)
1036
+
1037
+ Проверка через GitHub search по нескольким комбинациям («OLAP cube +
1038
+ CLI + Python + regex», «grep aggregator group-by», «"group-by" regex log
1039
+ aggregator CLI») дала **0 репозиториев прямых аналогов**. Есть частичные
1040
+ пересечения:
1041
+
1042
+ | Проект | Стек | Что делает | Чего нет из cubest |
1043
+ |------------------------------------------------------------------------|--------|-------------------------------------------------------|--------------------------------------------------|
1044
+ | [rholder/grepby](https://github.com/rholder/grepby) | Go | group-by count для потока grep-совпадений | нет OLAP-иерархии, форматов, пресетов, диаграмм |
1045
+ | [john-sterling/LogScraper](https://github.com/john-sterling/LogScraper) | Python | wrapper регексов + agg по named groups для логов | только для логов, только count/sum, нет форматов |
1046
+ | [KarnerTh/xogs](https://github.com/KarnerTh/xogs) | Go | YAML-профили + regex для live-log-агрегации | live-only, нет диаграмм, code/SDD-пресетов |
1047
+ | [ReagentX/Logria](https://github.com/ReagentX/Logria) | Rust | live-log с filter/aggregate | TUI-фокус, не CLI-агрегатор для batch |
1048
+ | [sancau/sherlog](https://github.com/sancau/sherlog) | Python | worker в отдельном процессе, льёт в PostgreSQL | не in-process OLAP, требует БД |
1049
+ | [Wolfsrudel/dev-scc](https://github.com/boyter/scc) | Go | быстрый LOC-каунтер | только код, нет regex/logs/dimensions |
1050
+ | [xioTechnologies/tokei](https://github.com/XAMPPRocky/tokei) | Rust | быстрый LOC-каунтер | только код |
1051
+ | [allinurl/goaccess](https://github.com/allinurl/goaccess) | C | web-log analyzer c HTML-отчётом | только nginx/apache, свой parser |
1052
+ | [saulpw/visidata](https://github.com/saulpw/visidata) | Python | интерактивный TUI-explorer таблиц | TUI-only, не CLI-агрегатор для тс агентам |
1053
+ | [multiprocessio/dsq](https://github.com/multiprocessio/dsq) | Go | SQL-запросы по CSV/JSON/logs | SQL, а не regex; нет диаграмм из коробки |
1054
+
1055
+ **Ниша cubest:** `single-pass OLAP-агрегатор для *любого* строчного
1056
+ потока (не только логов, не только кода) + сразу-в-визуализацию`. Ни
1057
+ одна из перечисленных утилит не совмещает regex/preset-based extraction,
1058
+ многоуровневый OLAP (dimensions × measures × rollup), 12 форматов вывода
1059
+ (включая ECharts/GraphViz/PlantUML/Mermaid/draw.io) и native-поддержку
1060
+ LLM-агентных workflow (files-from, machine-readable JSON/YAML/CSV).
1061
+
1062
+ ## Бизнес-эффекты (ориентиры)
1063
+
1064
+ Числа взяты из отраслевых benchmark'ов OLAP / AIOps / MTTR-снижения
1065
+ (Forrester, Research Square, Rootly benchmark 2025, incident.io ROI
1066
+ calc). Для cubest не заменяют полную AIOps-платформу, но покрывают
1067
+ 80% случаев «быстрого агрегата без клика по десятку дашбордов».
1068
+
1069
+ ### 1. Расследование инцидентов и MTTR
1070
+
1071
+ - **Manual investigation** обычно съедает 60-80% MTTR в распределённых
1072
+ системах — engineer вручную коррелирует логи и метрики
1073
+ - Auto-aggregate + готовые визуализации сокращают этот этап в разы:
1074
+ Forrester фиксирует **до 50% снижения MTTR** при добавлении
1075
+ observability + аналитического слоя, Rootly benchmark 2025 — до 70%
1076
+ на первом ответе
1077
+ - Кейс BT Group: MTTR от 2 часов до 85 секунд (97%) — крайний, но
1078
+ показательный пример того, как быстрый агрегат вместо ручного
1079
+ раскопа меняет числа
1080
+ - Nudgebee: снижение MTTR с 60 → 30 минут для mid-size enterprise даёт
1081
+ экономию **~$250k+/год** при downtime cost $10k/час
1082
+
1083
+ cubest вписывается в «первые 5 минут инцидента»: `nginx_access.gz` →
1084
+ топ-20 endpoint'ов по 5xx + p95(duration) в одну команду, без spin-up
1085
+ дашборда.
1086
+
1087
+ ### 2. Post-mortem и документирование
1088
+
1089
+ - Manual post-mortem reconstruction: **60-90 min per incident**
1090
+ (Slack-архивы, дашборды, звонки)
1091
+ - При 18 incident/month → 27 часов документарной археологии
1092
+ - В $110/hr fully-loaded SRE: **~$35k/год** только на post-mortem
1093
+ writing (incident.io ROI calc)
1094
+
1095
+ cubest-профиль поверх нужных логов + `--format md_table` даёт готовый
1096
+ таймлайн-фрагмент для post-mortem за минуту вместо часа.
1097
+
1098
+ ### 3. LLM-агенты и стоимость токенов
1099
+
1100
+ Основной value для AI-агентных workflow:
1101
+
1102
+ - **Замена 20-40 read/grep tool-вызовов одним** — типичный onboarding-
1103
+ проход агента съедает 30-60k input tokens только на листинги; агрегат
1104
+ через cubest — 500-2000 tokens
1105
+ - **На тысяче сессий в день** (SaaS с встроенным AI-помощником) это
1106
+ экономит десятки миллионов input tokens и переводит долгие сессии
1107
+ из «упирается в лимит контекста» в «делает больше за тот же бюджет»
1108
+ - Стоимостной ориентир: при $3-15 per M input tokens (Claude Opus/Sonnet)
1109
+ и 50k → 1k токенов экономии на сессию — снижение стоимости AI-запроса
1110
+ на нужную операцию в **20-50 раз**
1111
+
1112
+ ### 4. Экономия compute на data-warehouse
1113
+
1114
+ - OLAP-pre-aggregation в целом снижает runtime querying cost (ответы
1115
+ на BI-запросы уже свёрнуты) — общий industry-принцип
1116
+ - Для cubest: локальный OLAP-cut над экспортом ClickHouse/DuckDB
1117
+ выполняется без нагрузки на кластер — экономия compute BigQuery/
1118
+ Snowflake/Athena за счёт того, что второй-третий срез делается
1119
+ на инженерной машине, а не в облаке ($0 vs $-per-TB-scanned)
1120
+
1121
+ ### 5. Consolidation of tooling
1122
+
1123
+ - Отраслевой тренд 2026: **all-in-one incident tools** снижают tool
1124
+ sprawl (SigNoz/OpenObserve/Rootly comparisons)
1125
+ - cubest закрывает 15+ утилит одной установкой: scc, tokei, cloc,
1126
+ GoAccess, jq-агрегаты, yq-инвентарь, pyan (call-graph), самописные
1127
+ awk-скрипты, Graphviz-обвязки, `du -sh` — всё через один YAML/JSON
1128
+ профиль
1129
+
1130
+ ### 6. Developer productivity в PR-workflow
1131
+
1132
+ - PR-preflight автоматика (impact map, LOC-delta, TODO-статистика)
1133
+ снижает review latency (типовые данные: `-30% review turnaround` при
1134
+ готовых summary в PR-описании)
1135
+ - Формат `md_table` → `gh pr comment` — интеграция в 2 строки
1136
+
1137
+ **Дисклеймер:** цифры выше — это индустриальные benchmark'ы для
1138
+ observability/AIOps в целом, а не измеренный эффект от cubest.
1139
+ Скилл — не replacement Datadog/New Relic; это lightweight-агрегатор,
1140
+ который занимает нишу «между grep и BigQuery».
1141
+
1142
+ ## Ограничения
1143
+
1144
+ - Regex-фильтры `filters:` выполняются через `eval` в изолированной песочнице
1145
+ (`__builtins__` — только `len/min/max/abs/int/float/str/bool/any/all/sum/sorted/round`).
1146
+ Не запускай chart profiles от недоверенных пользователей.
1147
+ - Streaming не поддерживает `multiline: true` regex — сработает только по
1148
+ одной строке. Для мульти-line паттернов используй batch mode
1149
+ (файл <10 MiB и не `.gz`).
1150
+ - Дефолтные `exclude` при переопределении **заменяются целиком** — добавляй
1151
+ нужные обратно.
1152
+ - Overwrite поля `size` в extract: preset `paths` вычисляет через `os.stat`;
1153
+ если добавить своё `size` из regex, дублирования не будет — победит regex-
1154
+ правило, если оно применяется после `paths`.
1155
+
1156
+ ## Источники (о Graphify)
1157
+
1158
+ - [Graphify — knowledge graph for AI coding assistants](https://graphify.com/)
1159
+ - [Knowledge Graphs for Codebases: A Complete Guide to Graphify (Emelia)](https://emelia.io/hub/knowledge-graph-graphify-guide)
1160
+ - [10 Best Graphify Alternatives (Knolli)](https://www.knolli.ai/post/graphify-alternatives)
1161
+ - [Graphify + code-review-graph (dev.to)](https://dev.to/mir_mursalin_ankur/graphify-code-review-graph-build-a-self-updating-knowledge-graph-for-claude-code-and-other-ai-j1m)
1162
+
1163
+ ## 💖 Поддержка
1164
+
1165
+ Если cubest экономит тебе токены в ежедневных workflow с агентами или
1166
+ сокращает разбор инцидента — поддержи проект. Донаты идут напрямую
1167
+ в пункты roadmap (t-digest, потоковый CSV, снипеты для агентов) и
1168
+ инфраструктуру:
1169
+
1170
+ - **GitHub Sponsors** → https://github.com/sponsors/BaryshevS
1171
+ - **Open Collective** → https://opencollective.com/baryshevsv
1172
+
1173
+ Даже 3 доллара в месяц помогают держать проект живым. Спонсоры
1174
+ получают приоритет в разборе issues и упоминание в release notes.