@nitra/cursor 12.8.3 → 12.8.4

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 (114) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +1 -1
  3. package/rules/js/docs/index.md +3 -3
  4. package/rules/js/docs/main.md +6 -6
  5. package/rules/js/js/docs/check.md +12 -17
  6. package/rules/js/js/docs/index.md +4 -4
  7. package/rules/js/js/docs/tooling.md +8 -8
  8. package/rules/js/js/docs/utils_imports.md +21 -200
  9. package/rules/npm-module/js/docs/index.md +5 -5
  10. package/rules/npm-module/js/docs/rule_meta.md +13 -13
  11. package/rules/npm-module/js/docs/skill_meta.md +19 -9
  12. package/rules/npm-module/js/rule_meta.mjs +9 -9
  13. package/rules/npm-module/js/skill_meta.mjs +6 -6
  14. package/rules/test/js/docs/index.md +7 -7
  15. package/rules/test/js/docs/stryker_config.md +18 -35
  16. package/rules/test/js/docs/vitest-config-pool-forks.md +14 -12
  17. package/schemas/v8r-catalog.json +4 -4
  18. package/scripts/docs/index.md +16 -16
  19. package/scripts/docs/sync-setup-bun-deps-action.md +13 -14
  20. package/scripts/lib/check-mdc-template-refs.mjs +2 -2
  21. package/scripts/lib/docs/check-mdc-template-refs.md +12 -214
  22. package/scripts/lib/docs/index.md +36 -36
  23. package/scripts/lib/docs/mirror-parity.md +18 -157
  24. package/scripts/lib/docs/rule-meta.md +19 -22
  25. package/scripts/lib/docs/run-rule.md +11 -11
  26. package/scripts/lib/docs/skill-meta.md +17 -19
  27. package/scripts/lib/docs/timing-summary.md +6 -6
  28. package/scripts/lib/mirror-parity.mjs +1 -1
  29. package/scripts/lib/rule-meta.mjs +1 -1
  30. package/scripts/lib/run-rule.mjs +4 -4
  31. package/scripts/lib/skill-meta.mjs +1 -1
  32. package/scripts/utils/docs/index.md +14 -14
  33. package/scripts/utils/docs/resolve-js-root.md +12 -13
  34. /package/rules/abie/{meta.json → main.json} +0 -0
  35. /package/rules/abie/{abie.mdc → main.mdc} +0 -0
  36. /package/rules/adr/{meta.json → main.json} +0 -0
  37. /package/rules/adr/{adr.mdc → main.mdc} +0 -0
  38. /package/rules/bun/{meta.json → main.json} +0 -0
  39. /package/rules/bun/{bun.mdc → main.mdc} +0 -0
  40. /package/rules/capacitor/{meta.json → main.json} +0 -0
  41. /package/rules/capacitor/{capacitor.mdc → main.mdc} +0 -0
  42. /package/rules/changelog/{meta.json → main.json} +0 -0
  43. /package/rules/changelog/{changelog.mdc → main.mdc} +0 -0
  44. /package/rules/ci4/{meta.json → main.json} +0 -0
  45. /package/rules/ci4/{ci4.mdc → main.mdc} +0 -0
  46. /package/rules/doc-files/{meta.json → main.json} +0 -0
  47. /package/rules/doc-files/{doc-files.mdc → main.mdc} +0 -0
  48. /package/rules/docker/{meta.json → main.json} +0 -0
  49. /package/rules/docker/{docker.mdc → main.mdc} +0 -0
  50. /package/rules/efes/{meta.json → main.json} +0 -0
  51. /package/rules/efes/{efes.mdc → main.mdc} +0 -0
  52. /package/rules/feedback/{meta.json → main.json} +0 -0
  53. /package/rules/feedback/{feedback.mdc → main.mdc} +0 -0
  54. /package/rules/ga/{meta.json → main.json} +0 -0
  55. /package/rules/ga/{ga.mdc → main.mdc} +0 -0
  56. /package/rules/graphql/{meta.json → main.json} +0 -0
  57. /package/rules/graphql/{graphql.mdc → main.mdc} +0 -0
  58. /package/rules/hasura/{meta.json → main.json} +0 -0
  59. /package/rules/hasura/{hasura.mdc → main.mdc} +0 -0
  60. /package/rules/image-avif/{meta.json → main.json} +0 -0
  61. /package/rules/image-avif/{image-avif.mdc → main.mdc} +0 -0
  62. /package/rules/image-compress/{meta.json → main.json} +0 -0
  63. /package/rules/image-compress/{image-compress.mdc → main.mdc} +0 -0
  64. /package/rules/js/{meta.json → main.json} +0 -0
  65. /package/rules/js/{js.mdc → main.mdc} +0 -0
  66. /package/rules/js-bun-db/{meta.json → main.json} +0 -0
  67. /package/rules/js-bun-db/{js-bun-db.mdc → main.mdc} +0 -0
  68. /package/rules/js-bun-redis/{meta.json → main.json} +0 -0
  69. /package/rules/js-bun-redis/{js-bun-redis.mdc → main.mdc} +0 -0
  70. /package/rules/js-mssql/{meta.json → main.json} +0 -0
  71. /package/rules/js-mssql/{js-mssql.mdc → main.mdc} +0 -0
  72. /package/rules/js-run/{meta.json → main.json} +0 -0
  73. /package/rules/js-run/{js-run.mdc → main.mdc} +0 -0
  74. /package/rules/k8s/{meta.json → main.json} +0 -0
  75. /package/rules/k8s/{k8s.mdc → main.mdc} +0 -0
  76. /package/rules/nginx-default-tpl/{meta.json → main.json} +0 -0
  77. /package/rules/nginx-default-tpl/{nginx-default-tpl.mdc → main.mdc} +0 -0
  78. /package/rules/npm-module/{meta.json → main.json} +0 -0
  79. /package/rules/npm-module/{npm-module.mdc → main.mdc} +0 -0
  80. /package/rules/php/{meta.json → main.json} +0 -0
  81. /package/rules/php/{php.mdc → main.mdc} +0 -0
  82. /package/rules/python/{meta.json → main.json} +0 -0
  83. /package/rules/python/{python.mdc → main.mdc} +0 -0
  84. /package/rules/rego/{meta.json → main.json} +0 -0
  85. /package/rules/rego/{rego.mdc → main.mdc} +0 -0
  86. /package/rules/release/{meta.json → main.json} +0 -0
  87. /package/rules/release/{release.mdc → main.mdc} +0 -0
  88. /package/rules/rust/{meta.json → main.json} +0 -0
  89. /package/rules/rust/{rust.mdc → main.mdc} +0 -0
  90. /package/rules/security/{meta.json → main.json} +0 -0
  91. /package/rules/security/{security.mdc → main.mdc} +0 -0
  92. /package/rules/style/{meta.json → main.json} +0 -0
  93. /package/rules/style/{style.mdc → main.mdc} +0 -0
  94. /package/rules/tauri/{meta.json → main.json} +0 -0
  95. /package/rules/tauri/{tauri.mdc → main.mdc} +0 -0
  96. /package/rules/test/{meta.json → main.json} +0 -0
  97. /package/rules/test/{test.mdc → main.mdc} +0 -0
  98. /package/rules/text/{meta.json → main.json} +0 -0
  99. /package/rules/text/{text.mdc → main.mdc} +0 -0
  100. /package/rules/tool-surface/{meta.json → main.json} +0 -0
  101. /package/rules/tool-surface/{tool-surface.mdc → main.mdc} +0 -0
  102. /package/rules/vue/{meta.json → main.json} +0 -0
  103. /package/rules/vue/{vue.mdc → main.mdc} +0 -0
  104. /package/rules/worktree/{meta.json → main.json} +0 -0
  105. /package/rules/worktree/{worktree.mdc → main.mdc} +0 -0
  106. /package/skills/adr-normalize/{meta.json → main.json} +0 -0
  107. /package/skills/coverage-fix/{meta.json → main.json} +0 -0
  108. /package/skills/doc-aggregate/{meta.json → main.json} +0 -0
  109. /package/skills/doc-files/{meta.json → main.json} +0 -0
  110. /package/skills/lint/{meta.json → main.json} +0 -0
  111. /package/skills/llm-patch/{meta.json → main.json} +0 -0
  112. /package/skills/publish-telegram/{meta.json → main.json} +0 -0
  113. /package/skills/start-check/{meta.json → main.json} +0 -0
  114. /package/skills/taze/{meta.json → main.json} +0 -0
@@ -6,40 +6,40 @@ resource: npm/scripts/lib/
6
6
 
7
7
  # npm/scripts/lib
8
8
 
9
- | Файл | Тип |
10
- | --------------------------------------------------------------------------- | --------- |
11
- | [assert-project-root.mjs](assert-project-root.md) | JS Module |
12
- | [changed-files.mjs](changed-files.md) | JS Module |
13
- | [check-mdc-template-refs.mjs](check-mdc-template-refs.md) | JS Module |
14
- | [check-reporter.mjs](check-reporter.md) | JS Module |
15
- | [diff-added-lines.mjs](diff-added-lines.md) | JS Module |
9
+ | Файл | Тип |
10
+ |---|---|
11
+ | [assert-project-root.mjs](assert-project-root.md) | JS Module |
12
+ | [changed-files.mjs](changed-files.md) | JS Module |
13
+ | [check-mdc-template-refs.mjs](check-mdc-template-refs.md) | JS Module |
14
+ | [check-reporter.mjs](check-reporter.md) | JS Module |
15
+ | [diff-added-lines.mjs](diff-added-lines.md) | JS Module |
16
16
  | [discover-check-rules-from-cursor.mjs](discover-check-rules-from-cursor.md) | JS Module |
17
- | [discover-checkable-rules.mjs](discover-checkable-rules.md) | JS Module |
18
- | [ensure-tool.mjs](ensure-tool.md) | JS Module |
19
- | [generated-markdown.mjs](generated-markdown.md) | JS Module |
20
- | [gha-workflow.mjs](gha-workflow.md) | JS Module |
21
- | [inline-template-links.mjs](inline-template-links.md) | JS Module |
22
- | [list-project-rules-mdc.mjs](list-project-rules-mdc.md) | JS Module |
23
- | [list-rule-ids.mjs](list-rule-ids.md) | JS Module |
24
- | [load-cursor-config.mjs](load-cursor-config.md) | JS Module |
25
- | [mirror-parity.mjs](mirror-parity.md) | JS Module |
26
- | [read-n-cursor-config-lite.mjs](read-n-cursor-config-lite.md) | JS Module |
27
- | [resolve-target-files.mjs](resolve-target-files.md) | JS Module |
28
- | [root-notice.mjs](root-notice.md) | JS Module |
29
- | [rule-meta-helpers.mjs](rule-meta-helpers.md) | JS Module |
30
- | [rule-meta.mjs](rule-meta.md) | JS Module |
31
- | [rule-predicates.mjs](rule-predicates.md) | JS Module |
32
- | [run-conftest-batch.mjs](run-conftest-batch.md) | JS Module |
33
- | [run-lint-step.mjs](run-lint-step.md) | JS Module |
34
- | [run-lint.mjs](run-lint.md) | JS Module |
35
- | [run-rule-cli.mjs](run-rule-cli.md) | JS Module |
36
- | [run-rule.mjs](run-rule.md) | JS Module |
37
- | [run-standard-lint.mjs](run-standard-lint.md) | JS Module |
38
- | [run-standard-rule.mjs](run-standard-rule.md) | JS Module |
39
- | [skill-meta.mjs](skill-meta.md) | JS Module |
40
- | [sync-gitignore-worktree.mjs](sync-gitignore-worktree.md) | JS Module |
41
- | [template.mjs](template.md) | JS Module |
42
- | [timing-summary.mjs](timing-summary.md) | JS Module |
43
- | [workspaces.mjs](workspaces.md) | JS Module |
44
- | [worktree-notice.mjs](worktree-notice.md) | JS Module |
45
- | [worktree.mjs](worktree.md) | JS Module |
17
+ | [discover-checkable-rules.mjs](discover-checkable-rules.md) | JS Module |
18
+ | [ensure-tool.mjs](ensure-tool.md) | JS Module |
19
+ | [generated-markdown.mjs](generated-markdown.md) | JS Module |
20
+ | [gha-workflow.mjs](gha-workflow.md) | JS Module |
21
+ | [inline-template-links.mjs](inline-template-links.md) | JS Module |
22
+ | [list-project-rules-mdc.mjs](list-project-rules-mdc.md) | JS Module |
23
+ | [list-rule-ids.mjs](list-rule-ids.md) | JS Module |
24
+ | [load-cursor-config.mjs](load-cursor-config.md) | JS Module |
25
+ | [mirror-parity.mjs](mirror-parity.md) | JS Module |
26
+ | [read-n-cursor-config-lite.mjs](read-n-cursor-config-lite.md) | JS Module |
27
+ | [resolve-target-files.mjs](resolve-target-files.md) | JS Module |
28
+ | [root-notice.mjs](root-notice.md) | JS Module |
29
+ | [rule-meta-helpers.mjs](rule-meta-helpers.md) | JS Module |
30
+ | [rule-meta.mjs](rule-meta.md) | JS Module |
31
+ | [rule-predicates.mjs](rule-predicates.md) | JS Module |
32
+ | [run-conftest-batch.mjs](run-conftest-batch.md) | JS Module |
33
+ | [run-lint-step.mjs](run-lint-step.md) | JS Module |
34
+ | [run-lint.mjs](run-lint.md) | JS Module |
35
+ | [run-rule-cli.mjs](run-rule-cli.md) | JS Module |
36
+ | [run-rule.mjs](run-rule.md) | JS Module |
37
+ | [run-standard-lint.mjs](run-standard-lint.md) | JS Module |
38
+ | [run-standard-rule.mjs](run-standard-rule.md) | JS Module |
39
+ | [skill-meta.mjs](skill-meta.md) | JS Module |
40
+ | [sync-gitignore-worktree.mjs](sync-gitignore-worktree.md) | JS Module |
41
+ | [template.mjs](template.md) | JS Module |
42
+ | [timing-summary.mjs](timing-summary.md) | JS Module |
43
+ | [workspaces.mjs](workspaces.md) | JS Module |
44
+ | [worktree-notice.mjs](worktree-notice.md) | JS Module |
45
+ | [worktree.mjs](worktree.md) | JS Module |
@@ -3,171 +3,32 @@ type: JS Module
3
3
  title: mirror-parity.mjs
4
4
  resource: npm/scripts/lib/mirror-parity.mjs
5
5
  docgen:
6
- crc: 15dc336a
6
+ crc: d2140a00
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Модуль `mirror-parity.mjs` забезпечує перевірку парності (parity) між «дзеркальними» файлами правил Cursor у `.cursor/rules/n-<id>.mdc` та їх канонічними джерелами у `npm/rules/<id>/<id>.mdc`. Ідея така: репозиторій містить два представлення одного й того ж правила:
11
+ ## Огляд
10
12
 
11
- - канонічне джерело правила лежить у `npm/rules/<id>/<id>.mdc` (з можливими посиланнями на шаблони у тій самій теці);
12
- - дзеркало лежить у `.cursor/rules/n-<id>.mdc` і повинно бути результатом застосування трансформу `inlineTemplateLinks` до канону (тобто посилання на шаблони мають бути вставлені «інлайном»).
13
+ Модуль забезпечує паралельність (parity) дзеркал правил. Він порівнює вміст дзеркала `.cursor/rules/n-<id>.mdc` з канонічним вмістом `npm/rules/<id>/<id>.mdc`, який містить вбудовані шаблони (inlined-шаблони). Це гарантує, що локальні копії правил відповідають централізованим, трансформованим версіям, виявляючи дрейф, що виникає при зміні канонічного `.mdc` без регенерації дзеркала.
13
14
 
14
- Коли канонічний `.mdc` змінюють і забувають регенерувати дзеркало, виникає «дрейф» (drift). Цей модуль:
15
+ ## Поведінка
15
16
 
16
- - перелічує керовані дзеркала (ті, для яких знайдено канон);
17
- - обчислює очікуваний вміст дзеркала через ту саму трансформацію, що і синхронізатор;
18
- - виявляє ідентифікатори дрейфних правил (де `actual ≠ expected`).
17
+ listManagedMirrors
18
+ Визначає список керованих дзеркал правил, які мають канонічне джерело у `npm/rules`.
19
19
 
20
- Модуль використовується одночасно і як гард у тестах (очікувано `drift === []`), і для разової регенерації дзеркал. Контекст беклогу — адаптація flow #10.
20
+ expectedMirrorContent
21
+ Формує очікуваний вміст дзеркала, застосовуючи трансформацію до канонічного вмісту.
21
22
 
22
- ## Експорти / API
23
+ findMirrorDrift
24
+ Виявляє і повертає список ідентифікаторів дзеркал, вміст яких відрізняється від очікуваного канонічного.
23
25
 
24
- Модуль експортує три іменовані функції:
26
+ ## Публічний API
25
27
 
26
- - `listManagedMirrors(repoRoot)`синхронна; повертає опис керованих дзеркал.
27
- - `expectedMirrorContent(canonicalPath)`асинхронна (повертає `Promise<string>`); обчислює очікуваний вміст дзеркала.
28
- - `findMirrorDrift(repoRoot)`асинхронна; повертає масив id правил із дрейфом, відсортований за зростанням.
28
+ listManagedMirrors — перераховує дзеркала, які мають визначене основне джерело, і ігнорує зовнішні.
29
+ expectedMirrorContent — визначає, яким має бути вміст дзеркала, використовуючи основне джерело з вбудованими шаблонами.
30
+ findMirrorDrift — виявляє ідентифікатори дзеркал, чий фактичний вміст відрізняється від очікуваного.
29
31
 
30
- Жодних дефолтних експортів, побічних ефектів на рівні модуля немає (лише імпорти стандартних модулів і одного локального).
32
+ ## Гарантії поведінки
31
33
 
32
- ## Функції
33
-
34
- ### `listManagedMirrors(repoRoot)`
35
-
36
- Сигнатура: `function listManagedMirrors(repoRoot: string): { id: string, mirrorPath: string, canonicalPath: string }[]`
37
-
38
- Параметри:
39
-
40
- - `repoRoot` — абсолютний шлях до кореня репозиторію (директорія, у якій лежать `.cursor/` та `npm/`).
41
-
42
- Повертає масив об'єктів-описів дзеркал, де:
43
-
44
- - `id` — ідентифікатор правила без префіксу `n-` і без розширення `.mdc` (наприклад, для файлу `n-bun.mdc` → `bun`);
45
- - `mirrorPath` — абсолютний шлях до файлу дзеркала всередині `.cursor/rules/`;
46
- - `canonicalPath` — абсолютний шлях до канонічного `.mdc` всередині `npm/rules/<id>/`.
47
-
48
- Алгоритм:
49
-
50
- 1. Будує шлях до `.cursor/rules`.
51
- 2. Якщо такої директорії не існує (`existsSync` false) — повертає порожній масив (раннє повернення, безпечне для свіжих репо).
52
- 3. Зчитує перелік файлів директорії синхронно (`readdirSync`).
53
- 4. Фільтрує файли: повинні починатися з префіксу `'n-'` (константа `MIRROR_PREFIX`) і завершуватися розширенням `'.mdc'` (константа `MDC_EXT`).
54
- 5. Мапить кожен файл у об'єкт із обчисленими шляхами: `id` отримується вирізанням префіксу і розширення (`f.slice(MIRROR_PREFIX.length, -MDC_EXT.length)`).
55
- 6. Залишає лише ті записи, для яких реально існує канонічне джерело `canonicalPath` (друга фільтрація через `existsSync`). Це дозволяє пропускати «зовнішні» дзеркала, які не мають канону в монорепо.
56
-
57
- Side effects: лише читання директорії з диску (синхронні `existsSync`, `readdirSync`). Жодних записів, мережевих викликів, мутацій глобального стану.
58
-
59
- Помилки: якщо файлова система кине помилку під час `readdirSync` (наприклад, права доступу) — вона прокинеться вгору; для типового сценарію відсутності директорії `.cursor/rules` функція не падає (гард через `existsSync`).
60
-
61
- ### `expectedMirrorContent(canonicalPath)`
62
-
63
- Сигнатура: `function expectedMirrorContent(canonicalPath: string): Promise<string>`
64
-
65
- Параметри:
66
-
67
- - `canonicalPath` — абсолютний шлях до канонічного `.mdc`-файлу (`npm/rules/<id>/<id>.mdc`).
68
-
69
- Повертає `Promise<string>` — очікуваний (нормалізований) текст дзеркала після інлайнінгу шаблонів. Хоча сама функція не використовує `async`/`await`, її результат типізовано як `Promise`, оскільки делегує виклик до `inlineTemplateLinks`, яка є асинхронною (її результат може бути thenable). Це означає, що споживач має `await`-нути повернене значення.
70
-
71
- Алгоритм:
72
-
73
- 1. Синхронно зчитує вміст канонічного файлу як UTF-8 (`readFileSync(canonicalPath, 'utf8')`).
74
- 2. Викликає `inlineTemplateLinks(content, dirname(canonicalPath))`, передаючи прочитаний текст та теку канону як base для розв'язання шляхів до шаблонів.
75
- 3. Повертає результат трансформації.
76
-
77
- Side effects: одне читання з диску. Подальша поведінка щодо шаблонів інкапсульована в `inlineTemplateLinks` (див. її документацію). Контракт: цей же самий трансформ застосовує синк, тому очікуваний вміст детермінований по канону.
78
-
79
- Помилки: якщо файл за `canonicalPath` не існує або недоступний — `readFileSync` кине помилку. Викличні сторони мають гарантувати існування (`listManagedMirrors` уже фільтрує неіснуючі канони).
80
-
81
- ### `findMirrorDrift(repoRoot)`
82
-
83
- Сигнатура: `async function findMirrorDrift(repoRoot: string): Promise<string[]>`
84
-
85
- Параметри:
86
-
87
- - `repoRoot` — абсолютний шлях до кореня репозиторію.
88
-
89
- Повертає `Promise<string[]>` — відсортований за зростанням масив `id` правил, де дзеркало розійшлося з очікуваним вмістом.
90
-
91
- Алгоритм:
92
-
93
- 1. Заводить порожній масив `drift`.
94
- 2. Послідовно (через `for...of`) обходить усі керовані дзеркала, отримані з `listManagedMirrors(repoRoot)`.
95
- 3. Для кожного дзеркала `m`:
96
- - `await`-ить очікуваний вміст через `expectedMirrorContent(m.canonicalPath)`;
97
- - синхронно зчитує фактичний вміст файлу дзеркала `readFileSync(m.mirrorPath, 'utf8')`;
98
- - якщо стрічки не дорівнюють — додає `m.id` до `drift`.
99
- 4. Повертає `drift.sort()` (лексикографічне сортування).
100
-
101
- Side effects: тільки читання з диску. Не записує жодних файлів, не пише в лог.
102
-
103
- Зауваження щодо порівняння: рівність стрічок є точною (строге `!==` по UTF-8 тексту). Будь-яка різниця в пробілах, символах кінця рядка чи порядку інлайнених шаблонів буде розцінена як дрейф.
104
-
105
- ## Залежності
106
-
107
- Стандартна бібліотека Node.js:
108
-
109
- - `node:fs` — `existsSync`, `readdirSync`, `readFileSync`. Усі виклики синхронні. Імпорт зроблено через `node:`-префікс для явної прив'язки до built-in модуля.
110
- - `node:path` — `dirname`, `join`. Використовуються для безпечного складання абсолютних шляхів і отримання батьківської теки канону.
111
-
112
- Локальні модулі:
113
-
114
- - `./inline-template-links.mjs` — імпорт іменованої функції `inlineTemplateLinks(content, baseDir)`. Це той самий трансформ, що його використовує синк дзеркал; саме завдяки спільному використанню досягається консистентність між «гардом дрейфу» і «генератором дзеркал».
115
-
116
- Зовнішніх npm-залежностей немає.
117
-
118
- Константи на рівні модуля:
119
-
120
- - `MIRROR_PREFIX = 'n-'` — префікс імені файлів дзеркал.
121
- - `MDC_EXT = '.mdc'` — розширення файлів правил Cursor.
122
-
123
- ## Потік виконання / Використання
124
-
125
- Типові сценарії використання модуля:
126
-
127
- 1. Тест-гард парності (CI). Споживач передає корінь репо й перевіряє, що дрейф порожній:
128
-
129
- ```js
130
- import { findMirrorDrift } from './mirror-parity.mjs'
131
-
132
- const drift = await findMirrorDrift(repoRoot)
133
- if (drift.length) {
134
- throw new Error(`Mirror drift detected for: ${drift.join(', ')}`)
135
- }
136
- ```
137
-
138
- 2. Разова регенерація дзеркал. Споживач отримує список керованих дзеркал і для кожного перезаписує файл дзеркала очікуваним вмістом:
139
-
140
- ```js
141
- import { writeFileSync } from 'node:fs'
142
- import { listManagedMirrors, expectedMirrorContent } from './mirror-parity.mjs'
143
-
144
- for (const m of listManagedMirrors(repoRoot)) {
145
- const expected = await expectedMirrorContent(m.canonicalPath)
146
- writeFileSync(m.mirrorPath, expected)
147
- }
148
- ```
149
-
150
- (Сам модуль `mirror-parity.mjs` записів не виконує — це задача викличного скрипта.)
151
-
152
- Внутрішній потік виконання `findMirrorDrift`:
153
-
154
- 1. Виклик `listManagedMirrors(repoRoot)`:
155
- - перевірка існування `.cursor/rules`;
156
- - читання списку файлів;
157
- - фільтрація за префіксом `n-` і розширенням `.mdc`;
158
- - обчислення `id`, `mirrorPath`, `canonicalPath`;
159
- - відкидання дзеркал без канону.
160
- 2. Послідовний обхід отриманих описів:
161
- - читання канону → `inlineTemplateLinks` → очікуваний текст;
162
- - читання дзеркала → порівняння;
163
- - накопичення id з дрейфом.
164
- 3. Сортування результату та повернення.
165
-
166
- Контрактна гарантія: якщо синк використовує ту ж саму функцію `inlineTemplateLinks` для генерації дзеркал, то регенерація закриває будь-який дрейф, виявлений `findMirrorDrift`. Якщо дрейф виявлено — він завжди вказує на людську помилку (зміна канону без регенерації) або на розбіжність версій трансформу.
167
-
168
- Обмеження:
169
-
170
- - Обхід послідовний (без `Promise.all`) — простіший контракт по помилках, але повільніший на великих наборах правил. Зважаючи на типову кількість правил у `.cursor/rules`, це не критично.
171
- - Усі читання файлів синхронні, попри асинхронну сигнатуру `findMirrorDrift` — асинхронність зумовлена тільки інтерфейсом `inlineTemplateLinks`.
172
- - Префікс `n-` зашитий константою — додавання інших префіксів дзеркал вимагатиме зміни модуля.
173
- - Зовнішні дзеркала (без канону в `npm/rules/<id>/`) автоматично пропускаються; модуль не повідомляє про них окремо.
34
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -3,36 +3,33 @@ type: JS Module
3
3
  title: rule-meta.mjs
4
4
  resource: npm/scripts/lib/rule-meta.mjs
5
5
  docgen:
6
- crc: fa5ca866
6
+ crc: 36aea8cb
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Цей файл парсує метадані правил npm/rules/<id>/meta.json для автоматичного виявлення проблемних місць у коді. Він визначає, коли правило має бути активним, використовуючи різні специфікації, такі як завжди-ввімкнене правило, правило, яке активується після виявлення залежностей, або правило, яке активується на основі glob-шаблонів чи незводимих предикатів. Це дозволяє системі динамічно визначати та застосовувати правила, не потребуючи явного налаштування.
11
+ ## Огляд
12
+
13
+ Парсер інтерпретує метадані правил, що знаходяться у `npm/rules/<id>/meta.json`. Він реалізує data-driven логіку для визначення умов активації кожного детектора. Специфікації активації (`auto`) нормалізуються на основі вмісту `meta.json`, підтримуючи чотири типи: константа `RULE_ALWAYS` ("завжди"), залежності від інших правил, шаблони за допомогою `glob`, або незводимі предикати. Парсер не виконує операцій запису у файлову систему чи бази даних і забезпечує безпечну роботу, перехоплюючи помилки.
10
14
 
11
15
  ## Поведінка
12
16
 
13
- `RULE_ALWAYS`: визначає літерал для активації правила "завжди".
14
- `parseRuleAutoSpec`: нормалізує значення `meta.json.auto` у дискриміновану форму.
15
- `parseRuleLintPhase`: нормалізує значення `meta.json.lint` у фазу lint.
16
- `readRuleMetaRaw`: читає та парсить `meta.json` одного правила, повертаючи об’єкт або `null`.
17
+ RULE_ALWAYS константа, що позначає безумовну активацію правила.
18
+ parseRuleAutoSpec Нормалізує значення поля `auto` з метаданих правила у дискриміновану специфікацію активації.
19
+ parseRuleLintSpec Нормалізує значення поля `lint` з метаданих правила у специфікацію області застосування детектора.
20
+ readRuleMetaRaw Читає та парсить вміст `main.json` з каталогу правила, повертаючи його як об'єкт або `null` у разі помилки чи відсутності файлу.
17
21
 
18
22
  ## Публічний API
19
23
 
20
- - RULE_ALWAYS — Активує правило.
21
- - parseRuleAutoSpec — Перетворює значення `meta.json.auto` на конкретну опцію.
22
- - parseRuleLintPhase Перетворює значення `meta.json.lint` на фазу lint.
23
- - readRuleMetaRaw Зчитує та аналізує файл `meta.json` правила.
24
+ RULE_ALWAYS — константа, що вказує на безумовну активацію.
25
+ parseRuleAutoSpec — перетворює налаштування автоматичного визначення правил з `meta.json` у структурований формат.
26
+ parseRuleLintSpecперетворює налаштування лінтування з `meta.json` у визначення області дії детектора.
27
+ "per-file"визначає, що детектор працює з окремими зміненими файлами (порівняння змін з оригіналом).
28
+ "full" — вказує на повний, нероздільний аналіз між усіма файлами (активується лише при використанні прапорця `--full` або в CI).
29
+ readRuleMetaRaw — зчитує та обробляє метадані одного правила з файлу `meta.json`.
24
30
 
25
31
  ## Гарантії поведінки
26
32
 
27
- - `RULE_ALWAYS` повертає `true` якщо правило активне.
28
- - `parseRuleAutoSpec` повертає `true` якщо специфікація правила успішно розібрана.
29
- - `parseRuleAutoSpec` повертає `false` якщо специфікація правила не може бути розібрана.
30
- - `parseRuleLintPhase` повертає `true` якщо правило успішно розібрано на етапі linting.
31
- - `parseRuleLintPhase` повертає `false` якщо правило не може бути розібрано на етапі linting.
32
- - `readRuleMetaRaw` повертає `true` якщо метадані правила успішно прочитані.
33
- - `readRuleMetaRaw` повертає `false` якщо метадані правила не можуть бути прочитані.
34
- - У разі невдачі, функція повертає `false` або `null`.
35
- - Функції не кидають винятків.
36
- - Немає кешування.
37
- - Немає гарантій щодо стану файлів або каталогів.
38
- - Поля `worktree` правила не використовуються.
33
+ - Read-only: не виконує операцій запису (ФС/БД).
34
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
35
+ - За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
@@ -3,27 +3,27 @@ type: JS Module
3
3
  title: run-rule.mjs
4
4
  resource: npm/scripts/lib/run-rule.mjs
5
5
  docgen:
6
- crc: 27060842
7
- score: 95
6
+ crc: 7d0585e1
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 90
8
9
  ---
9
10
 
10
- Файл слугує оркестратором правила. Він координує виконання перевірок, включаючи перевірку гейту, JS-концернів та policy-концернів.
11
+ ## Огляд
12
+
13
+ Файл оркеструє виконання одного правила під CLI `fix`. Він послідовно застосовує гейт `applies` з `js/applies.mjs` для визначення придатності правила. Якщо гейт повертає `false`, правило не застосовується. Далі виконуються JS-концерни та Policy-концерни в алфавітному порядку. Резолвер `resolveTargetFiles` ділить кеш між концернами. Кожен concern створює власний репортер, а їхні exit-коди OR-уються в єдиний контракт, що забезпечує 0/1 результат для правила. Оркестратор спирається на конфігурації `target.json` та `.n-cursor.json`.
11
14
 
12
15
  ## Поведінка
13
16
 
14
- runTemplateSubsetConcern
15
- Перевіряє відповідність фактичного файлу канонічному шаблону.
17
+ runTemplateSubsetConcern виконує перевірку концерну, де канон визначається сніпетом у `target.json`, звіряючи його з актуальними файлами-таргетами.
16
18
 
17
- runRule
18
- Оркеструє виконання правила, включаючи перевірку гейту, JS-концернів та policy-концернів.
19
+ runRule оркеструє виконання одного правила, послідовно застосовуючи applies-гейт, виконуючи JS-концерни та запускаючи policy-концерни, а також перевіряючи відсутність markdown-посилань.
19
20
 
20
21
  ## Публічний API
21
22
 
22
- - runTemplateSubsetConcern — Snippet-driven перевірка концерну (`target.json:"check":"template"`): звіряє канон з фактичним файлом за допомогою глибокого підмножинного перевірки. Усі канонічні поля/елементи обов'язкові, зайві дозволені. Масиви співпадають за наявністю (незалежно від порядку). Зміна сніпета негайно впливає на примусовість.
23
- - runRule — Запускає одне правило: applies-гейт JS-концерни policy-концерни.
23
+ runTemplateSubsetConcern — Порівнює фактичний файл із канонічним шаблоном (з `target.json`) для перевірки, чи всі обов'язкові елементи присутні, дозволяючи додаткові.
24
+ runRule — Виконує окреме правило, яке проходить через перевірки застосовності, JavaScript-концерни та політики.
24
25
 
25
26
  ## Гарантії поведінки
26
27
 
27
- - Read-only: файл не виконує операцій запису у файлову систему.
28
+ - Read-only: не виконує операцій запису (ФС/БД).
28
29
  - Кешує результати в межах одного прогону.
29
- - Не звертається до мережі.
@@ -3,33 +3,31 @@ type: JS Module
3
3
  title: skill-meta.mjs
4
4
  resource: npm/scripts/lib/skill-meta.mjs
5
5
  docgen:
6
- crc: 0c638d18
6
+ crc: c0918db5
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Цей файл парсить метадані скілу з файлу `meta.json` та надає інформацію про його конфігурацію. Він служить єдиним джерелом правди про скіл, замінюючи старий `auto.md`, і використовується для визначення, чи потрібно запускати скіл в окремому worktree, чи з кореня репозиторію. Це забезпечує узгодженість даних про скіли та полегшує їх використання в інших частинах системи.
11
+ ## Огляд
12
+
13
+ Спільний парсер метаданих скіла, що зчитує дані з `npm/skills/<id>/meta.json`. Він є єдиним джерелом правди для конфігурації скілів, визначаючи умови автоактивації (через поле `auto`, де `SKILL_ALWAYS` означає "завжди"), чи виконувати скіл в окремому git-worktree (`worktree`), та чи вимагає скіл запуску з кореня репозиторію (`requireRoot`). Модуль надає механізми для парсингу цих метаданих, перевірки вимог до кореня та читання сирих даних. Він працює в режимі fail-safe, перехоплюючи помилки та повертаючи порожнє значення замість винятків.
10
14
 
11
15
  ## Поведінка
12
16
 
13
- SKILL_ALWAYS: визначає літерал для безумовної автоактивації.
14
- parseSkillAutoSpec: перетворює значення `auto` з `meta.json` у об’єкт `SkillAutoSpec`.
15
- skillRequiresRoot: визначає, чи вимагає скіл запуску з кореня репо.
16
- readSkillMetaRaw: читає та парсить `meta.json` одного скіла, повертаючи розпарсений об’єкт або `null`.
17
+ SKILL_ALWAYS надає літерал для безумовної автоактивації скіла.
18
+ parseSkillAutoSpec перетворює значення поля `auto` з метаданих скіла у специфікацію автоактивації.
19
+ skillRequiresRoot визначає, чи вимагає скіл запуску з кореня репозиторію, виходячи з метаданих.
20
+ readSkillMetaRaw читає та парсить файл `main.json` у каталозі скіла, повертаючи його вміст або `null` у разі помилки.
17
21
 
18
22
  ## Публічний API
19
23
 
20
- - SKILL_ALWAYS — Активує скіл завжди.
21
- - parseSkillAutoSpec — Перетворює специфікацію авто-скілу з JSON.
22
- - skillRequiresRoot — Перевіряє, чи потрібен скілу доступ до кореневої директорії.
23
- - readSkillMetaRaw — Зчитує та аналізує метадані скілу з файлу JSON.
24
+ SKILL_ALWAYS — маркер, що вказує на безумовну активацію
25
+ parseSkillAutoSpec — витягує налаштування автоматичного запуску з `meta.json`
26
+ skillRequiresRoot — визначає, чи потрібен запуск скіла з кореня репозиторію
27
+ readSkillMetaRaw — зчитує та обробляє метадані окремого скіла з `meta.json`
24
28
 
25
29
  ## Гарантії поведінки
26
30
 
27
- - Повертає `false` якщо не вдається розібрати `meta.json`.
28
- - Повертає `null` якщо не вдається визначити `auto.spec`.
29
- - `auto.spec` завжди є масивом id правил, якщо `auto.spec` визначено.
30
- - `worktree` має значення `true` лише для скілів, які потребують окремого git-worktree.
31
- - `requireRoot` має значення `true` лише для скілів, які мутують в CWD без worktree-ізоляції.
32
- - Якщо `worktree` має значення `true`, поле `requireRoot` не використовується.
33
- - Не використовує кеш.
34
- - Не кидає винятків.
35
- - Гарантує, що `meta.json` є єдиним джерелом правди для скілу.
31
+ - Read-only: не виконує операцій запису (ФС/БД).
32
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
33
+ - За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
@@ -3,24 +3,24 @@ type: JS Module
3
3
  title: timing-summary.mjs
4
4
  resource: npm/scripts/lib/timing-summary.mjs
5
5
  docgen:
6
- crc: ee74c1cd
6
+ crc: 47660e16
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 100
9
9
  ---
10
10
 
11
11
  ## Огляд
12
12
 
13
- Формує таблицю-резюме часу виконання для оркестратора `fix` або `lint`. Таблиця використовується після прогону всіх правил перевірки (`runFixCommand` у `bin/n-cursor.js`) або після прогону скриптів лінтингу (`runLintCli` у `scripts/lib/run-lint-cli.mjs`), які визначаються у `package.json`. Звіт містить деталі часу виконання для кожного елемента у форматі `<ціла>.<десята>s`, а маркер `❌` на рядку вказує на невдачу (`ok === false`).
13
+ Формує рядок, що відображає тривалість у форматі `<ціла>.<десята>s`, забезпечуючи стабільну одиницю вимірювання для всіх інтервалів. Генерує звіт про час виконання для orchestrator `fix` / `lint`, який включає деталі кожного вимірювання та загальний час. Звіт містить маркер `❌` на рядку, якщо відповідний вимірник не пройшов успішно. Дані для звітів отримуються з `package.json` та використовуються у точках виклику `runFixCommand` у `bin/n-cursor.js` та `runLintCli` у `scripts/lib/run-lint-cli.mjs`. Функція є чистою, не виконує I/O, і повертає готовий рядок з фінальним `\n`, друк якого здійснюється на стороні виклику.
14
14
 
15
15
  ## Поведінка
16
16
 
17
- formatDurationMs перетворює тривалість у мілісекундах у рядок формату `<ціла>.<десята>s`.
18
- formatTimingSummary генерує багаторядковий текст таблиці-резюме часу виконання на основі наданого заголовка та списку записів про час.
17
+ formatDurationMs форматує тривалість у мілісекундах як рядок у форматі `<ціла>.<десята>s`.
18
+ formatTimingSummary генерує багаторядковий текстовий звіт про час виконання, включаючи деталі кожного запису та загальний час.
19
19
 
20
20
  ## Публічний API
21
21
 
22
- ⏱ formatDurationMs: Перетворює мілісекунди на формат `<sec>.<десята>s`, використовуючи округлення вниз.
23
- ⏱ formatTimingSummary: Генерує багаторядковий вивід у форматі таблиці-резюме для стандартного виводу.
22
+ ⏱ formatDurationMs: Перетворює мілісекунди у формат `<sec>.<десята>s`, використовуючи округлення вниз.
23
+ ⏱ formatTimingSummary: Генерує багаторядковий вивід таблиці-резюме часу виконання.
24
24
 
25
25
  ## Гарантії поведінки
26
26
 
@@ -30,7 +30,7 @@ export function listManagedMirrors(repoRoot) {
30
30
  return {
31
31
  id,
32
32
  mirrorPath: join(rulesDir, f),
33
- canonicalPath: join(repoRoot, 'npm/rules', id, `${id}${MDC_EXT}`)
33
+ canonicalPath: join(repoRoot, 'npm/rules', id, `main${MDC_EXT}`)
34
34
  }
35
35
  })
36
36
  .filter(m => existsSync(m.canonicalPath))
@@ -70,7 +70,7 @@ export function parseRuleLintSpec(value) {
70
70
  * @returns {Record<string, unknown> | null} обʼєкт або `null` (немає файлу / невалідний JSON / не-обʼєкт)
71
71
  */
72
72
  export function readRuleMetaRaw(ruleDir) {
73
- const metaPath = join(ruleDir, 'meta.json')
73
+ const metaPath = join(ruleDir, 'main.json')
74
74
  if (!existsSync(metaPath)) return null
75
75
  try {
76
76
  const parsed = JSON.parse(readFileSync(metaPath, 'utf8'))
@@ -81,7 +81,7 @@ export async function runTemplateSubsetConcern(concernAbsDir, target, files, rul
81
81
  for (const file of files) {
82
82
  const rel = relative(process.cwd(), file) || file
83
83
  const actual = await parseByExt(file)
84
- const opts = { targetPath: rel, source: `${ruleId}.mdc` }
84
+ const opts = { targetPath: rel, source: 'main.mdc' }
85
85
  const violations = [
86
86
  ...(typeof data.snippet === 'string'
87
87
  ? checkTextSubset(actual, data.snippet, opts)
@@ -118,7 +118,7 @@ async function runPolicyConcern(bundledRulesDir, ruleId, concernName, walkCache)
118
118
  if (target.files.required && target.files.single) {
119
119
  const msg =
120
120
  target.missingMessage ??
121
- `${target.files.single} не існує — створи згідно ${ruleId}.mdc (${ruleId}.${concernName})`
121
+ `${target.files.single} не існує — створи згідно main.mdc (${ruleId}.${concernName})`
122
122
  reporter.fail(msg)
123
123
  }
124
124
  return reporter.getExitCode()
@@ -182,11 +182,11 @@ export async function runRule(rule, bundledRulesDir, walkCache) {
182
182
  }
183
183
 
184
184
  const ruleDir = join(bundledRulesDir, rule.id)
185
- const missing = await findMissingMdcRefs(ruleDir, rule.id)
185
+ const missing = await findMissingMdcRefs(ruleDir)
186
186
  if (missing.length > 0) {
187
187
  const reporter = createCheckReporter()
188
188
  for (const rel of missing) {
189
- reporter.fail(`${rule.id}.mdc: відсутнє markdown-посилання на template-файл ${rel}`)
189
+ reporter.fail(`main.mdc: відсутнє markdown-посилання на template-файл ${rel}`)
190
190
  }
191
191
  if (reporter.getExitCode() !== 0) totalCode = 1
192
192
  }
@@ -56,7 +56,7 @@ export function skillRequiresRoot(meta) {
56
56
  * @returns {Record<string, unknown> | null} розпарсений обʼєкт або `null` (немає файлу / невалідний JSON / не-обʼєкт)
57
57
  */
58
58
  export function readSkillMetaRaw(skillDir) {
59
- const metaPath = join(skillDir, 'meta.json')
59
+ const metaPath = join(skillDir, 'main.json')
60
60
  if (!existsSync(metaPath)) return null
61
61
  try {
62
62
  const parsed = JSON.parse(readFileSync(metaPath, 'utf8'))
@@ -6,18 +6,18 @@ resource: npm/scripts/utils/
6
6
 
7
7
  # npm/scripts/utils
8
8
 
9
- | Файл | Тип |
10
- | ----------------------------------------------------------- | --------- |
11
- | [ast-scan-utils.mjs](ast-scan-utils.md) | JS Module |
9
+ | Файл | Тип |
10
+ |---|---|
11
+ | [ast-scan-utils.mjs](ast-scan-utils.md) | JS Module |
12
12
  | [ensure-gitignore-entries.mjs](ensure-gitignore-entries.md) | JS Module |
13
- | [find-package-json-paths.mjs](find-package-json-paths.md) | JS Module |
14
- | [lock-cache-dir.mjs](lock-cache-dir.md) | JS Module |
15
- | [pass.mjs](pass.md) | JS Module |
16
- | [resolve-cargo-manifest.mjs](resolve-cargo-manifest.md) | JS Module |
17
- | [resolve-cmd.mjs](resolve-cmd.md) | JS Module |
18
- | [resolve-js-root.mjs](resolve-js-root.md) | JS Module |
19
- | [test-helpers.mjs](test-helpers.md) | JS Module |
20
- | [walk-cache.mjs](walk-cache.md) | JS Module |
21
- | [walkDir.mjs](walkDir.md) | JS Module |
22
- | [with-lock.mjs](with-lock.md) | JS Module |
23
- | [worktree-fingerprint.mjs](worktree-fingerprint.md) | JS Module |
13
+ | [find-package-json-paths.mjs](find-package-json-paths.md) | JS Module |
14
+ | [lock-cache-dir.mjs](lock-cache-dir.md) | JS Module |
15
+ | [pass.mjs](pass.md) | JS Module |
16
+ | [resolve-cargo-manifest.mjs](resolve-cargo-manifest.md) | JS Module |
17
+ | [resolve-cmd.mjs](resolve-cmd.md) | JS Module |
18
+ | [resolve-js-root.mjs](resolve-js-root.md) | JS Module |
19
+ | [test-helpers.mjs](test-helpers.md) | JS Module |
20
+ | [walk-cache.mjs](walk-cache.md) | JS Module |
21
+ | [walkDir.mjs](walkDir.md) | JS Module |
22
+ | [with-lock.mjs](with-lock.md) | JS Module |
23
+ | [worktree-fingerprint.mjs](worktree-fingerprint.md) | JS Module |
@@ -3,27 +3,26 @@ type: JS Module
3
3
  title: resolve-js-root.mjs
4
4
  resource: npm/scripts/utils/resolve-js-root.mjs
5
5
  docgen:
6
- crc: 2c2b9f11
6
+ crc: 99e5a8a4
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Цей файл визначає кореневий JavaScript-файл проєкту, необхідний для запуску інструментів аналізу коду. Він використовується як у великих проєктах з декількома workspace-ами, так і в окремих пакетах, забезпечуючи єдине місце для визначення кореневого розташування. Це спрощує інтеграцію з інструментами coverage та тестування.
11
+ ## Огляд
12
+
13
+ Визначає корінь JS-коду для проєктів, використовуючи `package.json` та `.n-cursor.json` як конфігураційні файли. Функція `resolveJsRoot` знаходить перший workspace (з підтримкою glob-патернів типу `cf/*`) для workspace-проєктів або корінь поточної директорії для single-package. Функція `resolveAllJsRoots` знаходить усі відповідні шляхи. Код свідомо ігнорує шляхи `.git` та `node_modules`. Ця утиліта є спільною для coverage-провайдера JS та test-концерну stryker_config (DRY).
10
14
 
11
15
  ## Поведінка
12
16
 
13
- resolveJsRoot: повертає абсолютний шлях до першого JS-кореня проєкту.
14
- resolveAllJsRoots: повертає масив абсолютних шляхів до всіх JS-коренів проєкту, враховуючи glob-патерни з `workspaces` у кореневому `package.json`. Якщо JS-коренів немає, повертає абсолютний шлях до кореневого каталогу.
17
+ resolveJsRoot повертає абсолютний шлях до першого JS-кореня проєкту, якщо він існує, або null, якщо кореневий package.json відсутній.
18
+ resolveAllJsRoots повертає масив абсолютних шляхів до всіх JS-коренів проєкту, враховуючи визначення `workspaces` у кореневому package.json, ігноруючи каталоги `.git` та `node_modules`.
15
19
 
16
20
  ## Публічний API
17
21
 
18
- - resolveJsRoot — Знаходить кореневий JS-файл проєкту.
19
- - resolveAllJsRoots — Знаходить всі кореневі JS-файли проєкту. Включає всі workspace-файли та їхні `package.json`, використовуючи glob-патерни. Для single-package повертає поточну директорію.
22
+ resolveJsRoot — знаходить кореневий каталог JavaScript-проєкту.
23
+ resolveAllJsRoots — повертає шляхи до коренів усіх JavaScript-проєктів у робочому просторі.
20
24
 
21
25
  ## Гарантії поведінки
22
26
 
23
- - Повертає `true`, якщо кореневий JS-файл знайдено.
24
- - Повертає `false`, якщо кореневий JS-файл не знайдено.
25
- - Повертає `null`, якщо не вдалося визначити кореневий JS-файл.
26
- - Не обробляє помилки, а повертає `false` або `null`.
27
- - Ігнорує директорії `.git` та `node_modules`.
28
- - Не використовує кешування.
29
- - Не здійснює мережевих запитів.
27
+ - Read-only: не виконує операцій запису (ФС/БД).
28
+ - Свідомо пропускає шляхи: `.git`, `node_modules`.