@nitra/cursor 3.22.0 → 3.23.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 (228) hide show
  1. package/.pi-template/extensions/n-cursor-adr/docs/index.md +181 -0
  2. package/CHANGELOG.md +31 -3
  3. package/bin/docs/n-cursor.md +636 -0
  4. package/bin/docs/rename-yaml-extensions.md +207 -0
  5. package/bin/n-cursor.js +30 -3
  6. package/package.json +1 -1
  7. package/rules/abie/docs/fix.md +18 -0
  8. package/rules/abie/js/docs/applies.md +26 -0
  9. package/rules/abie/js/docs/env_dns.md +32 -0
  10. package/rules/abie/js/docs/firebase_hosting.md +23 -0
  11. package/rules/abie/js/docs/hc_pairing.md +35 -0
  12. package/rules/abie/js/docs/ua_http_route.md +28 -0
  13. package/rules/abie/js/docs/ua_node_selector.md +28 -0
  14. package/rules/abie/lib/docs/enabled.md +29 -0
  15. package/rules/abie/lib/docs/env-dns.md +35 -0
  16. package/rules/abie/lib/docs/hc-yaml.md +33 -0
  17. package/rules/abie/lib/docs/http-route.md +44 -0
  18. package/rules/abie/lib/docs/k8s-tree.md +40 -0
  19. package/rules/abie/lib/docs/kustomization-patches.md +47 -0
  20. package/rules/abie/lib/docs/overlay-paths.md +38 -0
  21. package/rules/abie/lib/docs/yaml.md +29 -0
  22. package/rules/adr/docs/fix.md +148 -0
  23. package/rules/adr/js/docs/hooks.md +259 -0
  24. package/rules/bun/docs/fix.md +156 -0
  25. package/rules/bun/js/docs/layout.md +393 -0
  26. package/rules/capacitor/docs/fix.md +121 -0
  27. package/rules/capacitor/js/docs/platforms.md +295 -0
  28. package/rules/changelog/changelog.mdc +2 -2
  29. package/rules/changelog/docs/fix.md +174 -0
  30. package/rules/changelog/js/consistency.mjs +114 -13
  31. package/rules/changelog/js/docs/consistency.md +387 -0
  32. package/rules/changelog/lib/docs/package-manifest.md +210 -0
  33. package/rules/ci4/docs/fix.md +179 -0
  34. package/rules/ci4/js/docs/marksman_config.md +128 -0
  35. package/rules/docker/docker.mdc +8 -3
  36. package/rules/docker/docs/fix.md +171 -0
  37. package/rules/docker/js/docs/lint.md +258 -0
  38. package/rules/docker/lib/docs/docker-hadolint.md +184 -0
  39. package/rules/docker/lib/docs/docker-mirror.md +247 -0
  40. package/rules/docker/lib/docs/docker-native-addon.md +170 -0
  41. package/rules/docker/lib/docs/docker-nginx-user.md +219 -0
  42. package/rules/docker/lint/docs/lint.md +193 -0
  43. package/rules/efes/docs/fix.md +203 -0
  44. package/rules/feedback/docs/fix.md +140 -0
  45. package/rules/flow/docs/fix.md +152 -0
  46. package/rules/ga/docs/fix.md +158 -0
  47. package/rules/ga/js/docs/lint.md +100 -0
  48. package/rules/ga/js/docs/workflows.md +217 -0
  49. package/rules/ga/lint/docs/lint.md +209 -0
  50. package/rules/ga/policy/clean_merged_branch/clean_merged_branch.rego +11 -2
  51. package/rules/ga/policy/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +3 -4
  52. package/rules/graphql/docs/fix.md +126 -0
  53. package/rules/graphql/js/docs/tooling.md +264 -0
  54. package/rules/graphql/lib/docs/graphql-gql-scan.md +219 -0
  55. package/rules/hasura/docs/fix.md +120 -0
  56. package/rules/hasura/hasura.mdc +14 -0
  57. package/rules/hasura/js/docs/internal_urls.md +326 -0
  58. package/rules/image-avif/docs/fix.md +132 -0
  59. package/rules/image-avif/js/docs/avif_generation.md +241 -0
  60. package/rules/image-compress/docs/fix.md +150 -0
  61. package/rules/image-compress/js/docs/package_setup.md +191 -0
  62. package/rules/js-bun-db/docs/fix.md +148 -0
  63. package/rules/js-bun-db/js/docs/safety.md +231 -0
  64. package/rules/js-bun-db/js-bun-db.mdc +42 -13
  65. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +347 -0
  66. package/rules/js-bun-redis/docs/fix.md +123 -0
  67. package/rules/js-bun-redis/js/docs/imports.md +176 -0
  68. package/rules/js-bun-redis/lib/docs/redis-imports.md +223 -0
  69. package/rules/js-lint/docs/fix.md +117 -0
  70. package/rules/js-lint/js/docs/lint.md +250 -0
  71. package/rules/js-lint/js/docs/tooling.md +348 -0
  72. package/rules/js-lint/js/docs/utils_imports.md +207 -0
  73. package/rules/js-lint-ci/docs/fix.md +154 -0
  74. package/rules/js-lint-ci/js/docs/lint.md +144 -0
  75. package/rules/js-mssql/docs/fix.md +128 -0
  76. package/rules/js-mssql/js/docs/deps.md +263 -0
  77. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +367 -0
  78. package/rules/js-run/docs/fix.md +144 -0
  79. package/rules/js-run/js/docs/runtime.md +388 -0
  80. package/rules/js-run/lib/docs/bunyan-imports.md +117 -0
  81. package/rules/js-run/lib/docs/check-env-scan.md +433 -0
  82. package/rules/js-run/lib/docs/conn-file-rules.md +300 -0
  83. package/rules/js-run/lib/docs/conn-imports-scan.md +204 -0
  84. package/rules/js-run/lib/docs/promise-settimeout-scan.md +326 -0
  85. package/rules/k8s/docs/fix.md +129 -0
  86. package/rules/k8s/js/docs/manifests.md +344 -0
  87. package/rules/k8s/js/manifests.mjs +6 -2
  88. package/rules/k8s/k8s.mdc +4 -2
  89. package/rules/k8s/lint/docs/lint.md +411 -0
  90. package/rules/k8s/policy/network_policy/template/deployment.snippet.yaml +2 -0
  91. package/rules/k8s/policy/network_policy/template/stateful-set.snippet.yaml +2 -0
  92. package/rules/nginx-default-tpl/docs/fix.md +124 -0
  93. package/rules/nginx-default-tpl/js/docs/template.md +378 -0
  94. package/rules/npm-module/docs/fix.md +98 -0
  95. package/rules/npm-module/js/docs/package_structure.md +274 -0
  96. package/rules/npm-module/js/docs/rule_meta.md +137 -0
  97. package/rules/npm-module/js/docs/skill_meta.md +190 -0
  98. package/rules/php/docs/fix.md +107 -0
  99. package/rules/php/js/docs/tooling.md +152 -0
  100. package/rules/php/lint/docs/lint.md +215 -0
  101. package/rules/python/docs/fix.md +163 -0
  102. package/rules/python/js/docs/applies.md +108 -0
  103. package/rules/python/js/docs/tooling.md +153 -0
  104. package/rules/python/lint/docs/lint.md +322 -0
  105. package/rules/rego/docs/fix.md +121 -0
  106. package/rules/rego/js/docs/applies.md +174 -0
  107. package/rules/rego/js/docs/lint.md +118 -0
  108. package/rules/rego/lint/docs/lint.md +204 -0
  109. package/rules/release/docs/change.md +185 -0
  110. package/rules/release/docs/fix.md +119 -0
  111. package/rules/release/docs/release.md +222 -0
  112. package/rules/release/lib/docs/aggregate.md +246 -0
  113. package/rules/release/lib/docs/change-file.md +200 -0
  114. package/rules/release/lib/docs/fallback.md +203 -0
  115. package/rules/rust/docs/fix.md +129 -0
  116. package/rules/rust/js/docs/applies.md +140 -0
  117. package/rules/rust/lib/docs/has-cargo-toml.md +130 -0
  118. package/rules/security/docs/fix.md +86 -0
  119. package/rules/security/js/docs/lint.md +171 -0
  120. package/rules/security/js/docs/sample_secret.md +190 -0
  121. package/rules/security/js/docs/trufflehog.md +137 -0
  122. package/rules/security/js/lint.mjs +9 -1
  123. package/rules/style-lint/docs/fix.md +155 -0
  124. package/rules/style-lint/js/docs/lint.md +184 -0
  125. package/rules/style-lint/js/docs/tooling.md +194 -0
  126. package/rules/tauri/docs/fix.md +158 -0
  127. package/rules/tauri/js/docs/cargo_mutants_config.md +168 -0
  128. package/rules/tauri/js/docs/tooling.md +228 -0
  129. package/rules/test/coverage/coverage.mjs +15 -3
  130. package/rules/test/docs/fix.md +132 -0
  131. package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +138 -0
  132. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +134 -0
  133. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +160 -0
  134. package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +195 -0
  135. package/rules/test/js/docs/cargo_mutants_config.md +173 -0
  136. package/rules/test/js/docs/location.md +136 -0
  137. package/rules/test/js/docs/no-process-chdir.md +160 -0
  138. package/rules/test/js/docs/no-relative-fs-path.md +271 -0
  139. package/rules/test/js/docs/stryker_config.md +152 -0
  140. package/rules/test/js/docs/vitest-config-pool-forks.md +174 -0
  141. package/rules/text/docs/fix.md +118 -0
  142. package/rules/text/js/docs/forbidden-prettier.md +143 -0
  143. package/rules/text/js/docs/formatting.md +256 -0
  144. package/rules/text/js/docs/lint.md +122 -0
  145. package/rules/text/lint/docs/lint.md +220 -0
  146. package/rules/text/lint/docs/run-dotenv-linter.md +157 -0
  147. package/rules/text/lint/docs/run-shellcheck.md +212 -0
  148. package/rules/text/lint/docs/run-v8r.md +197 -0
  149. package/rules/vue/docs/fix.md +127 -0
  150. package/rules/vue/js/docs/packages.md +335 -0
  151. package/rules/vue/lib/docs/vue-forbidden-imports.md +261 -0
  152. package/rules/worktree/docs/fix.md +161 -0
  153. package/schemas/rule-meta.json +5 -1
  154. package/scripts/auto-rules.mjs +7 -4
  155. package/scripts/coverage-classify/docs/apply.md +202 -0
  156. package/scripts/coverage-classify/docs/cache.md +203 -0
  157. package/scripts/coverage-classify/docs/index.md +218 -0
  158. package/scripts/coverage-classify/docs/prompt.md +132 -0
  159. package/scripts/coverage-classify/docs/verdict-schema.md +169 -0
  160. package/scripts/coverage-fix-extract.mjs +122 -0
  161. package/scripts/coverage-fix.mjs +1 -1
  162. package/scripts/dispatcher/docs/graph.md +346 -0
  163. package/scripts/dispatcher/docs/index.md +236 -0
  164. package/scripts/dispatcher/docs/trace.md +296 -0
  165. package/scripts/dispatcher/index.mjs +1 -1
  166. package/scripts/dispatcher/lib/active.mjs +4 -8
  167. package/scripts/dispatcher/lib/commands.mjs +7 -11
  168. package/scripts/dispatcher/lib/docs/active.md +348 -0
  169. package/scripts/dispatcher/lib/docs/artifact.md +232 -0
  170. package/scripts/dispatcher/lib/docs/budget.md +167 -0
  171. package/scripts/dispatcher/lib/docs/capability.md +196 -0
  172. package/scripts/dispatcher/lib/docs/commands.md +210 -0
  173. package/scripts/dispatcher/lib/docs/events.md +182 -0
  174. package/scripts/dispatcher/lib/docs/executor.md +190 -0
  175. package/scripts/dispatcher/lib/docs/flow-lock.md +161 -0
  176. package/scripts/dispatcher/lib/docs/flow-resolve.md +267 -0
  177. package/scripts/dispatcher/lib/docs/gate.md +231 -0
  178. package/scripts/dispatcher/lib/docs/level.md +335 -0
  179. package/scripts/dispatcher/lib/docs/plan-panel.md +181 -0
  180. package/scripts/dispatcher/lib/docs/plan.md +200 -0
  181. package/scripts/dispatcher/lib/docs/planner.md +269 -0
  182. package/scripts/dispatcher/lib/docs/review.md +255 -0
  183. package/scripts/dispatcher/lib/docs/reviewer.md +240 -0
  184. package/scripts/dispatcher/lib/docs/snapshot.md +247 -0
  185. package/scripts/dispatcher/lib/docs/spec.md +203 -0
  186. package/scripts/dispatcher/lib/docs/state-store.md +303 -0
  187. package/scripts/dispatcher/lib/docs/subagent-runner.md +173 -0
  188. package/scripts/dispatcher/lib/executor.mjs +6 -1
  189. package/scripts/dispatcher/lib/flow-resolve.mjs +3 -1
  190. package/scripts/dispatcher/lib/level.mjs +29 -3
  191. package/scripts/dispatcher/lib/review.mjs +1 -1
  192. package/scripts/dispatcher/lib/subagent-runner.mjs +5 -3
  193. package/scripts/docs/auto-rules.md +376 -0
  194. package/scripts/docs/auto-skills.md +173 -0
  195. package/scripts/docs/build-agents-commands.md +183 -0
  196. package/scripts/docs/cli-entry.md +153 -0
  197. package/scripts/docs/coverage-fix.md +177 -0
  198. package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +189 -0
  199. package/scripts/lib/changed-files.mjs +4 -1
  200. package/scripts/lib/docs/changed-files.md +149 -0
  201. package/scripts/lib/docs/check-mdc-template-refs.md +222 -0
  202. package/scripts/lib/docs/check-reporter.md +175 -0
  203. package/scripts/lib/docs/discover-check-rules-from-cursor.md +157 -0
  204. package/scripts/lib/docs/discover-checkable-rules.md +165 -0
  205. package/scripts/lib/docs/ensure-tool.md +254 -0
  206. package/scripts/lib/docs/generated-markdown.md +275 -0
  207. package/scripts/lib/docs/gha-workflow.md +326 -0
  208. package/scripts/lib/docs/inline-template-links.md +303 -0
  209. package/scripts/lib/docs/list-rule-ids.md +156 -0
  210. package/scripts/lib/docs/load-cursor-config.md +147 -0
  211. package/scripts/lib/docs/mirror-parity.md +167 -0
  212. package/scripts/lib/worktree.mjs +26 -0
  213. package/scripts/worktree-cli.mjs +12 -2
  214. package/skills/coverage-fix/SKILL.md +34 -45
  215. package/skills/docgen/SKILL.md +44 -23
  216. package/skills/docgen/bench/etalon/firebase_hosting.md +19 -0
  217. package/skills/docgen/bench/etalon/k8s-tree.md +24 -0
  218. package/skills/docgen/bench/etalon/overlay-paths.md +24 -0
  219. package/skills/docgen/js/docgen-ignore.mjs +54 -0
  220. package/skills/docgen/js/docgen-scan.mjs +37 -21
  221. package/skills/llm-patch/SKILL.md +23 -2
  222. package/skills/start-check/SKILL.md +26 -53
  223. package/skills/start-check/js/check.mjs +211 -0
  224. package/skills/taze/SKILL.md +9 -3
  225. package/skills/taze/js/diff.mjs +154 -0
  226. package/types/bin/n-cursor.d.ts +1 -1
  227. package/skills/fix-tests/SKILL.md +0 -119
  228. package/skills/fix-tests/meta.json +0 -1
@@ -0,0 +1,207 @@
1
+ # `rename-yaml-extensions.mjs`
2
+
3
+ ## Огляд
4
+
5
+ Файл `npm/bin/rename-yaml-extensions.mjs` — це **тонкий CLI-адаптер** (bin-обгортка) для перейменування розширень YAML-файлів у двох конвенціях:
6
+
7
+ - у каталозі `k8s` — файли `.yml` перейменовуються на `.yaml`;
8
+ - у каталозі `.github` — файли `.yaml` перейменовуються на `.yml`.
9
+
10
+ Сама **бізнес-логіка** перейменування реалізована окремо у `../scripts/rename-yaml-extensions.mjs` (звідти імпортуються `parseRenameYamlArgs` і `renameYamlExtensions`). Файл `npm/bin/rename-yaml-extensions.mjs` лише:
11
+
12
+ 1. парсить аргументи командного рядка;
13
+ 2. викликає функцію бізнес-логіки `renameYamlExtensions`;
14
+ 3. форматує вивід у консоль (список перейменувань, повідомлення про відсутність змін, помилки);
15
+ 4. повертає код виходу (`0` — успіх, `1` — були помилки).
16
+
17
+ Файл є **модулем для головного CLI пакета `n-cursor`** (через `bin/n-cursor.js`). Публічна точка входу для користувача — підкоманда головного CLI:
18
+
19
+ - `npx @nitra/cursor rename-yaml-extensions [опції]`
20
+ - або у репозиторії пакета: `bun ./bin/n-cursor.js rename-yaml-extensions`.
21
+
22
+ Прямий запуск `node ./bin/rename-yaml-extensions.mjs` підтримується, але вважається режимом для розробки/тестів — у production-сценарії використовується диспетчер `n-cursor.js`.
23
+
24
+ Підтримувані опції:
25
+
26
+ - `--dry-run` — лише вивести список запланованих перейменувань, нічого не змінюючи у файловій системі;
27
+ - `--root=<шлях>` — корінь обходу (за замовчуванням — `process.cwd()`).
28
+
29
+ ## Експорти / API
30
+
31
+ Файл `npm/bin/rename-yaml-extensions.mjs` експортує одну функцію:
32
+
33
+ ### `runRenameYamlExtensionsCli(argv)`
34
+
35
+ - **Тип**: `async function (argv: string[]): Promise<number>`
36
+ - **Призначення**: запустити перейменування YAML-розширень із форматованим виводом у консоль.
37
+ - **Параметри**:
38
+ - `argv: string[]` — масив аргументів **без імені команди**. Тобто це все, що йде після `rename-yaml-extensions` при виклику через `n-cursor`, або `process.argv.slice(2)` при прямому запуску.
39
+ - **Повертає**: `Promise<number>` — код виходу:
40
+ - `0` — успіх (немає помилок, незалежно від кількості перейменованих файлів);
41
+ - `1` — у процесі трапилися помилки (наприклад, цільовий файл уже існує).
42
+
43
+ Експорт — **named export** (`export async function`). За замовчуванням (`default`) нічого не експортується.
44
+
45
+ ## Функції
46
+
47
+ ### `runRenameYamlExtensionsCli(argv)` (експортна)
48
+
49
+ Алгоритм виконання:
50
+
51
+ 1. **Парсинг аргументів**.
52
+ - Викликається `parseRenameYamlArgs(argv)`, яка повертає об'єкт `{ dryRun, root }`:
53
+ - `dryRun: boolean` — чи це режим симуляції;
54
+ - `root: string` — абсолютний/відносний корінь обходу файлів.
55
+ 2. **Префікс для виводу**.
56
+ - Якщо `dryRun === true`, рядки логу починаються з `[dry-run] `; інакше — з порожнього префіксу.
57
+ 3. **Виклик бізнес-логіки**.
58
+ - Викликається `renameYamlExtensions(root, { dryRun })`, яка повертає об'єкт `{ renamed, errors }`:
59
+ - `renamed: Array<{ relFrom: string, relTo: string }>` — успішні (або заплановані у dry-run) перейменування з відносними шляхами;
60
+ - `errors: string[]` — повідомлення про помилки (наприклад, конфлікт існуючого цільового файлу).
61
+ 4. **Вивід результатів**.
62
+ - Для кожного елемента `renamed` друкується рядок виду `${label}${relFrom} → ${relTo}` (у `stdout`).
63
+ - Якщо `renamed.length === 0` **і** `errors.length === 0` — друкується повідомлення `Немає файлів для перейменування (k8s + .yml → .yaml; .github + .yaml → .yml).` з префіксом `label`.
64
+ - Для кожного елемента `errors` друкується рядок ` ❌ ${err}` у `stderr` (через `console.error`).
65
+ 5. **Повернення коду**.
66
+ - Якщо `errors.length > 0` — повертається `1`; інакше — `0`.
67
+
68
+ Функція **не кидає** виключень самостійно: помилки бізнес-логіки повертаються як масив `errors` і виводяться у `stderr`. Якщо `renameYamlExtensions` чи `parseRenameYamlArgs` кинуть exception, він пробрасується вище — і у блоці `if (isRunAsCli(...))` приведе до необробленого reject промісу.
69
+
70
+ ### Топ-рівневий блок CLI
71
+
72
+ Не є функцією, але є виконуваним кодом на верхньому рівні модуля:
73
+
74
+ ```js
75
+ if (isRunAsCli(import.meta.url)) {
76
+ const code = await runRenameYamlExtensionsCli(process.argv.slice(2))
77
+ if (code !== 0) {
78
+ process.exitCode = 1
79
+ }
80
+ }
81
+ ```
82
+
83
+ Логіка:
84
+
85
+ - Перевіряється, чи цей модуль запущений як CLI (а не імпортований як бібліотека) через `isRunAsCli(import.meta.url)`.
86
+ - Якщо так — викликається `runRenameYamlExtensionsCli` з `process.argv.slice(2)` (аргументи без `node` та шляху до скрипту).
87
+ - Якщо код виходу не нульовий — встановлюється `process.exitCode = 1`. **Зауваження**: тут використано `process.exitCode = 1`, а **не** `process.exit(1)` — це дозволяє Node.js завершити поточний event loop коректно й уникнути обриву флешу `stdout`/`stderr`.
88
+
89
+ При імпорті модуля (як це робить `bin/n-cursor.js`) цей блок **не виконується**, бо `isRunAsCli` поверне `false`.
90
+
91
+ ## Залежності
92
+
93
+ ### Внутрішні (з цього ж пакета)
94
+
95
+ - `../scripts/cli-entry.mjs` — імпорт **`isRunAsCli`**.
96
+ - Призначення: визначає, чи поточний модуль запущено як CLI напряму (через `node ./bin/rename-yaml-extensions.mjs`) або імпортовано іншим модулем.
97
+ - Параметр: `import.meta.url` поточного модуля.
98
+ - `../scripts/rename-yaml-extensions.mjs` — імпорт **`parseRenameYamlArgs`** і **`renameYamlExtensions`**.
99
+ - `parseRenameYamlArgs(argv)` — розбирає прапорці `--dry-run` і `--root=<шлях>`, повертає `{ dryRun, root }`.
100
+ - `renameYamlExtensions(root, options)` — виконує фактичний обхід `k8s` та `.github` і перейменування файлів. Опція `{ dryRun }` керує тим, чи лише симулювати дію.
101
+
102
+ ### Зовнішні
103
+
104
+ Жодних `npm`-залежностей цей файл напряму не використовує. Усе, що потрібно, — це вбудовані Node.js глобали:
105
+
106
+ - `process` — для читання `process.argv` і встановлення `process.exitCode`;
107
+ - `console` — для `console.log` (успіх) і `console.error` (помилки);
108
+ - `import.meta.url` — для перевірки режиму запуску через `isRunAsCli`.
109
+
110
+ ### Зв'язки в інший бік (хто використовує цей файл)
111
+
112
+ - `npm/bin/n-cursor.js` — головний CLI пакета. Імпортує `runRenameYamlExtensionsCli` і викликає її для підкоманди `rename-yaml-extensions`.
113
+
114
+ ## Потік виконання / Використання
115
+
116
+ ### Сценарій 1. Запуск як підкоманда `n-cursor` (типовий випадок)
117
+
118
+ ```bash
119
+ npx @nitra/cursor rename-yaml-extensions
120
+ npx @nitra/cursor rename-yaml-extensions --dry-run
121
+ npx @nitra/cursor rename-yaml-extensions --root=./packages/my-app
122
+ ```
123
+
124
+ Послідовність:
125
+
126
+ 1. `n-cursor.js` отримує `process.argv`, визначає підкоманду `rename-yaml-extensions`.
127
+ 2. `n-cursor.js` імпортує `runRenameYamlExtensionsCli` з `./rename-yaml-extensions.mjs`.
128
+ 3. Викликає `runRenameYamlExtensionsCli(argvBezKomandy)`, де `argvBezKomandy` — усі аргументи **після** `rename-yaml-extensions`.
129
+ 4. Функція парсить опції, викликає бізнес-логіку, друкує результат, повертає код.
130
+ 5. `n-cursor.js` встановлює `process.exitCode` відповідно до повернутого коду.
131
+
132
+ ### Сценарій 2. Прямий запуск (розробка/тести)
133
+
134
+ ```bash
135
+ node ./bin/rename-yaml-extensions.mjs
136
+ node ./bin/rename-yaml-extensions.mjs --dry-run
137
+ node ./bin/rename-yaml-extensions.mjs --root=/abs/path
138
+ ```
139
+
140
+ Послідовність:
141
+
142
+ 1. Node.js завантажує модуль.
143
+ 2. Імпортуються `isRunAsCli`, `parseRenameYamlArgs`, `renameYamlExtensions`.
144
+ 3. Експортується `runRenameYamlExtensionsCli`.
145
+ 4. Виконується топ-рівневий блок `if (isRunAsCli(import.meta.url)) { ... }`.
146
+ 5. У ньому викликається `runRenameYamlExtensionsCli(process.argv.slice(2))`.
147
+ 6. За результатом встановлюється `process.exitCode = 1`, якщо є помилки.
148
+
149
+ ### Сценарій 3. Імпорт як бібліотеки
150
+
151
+ ```js
152
+ import { runRenameYamlExtensionsCli } from '@nitra/cursor/bin/rename-yaml-extensions.mjs'
153
+
154
+ const code = await runRenameYamlExtensionsCli(['--dry-run', '--root=./tmp'])
155
+ // code === 0 → успіх; code === 1 → були помилки
156
+ ```
157
+
158
+ У цьому випадку:
159
+
160
+ - `isRunAsCli(import.meta.url)` повертає `false` (бо модуль завантажено через `import`, а не як точку входу Node.js);
161
+ - топ-рівневий блок CLI **не виконується**;
162
+ - викликач сам обробляє повернутий код.
163
+
164
+ ### Приклади виводу
165
+
166
+ **Успішне перейменування**:
167
+
168
+ ```
169
+ k8s/deployment.yml → k8s/deployment.yaml
170
+ .github/workflows/ci.yaml → .github/workflows/ci.yml
171
+ ```
172
+
173
+ **Режим `--dry-run`**:
174
+
175
+ ```
176
+ [dry-run] k8s/deployment.yml → k8s/deployment.yaml
177
+ [dry-run] .github/workflows/ci.yaml → .github/workflows/ci.yml
178
+ ```
179
+
180
+ **Нічого не потрібно міняти**:
181
+
182
+ ```
183
+ Немає файлів для перейменування (k8s + .yml → .yaml; .github + .yaml → .yml).
184
+ ```
185
+
186
+ **Помилка** (наприклад, цільовий файл уже існує):
187
+
188
+ ```
189
+ ❌ k8s/deployment.yaml вже існує — пропускаю k8s/deployment.yml
190
+ ```
191
+
192
+ (І процес завершиться з кодом виходу `1`.)
193
+
194
+ ### Коди виходу
195
+
196
+ | Код | Значення |
197
+ | --- | ------------------------------------------------------------------------ |
198
+ | `0` | Успіх. Усі заплановані перейменування виконано (або нічого не потрібно). |
199
+ | `1` | Виникли помилки (масив `errors` непорожній). |
200
+
201
+ ### Архітектурні нотатки
202
+
203
+ - Файл свідомо тонкий: уся **алгоритмічна** робота (обхід директорій `k8s` та `.github`, перевірка існуючих файлів, фактичне `fs.rename`) — у `../scripts/rename-yaml-extensions.mjs`. Це дає змогу:
204
+ - **тестувати** бізнес-логіку без процесу-обгортки;
205
+ - **підключати** цю ж логіку до інших точок входу (наприклад, до підкоманд `n-cursor`).
206
+ - Використання `process.exitCode` замість `process.exit(N)` — best practice для CLI, що працюють із асинхронним I/O: дозволяє коректно дочекатися флешу потоків перед завершенням.
207
+ - Перевірка `isRunAsCli(import.meta.url)` — стандартний у цьому пакеті патерн dual-mode модулів (одночасно і CLI, і imported lib). Реалізація — у `../scripts/cli-entry.mjs`.
package/bin/n-cursor.js CHANGED
@@ -24,7 +24,7 @@
24
24
  * `npx \@nitra/cursor lint-docker` — канонічний lint-docker (docker.mdc): `hadolint` по `Dockerfile`/`*.Dockerfile`
25
25
  * `npx \@nitra/cursor lint-text` — канонічний lint-text (text.mdc): `cspell` → `shellcheck` (з auto-fix) →
26
26
  * `markdownlint-cli2 --fix` → `v8r` (json/json5/yaml/yml/toml)
27
- * `npx \@nitra/cursor docgen scan` — детермінований JSON-лістинг кодових файлів для скілу docgen (тека `docs/` поряд із джерелом)
27
+ * `npx \@nitra/cursor docgen scan` — детермінований JSON-лістинг кодових файлів для скілу docgen (відносні `sourcePath`; ignore-glob snippet у `npm/skills/docgen/js/docgen-ignore.mjs`; тека `docs/` поряд із джерелом)
28
28
  * `npx \@nitra/cursor docgen modules` — детермінований JSON-лістинг логічних модулів (межі за `package.json`) для Tier 2 скілу docgen
29
29
  * `npx \@nitra/cursor skill list` — скіли пакета без синку в проєкт
30
30
  * `npx \@nitra/cursor skill taze` — промпт на stdout
@@ -1154,7 +1154,7 @@ async function captureOutput(action) {
1154
1154
  process.stdout.write = (...args) => {
1155
1155
  const [chunk] = args
1156
1156
  buffer.push(typeof chunk === 'string' ? chunk : chunk.toString())
1157
- const cb = args.find((arg) => typeof arg === 'function')
1157
+ const cb = args.find(arg => typeof arg === 'function')
1158
1158
  if (cb) cb()
1159
1159
  return true
1160
1160
  }
@@ -1652,6 +1652,33 @@ try {
1652
1652
 
1653
1653
  break
1654
1654
  }
1655
+ case 'coverage-fix': {
1656
+ // n-cursor coverage-fix index|slice — read-only витяг вцілілих мутантів із
1657
+ // COVERAGE.md для скілу n-coverage-fix. Важкий парсинг несе скрипт (0 LLM-
1658
+ // токенів); агент отримує лише компактний index або зріз під один файл.
1659
+ const { runCoverageFixCli } = await import('../scripts/coverage-fix-extract.mjs')
1660
+ process.exitCode = await runCoverageFixCli(args)
1661
+
1662
+ break
1663
+ }
1664
+ case 'taze': {
1665
+ // n-cursor taze diff — read-only semver-diff package.json ↔ package.json.taze-bak
1666
+ // (root + воркспейси) для скілу n-taze: скрипт класифікує major-оновлення,
1667
+ // агент отримує готовий список замість ручного порівняння бекапів.
1668
+ const { runTazeCli } = await import('../skills/taze/js/diff.mjs')
1669
+ process.exitCode = await runTazeCli(args)
1670
+
1671
+ break
1672
+ }
1673
+ case 'start-check': {
1674
+ // n-cursor start-check scan|run — детермінована частина smoke-перевірки для
1675
+ // скілу n-start-check: scan виявляє воркспейси зі start і їх тип, run запускає
1676
+ // один із grace-таймаутом і класифікує OK/FAIL. Агент лишається з діагностикою.
1677
+ const { runStartCheckCli } = await import('../skills/start-check/js/check.mjs')
1678
+ process.exitCode = await runStartCheckCli(args)
1679
+
1680
+ break
1681
+ }
1655
1682
  case 'change': {
1656
1683
  const { runChangeCli } = await import('../rules/release/change.mjs')
1657
1684
  process.exitCode = await runChangeCli(args)
@@ -1723,7 +1750,7 @@ try {
1723
1750
  default: {
1724
1751
  console.error(`❌ Невідома команда: ${command}`)
1725
1752
  console.error(
1726
- ` Очікується: (без аргументів) синхронізація правил, check, rename-yaml-extensions, post-tool-use-fix, lint, lint-ga, lint-rego, lint-k8s, lint-docker, lint-text, coverage, change, release, skill, worktree, lint-ci, flow, trace, graph, docgen`
1753
+ ` Очікується: (без аргументів) синхронізація правил, check, rename-yaml-extensions, post-tool-use-fix, lint, lint-ga, lint-rego, lint-k8s, lint-docker, lint-text, coverage, coverage-fix, taze, start-check, change, release, skill, worktree, lint-ci, flow, trace, graph, docgen`
1727
1754
  )
1728
1755
  process.exitCode = 1
1729
1756
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "3.22.0",
3
+ "version": "3.23.0",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -0,0 +1,18 @@
1
+ # fix.mjs
2
+
3
+ ## Огляд
4
+
5
+ Точка входу правила `abie` для перевірки/виправлення проєкту. Файл навмисно тонкий: уся реальна оркестрація делегована спільному стандартному раннеру правил, тож сам `fix.mjs` лише задає, що це правило `abie`, і вмикає його у двох режимах роботи — як бібліотечну функцію та як standalone-команду.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Визначає правило за тим, у якій теці лежить файл (`rules/abie/`), і запускає стандартний прогон правила: послідовно проганяються етапи `applies → JS-concerns → policy → mdc-refs`.
10
+ 2. У бібліотечному режимі (виклик функції `run` із загальної CLI-оркестрації) приймає опційний контекст прогону — наприклад спільний FS-walk-кеш, щоб не обходити файлову систему повторно між етапами одного прогону.
11
+ 3. Якщо файл запущено напряму як команду (`bun rules/abie/fix.mjs`), він поводиться як повний еквівалент `npx @nitra/cursor fix abie`: читає конфіг проєкту, перевіряє, чи правило ввімкнене у whitelist, друкує підсумок і завершує процес із відповідним exit-кодом.
12
+ 4. Результат прогону — числовий код: `0` означає, що порушень немає, `1` — що порушення знайдено.
13
+
14
+ ## Гарантії поведінки
15
+
16
+ - Локальної логіки перевірки в цьому файлі немає: будь-яка зміна поведінки правила відбувається через спільний раннер чи передані опції контексту, а не через правки тут. Це утримує всі правила однотипними.
17
+ - Завершення процесу з exit-кодом відбувається лише у standalone-режимі (запуск напряму); при виклику як бібліотеки процес не завершується — повертається лише код результату, придатний для агрегації в загальному прогоні.
18
+ - Standalone-режим коректно обробляє випадок, коли правило не ввімкнене в конфізі: прогін просто пропускається з нейтральним (успішним) результатом замість помилки.
@@ -0,0 +1,26 @@
1
+ # applies.mjs
2
+
3
+ ## Огляд
4
+
5
+ Applies-гейт правила `abie` на рівні всього правила. Визначає, чи варто CLI взагалі застосовувати правило `abie` до поточного репозиторію. Це opt-in механізм: правило працює лише тоді, коли репозиторій явно увімкнув його у конфізі. Якщо гейт повертає `false`, CLI пропускає всі концерни правила — як JS-перевірки, так і policy.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Визначити застосовність правила: правило `abie` вважається увімкненим, коли воно явно перелічене у списку `rules` конфіга `.n-cursor.json` у корені репозиторію.
10
+ 2. Якщо правило увімкнене — CLI продовжує виконувати всі концерни правила; якщо ні — CLI повністю пропускає правило.
11
+ 3. Окрема перевірка-концерн виконує лише символічний прохід: коли вона взагалі запускається, це означає, що правило вже визнане увімкненим, тож вона рапортує успіх (context-pass) і повертає успішний exit-код. Справжню роботу виконують інші концерни правила, а не цей файл.
12
+
13
+ Приклад конфіга, який вмикає правило:
14
+
15
+ ```json
16
+ {
17
+ "rules": ["abie"]
18
+ }
19
+ ```
20
+
21
+ ## Гарантії поведінки
22
+
23
+ - Read-only: гейт лише читає конфіг репозиторію і нічого не змінює.
24
+ - Fail-safe за замовчуванням: за відсутності файла `.n-cursor.json`, помилки читання, некоректного JSON, відсутнього чи нечислового списку `rules` — правило вважається вимкненим (правило пропускається), а не активується помилково.
25
+ - Зіставлення назви правила толерантне до регістру й пробілів навколо значення.
26
+ - Символічний прохід-концерн не кидає винятків і завжди повертає успішний exit-код.
@@ -0,0 +1,32 @@
1
+ # env_dns.mjs
2
+
3
+ ## Огляд
4
+
5
+ Перевірка-чек правила `abie.mdc`: сканує env-файли abie й гарантує, що внутрішньокластерні URL у них вказують на правильний GKE-кластер відповідно до імені файла. Це захист від типової помилки, коли `dev`-конфіг випадково посилається на `ua`-кластер (або навпаки). Якщо в репозиторії немає abie env-файлів, перевірка мовчки проходить.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Завантажує перелік ігнорованих шляхів із cursor-конфігу й збирає всі abie env-файли в репозиторії. abie env-файлом вважається файл із basename `dev.env` або `ua.env` (опційно з провідною крапкою — `.dev.env`, `.ua.env`).
10
+ 2. Локальний `.env` без імені кластера (файл розробника) та інші env-файли (наприклад `production.env`) під перевірку не підпадають.
11
+ 3. Якщо жодного abie env-файла не знайдено — фіксує `pass` із поясненням, що перевірку пропущено, і завершується успішно.
12
+ 4. Для кожного знайденого файла визначає очікуваний кластер за іменем:
13
+ - `dev.env` → кластер `abie-dev.internal`, namespace мусить починатися з `dev-`.
14
+ - `ua.env` → кластер `abie-ua.internal`, namespace мусить починатися з `ua-`.
15
+ 5. Читає вміст файла. Якщо файл не читається — фіксує `fail` із текстом помилки й переходить до наступного.
16
+ 6. У вмісті шукає всі URL виду `http://<svc>.<ns>.svc.<dns>` (з опційним портом і шляхом) і для кожного перевіряє: частина `<dns>` збігається з очікуваним DNS кластера, а namespace `<ns>` починається з очікуваного префікса.
17
+ 7. Один невідповідний URL може дати дві окремі скарги (невірний DNS і невірний namespace). Той самий URL, що трапився у двох змінних, рахується двічі.
18
+ 8. Якщо у файлі немає невідповідностей — `pass`; інакше кожне порушення стає окремим `fail` із зазначенням файла, проблемного URL і очікуваного значення.
19
+
20
+ Приклад порушення для `dev.env`: URL `http://api.ua-core.svc.abie-ua.internal` дасть скарги, бо очікувався DNS `abie-dev.internal` і namespace-префікс `dev-`.
21
+
22
+ ## Публічний API
23
+
24
+ `check(cwd)` — запускає перевірку від кореня репозиторію (за замовчуванням поточна робоча директорія) і повертає код виходу: `0`, якщо порушень немає, інакше ненульовий. Це стандартна точка інтеграції чек-механізму правил.
25
+
26
+ ## Гарантії поведінки
27
+
28
+ - Read-only: файли лише читаються, нічого не змінюється й не створюється.
29
+ - Fail-safe за відсутності даних: репозиторій без abie env-файлів — це успіх, а не помилка.
30
+ - Нечитабельний файл не валить весь прогон: він стає окремою скаргою, решта файлів перевіряються далі.
31
+ - Файли без розпізнаного імені кластера пропускаються без помилки.
32
+ - Файли обробляються в детермінованому (відсортованому) порядку, тож вивід стабільний між запусками.
@@ -0,0 +1,23 @@
1
+ # firebase_hosting.mjs
2
+
3
+ ## Огляд
4
+
5
+ Перевірка правила `abie`: забороняє артефакти Firebase Hosting у підкаталогах репозиторію. За `abie.mdc` Firebase Hosting у проєкті не дозволено, тож наявність його конфігураційних файлів вважається порушенням. Перевірка лише читає файлову систему й рапортує — нічого не змінює.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Зчитується вміст кореня репозиторію (за замовчуванням — поточний робочий каталог).
10
+ 2. Якщо корінь не вдалося прочитати — фіксується помилка з поясненням і перевірка завершується невдало.
11
+ 3. Відбираються лише підкаталоги **першого рівня**, окрім службових `.git` та `node_modules`. Сам корінь репозиторію навмисно не перевіряється: однойменні файли там можуть належати суміжним проєктам і не є порушенням.
12
+ 4. У кожному відібраному підкаталозі шукаються заборонені артефакти Firebase Hosting:
13
+ - файли `.firebaserc` та `firebase.json`;
14
+ - директорія `.firebase/`.
15
+ 5. На кожен знайдений артефакт видається повідомлення про порушення з відносним шляхом і вимогою його видалити (шлях нормалізується до `/`-роздільників). Обхід не переривається на першій знахідці — повідомляються всі порушення.
16
+ 6. Якщо у жодному підкаталозі артефактів не знайдено — видається підтвердження успіху.
17
+
18
+ ## Гарантії поведінки
19
+
20
+ - Read-only: перевірка лише читає каталоги й перевіряє наявність файлів, нічого не створює й не видаляє.
21
+ - Fail-safe щодо помилок читання кореня: замість винятку повертається ненульовий код виходу з діагностичним повідомленням.
22
+ - Повертає `0`, якщо порушень немає, і `1`, якщо знайдено хоча б один заборонений артефакт (або корінь не прочитався).
23
+ - Сканується лише перший рівень вкладеності: глибші підкаталоги та сам корінь не перевіряються (рекурсивного обходу немає).
@@ -0,0 +1,35 @@
1
+ # hc_pairing.mjs
2
+
3
+ ## Огляд
4
+
5
+ Перевірка правила abie: для кожного каталогу в дереві `k8s/`, що містить маніфест `kind: Deployment`, поруч обовʼязково має лежати файл `hc.yaml` із коректним modeline `$schema`. Файл — JS-частина правила: він відповідає лише за FS-парність (Deployment ↔ hc.yaml) та перший рядок-modeline. Структурну валідацію самого `HealthCheckPolicy` (apiVersion, requestPath, port, targetRef із суфіксом `-hl`) виконує окремий Rego-механізм через CLI і тут не дублюється.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Завантажує перелік ігнорованих шляхів із конфігурації cursor і збирає всі `.yaml`/`.yml` файли під сегментом `k8s/`.
10
+ 2. Визначає множину каталогів, де серед цих файлів зустрічається хоча б один `kind: Deployment`.
11
+ 3. Якщо Deployment-каталогів немає — перевірку повністю пропускає з повідомленням-pass і завершується успішно.
12
+ 4. Інакше для кожного Deployment-каталогу (у відсортованому порядку) перевіряє сусідній `hc.yaml`:
13
+ - файлу немає поруч → fail з вимогою додати `HealthCheckPolicy`;
14
+ - файл не вдалося прочитати → fail із текстом помилки читання;
15
+ - файл є → перевіряє його modeline.
16
+ 5. Modeline валідний лише тоді, коли перший рядок файлу — `# yaml-language-server: $schema=…` із точним очікуваним URL CRD-схеми (`networking.gke.io/healthcheckpolicy_v1.json`). Порожній перший рядок, відсутність modeline або інший URL → fail.
17
+ 6. Підсумковий exit-код формується з накопичених pass/fail: 0, якщо всіх правил дотримано.
18
+
19
+ Очікуваний перший рядок `hc.yaml`:
20
+
21
+ ```
22
+ # yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/networking.gke.io/healthcheckpolicy_v1.json
23
+ ```
24
+
25
+ ## Де використовується
26
+
27
+ Це check-модуль правила abie (`abie.mdc`) у складі lint-набору cursor. Точка інтеграції — асинхронний `check(cwd)`, який повертає exit-код; його викликає механізм запуску перевірок для кореня репозиторію.
28
+
29
+ ## Гарантії поведінки
30
+
31
+ - Read-only: модуль лише читає файлову систему й нічого не змінює.
32
+ - Fail-safe для порожнього дерева: відсутність Deployment-маніфестів трактується як успіх, а не помилка.
33
+ - Помилка читання конкретного `hc.yaml` не зупиняє прогон — вона фіксується як окремий fail, а перевірка решти каталогів триває.
34
+ - Каталог `.github/` свідомо виключений зі збору YAML (належить іншому правилу), як і шляхи з cursor-ignore.
35
+ - Зіставлення modeline точне: будь-яке відхилення URL чи формату першого рядка дає зрозуміле повідомлення з посиланням на `abie.mdc`.
@@ -0,0 +1,28 @@
1
+ # ua_http_route
2
+
3
+ ## Огляд
4
+
5
+ Перевірка правила `abie.mdc`, що валідує наявність і коректність inline-patch `HTTPRoute` для `ua`-overlay у Vite-пакетах Kubernetes-маніфестів. Спрацьовує лише для пакетів, які мають `vite.config.{js,mjs,ts}` — для решти перевірка нейтральна (passthrough). Запускається як CLI-check і повертає код виходу для CI.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Завантажує перелік ігнорованих шляхів з cursor-конфігу та обходить дерево `k8s/` репозиторію, збираючи всі YAML-маніфести.
10
+ 2. Відбирає серед них файли `ua/kustomization.yaml`. Якщо таких немає — фіксує успіх із поясненням, що patch `HTTPRoute (ua)` не вимагається, і завершується.
11
+ 3. Для кожного знайденого `ua/kustomization.yaml`:
12
+ - Якщо в каталозі пакета (батьківському щодо `k8s/`) немає `vite.config.{js,mjs,ts}` — перевірка для цього overlay пропускається з відміткою «не застосовується» (gate за Vite-пакетом).
13
+ - Інакше визначає каталог пакета. Якщо його не вдається встановити — фіксує внутрішню помилку overlay.
14
+ 4. Аналізує base-`HTTPRoute` пакета на наявність посилань на спільні сервіси (`auth-run-hl`, `file-link-hl`). У base кожен такий `backendRef` має містити `namespace: dev`; помилки в base-маніфесті повідомляються як fail, і за наявності таких помилок overlay далі не перевіряється. Результат аналізу кешується на рівні пакета, щоб не повторювати його для кількох overlay одного пакета.
15
+ 5. Читає вміст `ua/kustomization.yaml`. При помилці читання — fail із текстом помилки.
16
+ 6. Витягує об'єднаний текст nginx-run patch-ів з kustomization і перевіряє, що inline-patch `HTTPRoute` для namespace `ua` відповідає `abie.mdc`: непорожній `target.name`, перепис `/spec/hostnames` (домени abie), `/spec/parentRefs/0/namespace` (`ua` або `ua-*`), а також JSON6902-patch-и на `/spec/rules/…/backendRefs/…/namespace` зі `value: ua`. Очікувана кількість таких patch-ів дорівнює кількості посилань на спільні сервіси в base. Невідповідність повідомляється як fail, відповідність — як pass.
17
+
18
+ ## Де використовується
19
+
20
+ Частина набору перевірок правила `abie` (`npm/rules/abie`). Викликається як check-функція з кореня репозиторію; типово запускається інфраструктурою лінту/CI, що збирає та запускає `check`-модулі правил.
21
+
22
+ ## Гарантії поведінки
23
+
24
+ - Read-only: лише читає маніфести й конфіги, нічого не змінює у файловій системі.
25
+ - За відсутності `ua/kustomization.yaml` чи `vite.config` перевірка не вимагає patch і фіксує успіх (opt-in за Vite-пакетом).
26
+ - Помилка читання `ua/kustomization.yaml` не зупиняє обхід інших overlay — повідомляється як окремий fail, цикл продовжується.
27
+ - Помилки в base-`HTTPRoute` блокують лише overlay свого пакета, не впливаючи на інші пакети.
28
+ - Результат — агрегований код виходу (0 за умови всіх pass), придатний для використання в CI.
@@ -0,0 +1,28 @@
1
+ # ua_node_selector
2
+
3
+ ## Огляд
4
+
5
+ Check-правило `abie`, яке гарантує: якщо в дереві `k8s/` пакета присутній `Deployment`, то в `ua`-оверлеї (`ua/kustomization.yaml`) обовʼязково має бути inline-patch на цей `Deployment` зі шляхом `/spec/template/spec/nodeSelector` і `preem: false`. Так продакшн-навантаження (`ua`-оверлей) закріплюється за непреемптивними (стабільними) нодами. Перевіряється лише abie-специфічна вимога; структурні обмеження формату JSON6902-патчів (наприклад, заборона `remove + add` на той самий path) перевіряє окреме правило k8s і тут не дублюються.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Зчитує перелік шляхів-винятків (cursor-ignore) і збирає всі k8s YAML-файли в межах кореня репозиторію.
10
+ 2. Визначає директорії, де оголошено `Deployment`. Якщо `Deployment` у дереві немає — правило проходить (pass) із поясненням, що patch `nodeSelector` для `ua` не вимагається, і завершується.
11
+ 3. Серед знайдених YAML відбирає файли, що є `ua/kustomization.yaml`. Якщо `Deployment` є, але жодного `ua`-kustomization не знайдено — це провал (fail) з вказівкою додати `ua/kustomization.yaml` із потрібним patch.
12
+ 4. Для кожного знайденого `ua/kustomization.yaml`:
13
+ - Якщо в дереві k8s саме того пакета, до якого належить цей оверлей, немає `Deployment` — patch не вимагається, правило проходить для цього файлу.
14
+ - Інакше читає вміст файлу. Якщо файл не вдалося прочитати — фіксує провал із текстом помилки й переходить до наступного.
15
+ - Перевіряє наявність коректного patch на target kind `Deployment` зі шляхом `/spec/template/spec/nodeSelector` та `preem: false`. За відсутності — провал; за наявності — прохід.
16
+ 5. Підсумковий код виходу формується з накопичених pass/fail: нуль, якщо жодного провалу не зафіксовано.
17
+
18
+ ## Де використовується
19
+
20
+ Файл — один із check-модулів набору правил `abie` (`npm/rules/abie/js/`). Запускається інфраструктурою перевірок правил, яка викликає експортовану функцію `check` і інтерпретує повернутий код виходу як результат лінту репозиторію.
21
+
22
+ ## Гарантії поведінки
23
+
24
+ - Read-only: жодних файлів не змінює, лише читає YAML-конфігурації; мережу не використовує.
25
+ - Fail-safe для відсутніх ресурсів: відсутність `Deployment` у дереві трактується як легітимний прохід, а не помилка.
26
+ - Помилка читання окремого `ua/kustomization.yaml` не зупиняє перевірку — фіксується як провал для конкретного файлу, решта файлів продовжує оброблятися.
27
+ - Кожен `ua`-файл оцінюється незалежно; результат правила агрегує всі окремі pass/fail.
28
+ - Шляхи у звітах нормалізуються до відносних із прямими слешами, тож вивід стабільний і коректний незалежно від платформи (POSIX/Windows).
@@ -0,0 +1,29 @@
1
+ # enabled.mjs
2
+
3
+ ## Огляд
4
+
5
+ Модуль-предикат, який визначає, чи увімкнено правило **abie** у конфігурації репозиторію. Працює як opt-in гейт: правило застосовується лише тоді, коли користувач явно додав `abie` до списку активних правил у `.n-cursor.json`. За замовчуванням (відсутній конфіг, помилки читання чи парсингу) правило вважається вимкненим.
6
+
7
+ ## Поведінка
8
+
9
+ 1. Шукає файл `.n-cursor.json` у корені репозиторію.
10
+ 2. Якщо файл відсутній — повертає «вимкнено».
11
+ 3. Читає та парсить вміст як JSON. Будь-яка помилка читання чи невалідний JSON трактується як «вимкнено».
12
+ 4. Бере поле `rules`. Якщо це не масив — повертає «вимкнено».
13
+ 5. Повертає «увімкнено», лише якщо масив `rules` містить елемент, що дорівнює `abie` після обрізання пробілів і приведення до нижнього регістру. Записи `"abie"`, `" ABIE "`, `"Abie"` усі вмикають правило. Щоб вимкнути — прибрати ім'я з `rules` (або видалити поле чи файл).
14
+
15
+ Приклад конфігурації, що вмикає правило:
16
+
17
+ ```json
18
+ { "rules": ["abie"] }
19
+ ```
20
+
21
+ ## Де використовується
22
+
23
+ Підключається до applies-механізму правила `abie` (`npm/rules/abie/js/applies.mjs`) як рішення «чи запускати правило». Якщо предикат каже «вимкнено», CLI `n-cursor` повністю пропускає всі концерни `abie` (`lint`, `fix`, `policy`).
24
+
25
+ ## Гарантії поведінки
26
+
27
+ - Read-only: модуль лише читає конфігураційний файл, нічого не змінює й не звертається до мережі.
28
+ - Fail-safe: за будь-якої проблеми (немає файлу, недоступний для читання, битий JSON, `rules` не масив) повертає «вимкнено» замість винятку — правило тихо вимикається, а не ламає прогін CLI.
29
+ - Толерантний матчинг назви: зайві пробіли та регістр у назві `abie` не заважають розпізнаванню; нерядкові елементи `rules` безпечно ігноруються.
@@ -0,0 +1,35 @@
1
+ # env-dns
2
+
3
+ ## Огляд
4
+
5
+ Бібліотека чистих функцій для перевірки кластерного DNS у env-файлах abie. abie розгорнуто у двох GKE-кластерах (`abie-dev.internal` та `abie-ua.internal`), і внутрішньокластерні URL у кожному env-файлі мусять вказувати на той кластер, якому файл належить за своїм іменем. Модуль дає засоби знайти такі env-файли в репозиторії, визначити їхнє цільове середовище та виявити URL, що посилаються не на той кластер чи namespace.
6
+
7
+ ## Поведінка
8
+
9
+ 1. **Класифікація env-файла за іменем.** Файл вважається abie env-файлом, якщо його basename — `dev.env` або `ua.env` (опціонально з провідною крапкою: `.dev.env`, `.ua.env`). Із такого імені витягується середовище — `dev` або `ua`. Будь-який інший файл (наприклад `production.env` чи безіменний `.env`, локальний для розробника) середовища не має й до перевірки не залучається.
10
+
11
+ 2. **Зіставлення середовища з очікуваннями.** Кожному середовищу відповідає фіксована пара — очікуваний кластерний DNS і обов'язковий префікс namespace:
12
+ - `dev` → DNS `abie-dev.internal`, namespace має починатися з `dev-`
13
+ - `ua` → DNS `abie-ua.internal`, namespace має починатися з `ua-`
14
+
15
+ 3. **Сканування внутрішніх URL.** У вмісті env-файла шукаються всі URL виду `http://<svc>.<ns>.svc.<dns>` (з опціональними портом і шляхом). Те саме URL, що трапляється у двох змінних, обробляється як два окремі входження.
16
+
17
+ 4. **Звітування про невідповідності.** Для кожного знайденого URL формується помилка, якщо:
18
+ - його кластерний DNS не дорівнює очікуваному для цього середовища;
19
+ - його namespace не починається з очікуваного префікса.
20
+ Один URL може дати дві окремі помилки (і за DNS, і за namespace). Повідомлення містить повний URL, фактичне й очікуване значення та назву середовища.
21
+
22
+ 5. **Збір файлів для перевірки.** Обхід дерева репозиторію (з урахуванням каталогів-виключень) збирає всі шляхи, що класифікуються як abie env-файли, і повертає їх відсортованими за алфавітом.
23
+
24
+ Приклад невідповідності: у файлі `app.dev.env` рядок `http://api.ua-core.svc.abie-ua.internal` дасть дві помилки — DNS `abie-ua.internal` не відповідає env `dev` (очікується `abie-dev.internal`), а namespace `ua-core` не починається з `dev-`.
25
+
26
+ ## Де використовується
27
+
28
+ Функції модуля викликає чек abie у `npm/rules/abie/js/env_dns.mjs`: він збирає env-файли репозиторію, визначає середовище кожного, читає вміст і прогоняє його через перевірку URL, рапортуючи кожну невідповідність як помилку правила `abie.mdc`. Якщо abie env-файлів у репозиторії немає, чек повідомляє про пропуск.
29
+
30
+ ## Гарантії поведінки
31
+
32
+ - Функції перевірки вмісту чисті й read-only щодо переданого тексту: вони не звертаються до файлової системи й не мутують вхідні дані.
33
+ - Перевірка вмісту не кидає винятків: для невідомого середовища або вмісту без внутрішніх URL повертається порожній список помилок (трактується як «усе гаразд»).
34
+ - Класифікація за іменем для будь-якого не-abie файла повертає «немає середовища», тож сторонні env-файли мовчки виключаються з перевірки.
35
+ - Збір файлів повертає детермінований, відсортований за алфавітом перелік; читання файлів та обробку помилок доступу виконує сам чек-споживач, а не цей модуль.
@@ -0,0 +1,33 @@
1
+ # hc-yaml.mjs
2
+
3
+ ## Огляд
4
+
5
+ Модуль валідує перший рядок-modeline у файлах `hc.yaml` для правила abie. Мета — гарантувати, що файл декларує очікувану `$schema` Kubernetes-ресурсу `HealthCheckPolicy`, аби редактор давав коректні автодоповнення й валідацію за CRD-каталогом. Структурна (per-document) перевірка самого вмісту політики виконується окремо в Rego-політиці `policy/health_check_policy/health_check_policy.rego`, не тут.
6
+
7
+ ## Поведінка
8
+
9
+ 1. З вмісту файла прибирається BOM, текст розбивається на рядки.
10
+ 2. Перевіряється лише перший рядок:
11
+ - якщо файл порожній або перший рядок порожній — повертається помилка про відсутній modeline;
12
+ - якщо перший рядок не відповідає формату modeline `# yaml-language-server: $schema=…` — повертається помилка про обов'язковий modeline;
13
+ - якщо modeline присутній, але URL `$schema` не збігається з очікуваним — повертається помилка з правильним URL для підказки.
14
+ 3. Якщо перший рядок коректний — повертається `null` (валідація пройдена).
15
+
16
+ Очікуваний перший рядок файла `hc.yaml`:
17
+
18
+ ```yaml
19
+ # yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/networking.gke.io/healthcheckpolicy_v1.json
20
+ ```
21
+
22
+ Кожне повідомлення про помилку починається з відносного шляху до файла й завершується маркером `(abie.mdc)`.
23
+
24
+ ## Де використовується
25
+
26
+ Викликається в `npm/rules/abie/js/hc_pairing.mjs`: для кожного знайденого `hc.yaml` перевіряється modeline і репортиться `modeline OK` при `null` або відповідний текст помилки інакше. Константа з очікуваним URL також слугує єдиним джерелом істини для тестів і повідомлень.
27
+
28
+ ## Гарантії поведінки
29
+
30
+ - Read-only: аналізує лише переданий рядок-вміст, не виконує жодного I/O й не змінює вхідних даних.
31
+ - Не кидає винятків на штатних рядкових даних; на порожньому чи некоректному вмісті повертає описову помилку замість збою.
32
+ - Працює з сирим текстом без повного YAML-парсингу — перевіряється виключно перший рядок.
33
+ - Результат завжди детермінований: або точний текст помилки, або `null`.