@7n/rules 1.25.1 → 1.27.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 (37) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/bin/n-rules.js +16 -1
  3. package/package.json +2 -1
  4. package/rules/doc-files/docgen-crc/docs/main.md +1 -1
  5. package/rules/doc-files/docgen-crc/main.mjs +5 -12
  6. package/rules/doc-files/docgen-gen/docs/main.md +1 -1
  7. package/rules/doc-files/docgen-gen/main.mjs +12 -4
  8. package/rules/doc-files/docgen-scan/docs/main.md +2 -2
  9. package/rules/doc-files/docgen-scan/main.mjs +6 -13
  10. package/rules/js/eslint/concern.json +1 -0
  11. package/schemas/concern.json +4 -0
  12. package/scripts/lib/concern-meta.mjs +14 -1
  13. package/scripts/lib/docs/concern-meta.md +3 -6
  14. package/scripts/lib/docs/plugin-api.md +1 -2
  15. package/scripts/lib/docs/resolve-plugins.md +1 -1
  16. package/scripts/lib/lint-surface/docs/ladder.md +3 -5
  17. package/scripts/lib/lint-surface/docs/run-fix.md +3 -2
  18. package/scripts/lib/lint-surface/ladder.mjs +18 -9
  19. package/scripts/lib/lint-surface/run-fix.mjs +15 -2
  20. package/scripts/lib/plugin-api.mjs +33 -4
  21. package/scripts/lib/resolve-plugins.mjs +2 -1
  22. package/scripts/utils/docs/test-helpers.md +2 -1
  23. package/skills/doc-files/SKILL.md +1 -1
  24. package/skills/taze/SKILL.md +31 -79
  25. package/skills/taze/js/docs/orchestrate.md +9 -12
  26. package/skills/taze/js/orchestrate.mjs +25 -153
  27. package/rules/doc-files/docgen-extract/concern.json +0 -3
  28. package/rules/doc-files/docgen-extract/docs/main.md +0 -38
  29. package/rules/doc-files/docgen-extract/main.mjs +0 -275
  30. package/rules/doc-files/units/concern.json +0 -3
  31. package/rules/doc-files/units/docs/main.md +0 -31
  32. package/rules/doc-files/units/main.mjs +0 -19
  33. package/rules/doc-files/units-js/concern.json +0 -3
  34. package/rules/doc-files/units-js/docs/main.md +0 -32
  35. package/rules/doc-files/units-js/main.mjs +0 -141
  36. package/skills/taze/js/diff.mjs +0 -140
  37. package/skills/taze/js/docs/diff.md +0 -55
@@ -1,144 +1,96 @@
1
1
  ---
2
2
  name: n-taze
3
3
  description: >-
4
- Оновлення версій модулів проекту (bun/npm вбудовано; інші екосистеми — Rust,
4
+ Оновлення версій модулів проекту до останніх (усі екосистеми — JS/npm, Rust,
5
5
  Python тощо — через активні lang-плагіни) з аналізом major-змін і
6
6
  автоматичним рефакторингом несумісного коду
7
- version: '1.2'
7
+ version: '2.0'
8
8
  ---
9
9
 
10
10
  # n-taze — Оновлення версій проекту
11
11
 
12
12
  ## Мета
13
13
 
14
- Оновити всі модулі проекту (npm/bun-залежності вбудовано; інші екосистеми — за активними lang-плагінами, їхні гілки описані у фрагментах наприкінці цього файлу) до останніх версій, виявити major-оновлення, перевірити сумісність змін з кодом проекту і за потреби зрефакторити несумісні місця.
14
+ Оновити всі модулі проекту до останніх версій, виявити major-оновлення, перевірити сумісність змін з кодом проекту і за потреби зрефакторити несумісні місця. Кожна екосистема (JS/npm/bun, Rust/Cargo, Python/uv, …) — гілка відповідного lang-плагіна; конкретні команди гілок описані у фрагментах плагінів наприкінці цього файлу.
15
15
 
16
- ## Оркестрація (npm/bun + екосистемні гілки плагінів) — не одним промптом
16
+ ## Оркестрація — не одним промптом
17
17
 
18
18
  `npx @7n/rules skill pi|cursor|codex taze` **не** передає цей файл одним суцільним
19
19
  промптом в один агентський хід — так робив старий дизайн, і саме тому реальний
20
20
  прогін міг зависати без жодної діагностики (один величезний непрозорий хід на
21
21
  весь монорепо, без проміжних зупинок для перевірки прогресу). Замість цього `npm/skills/taze/js/orchestrate.mjs`:
22
22
 
23
- 1. Детерміновано, без LLM, виконує кроки 1-3 нижче: npm/bun вбудовано (бекап `bunx taze -w -r latest` → `bun install` → `n-rules taze diff`), а кожну екосистемну гілку — через її EcosystemProvider (detect → backup → bump → diff; деталі команд — у фрагменті відповідного плагіна наприкінці файлу).
24
- 2. Для кожного **окремого** major-запису з diff-у — один ізольований, обмежений виклик обраного раннера (кроки 4-6, лише для цього запису; промпт генерує `buildDependencyPrompt` ядра або `promptFor` провайдера, не цей SKILL.md).
23
+ 1. Детерміновано, без LLM, виконує кроки 1-3 нижче для кожної екосистемної гілки через її EcosystemProvider (detect → backup → bump → diff; конкретні команди — у фрагменті відповідного плагіна наприкінці файлу).
24
+ 2. Для кожного **окремого** major-запису з diff-у — один ізольований, обмежений виклик обраного раннера (кроки 4-6, лише для цього запису; промпт генерує `promptFor` провайдера, не цей SKILL.md).
25
25
  3. Детерміновано прибирає бекапи (крок 7) і компонує звіт (крок 8) з результатів усіх ітерацій.
26
26
 
27
- Не-npm екосистеми оркестратор веде через **EcosystemProvider-порт**
27
+ Усі екосистеми оркестратор веде через **EcosystemProvider-порт**
28
28
  (`@7n/rules/plugin-api`, spec `docs/specs/2026-07-18-lang-plugins-extraction-spec.md`)
29
29
  — lang-плагіни доставляються автоматично при першому запуску за файловим
30
- сигналом (extension-point `taze`) і додають свої гілки як фрагменти цього
31
- SKILL.md (блок наприкінці файлу). На чисто-JS проєкті без таких сигналів у
32
- звіті немає навіть згадки про інші екосистеми. Якщо тулчейн гілки не
33
- встановлено вона пропускається з причиною у звіті, не блокуючи інші.
30
+ сигналом (extension-point `taze`; JS/npm `@7n/rules-lang-js` за кореневим
31
+ `package.json`) і додають свої гілки як фрагменти цього SKILL.md (блок
32
+ наприкінці файлу). Ядро двигун без мовної специфіки: без сигналу екосистеми
33
+ у звіті немає навіть згадки про неї. Якщо тулчейн гілки не встановлено — вона
34
+ пропускається з причиною у звіті, не блокуючи інші.
34
35
 
35
36
  Переваги: падіння/timeout на одному пакеті/крейті не втрачає прогрес по інших;
36
37
  кожен виклик успадковує власний timeout раннера (короткий, бо скоуп малий —
37
38
  один запис, не весь монорепо); видно прогрес по записах, а не чорну скриньку.
38
39
 
39
- Кроки 1-8 нижче лишаються джерелом правди щодо ЗМІСТУ роботи npm/bun-гілки
40
- скелетом для екосистемних)оркестратор їх виконує програмно (1-3/7/8)
41
- або як промпт на один запис (4-6). Мовні відповідники кроків у фрагментах
42
- плагінів наприкінці файлу.
40
+ Кроки 1-8 нижче **скелет** роботи будь-якої гілки (що означає кожен крок);
41
+ конкретні команди кожної екосистемиу фрагменті її плагіна. Оркестратор
42
+ виконує кроки 1-3/7/8 програмно, 4-6 як промпт на один запис.
43
43
 
44
44
  ## Передумови
45
45
 
46
- - Чисте робоче дерево (`git status` без незакомічених змін у `package.json` / `bun.lock` / `node_modules`) — інакше різницю не відрізнити від оновлення.
47
- - Встановлений `bun` і доступний `bunx`.
48
- - Запуск з кореня проекту (де лежить `package.json` / `bun.lock`).
49
- - Передумови екосистемних гілок (інструменти на кшталт cargo-edit чи uv) — у фрагментах плагінів наприкінці файлу; відсутній тулчейн не блокує інші гілки.
46
+ - Чисте робоче дерево (`git status` без незакомічених змін у маніфестах/lock-файлах залежностей) — інакше різницю не відрізнити від оновлення.
47
+ - Запуск з кореня проекту.
48
+ - Передумови конкретних гілок (bun/bunx, cargo-edit, uv тощо) — у фрагментах плагінів наприкінці файлу; відсутній тулчейн не блокує інші гілки.
50
49
 
51
- ## Workflow
50
+ ## Workflow (скелет — конкретика у фрагментах плагінів)
52
51
 
53
52
  ### 1. Зафіксувати стартовий стан
54
53
 
55
- Перед оновленням зберегти список поточних версій, щоб потім обчислити, які модулі стрибнули через major:
56
-
57
- ```bash
58
- cp package.json package.json.taze-bak
59
- cp bun.lock bun.lock.taze-bak
60
- ```
61
-
62
- (У monorepo — також усі `*/package.json` воркспейсів. Файли тимчасові, видалити в кінці.)
54
+ Перед оновленням зберегти копії маніфестів залежностей (`<manifest>.taze-bak`) — щоб потім детерміновано обчислити, які модулі стрибнули через major. Файли тимчасові, видаляються в кінці.
63
55
 
64
56
  ### 2. Запустити оновлення
65
57
 
66
- ```bash
67
- bunx taze -w -r latest
68
- bun install
69
- ```
70
-
71
- - `-w` — записати нові версії у `package.json`.
72
- - `-r` — рекурсивно по всіх воркспейсах.
73
- - `latest` — піднімати навіть major.
58
+ Командою екосистеми підняти всі залежності до останніх версій, **включно з major**, і синхронізувати lock-файл.
74
59
 
75
60
  ### 3. Виявити major-оновлення
76
61
 
77
- > **Не порівнюй `package.json` вручну.** Класифікацію semver несе CLIдетерміновано, по всіх воркспейсах.
78
-
79
- ```bash
80
- n-rules taze diff
81
- ```
62
+ > **Не порівнюй маніфести вручну.** Класифікацію semver несе детермінований diff гілки (порівняння з `.taze-bak`-бекапом за caret-правилом: major = змінилась найлівіша ненульова компонента `1.x→2.x`, `0.4.x→0.5.x`, `0.0.3→0.0.4`).
82
63
 
83
- Друкує компактний JSON: `{ "major": [{workspace, pkg, from, to}], "minorPatch": <N>, "totalChanged": <N> }`. `major` список залежностей, у яких змінилась найлівіша ненульова компонента semver (`1.x→2.x`, `0.4.x→0.5.x`, `0.0.3→0.0.4`); саме він іде в кроки 4–6. `minorPatch` лічба сумісних (для звіту в кроці 8).
84
-
85
- Покриває **прямі** залежності з `package.json` (root + воркспейси). Транзитивні major-стрибки (`bun.lock`) — за потреби переглянь окремо; основний ризик breaking-змін — у прямих.
64
+ Major-записи йдуть у кроки 4–6; лічба сумісних (minor/patch) — у звіт кроку 8. Покриваються **прямі** залежності; транзитивніза потреби окремо.
86
65
 
87
66
  ### 4. Зібрати breaking changes по кожному major-оновленню
88
67
 
89
- Для кожного модуля зі списку зібрати фактичні відмінності одним з джерелпорядку пріоритету):
90
-
91
- 1. **CHANGELOG / Releases репозиторію модуля** — найшвидше і найточніше. Адресу репозиторію взяти з `package.json` модуля у `node_modules/<name>/package.json` (поле `repository`). Дістати релізи між старою і новою версією.
92
- 2. **Git-різниця в `node_modules/<name>`** — якщо CHANGELOG відсутній або неінформативний, порівняти попередню версію (з кешу bun: `~/.bun/install/cache/<name>@<old-version>/`) з новою (`node_modules/<name>/`) через `diff -r` по `dist/` / `*.d.ts` / публічних entry-points з `exports`.
93
- 3. **Якщо немає кешованої старої версії** — встановити її окремо в тимчасову теку (`mkdir -p /tmp/taze-old && cd /tmp/taze-old && bun add <name>@<old-version>`) і порівняти.
94
-
95
- Цікавлять: видалені/перейменовані експорти, змінені сигнатури функцій, змінені типи, змінена поведінка за замовчуванням, видалені CLI-прапорці.
68
+ Для кожного запису зі списку зібрати фактичні відмінності: CHANGELOG/Releases репозиторію пакета (джерело адреси — у фрагменті гілки), а без них — diff публічного API між кешованою старою версією і новою. Цікавлять: видалені/перейменовані експорти, змінені сигнатури, змінені типи, змінена поведінка за замовчуванням, видалені CLI-прапорці.
96
69
 
97
70
  ### 5. Перевірити сумісність з кодом проекту
98
71
 
99
- Для кожного breaking change знайти його використання в коді проекту:
100
-
101
- ```bash
102
- rg -n "<імпорт|функція|опція>" --type ts --type js --type vue
103
- ```
104
-
105
- Класифікувати:
106
-
107
- - **сумісно** — проект не використовує зачеплене API → нічого не робити.
108
- - **несумісно** — використання знайдено → перейти до п. 6.
72
+ Для кожного breaking change знайти використання зачепленого API в коді (`rg -n` по мові гілки). Класифікувати: **сумісно** — не використовується → нічого не робити; **несумісно** — перейти до п. 6.
109
73
 
110
74
  ### 6. Рефакторинг несумісних місць
111
75
 
112
- Для кожного несумісного місця — застосувати міграцію згідно з changelog модуля (перейменувати імпорт, оновити сигнатуру виклику, замінити видалену опцію еквівалентом тощо). Після правок:
113
-
114
- ```bash
115
- npx @7n/rules lint
116
- bun run typecheck # якщо є
117
- bun test # якщо є
118
- ```
76
+ Застосувати міграцію згідно з changelog пакета (перейменувати імпорт, оновити сигнатуру виклику, замінити видалену опцію еквівалентом тощо). Після правок — прогнати перевірки гілки (лінт/typecheck/тести — конкретні команди у фрагменті). Нетривіальна або неоднозначна міграція — **не вгадувати**: TODO у коді з посиланням на CHANGELOG і запис у звіт як ручна дія.
119
77
 
120
78
  ### 7. Прибрати тимчасові файли
121
79
 
122
- ```bash
123
- rm package.json.taze-bak bun.lock.taze-bak
124
- ```
125
-
126
- (І решту бекапів воркспейсів, якщо створювались.)
80
+ Видалити всі `.taze-bak`-бекапи, створені на кроці 1.
127
81
 
128
82
  ### 8. Звіт користувачу
129
83
 
130
- Коротко в одному повідомленні:
84
+ Для кожної обробленої гілки — окрема секція:
131
85
 
132
- - **Оновлено (minor/patch):** кількість пакетів (`minorPatch` із кроку 3), без деталей.
86
+ - **Оновлено (minor/patch):** кількість пакетів, без деталей.
133
87
  - **Major-оновлення:** список `<name>: <old> → <new>` з посиланням на release notes.
134
88
  - **Зрефакторено автоматично:** список файлів і коротко що саме змінено.
135
89
  - **Потребує ручного втручання:** список TODO з причиною (нетривіальна міграція / неоднозначність / падіння тестів).
136
- - **Стан перевірок:** `lint` / `typecheck` / `test` — pass/fail з номером рядка, де впало.
137
-
138
- Для кожної обробленої екосистемної гілки — окрема секція з тим самим переліком (оновлено / major / зрефакторено / потребує ручного втручання) і власними перевірками (див. фрагменти плагінів наприкінці файлу).
90
+ - **Стан перевірок:** перевірки гілки — pass/fail з номером рядка, де впало.
139
91
 
140
92
  ## Примітка
141
93
 
142
94
  - Не запускати `npx @7n/rules lint` паралельно з іншими ESLint-задачами — діє правило з кореневого `CLAUDE.md`.
143
95
  - Якщо проект — `npm/` пакет цього репо, після змін у `package.json` / коді треба підняти `version` і додати запис у `CHANGELOG.md` згідно з `npm/CLAUDE.md`.
144
- - При великій кількості major-оновлень розбити PR по одному модулю на коміт — щоб `git bisect` залишався корисним. Це стосується і пакетів екосистемних гілок окремо від npm-пакетів.
96
+ - При великій кількості major-оновлень розбити PR по одному модулю на коміт — щоб `git bisect` залишався корисним. Це стосується пакетів кожної гілки окремо.
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: orchestrate.mjs
4
4
  resource: npm/skills/taze/js/orchestrate.mjs
5
5
  docgen:
6
- crc: 6a269363
6
+ crc: c1bcfe63
7
7
  model: openai-codex/gpt-5.4-mini
8
8
  score: 100
9
9
  issues: judge:inaccurate:0.98
@@ -12,30 +12,27 @@ docgen:
12
12
 
13
13
  ## Огляд
14
14
 
15
- Оркеструє taze детерміновано, без LLM для службових кроків: бекап маніфестів масовий bump diff-класифікація major vs minor/patch прибирання бекапів Markdown-звіт. Для КОЖНОГО окремого major-пакета з diff-у виконує один ізольований, обмежений виклик обраного раннера лише перевірка сумісності й рефакторинг, не сам bump. npm/bun-гілка вбудована; решта екосистем `EcosystemProvider`-и (контракт `@7n/rules/plugin-api`), завантажені з плагінів (`@7n/rules-lang-rust`, `@7n/rules-lang-python`, …; extension-point `taze`) вбудованих провайдерів немає. Файл виконує реальні файлові операції (бекапи) і запускає зовнішні команди (`bunx`, `bun`, `git`, команди провайдерів) — не read-only.
15
+ Оркеструє taze як чистий цикл по EcosystemProvider-ах (фаза 5a spec lang-plugins-extraction: ядро двигун без мовної специфіки). ВСІ екосистеми, включно з npm/bun (`@7n/rules-lang-js`), приходять з плагінів (extension-point `taze`): для кожного провайдераdetect available backup bump diff, далі по одному ізольованому виклику раннера на кожен major-запис (`promptFor` провайдера), потім cleanup і композиція Markdown-звіту. Виконує файлові операції і запускає зовнішні команди (git, npx для worktree-бутстрапу, команди провайдерів) — не read-only.
16
16
 
17
17
  ## Поведінка
18
18
 
19
- - **buildDependencyPrompt** — формує промпт ОДНОГО ітеративного виклику (лише перевірка сумісності й рефакторинг) для одного major-пакета npm/bun.
20
19
  - **callRunner** — диспетчер одного ітеративного виклику: `pi` — вбудований pi-агент (текст через `deps.out`), `cursor`/`codex` — napi-міст ACP (`@7n/llm-lib/acp`).
21
- - **backupWorkspacePackageFiles** / **cleanupBackups** — бекап і прибирання `package.json` кожного воркспейсу.
22
20
  - **loadPluginTazeProviders** — завантажує провайдерів з активних плагінів: `.n-rules.json`/автодетект → `resolvePlugins` (плагін доставляється автоматично при першому запуску) → handler-модулі extension-point `taze` → валідація `assertEcosystemProvider`; битий плагін — warning і пропуск, не провал.
23
- - **formatReport** — компонує підсумковий Markdown-звіт (npm-гілка + секція на кожну екосистему з manifests; екосистема без manifests — тиша) без окремого LLM-виклику.
24
- - **runTazeOrchestrator** — повний прогін: перевіряє, що `cwd` ізольований worktree, виконує npm-гілку, далі кожного провайдера наскрізь (detect available backup bump diff ізольовані виклики раннера по major-записах → cleanup) і повертає звіт.
21
+ - **formatReport** — Markdown-звіт: рівноправна секція на кожну екосистему з manifests (без manifests — тиша) + загальний підсумок; без окремого LLM-виклику.
22
+ - **runTazeOrchestrator** — повний прогін: гарантує ізольований worktree (авто-створює `<branch>-taze` через `npx @7n/mt worktree create`, після завершення переносить зміни назад і прибирає авто-створене дерево), проганяє кожного провайдера наскрізь і повертає `{ ok, report, ecosystems }`. Без жодного taze-провайдера попередження (для npm/bun-гілки потрібен `@7n/rules-lang-js`).
23
+ - **bringChangesBackToOriginal** / **removeAutoCreatedWorktree** — перенесення незакомічених змін з авто-створеного worktree у вихідне дерево і його прибирання.
25
24
 
26
25
  ## Публічний API
27
26
 
28
- - buildDependencyPrompt — промпт одного npm-major-запису.
29
27
  - callRunner — виклик обраного раннера (`pi`/`cursor`/`codex`) з одним промптом.
30
- - backupWorkspacePackageFiles / cleanupBackups — бекап/прибирання `package.json` воркспейсів.
31
28
  - loadPluginTazeProviders — валідні EcosystemProvider-и з handler-модулів плагінів.
32
- - formatReport — фінальний Markdown-звіт із npm-результатів і записів екосистем.
29
+ - formatReport — фінальний Markdown-звіт із записів екосистем.
33
30
  - runTazeOrchestrator — повна оркестрація taze; `deps.ecosystemProviders` повністю замінює список провайдерів (для тестів).
31
+ - bringChangesBackToOriginal / removeAutoCreatedWorktree — життєвий цикл авто-створеного worktree.
34
32
 
35
33
  ## Гарантії поведінки
36
34
 
37
- - Виконує файлові операції (копіювання/видалення бекапів) і запускає зовнішні команди — НЕ read-only.
38
- - Перед будь-якою мутацією перевіряє, що `cwd` ізольований worktree (`assertRunningInWorktree`), інакше кидає виняток.
39
- - npm/bun-гілка активна лише за кореневим package.json: на чисто-Python/Rust репо вона тихо пропускається (лог + без npm-рядків у звіті), а не валить прогін через `bun install → exit 1`.
35
+ - Виконує файлові операції і запускає зовнішні команди — НЕ read-only.
36
+ - Кроки оркестрації виконуються лише в ізольованому worktree; авто-створене дерево прибирається у `finally` навіть при винятку, зміни переносяться назад.
40
37
  - Виняток усередині одного провайдера (bump/diff/команда) не зупиняє інших — фіксується в `error` запису екосистеми й у звіті; `ok` результату тоді false.
41
38
  - Падіння одного пакета в ізольованому виклику раннера не втрачає прогрес по інших записах.
@@ -1,8 +1,5 @@
1
1
  /** @see ./docs/orchestrate.md */
2
2
  import { spawnSync } from 'node:child_process'
3
- import { existsSync } from 'node:fs'
4
- import { copyFile, rm } from 'node:fs/promises'
5
- import { join } from 'node:path'
6
3
  import { pathToFileURL } from 'node:url'
7
4
 
8
5
  import {
@@ -13,38 +10,9 @@ import {
13
10
  import { assertEcosystemProvider } from '../../../scripts/lib/plugin-api.mjs'
14
11
  import { readNRulesConfigLite } from '../../../scripts/lib/read-n-rules-config-lite.mjs'
15
12
  import { getHandlers, resolvePlugins } from '../../../scripts/lib/resolve-plugins.mjs'
16
- import { getMonorepoPackageRootDirs } from '../../../scripts/lib/workspaces.mjs'
17
- import { collectTazeDiff } from './diff.mjs'
18
13
 
19
14
  export { bringChangesBackToOriginal, removeAutoCreatedWorktree } from '../../../scripts/lib/auto-worktree.mjs'
20
15
 
21
- /** Суфікс бекапу package.json — той самий, що й у `diff.mjs`/кроці 1 SKILL.md. */
22
- const BACKUP_SUFFIX = '.taze-bak'
23
-
24
- /**
25
- * Промпт ОДНОГО ітеративного виклику — лише кроки 4-6 SKILL.md (breaking
26
- * changes → сумісність коду → рефакторинг) для ОДНОГО major-пакета. Кроки
27
- * 1-3/7/8 виконує оркестратор детерміновано, без LLM.
28
- * @param {{workspace: string, pkg: string, from: string, to: string}} entry запис major-diff (з `collectTazeDiff`)
29
- * @returns {string} готовий промпт
30
- */
31
- export function buildDependencyPrompt({ workspace, pkg, from, to }) {
32
- return [
33
- '# Major-оновлення одного пакета: перевірка сумісності й рефакторинг',
34
- '',
35
- `Пакет \`${pkg}\` у воркспейсі \`${workspace}\`: **${from} → ${to}** — вже застосовано в package.json/bun.lock (кроки 1-3 виконано детерміновано, без тебе). Твоя задача — лише breaking-changes-перевірка й, за потреби, рефакторинг.`,
36
- '',
37
- '## Кроки',
38
- `1. Зібрати breaking changes цього оновлення: CHANGELOG/Releases репозиторію модуля (поле \`repository\` у \`node_modules/${pkg}/package.json\`), або git/diff між закешованою старою версією (\`~/.bun/install/cache/${pkg}@<стара-версія>/\`) і новою (\`node_modules/${pkg}/\`).`,
39
- `2. Знайти використання зачепленого API в коді проєкту (\`rg -n\` по імпортах/викликах \`${pkg}\`).`,
40
- '3. Сумісно — нічого не робити. Несумісно — застосувати міграцію (перейменувати імпорт, оновити сигнатуру виклику, замінити видалену опцію еквівалентом).',
41
- '4. Якщо були правки — запусти `npx @7n/rules lint`, typecheck/test якщо є в проєкті.',
42
- '5. Нетривіальна/неоднозначна міграція — не вгадуй, залиш TODO-коментар із посиланням на CHANGELOG.',
43
- '',
44
- 'У відповіді одним абзацом підсумуй: сумісно / зрефакторено (які файли) / TODO (чому).'
45
- ].join('\n')
46
- }
47
-
48
16
  /**
49
17
  * Диспетчер одного ітеративного виклику на обраний раннер. `pi` — вбудований
50
18
  * pi-агент (`@7n/llm-lib/agent-skill`; текст перехоплюється через `deps.out`,
@@ -87,58 +55,6 @@ export async function callRunner(runner, prompt, cwd, deps = {}) {
87
55
  }
88
56
  }
89
57
 
90
- /**
91
- * Синхронно виконує детерміновану команду (bunx/bun), кидає з
92
- * exit-кодом+stderr при провалі.
93
- * @param {string} cmd бінарник
94
- * @param {string[]} args аргументи
95
- * @param {string} cwd робочий каталог
96
- * @param {typeof spawnSync} spawnFn інжект для тестів
97
- * @returns {string} stdout
98
- */
99
- function runCommand(cmd, args, cwd, spawnFn) {
100
- const result = spawnFn(cmd, args, { cwd, encoding: 'utf8' })
101
- if (result.status !== 0) {
102
- throw new Error(`${cmd} ${args.join(' ')} → exit ${result.status}: ${result.stderr || result.stdout}`)
103
- }
104
- return result.stdout
105
- }
106
-
107
- /**
108
- * Бекапить package.json кожного воркспейсу (крок 1 SKILL.md) — потрібно для
109
- * класифікації major/minor через `collectTazeDiff` після bump-у.
110
- * @param {string} cwd корінь репо
111
- * @param {{ getMonorepoPackageRootDirs?: (cwd: string) => Promise<string[]>, copyFile?: (src: string, dest: string) => Promise<void> }} [deps] інжекти
112
- * @returns {Promise<string[]>} відносні шляхи воркспейсів, що мали package.json
113
- */
114
- export async function backupWorkspacePackageFiles(cwd, deps = {}) {
115
- const getRoots = deps.getMonorepoPackageRootDirs ?? getMonorepoPackageRootDirs
116
- const copy = deps.copyFile ?? copyFile
117
- const roots = await getRoots(cwd)
118
- const backedUp = []
119
- for (const ws of roots) {
120
- const pkgPath = join(cwd, ws, 'package.json')
121
- if (!existsSync(pkgPath)) continue
122
- await copy(pkgPath, `${pkgPath}${BACKUP_SUFFIX}`)
123
- backedUp.push(ws)
124
- }
125
- return backedUp
126
- }
127
-
128
- /**
129
- * Прибирає бекапи package.json після завершення (крок 7 SKILL.md).
130
- * @param {string} cwd корінь репо
131
- * @param {string[]} workspaces воркспейси з бекапом (з `backupWorkspacePackageFiles`)
132
- * @param {{ rm?: (path: string, opts?: object) => Promise<void> }} [deps] інжект
133
- * @returns {Promise<void>}
134
- */
135
- export async function cleanupBackups(cwd, workspaces, deps = {}) {
136
- const remove = deps.rm ?? rm
137
- for (const ws of workspaces) {
138
- await remove(join(cwd, ws, `package.json${BACKUP_SUFFIX}`), { force: true })
139
- }
140
- }
141
-
142
58
  /**
143
59
  * Завантажує EcosystemProvider-и з активних плагінів проєкту: `.n-rules.json`
144
60
  * (або автодетект за файловими сигналами — `pyproject.toml` → lang-python) →
@@ -265,50 +181,39 @@ function appendEcosystemSection(lines, eco) {
265
181
 
266
182
  /**
267
183
  * Компонує підсумковий звіт (крок 8 SKILL.md) детерміновано з результатів
268
- * ітерацій — без окремого LLM-виклику для самого звіту.
269
- * @param {{
270
- * minorPatch: number,
271
- * totalChanged: number,
272
- * results: Array<{pkg:string, workspace:string, from:string, to:string, ok:boolean, error:string|null}>,
273
- * ecosystems?: Array<object>,
274
- * npmPresent?: boolean
275
- * }} args дані звіту (`ecosystems` — записи з `runEcosystem`, по одному на провайдера;
276
- * `npmPresent: false` — репо без кореневого package.json, npm-рядки не друкуються)
184
+ * ітерацій — без окремого LLM-виклику для самого звіту. Усі екосистеми
185
+ * (включно з npm/bun — плагін `@7n/rules-lang-js`, фаза 5a) — рівноправні
186
+ * секції; екосистема без manifests — тиша.
187
+ * @param {{ ecosystems?: Array<object> }} args записи з `runEcosystem`, по одному на провайдера
277
188
  * @returns {string} markdown-звіт
278
189
  */
279
- export function formatReport({ minorPatch, totalChanged, results, ecosystems = [], npmPresent = true }) {
280
- const lines = ['## taze: підсумок', '']
281
- if (npmPresent) {
282
- lines.push(`- **Оновлено (minor/patch):** ${minorPatch}`, `- **Major-оновлення:** ${results.length}`)
283
- for (const r of results) {
284
- lines.push(formatResultLine(r, r.workspace))
285
- }
286
- }
190
+ export function formatReport({ ecosystems = [] }) {
191
+ const lines = ['## taze: підсумок']
287
192
 
288
- let ecosystemsTotal = 0
193
+ let total = 0
289
194
  for (const eco of ecosystems) {
290
- ecosystemsTotal += appendEcosystemSection(lines, eco)
195
+ total += appendEcosystemSection(lines, eco)
291
196
  }
292
197
 
293
- lines.push('', `- **Всього змінено:** ${totalChanged + ecosystemsTotal}`)
198
+ lines.push('', `- **Всього змінено:** ${total}`)
294
199
  return lines.join('\n')
295
200
  }
296
201
 
297
202
  /**
298
- * Оркеструє taze: детерміновані кроки (бекап масовий bump → diff →
299
- * прибирання звіт) без LLM, і по одному ізольованому, обмеженому по
300
- * обсягу виклику `callRunner` на кожен major-пакет (кроки 4-6 SKILL.md)
301
- * замість одного величезного непрозорого ходу на весь монорепо. npm/bun-гілка
302
- * вбудована; решта екосистем EcosystemProvider-и, завантажені з плагінів
303
- * (`@7n/rules-lang-*`, extension-point `taze`; фаза 2 spec — Rust теж плагін).
304
- * Падіння одного пакета/однієї екосистеми не втрачає прогрес по інших.
203
+ * Оркеструє taze: чистий цикл по EcosystemProvider-ах (кроки 1-3/7/8
204
+ * детерміновано в провайдері, кроки 4-6 по одному ізольованому виклику
205
+ * `callRunner` на кожен major-запис) замість одного величезного непрозорого
206
+ * ходу на весь монорепо. Ядро — двигун без мовної специфіки (фаза 5a spec):
207
+ * ВСІ екосистеми, включно з npm/bun (`@7n/rules-lang-js`), приходять з
208
+ * плагінів (extension-point `taze`). Падіння одного пакета/однієї екосистеми
209
+ * не втрачає прогрес по інших.
305
210
  * @param {{
306
211
  * cwd?: string,
307
212
  * runner?: 'pi' | 'cursor' | 'codex',
308
213
  * log?: (line: string) => void,
309
- * deps?: { spawnFn?: typeof spawnSync, collectTazeDiff?: (cwd: string) => Promise<object>, callRunner?: (runner: string, prompt: string, cwd: string, deps: object) => Promise<{ok: boolean, text: string, error: string|null}>, ecosystemProviders?: object[] } & Record<string, unknown>
214
+ * deps?: { spawnFn?: typeof spawnSync, callRunner?: (runner: string, prompt: string, cwd: string, deps: object) => Promise<{ok: boolean, text: string, error: string|null}>, ecosystemProviders?: object[] } & Record<string, unknown>
310
215
  * }} [options] опції + інжекти для тестів (`deps.ecosystemProviders` повністю замінює список провайдерів)
311
- * @returns {Promise<{ ok: boolean, report: string, results: Array<object>, ecosystems: Array<object> }>} результат
216
+ * @returns {Promise<{ ok: boolean, report: string, ecosystems: Array<object> }>} результат
312
217
  */
313
218
  export async function runTazeOrchestrator(options = {}) {
314
219
  const runner = options.runner ?? 'pi'
@@ -325,55 +230,22 @@ export async function runTazeOrchestrator(options = {}) {
325
230
  const cwd = worktree.cwd
326
231
 
327
232
  try {
328
- // npm/bun-гілка активна лише за кореневим package.json — на чисто-Python/Rust
329
- // репо `bun install` падає з exit 1, і без цього гейта весь прогін гинув би
330
- // до екосистемних провайдерів. Той самий принцип «тиші», що й для мовних
331
- // екосистем: немає сигналу — немає ані кроків, ані згадки у звіті.
332
- const npmPresent = existsSync(join(cwd, 'package.json'))
333
- let diff = { major: [], minorPatch: 0, totalChanged: 0 }
334
- const results = []
335
- if (npmPresent) {
336
- log('📦 Бекап package.json...')
337
- const backedUpWorkspaces = await backupWorkspacePackageFiles(cwd, deps)
338
-
339
- log('⬆️ bunx taze -w -r latest...')
340
- runCommand('bunx', ['taze', '-w', '-r', 'latest'], cwd, spawnFn)
341
- log('📥 bun install...')
342
- runCommand('bun', ['install'], cwd, spawnFn)
343
-
344
- const collectDiff = deps.collectTazeDiff ?? collectTazeDiff
345
- diff = await collectDiff(cwd)
346
- log(`🔍 diff: ${diff.major.length} major, ${diff.minorPatch} minor/patch`)
347
-
348
- for (const entry of diff.major) {
349
- log(`🔧 ${entry.pkg} (${entry.workspace}): ${entry.from} → ${entry.to}...`)
350
- const outcome = await call(runner, buildDependencyPrompt(entry), cwd, deps)
351
- results.push({ ...entry, ...outcome })
352
- log(outcome.ok ? ` ✅ ${entry.pkg}` : ` ❌ ${entry.pkg}: ${outcome.error}`)
353
- }
354
-
355
- await cleanupBackups(cwd, backedUpWorkspaces, deps)
356
- } else {
357
- log('⏭ npm/bun: кореневого package.json немає — гілка пропущена')
358
- }
359
-
360
233
  const providers = deps.ecosystemProviders ?? (await loadPluginTazeProviders(cwd, log, deps))
234
+ if (providers.length === 0) {
235
+ log(
236
+ '⏭ Жодного taze-провайдера: жоден активний плагін не надає extension-point `taze` (для npm/bun-гілки потрібен @7n/rules-lang-js)'
237
+ )
238
+ }
361
239
  const ecosystems = []
362
240
  for (const provider of providers) {
363
241
  ecosystems.push(await runEcosystem(provider, { cwd, runner, log, deps, spawnFn, call }))
364
242
  }
365
243
 
366
- const report = formatReport({
367
- minorPatch: diff.minorPatch,
368
- totalChanged: diff.totalChanged,
369
- results,
370
- ecosystems,
371
- npmPresent
372
- })
244
+ const report = formatReport({ ecosystems })
373
245
  log(report)
374
246
 
375
247
  const ecosystemsOk = ecosystems.every(eco => eco.error === null && eco.results.every(r => r.ok))
376
- return { ok: results.every(r => r.ok) && ecosystemsOk, report, results, ecosystems }
248
+ return { ok: ecosystemsOk, report, ecosystems }
377
249
  } finally {
378
250
  // Лише для АВТОстворених worktree — якщо викликач уже сидів у своєму
379
251
  // worktree (worktree.autoCreated === false), це не наш worktree і не
@@ -1,3 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json"
3
- }
@@ -1,38 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: main.mjs
4
- resource: npm/rules/doc-files/docgen-extract/main.mjs
5
- docgen:
6
- crc: a9332a80
7
- model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
- score: 100
9
- issues: judge:inaccurate:0.99
10
- judgeModel: openai-codex/gpt-5.4-mini
11
- ---
12
-
13
- ## Огляд
14
-
15
- Екстрагує факти за допомогою функції `extractFacts`, звертаючись до мережі та використовуючи кешування в межах одного прогону. При цьому ігнорує каталоги, такі як `.github`, `.git`, `node_modules`, `base/`, `ua/` та `.firebase`.
16
-
17
- ## Поведінка
18
-
19
- 1. Аналізує вміст коду для створення детального набору фактів про файл.
20
- 2. Визначає словник і визначає, чи є код написаний на JavaScript, TypeScript або TypeScript (ESM).
21
- 3. Витягує загальний опис файлу, якщо він присутній у верхньому блоці коментарів.
22
- 4. Визначає всі функції, які є публічно доступними (експортованими), разом із їхніми описами та параметрами.
23
- 5. Класифікує імпорти на внутрішні, сторонні (npm) та вбудовані (stdlib).
24
- 6. Визначає, чи є код:
25
- - Стійким до винятків (catchesErrors).
26
- - Здатним працювати без доступу до мережі (readOnly).
27
- - Використовуючи механізми кешування (caches).
28
- - Згодом повертаючи хибні значення у випадку помилки (returnsFalsyOnFail).
29
- 7. Ігнорує шляхи, що відповідають шаблонам: .github, .git, node_modules, base/, ua/, .firebase.
30
-
31
- ## Публічний API
32
-
33
- extractFacts — витягує з коду файлу список значущих тверджень (фактів).
34
-
35
- ## Гарантії поведінки
36
-
37
- - Кешує результати в межах одного прогону.
38
- - Свідомо пропускає шляхи: `.github`, `.git`, `node_modules`, `base/`, `ua/`, `.firebase`.