@7n/rules-lang-js 0.9.0 → 0.11.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 (59) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/package.json +1 -1
  3. package/rules/bun/package_json/package_json.mdc +3 -1
  4. package/rules/bun/package_json/package_json.rego +36 -1
  5. package/rules/npm-module/npm_package_json/npm_package_json.mdc +18 -3
  6. package/rules/npm-module/npm_package_json/npm_package_json.rego +42 -5
  7. package/rules/storybook/adopt/docs/index.md +9 -0
  8. package/rules/storybook/adopt/docs/main.md +45 -0
  9. package/rules/storybook/adopt/main.mjs +382 -0
  10. package/rules/storybook/ci/concern.json +15 -0
  11. package/rules/storybook/ci/docs/fix-ci.md +39 -0
  12. package/rules/storybook/ci/docs/index.md +10 -0
  13. package/rules/storybook/ci/docs/main.md +50 -0
  14. package/rules/storybook/ci/fix-ci.mjs +105 -0
  15. package/rules/storybook/ci/main.mjs +112 -0
  16. package/rules/storybook/ci/template/lint-storybook.yml.snippet.yml +41 -0
  17. package/rules/storybook/ci/template/setup-playwright-chromium.action.yml +34 -0
  18. package/rules/storybook/hygiene/concern.json +4 -0
  19. package/rules/storybook/hygiene/docs/index.md +9 -0
  20. package/rules/storybook/hygiene/docs/main.md +45 -0
  21. package/rules/storybook/hygiene/main.mjs +254 -0
  22. package/rules/storybook/main.json +1 -0
  23. package/rules/storybook/main.mdc +66 -0
  24. package/rules/storybook/mocking/concern.json +3 -0
  25. package/rules/storybook/mocking/mocking.mdc +132 -0
  26. package/rules/storybook/scaffold/concern.json +5 -0
  27. package/rules/storybook/scaffold/docs/fix-scaffold.md +29 -0
  28. package/rules/storybook/scaffold/docs/index.md +10 -0
  29. package/rules/storybook/scaffold/docs/main.md +36 -0
  30. package/rules/storybook/scaffold/fix-scaffold.mjs +150 -0
  31. package/rules/storybook/scaffold/main.mjs +196 -0
  32. package/rules/storybook/scaffold/template/docs/index.md +10 -0
  33. package/rules/storybook/scaffold/template/docs/main.md +29 -0
  34. package/rules/storybook/scaffold/template/docs/preview.md +46 -0
  35. package/rules/storybook/scaffold/template/main.js +92 -0
  36. package/rules/storybook/scaffold/template/mocks/docs/gql-sse.md +36 -0
  37. package/rules/storybook/scaffold/template/mocks/docs/index.md +9 -0
  38. package/rules/storybook/scaffold/template/mocks/gql-sse.js +25 -0
  39. package/rules/storybook/scaffold/template/preview.js +47 -0
  40. package/rules/storybook/scope/concern.json +4 -0
  41. package/rules/storybook/scope/docs/index.md +9 -0
  42. package/rules/storybook/scope/docs/main.md +62 -0
  43. package/rules/storybook/scope/main.mjs +202 -0
  44. package/rules/storybook/vitest-config/concern.json +8 -0
  45. package/rules/storybook/vitest-config/docs/fix-vitest-config.md +37 -0
  46. package/rules/storybook/vitest-config/docs/index.md +10 -0
  47. package/rules/storybook/vitest-config/docs/main.md +71 -0
  48. package/rules/storybook/vitest-config/fix-vitest-config.mjs +356 -0
  49. package/rules/storybook/vitest-config/main.mjs +389 -0
  50. package/rules/storybook/vitest-config/template/docs/index.md +12 -0
  51. package/rules/storybook/vitest-config/template/docs/storybook-project-entry.md +33 -0
  52. package/rules/storybook/vitest-config/template/docs/unit-project-entry.md +30 -0
  53. package/rules/storybook/vitest-config/template/docs/vitest.config.baseline.md +28 -0
  54. package/rules/storybook/vitest-config/template/docs/vitest.stryker.config.baseline.md +31 -0
  55. package/rules/storybook/vitest-config/template/storybook-project-entry.js +26 -0
  56. package/rules/storybook/vitest-config/template/unit-project-entry.js +5 -0
  57. package/rules/storybook/vitest-config/template/vitest.config.baseline.mjs +38 -0
  58. package/rules/storybook/vitest-config/template/vitest.stryker.config.baseline.mjs +19 -0
  59. package/rules/storybook/vitest-config/vitest-config.mdc +37 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.0] - 2026-07-21
4
+
5
+ ### Added
6
+
7
+ - storybook: новий concern `ci` (ADR Кластер 5, CI-частина) — канонічний composite action `setup-playwright-chromium` (кеш Playwright-браузерів, лише chromium) і `.github/workflows/lint-storybook.yml` (швидкий PR-прогін `vitest --project=storybook`), гейтований `requires.capability: ci:github`
8
+
9
+ ### Fixed
10
+
11
+ - storybook: viteFinal-фільтр стійкий до VueMacros-стека (Promise/масив-резолв, сімейний фільтр vite:*/vue-macros), vitest@^4 provider-factory (@vitest/browser-playwright) замість застарілого рядка `'playwright'`, flat-root layout у detectStoriesGlob (components без src/), точковий alias-мок одного модуля в mocking.mdc, і STORIES_RE false positive на `storybookTest({ configDir })` без явного include — усе за результатами пілота adopt-діагностики на nitra/components. Заодно governance package_json.rego: allowlist доповнено `@vitest/browser-playwright`.
12
+
13
+ ## [0.10.0] - 2026-07-21
14
+
15
+ ### Added
16
+
17
+ - storybook: канон Storybook хвилі 1 для Vue-компонентних бібліотек — детекція скоупу (isVueComponentLibraryPkg, поріг ≥3 .vue, opt-out), канонічний скафолд .storybook/main.js+preview.js+mocks/gql-sse.js, package.json#scripts.storybook (ADR канон-storybook-для-vue-компонентних-бібліотек)
18
+ - npm-module/bun: governance-виняток канону Storybook (кластер 7 ADR канон-storybook-для-vue-компонентних-бібліотек) — npm_package_json.rego дозволяє канонічні Storybook-devDeps (storybook, @storybook/vue3-vite, @storybook/vue3, msw, msw-storybook-addon) у npm/package.json із зафіксованою точною версією (deny на неканонічний пакет або неканонічну версію); bun/package_json.rego розширює root-only test peers на @vitest/browser + playwright (browser-mode provider для named vitest project "storybook", лише chromium) та @storybook/addon-vitest (storybookTest-плагін того самого vitest-конфіга) — Storybook-identity-пакети у корінь свідомо не додаються
19
+ - storybook: vitest-config-концерн хвилі 1 (ADR Кластер 5) — canonical test.projects unit+storybook (browser-mode, лише chromium, stories-glob) дописується поверх наявного vitest-конфіга, ізольований vitest.stryker.config генерується поруч (Stryker крашиться на browser-mode projects)
20
+ - storybook: концерни mocking (docs-only рецепти router/tfm/Apollo-MSW/Pinia/page-story) і hygiene (undeclared third-party imports у .vue, auto-detect sassVariables) — ADR Кластер 3/6
21
+
22
+ ### Fixed
23
+
24
+ - storybook: підключено concern-и scope/scaffold/vitest-config до unified lint-рушія (lint-блок у concern.json — check:true без lint мовчки ігнорувався run-detectors.mjs), додано --adopt-режим (adopt/main.mjs) і скіл n-storybook
25
+
3
26
  ## [0.9.0] - 2026-07-20
4
27
 
5
28
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/rules-lang-js",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Плагін @7n/rules: JS/npm/bun-екосистема — lint-правила (js/bun/vue/js-run/npm-module/db), taze-провайдер (package.json, bunx taze) і doc-files-екстрактори (oxc AST)",
5
5
  "keywords": [
6
6
  "javascript",
@@ -9,6 +9,8 @@ Rego-пакет: `bun.package_json`
9
9
  Gate виносить два класи deny:
10
10
 
11
11
  1. **Заборонені top-level поля** — будь-яке поле з `package.json.deny.json` присутнє у файлі (навіть із порожнім значенням `{}`).
12
- 2. **devDependencies не з білого списку** — дозволені лише `@nitra/*`/`@7n/*` та root-only тестові peer/tools (`vitest`, `@vitest/coverage-v8`, `@stryker-mutator/vitest-runner`, `@playwright/test`). Будь-який інший пакет → deny. CLI-тули, які `n-rules lint` спавнить через `bunx` (oxlint, jscpd, v8r, github-actionlint тощо), у root не пінуються — вони приїжджають як `dependencies` пакета `@7n/rules` (npm-module.mdc).
12
+ 2. **devDependencies не з білого списку** — дозволені лише `@nitra/*`/`@7n/*` та root-only тестові peer/tools (`vitest`, `@vitest/coverage-v8`, `@vitest/browser`, `@vitest/browser-playwright`, `@stryker-mutator/vitest-runner`, `@stryker-mutator/core`, `@playwright/test`, `playwright`, `@storybook/addon-vitest`, `@7n/test`). Будь-який інший пакет → deny. CLI-тули, які `n-rules lint` спавнить через `bunx` (oxlint, jscpd, v8r, github-actionlint тощо), у root не пінуються — вони приїжджають як `dependencies` пакета `@7n/rules` (npm-module.mdc).
13
+
14
+ `@vitest/browser`/`@vitest/browser-playwright`/`playwright`/`@storybook/addon-vitest` — додані для named vitest project "storybook" (канон Storybook, кластер 5: browser-mode, лише chromium) — той самий root vitest.config, що й `unit`-проект; `@storybook/addon-vitest` постачає `storybookTest`-плагін для цього vitest-конфіга (канонічний template правила `storybook`). `@vitest/browser-playwright` — окремий npm-пакет: vitest@^4 прибрав рядкове API browser-провайдера (`provider: 'playwright'`), потрібна factory `import { playwright } from '@vitest/browser-playwright'` → `provider: playwright()` (звірено з реальним `bun.lock` пілотного консюмера — усі три `@vitest/*`/`playwright`-пакети встановлені поруч). **Межа з `npm-module.mdc`**: Storybook-специфічні identity-пакети (`storybook`, `@storybook/vue3-vite`, `@storybook/vue3`, `msw`, `msw-storybook-addon`) у цей allowlist **не** додаються — вони живуть у `npm/package.json` консюмер-пакета (канон Storybook, кластер 7 Governance), бо `isStorybookRoot()` у `@7n/test` детектує Storybook-скоуп саме за тим файлом, не кореневим. `@storybook/addon-vitest` — виняток із цієї межі: він test-tooling (vitest-плагін), а не identity-маркер, тож root, як і решта vitest-peer'ів.
13
15
 
14
16
  Перевірки, що потребують FS або cross-file контексту (наприклад наявність `yarn.lock`), лишаються у JS-шарі.
@@ -8,6 +8,16 @@
8
8
  # - `devDependencies` лише `@nitra/*` + root-only тестові peer/tools для `@7n/test coverage`
9
9
  # (правило `test` enabled завжди — див. `test/auto.md`; published workspace-и не мають
10
10
  # `devDependencies` за `npm-module.mdc`)
11
+ # - `@vitest/browser`/`@vitest/browser-playwright`/`playwright`/`@storybook/addon-vitest`
12
+ # (browser-mode provider factory + `storybookTest`-плагін для named vitest project
13
+ # "storybook", лише chromium — канон Storybook кластер 5) теж root-only test peers:
14
+ # той самий vitest.config, що й `unit`-проект, живе в корені монорепо-споживача.
15
+ # Storybook-специфічні
16
+ # identity-пакети (`storybook`, `@storybook/vue3*`, `msw*`) НЕ сюди — вони живуть у
17
+ # `npm/package.json` (канон Storybook кластер 7, `npm-module.mdc`), бо
18
+ # `isStorybookRoot()` @7n/test читає саме той файл, не кореневий package.json.
19
+ # `@storybook/addon-vitest` — виняток із цього правила: це test-tooling (плагін
20
+ # vitest-конфіга), а не Storybook-identity-маркер, тож root, а не npm/package.json.
11
21
  #
12
22
  # Перевірки, які потребують FS / cross-file контексту, лишаються у JS.
13
23
  package bun.package_json
@@ -50,7 +60,32 @@ deny contains msg if {
50
60
  # @stryker-mutator/core — обов'язковий exact-pin peer vitest-runner@9+ (раніше тягнувся транзитивно)
51
61
  # @7n/test — оркестратор `coverage` (npx @7n/test coverage); devDependency, щоб npx резолвив
52
62
  # локально без мережевого fetch щоразу.
53
- allowed_root_test_deps := {"vitest", "@vitest/coverage-v8", "@stryker-mutator/vitest-runner", "@stryker-mutator/core", "@playwright/test", "@7n/test"}
63
+ # @vitest/browser + @vitest/browser-playwright + playwright — провайдер browser-mode для
64
+ # named vitest project "storybook" (канон Storybook кластер 5: лише chromium, PR —
65
+ # швидкий --project=storybook). vitest@^4 прибрав рядкове API провайдера
66
+ # (`provider: 'playwright'`) — `@vitest/browser-playwright` постачає factory
67
+ # `import { playwright } from '@vitest/browser-playwright'` → `provider: playwright()`,
68
+ # окремий npm-пакет, не входить у `@vitest/browser` (звірено з реальним bun.lock пілота —
69
+ # усі три пакети встановлені поруч). `playwright` (не `@playwright/test`) — сирий driver,
70
+ # який `@vitest/browser-playwright` використовує як provider; `@playwright/test` лишається
71
+ # окремо для змістовних E2E-сценаріїв (n-vue.mdc).
72
+ # @storybook/addon-vitest — постачає `storybookTest` для vitest-плагіна в канонічному
73
+ # vitest.config named-проекту "storybook" (той самий канон Storybook кластер 5); версія
74
+ # з лінійки Storybook 9.x (узгоджена з `storybook`@9.1.10, запіненим у
75
+ # npm_package_json.rego) — allowlist тут за іменем, точний пінінг версії root-tooling
76
+ # не робимо (на відміну від Storybook-identity-пакетів у npm/package.json).
77
+ allowed_root_test_deps := {
78
+ "vitest",
79
+ "@vitest/coverage-v8",
80
+ "@vitest/browser",
81
+ "@vitest/browser-playwright",
82
+ "@stryker-mutator/vitest-runner",
83
+ "@stryker-mutator/core",
84
+ "@playwright/test",
85
+ "playwright",
86
+ "@storybook/addon-vitest",
87
+ "@7n/test",
88
+ }
54
89
 
55
90
  allowed_root_dev_dependency(name) if {
56
91
  startswith(name, "@nitra/")
@@ -16,10 +16,13 @@ Rego-пакет: `npm-module.npm_package_json`
16
16
  - Обовʼязкове, має бути непорожнім масивом.
17
17
  - Subset-of перевірка: кожне значення з канонічного сніпету має бути присутнє у `files`. За замовчуванням — `"types"` обовʼязковий.
18
18
 
19
- **Поле `devDependencies`** (inverse-pattern, логіка в rego):
19
+ **Поле `devDependencies`** (inverse-pattern + Storybook-виняток, логіка в rego):
20
20
 
21
21
  - Не публікуються користувачам пакета — має бути відсутнє або порожнє `{}`.
22
- - Наявність будь-яких devDeps deny з переліком залежностей. Dev-інструментарій переноситься у кореневий `package.json`; CLI-тули, які пакет спавнить через `bunx` у репозиторіях-споживачах (пінінг версій),у `dependencies` (кореневе bun-правило `package_json` такі пакети в root devDeps не пускає).
22
+ - **Виняток канонічні Storybook-пакети** (канон Storybook, кластер 7 Governance: `docs/adr/канон-storybook-для-vue-компонентних-бібліотек.md`): `storybook`, `@storybook/vue3-vite`, `@storybook/vue3`, `msw`, `msw-storybook-addon` дозволені як devDeps саме тут, у `npm/package.json` консюмер-пакета **не** в кореневому `package.json`. Обґрунтування: майбутній `isStorybookRoot()` у `@7n/test` читає саме цей файл, щоб визначити Storybook-скоуп workspace-пакета, тож маркер-пакети мають бути видимі тут, а не в кореневих tooling-deps. Версія кожного канонічного пакета зафіксована точно (map `storybook_canon_dev_deps` у rego) — присутність пакета з іншою версією теж deny (окреме повідомлення, не плутати з allowlist-забороною).
23
+ - Будь-який інший devDep (не з канонічного Storybook-списку) → deny з переліком імен. Dev-інструментарій переноситься у кореневий `package.json`; CLI-тули, які пакет спавнить через `bunx` у репозиторіях-споживачах (пінінг версій), — у `dependencies` (кореневе bun-правило `package_json` такі пакети в root devDeps не пускає).
24
+
25
+ Канон Storybook-devDeps та їхні версії — static map у `npm_package_json.rego` (не template-driven: це опційний allowlist, а не mandatory-presence дані, тож генеричний T0-fix-writer цього concern-а їх у кожен `package.json` не мерджить — див. коментар на початку rego-файлу).
23
26
 
24
27
  Канонічний сніпет `files`: [package.json.snippet.json](./template/package.json.snippet.json)
25
28
 
@@ -50,8 +53,20 @@ FS-перевірки (наявність файлу зі шляху `types`, с
50
53
  { "files": ["bin", "mdc"] }
51
54
  ```
52
55
 
53
- ✗ Неправильно — наявні `devDependencies`:
56
+ ✗ Неправильно — наявні `devDependencies`, не з канонічного Storybook-списку:
54
57
 
55
58
  ```json
56
59
  { "devDependencies": { "@7n/rules": "^1.0.0" } }
57
60
  ```
61
+
62
+ ✓ Правильно — канонічний Storybook-devDep із зафіксованою версією (канон Storybook):
63
+
64
+ ```json
65
+ { "devDependencies": { "storybook": "9.1.10" } }
66
+ ```
67
+
68
+ ✗ Неправильно — Storybook-devDep присутній, але версія не збігається з каноном:
69
+
70
+ ```json
71
+ { "devDependencies": { "storybook": "8.0.0" } }
72
+ ```
@@ -6,7 +6,17 @@
6
6
  #
7
7
  # Логіка, що ЛИШАЄТЬСЯ у rego (inverse-patterns, не виносяться у template):
8
8
  # - форма поля `types` (regex pattern: `./types/index.d.ts` або `./types/<…>.d.ts|.d.mts`);
9
- # - `devDependencies` мають бути відсутні або порожні (inverse-pattern — заборона будь-яких).
9
+ # - `devDependencies` мають бути відсутні/порожні АБО належати канонічному
10
+ # Storybook-allowlist із зафіксованою точною версією (канон Storybook, кластер 7
11
+ # Governance: `docs/adr/канон-storybook-для-vue-компонентних-бібліотек.md`).
12
+ # Storybook-devDeps живуть саме у `npm/package.json` консюмер-пакета
13
+ # (а не в кореневому package.json), бо майбутній `isStorybookRoot()` у
14
+ # `@7n/test` читає саме цей файл, щоб визначити Storybook-скоуп пакета.
15
+ # Канон — static map (той самий підхід, що й `allowed_root_test_deps` у
16
+ # `bun.package_json`), НЕ template: це не mandatory-presence дані (більшість
17
+ # npm-пакетів Storybook не має), тож генеричний T0-fix-writer цього
18
+ # concern-а (`createTemplateFixPattern`, deep-merge усього `template.snippet`
19
+ # у target) канонічні devDeps у кожен package.json не домерджує.
10
20
  #
11
21
  # FS-перевірки (наявність файлу зі шляху `types`, скан tarball на тест-патерни) — у JS.
12
22
  package npm_module.npm_package_json
@@ -20,10 +30,27 @@ types_field_template := concat(" ", [
20
30
 
21
31
  dev_deps_template := concat(" ", [
22
32
  "npm/package.json: \"devDependencies\" не публікуються користувачам пакета —",
33
+ "дозволені лише канонічні Storybook-пакети (isStorybookRoot(), канон Storybook);",
23
34
  "dev-інструментарій перенеси у кореневий package.json, а CLI-тули, які пакет",
24
35
  "спавнить через bunx у споживачів, — у \"dependencies\": %v (npm-module.mdc)",
25
36
  ])
26
37
 
38
+ storybook_version_template := concat(" ", [
39
+ "npm/package.json: devDependencies.%v = %q не відповідає зафіксованій версії",
40
+ "Storybook-канону %q — вирівняй версію пакета до канону (npm-module.mdc, канон Storybook)",
41
+ ])
42
+
43
+ # Канонічні Storybook-devDeps (isStorybookRoot()-маркери, канон Storybook кластер 7):
44
+ # зафіксована точна версія — єдина дозволена версія для кожного пакета. Оновлення —
45
+ # ручна правка цієї map.
46
+ storybook_canon_dev_deps := {
47
+ "storybook": "9.1.10",
48
+ "@storybook/vue3-vite": "9.1.10",
49
+ "@storybook/vue3": "9.1.10",
50
+ "msw": "2.11.3",
51
+ "msw-storybook-addon": "2.0.5",
52
+ }
53
+
27
54
  # ── deny: types (regex — лишається в rego) ───────────────────────────────
28
55
 
29
56
  deny contains msg if {
@@ -57,13 +84,23 @@ deny contains msg if {
57
84
  msg := sprintf("npm/package.json: масив \"%s\" має містити %q (npm-module.mdc)", [field, required])
58
85
  }
59
86
 
60
- # ── deny: devDependencies (inverse-pattern, лишається в rego) ────────────
87
+ # ── deny: devDependencies (inverse-pattern + Storybook-allowlist виняток)
88
+
89
+ deny contains msg if {
90
+ dev := object.get(input, "devDependencies", {})
91
+ forbidden_names := [n | some n, _ in dev; not n in object.keys(storybook_canon_dev_deps)]
92
+ count(forbidden_names) > 0
93
+ msg := sprintf(dev_deps_template, [concat(", ", sort(forbidden_names))])
94
+ }
95
+
96
+ # ── deny: Storybook-devDep присутній, але версія розходиться з каноном ──
61
97
 
62
98
  deny contains msg if {
63
99
  dev := object.get(input, "devDependencies", {})
64
- count(dev) > 0
65
- names := concat(", ", sort([n | some n, _ in dev]))
66
- msg := sprintf(dev_deps_template, [names])
100
+ some name, version in dev
101
+ canonical := storybook_canon_dev_deps[name]
102
+ version != canonical
103
+ msg := sprintf(storybook_version_template, [name, version, canonical])
67
104
  }
68
105
 
69
106
  # ── helpers ────────────────────────────────────────────────────────────────
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: Directory Index
3
+ title: plugins/lang-js/rules/storybook/adopt
4
+ resource: plugins/lang-js/rules/storybook/adopt/
5
+ ---
6
+
7
+ | Файл | Тип |
8
+ | ------------------- | --------- |
9
+ | [main.mjs](main.md) | JS Module |
@@ -0,0 +1,45 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: plugins/lang-js/rules/storybook/adopt/main.mjs
5
+ docgen:
6
+ crc: c8e6e421
7
+ model: openai-codex/gpt-5.4-mini
8
+ score: 90
9
+ issues: anchor-miss:(mocking.mdc),anchor-miss:(vitest-config.mdc),judge:inaccurate:0.99
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Режим adopt для канону Storybook у Vue-бібліотеках: звіряє пакети з канонічними секціями `main.js`, `preview.js`, `mocks/gql-sse.js`, `package.json#scripts.storybook`, `vitest test.projects` і `vitest.stryker.config`, а для вже наявних ручних `.storybook/` без сліпого перезапису показує діагностику diff по секціях. Автофікс (`--fix-missing`) додає лише повністю відсутні секції, з тим самим рендером, що й T0-фікс concern-ів `scaffold`/`vitest-config`, без втручання в наявні розбіжні файли. Дає CLI-звіт по кожному пакету зі станом `status` і секціями `SECTION`, окремо фіксуючи `diagnosePackage`, `fixMissingSections`, `runAdopt` і `formatReport`; помилки перехоплює fail-safe, тому збій або діагностики, або фіксу для одного пакета переводить лише його в `status: 'broken'`, а решта пакетів продовжують оброблятися.
16
+ ## Поведінка
17
+
18
+ - `STATUS` — задає фіксовані стани діагностики секцій Storybook: збіг, розбіжність або відсутність.
19
+ - `SECTION` — задає стабільні назви секцій звіту, щоб adopt-перевірка й `--fix-missing` узгоджено посилалися на ті самі частини конфігурації.
20
+ - `diagnosePackage` — перевіряє пакет по секціях і повертає підсумок: канонічний, з відсутніми файлами або з відмінностями; помилки окремих секцій не валять увесь пакет.
21
+ - `fixMissingSections` — створює лише ті канонічні секції, яких у пакеті немає взагалі, і не перезаписує наявні розбіжні файли.
22
+ - `runAdopt` — проганяє adopt-перевірку по всіх або вибраних пакетах у скоупі, із fail-safe поведінкою: збій одного пакета переходить у `broken`, але інші обробляються далі.
23
+ - `formatReport` — перетворює результати adopt-прогону на лаконічний український звіт для CLI, включно з переліком згенерованого або повідомленням про відсутність пакетів у скоупі.
24
+
25
+ ## Публічний API
26
+
27
+ - STATUS — Статуси однієї секції діагностики (діагностика ≠ lint-violation — тут завжди 4 значення).
28
+ - SECTION — Канонічні назви секцій (стабільні — на них зав'язаний `--fix-missing`-switch).
29
+ - diagnosePackage — Діагностика одного пакета в скоупі по секціях. Ніколи не кидає — збій окремої
30
+ секції (парсинг/IO) відображається як секція `differ`, а не виняток, що впав
31
+ би на весь пакет; лишається на розсуд `diagnosePackage` (circuit breaker рівня
32
+ пакета — тут не потрібен, бо секції вже ізольовані одна від одної).
33
+ - fixMissingSections — Генерує канонічний вміст лише для секцій зі статусом `missing` одного пакета
34
+ (adopt-автофікс НІКОЛИ не чіпає секції зі статусом `differ` — інструкція
35
+ для агента/людини, не сліпий перезапис). Кожна секція фіксується незалежно;
36
+ збій однієї не блокує решту (той самий circuit-breaker принцип, лише на дрібнішому рівні).
37
+ - runAdopt — Adopt-прогін усіх (чи обраних) пакетів у скоупі. Circuit breaker (ADR Кластер 8):
38
+ збій діагностики/фіксу ОДНОГО пакета деградує до `status: 'broken'` для нього —
39
+ решта пакетів обробляються далі, весь прогін ніколи не падає через один зламаний.
40
+ відсутні секції; `rootDirs` — звузити прогін до цих коренів пакетів (порожньо/відсутнє → усі в скоупі)
41
+ - formatReport — Форматує людський звіт по результатах `runAdopt` (українською, для виводу скіла в CLI).
42
+
43
+ ## Гарантії поведінки
44
+
45
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).