@nitra/cursor 1.13.82 → 1.13.84

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 (148) hide show
  1. package/.claude-template/commands/n-check.md +2 -2
  2. package/CHANGELOG.md +59 -26
  3. package/README.md +11 -11
  4. package/bin/n-cursor.js +38 -67
  5. package/package.json +1 -1
  6. package/rules/abie/abie.mdc +9 -9
  7. package/rules/abie/fix.mjs +19 -0
  8. package/rules/abie/policy/base_deployment_preem/base_deployment_preem.rego +2 -2
  9. package/rules/abie/policy/health_check_policy/health_check_policy.rego +2 -2
  10. package/rules/abie/policy/http_route_base/http_route_base.rego +1 -1
  11. package/rules/abie/utils/k8s-tree.mjs +1 -1
  12. package/rules/adr/adr.mdc +1 -1
  13. package/rules/adr/fix.mjs +19 -0
  14. package/rules/adr/{fix → js}/hooks/check.mjs +1 -1
  15. package/rules/bun/bun.mdc +1 -1
  16. package/rules/bun/fix.mjs +19 -0
  17. package/rules/bun/{fix → js}/layout/check.mjs +1 -1
  18. package/rules/capacitor/fix.mjs +19 -0
  19. package/rules/capacitor/policy/package_json/package_json.rego +3 -3
  20. package/rules/changelog/changelog.mdc +2 -2
  21. package/rules/changelog/fix.mjs +19 -0
  22. package/rules/ci4/ci4.mdc +1 -1
  23. package/rules/ci4/fix.mjs +19 -0
  24. package/rules/docker/docker.mdc +7 -7
  25. package/rules/docker/fix.mjs +19 -0
  26. package/rules/docker/lint/lint.mjs +2 -2
  27. package/rules/docker/policy/package_json/package_json.rego +1 -1
  28. package/rules/efes/efes.mdc +1 -1
  29. package/rules/efes/fix.mjs +19 -0
  30. package/rules/feedback/feedback.mdc +2 -2
  31. package/rules/feedback/fix.mjs +19 -0
  32. package/rules/ga/fix.mjs +19 -0
  33. package/rules/ga/lint/lint.mjs +6 -6
  34. package/rules/ga/policy/workflow_common/workflow_common.rego +1 -1
  35. package/rules/graphql/fix.mjs +19 -0
  36. package/rules/graphql/{fix → js}/tooling/graphql-gql-scan.mjs +1 -1
  37. package/rules/graphql/policy/vscode_extensions/vscode_extensions.rego +2 -2
  38. package/rules/hasura/fix.mjs +19 -0
  39. package/rules/hasura/policy/svc_hl/svc_hl.rego +1 -1
  40. package/rules/image-avif/fix.mjs +19 -0
  41. package/rules/image-avif/image-avif.mdc +1 -1
  42. package/rules/image-avif/{fix → js}/avif_generation/check.mjs +1 -1
  43. package/rules/image-compress/fix.mjs +19 -0
  44. package/rules/image-compress/{fix → js}/package_setup/check.mjs +1 -1
  45. package/rules/js-bun-db/fix.mjs +19 -0
  46. package/rules/js-bun-redis/fix.mjs +19 -0
  47. package/rules/js-bun-redis/policy/package_json/package_json.rego +1 -1
  48. package/rules/js-lint/fix.mjs +19 -0
  49. package/rules/js-lint/{fix → js}/tooling/check.mjs +5 -5
  50. package/rules/js-lint/{fix → js}/tooling/rebuild-oxlint-canonical.mjs +1 -1
  51. package/rules/js-lint/js-lint.mdc +3 -3
  52. package/rules/js-mssql/fix.mjs +19 -0
  53. package/rules/js-mssql/policy/package_json/package_json.rego +2 -2
  54. package/rules/js-run/fix.mjs +19 -0
  55. package/rules/js-run/{fix → js}/runtime/check.mjs +3 -3
  56. package/rules/k8s/fix.mjs +19 -0
  57. package/rules/k8s/{fix → js}/manifests/check.mjs +1 -1
  58. package/rules/k8s/k8s.mdc +13 -13
  59. package/rules/k8s/lint/lint.mjs +2 -2
  60. package/rules/k8s/policy/base_kustomization/base_kustomization.rego +3 -3
  61. package/rules/k8s/policy/base_manifest/base_manifest.rego +2 -2
  62. package/rules/k8s/policy/gateway/gateway.rego +2 -2
  63. package/rules/k8s/policy/hasura_configmap/hasura_configmap.rego +3 -3
  64. package/rules/k8s/policy/hasura_httproute/hasura_httproute.rego +1 -1
  65. package/rules/k8s/policy/hpa_pdb/hpa_pdb.rego +1 -1
  66. package/rules/k8s/policy/kustomization/kustomization.rego +2 -2
  67. package/rules/k8s/policy/manifest/manifest.rego +4 -4
  68. package/rules/k8s/policy/svc_hl_yaml/svc_hl_yaml.rego +2 -2
  69. package/rules/k8s/policy/svc_yaml/svc_yaml.rego +2 -2
  70. package/rules/nginx-default-tpl/fix.mjs +19 -0
  71. package/rules/nginx-default-tpl/{fix → js}/template/check.mjs +1 -1
  72. package/rules/nginx-default-tpl/policy/vscode_extensions/vscode_extensions.rego +2 -2
  73. package/rules/nginx-default-tpl/policy/vscode_settings/vscode_settings.rego +1 -1
  74. package/rules/npm-module/fix.mjs +19 -0
  75. package/rules/npm-module/{fix → js}/package_structure/check.mjs +3 -3
  76. package/rules/php/fix.mjs +19 -0
  77. package/rules/php/{fix → js}/tooling/check.mjs +2 -2
  78. package/rules/rego/fix.mjs +19 -0
  79. package/rules/security/fix.mjs +19 -0
  80. package/rules/security/security.mdc +3 -3
  81. package/rules/style-lint/fix.mjs +19 -0
  82. package/rules/style-lint/{fix → js}/tooling/check.mjs +2 -2
  83. package/rules/tauri/fix.mjs +19 -0
  84. package/rules/tauri/{fix → js}/tooling/check.mjs +1 -1
  85. package/rules/tauri/policy/vscode_extensions/vscode_extensions.rego +2 -2
  86. package/rules/test/fix.mjs +19 -0
  87. package/rules/test/test.mdc +2 -2
  88. package/rules/text/fix.mjs +19 -0
  89. package/rules/text/{fix → js}/formatting/check.mjs +2 -2
  90. package/rules/text/text.mdc +1 -1
  91. package/rules/vue/fix.mjs +19 -0
  92. package/rules/vue/{fix → js}/packages/check.mjs +1 -1
  93. package/rules/vue/policy/package_json/package_json.rego +1 -1
  94. package/rules/vue/vue.mdc +1 -1
  95. package/schemas/n-cursor.json +1 -1
  96. package/scripts/auto-rules.mjs +3 -3
  97. package/scripts/build-agents-commands.mjs +1 -1
  98. package/scripts/claude-stop-hook.mjs +1 -1
  99. package/scripts/sync-claude-config.mjs +2 -2
  100. package/scripts/utils/ast-scan-utils.mjs +3 -3
  101. package/scripts/utils/discover-check-rules-from-cursor.mjs +1 -1
  102. package/scripts/utils/discover-checkable-rules.mjs +30 -18
  103. package/scripts/utils/list-rule-ids.mjs +23 -0
  104. package/scripts/utils/read-n-cursor-config-lite.mjs +59 -0
  105. package/scripts/utils/run-rule-cli.mjs +37 -0
  106. package/scripts/utils/run-rule.mjs +7 -7
  107. package/scripts/utils/run-standard-rule.mjs +34 -0
  108. package/scripts/utils/walk-cache.mjs +24 -0
  109. package/scripts/utils/workspaces.mjs +1 -1
  110. package/skills/fix/SKILL.md +5 -5
  111. package/skills/lint/SKILL.md +1 -1
  112. /package/rules/abie/{fix → js}/applies/check.mjs +0 -0
  113. /package/rules/abie/{fix → js}/env_dns/check.mjs +0 -0
  114. /package/rules/abie/{fix → js}/firebase_hosting/check.mjs +0 -0
  115. /package/rules/abie/{fix → js}/hc_pairing/check.mjs +0 -0
  116. /package/rules/abie/{fix → js}/ua_http_route/check.mjs +0 -0
  117. /package/rules/abie/{fix → js}/ua_node_selector/check.mjs +0 -0
  118. /package/rules/adr/{fix → js}/hooks/template/.gitignore.snippet +0 -0
  119. /package/rules/capacitor/{fix → js}/platforms/check.mjs +0 -0
  120. /package/rules/changelog/{fix → js}/consistency/check.mjs +0 -0
  121. /package/rules/changelog/{fix → js}/consistency/package-manifest.mjs +0 -0
  122. /package/rules/docker/{fix → js}/lint/check.mjs +0 -0
  123. /package/rules/docker/{fix → js}/lint/docker-hadolint.mjs +0 -0
  124. /package/rules/docker/{fix → js}/lint/docker-mirror.mjs +0 -0
  125. /package/rules/ga/{fix → js}/workflows/check.mjs +0 -0
  126. /package/rules/graphql/{fix → js}/tooling/check.mjs +0 -0
  127. /package/rules/hasura/{fix → js}/internal_urls/check.mjs +0 -0
  128. /package/rules/js-bun-db/{fix → js}/safety/bun-sql-scan.mjs +0 -0
  129. /package/rules/js-bun-db/{fix → js}/safety/check.mjs +0 -0
  130. /package/rules/js-bun-redis/{fix → js}/imports/check.mjs +0 -0
  131. /package/rules/js-lint/{fix → js}/tooling/knip-canonical.json +0 -0
  132. /package/rules/js-lint/{fix → js}/tooling/oxlint-canonical-skeleton.json +0 -0
  133. /package/rules/js-lint/{fix → js}/tooling/oxlint-canonical.json +0 -0
  134. /package/rules/js-lint/{fix → js}/tooling/oxlint-rules.tsv +0 -0
  135. /package/rules/js-mssql/{fix → js}/deps/check.mjs +0 -0
  136. /package/rules/js-mssql/{fix → js}/deps/mssql-pool-scan.mjs +0 -0
  137. /package/rules/js-run/{fix → js}/runtime/bunyan-imports.mjs +0 -0
  138. /package/rules/js-run/{fix → js}/runtime/check-env-scan.mjs +0 -0
  139. /package/rules/js-run/{fix → js}/runtime/conn-file-rules.mjs +0 -0
  140. /package/rules/js-run/{fix → js}/runtime/conn-imports-scan.mjs +0 -0
  141. /package/rules/js-run/{fix → js}/runtime/promise-settimeout-scan.mjs +0 -0
  142. /package/rules/k8s/{fix → js}/kubescape_exceptions/template/.kubescape-exceptions.json.snippet.json +0 -0
  143. /package/rules/rego/{fix → js}/applies/check.mjs +0 -0
  144. /package/rules/security/{fix → js}/sample_secret/check.mjs +0 -0
  145. /package/rules/security/{fix → js}/trufflehog/check.mjs +0 -0
  146. /package/rules/security/{fix → js}/trufflehog/template/.trufflehog-exclude.snippet.txt +0 -0
  147. /package/rules/test/{fix → js}/location/check.mjs +0 -0
  148. /package/rules/vue/{fix → js}/packages/vue-forbidden-imports.mjs +0 -0
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  description: >-
3
- Запустити всі програмні перевірки правил (`npx @nitra/cursor check`)
3
+ Запустити всі програмні перевірки правил (`npx @nitra/cursor fix`)
4
4
  ---
5
5
 
6
6
  # n-check
7
7
 
8
- Запусти `npx @nitra/cursor check` і пройдися по результатах.
8
+ Запусти `npx @nitra/cursor fix` і пройдися по результатах.
9
9
 
10
10
  - Якщо є помилки — виправи відповідно до правила, на яке вказує перевірка.
11
11
  - Якщо все чисто — підтверди коротким повідомленням і переходь до наступного кроку.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,39 @@
4
4
 
5
5
  Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
6
6
 
7
+ ## [1.13.84] - 2026-05-23
8
+
9
+ ### Changed
10
+
11
+ - **CLI команда `check` перейменована на `fix`** (узгоджено з ім'ям файла `rules/<id>/fix.mjs`). `npx @nitra/cursor fix [<rule>...]` — новий канонічний формат. Команда `check` залишається як deprecated alias з warning'ом — буде видалена в наступній major-версії.
12
+ - **CLI стає spawn-wrapper:** замість inline dynamic import у `runChecks`, `fix [<rule>...]` тепер просто послідовно спавнить `bun rules/<id>/fix.mjs` per rule (один шлях у коді — `fix.mjs` як єдина авторитативна точка входу). Discovery з `.cursor/rules/*.mdc` без аргументів зберігається.
13
+ - **`rules/<id>/fix.mjs` отримує standalone-режим:** блок `if (import.meta.main)` тепер делегує новій утиліті `runRuleCli`, яка читає `.n-cursor.json` (через light reader), перевіряє whitelist + друкує per-rule summary. `bun rules/<id>/fix.mjs` тепер повний еквівалент `npx @nitra/cursor fix <id>`.
14
+ - **Документація переписана:** всі `npx @nitra/cursor check <rule>` у `.mdc`, `.cursor/rules/`, `README.md`, skills, JSDoc pass-повідомленнях оновлено на `fix`. Один формат у документації; CLI alias `check` лишається тільки для backward compatibility.
15
+
16
+ ### Added
17
+
18
+ - **`scripts/utils/run-rule-cli.mjs`** — standalone runner з config-loading + summary; використовується `fix.mjs::main` блоком.
19
+ - **`scripts/utils/read-n-cursor-config-lite.mjs`** — мінімальний read-only `.n-cursor.json` reader (без auto-detection / sync — це окрема справа CLI). API: `readNCursorConfigLite()`, `isRuleEnabled(config, ruleId)`. Open-by-default: якщо файл відсутній — правило вважається активним (для debug).
20
+
21
+ ## [1.13.83] - 2026-05-23
22
+
23
+ ### Changed
24
+
25
+ - **Per-rule `fix.mjs` entry-point + rename `fix/` → `js/`:** кожне з 30 правил тепер має `rules/<id>/fix.mjs` — 11-рядковий wrapper над новим `runStandardRule`. CLI більше не робить convention-based discovery на верхньому рівні — перебирає правила через `listRuleIds` і викликає `await import(rules/<id>/fix.mjs).run({ walkCache })`. Каталог `fix/<concern>/` перейменовано на `js/<concern>/` для усунення колізії з кореневим `fix.mjs` та узгодження з `policy/` (за технологією, не функцією).
26
+ - **Локальна логіка в `fix.mjs` заборонена** — розширення поведінки правил тільки через опції в `RuleContext` (зараз: `walkCache`; зарезервовано на майбутнє: `skipMdcRefs`, `skipApplies`, `onlyConcerns`). Простір варіацій повністю описано в `RuleContext` JSDoc; convention-drift виключений на рівні дизайну.
27
+ - **Shared `walkCache`** як module-level singleton у `scripts/utils/walk-cache.mjs` (`getOrCreateWalkCache` + `resetWalkCache` для тестів). CLI створює один cache на прогон і прокидає через ctx до всіх concerns.
28
+ - **Нові utils:** `scripts/utils/run-standard-rule.mjs`, `scripts/utils/list-rule-ids.mjs`, `scripts/utils/walk-cache.mjs`. Експорт `discoverOneRule(ruleDir, ruleId)` з `discover-checkable-rules.mjs` (виокремлено з існуючого `discoverCheckableRules` — DRY).
29
+ - **Нові тести:** `tests/fix-mjs-contract.test.mjs` (91 кейс — smoke на всі 30 правил), `tests/run-standard-rule.test.mjs`, `tests/list-rule-ids.test.mjs`, `tests/walk-cache.test.mjs`, `tests/discover-one-rule.test.mjs`. Існуючі тести оновлено в частині import-шляхів `/fix/<concern>` → `/js/<concern>` (логіка не змінювалась); видалено застарілий `discoverCheckableRules > legacy js/-структура ігнорується` — `js/` тепер canonical convention.
30
+
31
+ ### Breaking
32
+
33
+ - **Для зовнішніх інтеграторів, що пишуть власні правила:** каталог `rules/<id>/fix/<concern>/check.mjs` перейменовано на `rules/<id>/js/<concern>/check.mjs`; додатково потрібен файл `rules/<id>/fix.mjs` з канонічним вмістом (див. будь-яке вбудоване правило для шаблону). CLI більше не запустить правило без `fix.mjs`.
34
+
35
+ ### Notes
36
+
37
+ - Зворотна сумісність CLI: `npx @nitra/cursor fix` та `npx @nitra/cursor fix abie` працюють як раніше.
38
+ - Use-cases: `bun npm/rules/abie/fix.mjs` (debug); `bun npm/rules/${{ matrix.rule }}/fix.mjs` (CI per-rule jobs); IDE Run-button на `fix.mjs`.
39
+
7
40
  ## [1.13.82] - 2026-05-23
8
41
 
9
42
  ### Changed
@@ -14,7 +47,7 @@
14
47
  - `rules/test/fix/location/check.mjs` — перевіряє **лише `*.test.mjs`**, `*_test.rego` свідомо виключено з область перевірки (зафіксовано у docstring).
15
48
  - Додано test-case у `rules/test/fix/location/tests/check.test.mjs`: `*_test.rego` поряд із полісі НЕ є порушенням.
16
49
  - **Відкат переміщення `*_test.rego`**: 69 файлів, які раніше було помилково перенесено у `policy/<concern>/tests/<name>_test.rego`, повернуто у `policy/<concern>/<name>_test.rego` через `git mv`. Порожні `tests/` піддиректорії під `policy/` видалено.
17
- - **`npx @nitra/cursor check test`** охоплює лише JS-тести: «✅ Всі 77 файлів *.test.mjs у каталозі tests/». Rego-тести продовжують перевірятись через `conftest verify` у правилі `rego`.
50
+ - **`npx @nitra/cursor fix test`** охоплює лише JS-тести: «✅ Всі 77 файлів *.test.mjs у каталозі tests/». Rego-тести продовжують перевірятись через `conftest verify` у правилі `rego`.
18
51
 
19
52
  ## [1.13.81] - 2026-05-23
20
53
 
@@ -42,7 +75,7 @@
42
75
  - Ручні фіксапи 4 тестів із HERE/`..` path patterns (sync-setup-bun-deps-action, inline-template-links, rules/adr/fix/hooks, rules/abie/utils/enabled) — додано додатковий `..`, бо тести стали на рівень глибше.
43
76
  - `package.json#files` негативні globs (`!**/*.test.mjs`, `!**/__fixtures__/**`, `!**/fixtures/**`) працюють рекурсивно — без змін.
44
77
  - **77 тестів** проходять у новому layout (76 існуючих + 1 нового правила): `bun test` 843 pass / 2 fail (обидва — pre-existing `with-lock` issues, не пов'язані).
45
- - `npx @nitra/cursor check test` → `✅ Всі 77 файлів *.test.mjs у каталозі tests/ (test.mdc)`.
78
+ - `npx @nitra/cursor fix test` → `✅ Всі 77 файлів *.test.mjs у каталозі tests/ (test.mdc)`.
46
79
 
47
80
  ## [1.13.79] - 2026-05-23
48
81
 
@@ -196,7 +229,7 @@
196
229
 
197
230
  ### Added
198
231
 
199
- - Нове `alwaysApply`-правило **`feedback`** ([feedback.mdc](rules/feedback/feedback.mdc)) — ефемерний канал зворотного звʼязку до пакета `@nitra/cursor`. Виконуючи будь-який скіл пакета (`n-lint`, `n-fix`, `n-taze`, `n-adr-normalize`, `n-llm-patch`, `n-publish-telegram`, `mdc-check`), агент проходить крізь `.cursor/rules/`, `SKILL.md` і `npx @nitra/cursor check` — і бачить «тертя»: неоднозначні інструкції, відсутні `check-*.mjs`, false positive, порушення без автофіксу, повторювані патерни. Правило вимагає наприкінці скілу, **після** основного резюме, додати у відповідь чату секцію `## 🔧 Покращення @nitra/cursor` з пунктами за схемою `target` (`rule`/`skill`/`check`) · `id` · `kind` (`ambiguous-doc`/`missing-check`/`false-positive`/`no-autofix`/`recurring-pattern`) · `evidence` · `suggestion`. Резюме **навмисно ефемерне** — живе лише у відповіді чату: правило забороняє запис файлів/чернеток, GitHub issue/PR і редагування самого пакета; розробник, читаючи відповідь, сам вирішує, чи переносити пункт у пакет. Якщо тертя не було — секція повністю пропускається. Правило чисто документаційне (як `ci4`), `check-*.mjs` не має, бо поведінка агента програмно не верифікується. Зачеплено: новий каталог [rules/feedback/](rules/feedback/) з `feedback.mdc` (`version: '1.0'`), додано `"feedback"` у `rules` кореневого `.n-cursor.json` — після синку правило копіюється як `.cursor/rules/n-feedback.mdc` і потрапляє в `AGENTS.md`.
232
+ - Нове `alwaysApply`-правило **`feedback`** ([feedback.mdc](rules/feedback/feedback.mdc)) — ефемерний канал зворотного звʼязку до пакета `@nitra/cursor`. Виконуючи будь-який скіл пакета (`n-lint`, `n-fix`, `n-taze`, `n-adr-normalize`, `n-llm-patch`, `n-publish-telegram`, `mdc-check`), агент проходить крізь `.cursor/rules/`, `SKILL.md` і `npx @nitra/cursor fix` — і бачить «тертя»: неоднозначні інструкції, відсутні `check-*.mjs`, false positive, порушення без автофіксу, повторювані патерни. Правило вимагає наприкінці скілу, **після** основного резюме, додати у відповідь чату секцію `## 🔧 Покращення @nitra/cursor` з пунктами за схемою `target` (`rule`/`skill`/`check`) · `id` · `kind` (`ambiguous-doc`/`missing-check`/`false-positive`/`no-autofix`/`recurring-pattern`) · `evidence` · `suggestion`. Резюме **навмисно ефемерне** — живе лише у відповіді чату: правило забороняє запис файлів/чернеток, GitHub issue/PR і редагування самого пакета; розробник, читаючи відповідь, сам вирішує, чи переносити пункт у пакет. Якщо тертя не було — секція повністю пропускається. Правило чисто документаційне (як `ci4`), `check-*.mjs` не має, бо поведінка агента програмно не верифікується. Зачеплено: новий каталог [rules/feedback/](rules/feedback/) з `feedback.mdc` (`version: '1.0'`), додано `"feedback"` у `rules` кореневого `.n-cursor.json` — після синку правило копіюється як `.cursor/rules/n-feedback.mdc` і потрапляє в `AGENTS.md`.
200
233
  - `check security`: новий concern **`security.sample_secret`** — placeholder фейкових credential-значень у прикладних файлах має бути `sample-secret`, а не bare `secret`. Причина: `sample-secret` містить підрядок `sample` із вшитого списку `DefaultFalsePositives` TruffleHog і відсіюється сканером гарантовано та незалежно від версії; bare `secret` наразі ігнорується лише тому, що випадково присутнє у словнику `fp_words.txt` — крихка поведінка, що залежить від версії інструмента. [check.mjs](rules/security/fix/sample_secret/check.mjs) обходить дерево, відбирає прикладні файли (basename із суфіксом `.example`/`.sample`/`.template`/`.dist` чи infix `.example.`/`.sample.`/`.template.`, а також усе всередині каталогів `fixtures`/`fixture`/`__fixtures__`) і порядково шукає `secret` у позиції значення — одразу після `=`, `:` або `=>` з опційними лапками; імена ключів (`client_secret`, `JWT_SECRET`) не чіпаються, бо матч прив'язаний до значення. Решта файлів не сканується — там `secret` майже завжди частина реального коду. Скан текстовий (regex, не AST/Rego): прикладні файли — різнорідні конфіги (`.env`, YAML, JSON, TOML, plain `.dist`) без єдиного AST, а відбір файлів потребує обходу дерева. Зачеплено: [check.mjs](rules/security/fix/sample_secret/check.mjs) і [check.test.mjs](rules/security/fix/sample_secret/check.test.mjs) (новий concern + 9 тестів), [security.mdc](rules/security/security.mdc) (нова секція «Placeholder для секретів — `sample-secret`» та секція «Перевірка»). Bump `security.mdc` `2.0` → `2.1`.
201
234
 
202
235
  ## [1.13.57] - 2026-05-19
@@ -666,14 +699,14 @@
666
699
  - **`tauri`** (`1.0 → 1.1`) — `globs: "**/src-tauri/**,**/tauri.conf.json"`
667
700
  - **`js-lint`** (`1.21 → 1.22`) — `globs: "**/{.oxlintrc.json,eslint.config.js,.jscpd.json,knip.json,package.json},**/*.{js,mjs,cjs,jsx,ts,tsx}"`
668
701
  - **`js-run`** (`1.7 → 1.8`) — `globs: "**/package.json,**/jsconfig.json,**/src/**/*.{js,mjs,cjs,ts,tsx}"`
669
- - **Мотивація:** усі 9 правил мають повне покриття `npx @nitra/cursor check <rule>` (JS-перевірка + Rego policy). Тримати їх `alwaysApply: true` без потреби палить контекст AI у сесіях, де редагується непов'язаний код. Помилка → check ловить → AI виправляє — той самий цикл, що для `security@1.12.1` і `changelog`/`image-compress`/`php`/`vue`.
702
+ - **Мотивація:** усі 9 правил мають повне покриття `npx @nitra/cursor fix <rule>` (JS-перевірка + Rego policy). Тримати їх `alwaysApply: true` без потреби палить контекст AI у сесіях, де редагується непов'язаний код. Помилка → check ловить → AI виправляє — той самий цикл, що для `security@1.12.1` і `changelog`/`image-compress`/`php`/`vue`.
670
703
  - **Залишено `alwaysApply: true`** — `text` (cross-cutting cspell-словник, апостроф), `adr` (про процес capture/normalize hooks), `ci4` (0 програмних чекерів — без AI-контексту правило мертве), `abie` (має JS `applies`-гейт, у не-abie репо мовчить; файли розкидані).
671
704
 
672
705
  ## [1.12.1] - 2026-05-17
673
706
 
674
707
  ### Changed
675
708
 
676
- - **`npm/rules/security/security.mdc`** — `alwaysApply: true` → `alwaysApply: false` + `globs: "**/.gitleaks.toml,**/package.json,**/.github/workflows/**/*.yml"`. AI-контекст правила тепер підвантажується лише при роботі з релевантними файлами (за зразком `changelog`/`image-compress`/`php`), а не на кожен турн. Програмна валідація через `npx @nitra/cursor check security` залишається завжди увімкненою (через `auto.md = завжди`) і ловить помилки незалежно від AI-контексту. Версія frontmatter `1.0` → `1.1`.
709
+ - **`npm/rules/security/security.mdc`** — `alwaysApply: true` → `alwaysApply: false` + `globs: "**/.gitleaks.toml,**/package.json,**/.github/workflows/**/*.yml"`. AI-контекст правила тепер підвантажується лише при роботі з релевантними файлами (за зразком `changelog`/`image-compress`/`php`), а не на кожен турн. Програмна валідація через `npx @nitra/cursor fix security` залишається завжди увімкненою (через `auto.md = завжди`) і ловить помилки незалежно від AI-контексту. Версія frontmatter `1.0` → `1.1`.
677
710
  - **Мотивація:** правило має повне покриття перевіркою (Rego + JS-check); тримати його `alwaysApply: true` не дає AI додаткової цінності понад те, що `check security` ловить програмно — лише марно займає контекстне вікно при роботі з кодом, не повʼязаним з конфігурацією security.
678
711
 
679
712
  ## [1.12.0] - 2026-05-16
@@ -700,7 +733,7 @@
700
733
 
701
734
  ### Removed
702
735
 
703
- - **`npm/package.json#devDependencies`** — повторно видалено `@nitra/cursor: ^1.11.16` self-reference, який повернувся в коміті `8ae6e9e auto adr` (автоматичний stop-hook fix). Той самий блок уже прибирали в `1.11.14` (див. запис нижче) — потрапив назад через автофікс. `npx @nitra/cursor check npm-module` знову зелений.
736
+ - **`npm/package.json#devDependencies`** — повторно видалено `@nitra/cursor: ^1.11.16` self-reference, який повернувся в коміті `8ae6e9e auto adr` (автоматичний stop-hook fix). Той самий блок уже прибирали в `1.11.14` (див. запис нижче) — потрапив назад через автофікс. `npx @nitra/cursor fix npm-module` знову зелений.
704
737
 
705
738
  ## [1.11.16] - 2026-05-16
706
739
 
@@ -720,36 +753,36 @@
720
753
 
721
754
  ### Removed
722
755
 
723
- - **`npm/package.json#devDependencies`** — повністю видалено блок (містив лише self-reference `@nitra/cursor: ^1.11.9`). `npx @nitra/cursor check npm-module` зафіксував порушення: `devDependencies` не публікуються користувачам пакета, але інструменти, що **потрібні** для розробки пакета, мають жити в кореневому `package.json` (у workspace-root) як `@nitra/cursor: workspace:*` (там уже є). Self-reference у `npm/package.json` лишався з попередньої практики, але **публікувався** у npm-tarball (хоч і ігнорувався установником, оскільки лізе у nested deps), забруднюючи метадані пакета.
756
+ - **`npm/package.json#devDependencies`** — повністю видалено блок (містив лише self-reference `@nitra/cursor: ^1.11.9`). `npx @nitra/cursor fix npm-module` зафіксував порушення: `devDependencies` не публікуються користувачам пакета, але інструменти, що **потрібні** для розробки пакета, мають жити в кореневому `package.json` (у workspace-root) як `@nitra/cursor: workspace:*` (там уже є). Self-reference у `npm/package.json` лишався з попередньої практики, але **публікувався** у npm-tarball (хоч і ігнорувався установником, оскільки лізе у nested deps), забруднюючи метадані пакета.
724
757
  - **`knip.json#workspaces.npm.ignoreDependencies: ["@nitra/cursor"]`** — workaround, доданий у 1.11.13 для приховання knip-violation на self-reference, тепер не потрібен (першопричина прибрана). Знято, щоб конфіг лишався чистим.
725
758
 
726
759
  ## [1.11.13] - 2026-05-16
727
760
 
728
761
  ### Fixed
729
762
 
730
- - **`npm/rules/{bun,image-compress,js-bun-redis,js-run,php,style-lint,text}/fix/<concern>/check.mjs`** — escape `@nitra` як `\@nitra` у JSDoc-блоках (`/** … */`), де `npx @nitra/cursor check` стояв всередині backticks. ESLint-плагін `jsdoc/escape-inline-tags` парсив `@nitra` як інлайн-тег (false-positive у backticks) і видавав 8 warnings. Виправлення — escape-символ `\` перед `@`, як уже зроблено в інших місцях коду (CHANGELOG 1.11.5 для `js-run`). Pass-повідомлення та `//`-коментарі поза JSDoc не зачіпало — там парсер не активний.
763
+ - **`npm/rules/{bun,image-compress,js-bun-redis,js-run,php,style-lint,text}/fix/<concern>/check.mjs`** — escape `@nitra` як `\@nitra` у JSDoc-блоках (`/** … */`), де `npx @nitra/cursor fix` стояв всередині backticks. ESLint-плагін `jsdoc/escape-inline-tags` парсив `@nitra` як інлайн-тег (false-positive у backticks) і видавав 8 warnings. Виправлення — escape-символ `\` перед `@`, як уже зроблено в інших місцях коду (CHANGELOG 1.11.5 для `js-run`). Pass-повідомлення та `//`-коментарі поза JSDoc не зачіпало — там парсер не активний.
731
764
  - **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк) — заголовок секції перейменовано з **«Скоуп»** на **«Scope»**, бо cspell флагав «Скоуп» як unknown word. Англійський «Scope» зрозумілий і не вимагає розширення словника. Тіло секції без змін.
732
765
 
733
766
  ## [1.11.12] - 2026-05-15
734
767
 
735
768
  ### Removed
736
769
 
737
- - **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 3 реструктуризації: dual-mode підтримка `js/` (legacy) прибрана. Після завершення масового переїзду у 1.11.10 (всі 26 правил у `rules/<id>/fix/`) інфраструктура `n-cursor check` тепер сканує **тільки** `rules/<id>/fix/<concern>/check*.mjs`. Конкретно: (1) у `discoverCheckableRules` видалено `listJsConcerns(js/, 'js')`-виклик, утиліту `mergeJsConcerns` (fatal на дублікат `js/`+`fix/`) і поле `rootDir` у `JsConcern`-типі; (2) у `run-rule.mjs::resolveJsCheckPath` `concern.rootDir ?? 'js'` замінено на хардкод `'fix'`; (3) JSDoc на початку обох файлів і на `evaluateAppliesGate` оновлено з `js/applies/check.mjs` на `fix/applies/check.mjs`; (4) коментар на `discoverCheckScripts` у `npm/bin/n-cursor.js` оновлено — згадку legacy `js/check.mjs` прибрано. Жодне правило в `rules/` не торкається — лише сканер.
770
+ - **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 3 реструктуризації: dual-mode підтримка `js/` (legacy) прибрана. Після завершення масового переїзду у 1.11.10 (всі 26 правил у `rules/<id>/fix/`) інфраструктура `n-cursor fix` тепер сканує **тільки** `rules/<id>/fix/<concern>/check*.mjs`. Конкретно: (1) у `discoverCheckableRules` видалено `listJsConcerns(js/, 'js')`-виклик, утиліту `mergeJsConcerns` (fatal на дублікат `js/`+`fix/`) і поле `rootDir` у `JsConcern`-типі; (2) у `run-rule.mjs::resolveJsCheckPath` `concern.rootDir ?? 'js'` замінено на хардкод `'fix'`; (3) JSDoc на початку обох файлів і на `evaluateAppliesGate` оновлено з `js/applies/check.mjs` на `fix/applies/check.mjs`; (4) коментар на `discoverCheckScripts` у `npm/bin/n-cursor.js` оновлено — згадку legacy `js/check.mjs` прибрано. Жодне правило в `rules/` не торкається — лише сканер.
738
771
  - **`npm/scripts/utils/discover-checkable-rules.test.mjs`**, **`npm/scripts/utils/run-rule.test.mjs`** — прибрано тести dual-mode: `правило з тільки JS-концерном у legacy js/`, `правило з різними концернами у js/ і fix/`, `дублікат концерну в js/ і fix/ — fatal`, `пропускає js/utils/ як концерн`, `концерн з rootDir="fix"`, `концерн без rootDir (legacy-тести) fallback до js/`, `applies-гейт у fix/applies/`. Додано: `legacy js/-структура ігнорується (concern у js/<name>/ не підхоплюється)` — гарантує, що випадковий залишок `js/`-дерева у правилі не виконається, та `правило з кількома JS-концернами в fix/ — всі присутні, відсортовані`. Тестовий хелпер `addJsConcern` / `writeConcernJs` — за замовчуванням пишуть у `fix/` без параметра rootDir.
739
772
 
740
773
  ## [1.11.11] - 2026-05-15
741
774
 
742
775
  ### Removed
743
776
 
744
- - **`npm/scripts/lint-conftest.mjs`** — скрипт видалено повністю. Його єдина функція — ітерувати policy-концерни через `discoverCheckableRules` і запускати `runConftestBatch` на реальних файлах — **повністю дублювала** `npx @nitra/cursor check` (CHANGELOG 1.11.5: «`bun.bunfig`, `text.cspell`, `npm_module.npm_publish_yml` тепер прогоняються через CLI `check <id>` без додаткового `bun run lint-conftest`»). Окремий канал залишався лише як IDE-fast-feedback, але через одне джерело правди (`target.json` поруч з `.rego`) другий entry-point не дає нічого нового. Кореневий `package.json` оновлено: скрипт `lint-conftest` прибрано, ланцюжок `lint` тепер `bun run lint-rego && bun run lint-js && …` (без `lint-conftest`).
777
+ - **`npm/scripts/lint-conftest.mjs`** — скрипт видалено повністю. Його єдина функція — ітерувати policy-концерни через `discoverCheckableRules` і запускати `runConftestBatch` на реальних файлах — **повністю дублювала** `npx @nitra/cursor fix` (CHANGELOG 1.11.5: «`bun.bunfig`, `text.cspell`, `npm_module.npm_publish_yml` тепер прогоняються через CLI `check <id>` без додаткового `bun run lint-conftest`»). Окремий канал залишався лише як IDE-fast-feedback, але через одне джерело правди (`target.json` поруч з `.rego`) другий entry-point не дає нічого нового. Кореневий `package.json` оновлено: скрипт `lint-conftest` прибрано, ланцюжок `lint` тепер `bun run lint-rego && bun run lint-js && …` (без `lint-conftest`).
745
778
 
746
779
  ### Changed
747
780
 
748
- - **`npm/README.md`** — секція «Структура пакету» переписана під поточний layout (`rules/<id>/<id>.mdc` замість застарілих `mdc/`). Додано підсекцію **«Структура одного правила»** з принципом fix/lint/policy: технологія реалізації визначає директорію — JS для `npx @nitra/cursor check` у `fix/<concern>/`, JS для `bun run lint-<id>` у `lint/`, rego для `npx @nitra/cursor check` у `policy/<concern>/`. Решта `mdc/`-посилань у README також виправлені на `rules/`.
781
+ - **`npm/README.md`** — секція «Структура пакету» переписана під поточний layout (`rules/<id>/<id>.mdc` замість застарілих `mdc/`). Додано підсекцію **«Структура одного правила»** з принципом fix/lint/policy: технологія реалізації визначає директорію — JS для `npx @nitra/cursor fix` у `fix/<concern>/`, JS для `bun run lint-<id>` у `lint/`, rego для `npx @nitra/cursor fix` у `policy/<concern>/`. Решта `mdc/`-посилань у README також виправлені на `rules/`.
749
782
  - **`.cursor/rules/conftest.mdc`** — крок 5 у workflow «нова перевірка» переписано: окремої реєстрації нового rego-пакета в TARGETS більше не потрібно (TARGETS видалено разом із `lint-conftest.mjs`); `discoverCheckableRules` автоматично підхоплює пакет за наявності `target.json` поруч з `.rego`.
750
783
  - **`.cursor/rules/scripts.mdc`** — згадку `lint-conftest.mjs` прибрано зі списку «крос-правильної інфраструктури» у `npm/scripts/`.
751
- - **`npm/rules/abie/abie.mdc`** (cross-reference) — `npx @nitra/cursor lint-conftest` → `npx @nitra/cursor check abie`; `npm/policy/abie/` → `npm/rules/abie/policy/`; `check-abie.mjs` → `fix/<concern>/check.mjs`.
752
- - **`npm/rules/**/fix/<concern>/check.mjs`** (10 файлів) та **`npm/rules/**/policy/<concern>/<name>.rego`** (7 файлів) — у коментарях і `pass()`-повідомленнях `bun run lint-conftest` замінено на `npx @nitra/cursor check` (структурна валідація живить fix-канал; окремого `lint-conftest`-каналу більше немає). Для conditional rego-полісі без `target.json` (ті, що не auto-discoverable) текст коментарів переформульовано — замість «глобально у `lint-conftest` НЕ реєструється» тепер «без `target.json` поруч (не auto-discoverable через `n-cursor check`)».
784
+ - **`npm/rules/abie/abie.mdc`** (cross-reference) — `npx @nitra/cursor lint-conftest` → `npx @nitra/cursor fix abie`; `npm/policy/abie/` → `npm/rules/abie/policy/`; `check-abie.mjs` → `fix/<concern>/check.mjs`.
785
+ - **`npm/rules/**/fix/<concern>/check.mjs`** (10 файлів) та **`npm/rules/**/policy/<concern>/<name>.rego`** (7 файлів) — у коментарях і `pass()`-повідомленнях `bun run lint-conftest` замінено на `npx @nitra/cursor fix` (структурна валідація живить fix-канал; окремого `lint-conftest`-каналу більше немає). Для conditional rego-полісі без `target.json` (ті, що не auto-discoverable) текст коментарів переформульовано — замість «глобально у `lint-conftest` НЕ реєструється» тепер «без `target.json` поруч (не auto-discoverable через `n-cursor fix`)».
753
786
 
754
787
  ## [1.11.10] - 2026-05-15
755
788
 
@@ -763,7 +796,7 @@
763
796
 
764
797
  ### Changed
765
798
 
766
- - **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 1 реструктуризації `rules/<id>/js/` → `rules/<id>/{fix,lint}/`: інфраструктура `n-cursor check` тепер **dual-mode** — сканує JS-концерни одночасно у `rules/<id>/js/<concern>/` (legacy) і `rules/<id>/fix/<concern>/` (новий формат). Кожен знайдений концерн штампується полем `rootDir: 'js' | 'fix'`; `runRule` використовує його для побудови шляху імпорту через `resolveJsCheckPath`. Концерн з однаковим іменем у обох каталогах одного правила — fatal-помилка з підказкою «заверши міграцію цього концерну у fix/ і видали `js/<name>/`», щоб не лишалось напіввиконаних move-ів. `utils/` пропускається в обох коренях. Жодне правило ще не переїхало у фазі 1 — це лише підготовка інфраструктури; для зворотної сумісності `resolveJsCheckPath` має fallback `rootDir ?? 'js'`, тож тести, що збирають `jsConcerns` вручну без `rootDir`, продовжують працювати без змін. CLI-точки входу `n-cursor lint-X` (статичні `import` у `npm/bin/n-cursor.js:79-83`) переїдуть пізніше — у фазах 2/3 (move + оновлення imports).
799
+ - **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 1 реструктуризації `rules/<id>/js/` → `rules/<id>/{fix,lint}/`: інфраструктура `n-cursor fix` тепер **dual-mode** — сканує JS-концерни одночасно у `rules/<id>/js/<concern>/` (legacy) і `rules/<id>/fix/<concern>/` (новий формат). Кожен знайдений концерн штампується полем `rootDir: 'js' | 'fix'`; `runRule` використовує його для побудови шляху імпорту через `resolveJsCheckPath`. Концерн з однаковим іменем у обох каталогах одного правила — fatal-помилка з підказкою «заверши міграцію цього концерну у fix/ і видали `js/<name>/`», щоб не лишалось напіввиконаних move-ів. `utils/` пропускається в обох коренях. Жодне правило ще не переїхало у фазі 1 — це лише підготовка інфраструктури; для зворотної сумісності `resolveJsCheckPath` має fallback `rootDir ?? 'js'`, тож тести, що збирають `jsConcerns` вручну без `rootDir`, продовжують працювати без змін. CLI-точки входу `n-cursor lint-X` (статичні `import` у `npm/bin/n-cursor.js:79-83`) переїдуть пізніше — у фазах 2/3 (move + оновлення imports).
767
800
  - **`npm/scripts/utils/discover-checkable-rules.test.mjs`**, **`npm/scripts/utils/run-rule.test.mjs`** — додано покриття нового `fix/`-кореня: окремі тести на discovery концерну у `fix/`, mix `js/`+`fix/` різних концернів одного правила, fatal на дублікат, пропуск `fix/utils/`, runRule з `rootDir: 'fix'`, applies-гейт у `fix/applies/`, та fallback на `js/` для концернів без `rootDir` (зворотна сумісність із наявними тестовими фікстурами).
768
801
 
769
802
  ## [1.11.8] - 2026-05-15
@@ -776,7 +809,7 @@
776
809
 
777
810
  ### Changed
778
811
 
779
- - **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк) — `/n-fix` більше **не запускає** `bun run lint` і **не делегує** до `/n-lint`. Крок 6 (`bun run lint` з делегуванням, доданий у 1.11.6) повністю видалено; замість нього на початку SKILL.md додано секцію **«Scope»**, де явно зафіксовано: `/n-fix` опікується лише структурою проєкту (правила `.cursor/rules/` + `npx @nitra/cursor check`), а лінт-порушення у самому коді (ESLint/oxlint/jscpd/cspell/knip/sonarjs/stylelint) — поза скоупом і виправляються винятково через `/n-lint`. Кроки 7→6 і 8→7 переномеровано; остаточний пункт 7 додатково нагадує, що лінт-помилки не входять у критерій успіху `/n-fix`. Мета — щоб агент, що виконує `/n-fix`, не плутав свою задачу з `/n-lint` і не запускав важкий `bun run lint` без потреби; те, що діагностує `/n-lint`, виправляється там же, а не дублюється тут.
812
+ - **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк) — `/n-fix` більше **не запускає** `bun run lint` і **не делегує** до `/n-lint`. Крок 6 (`bun run lint` з делегуванням, доданий у 1.11.6) повністю видалено; замість нього на початку SKILL.md додано секцію **«Scope»**, де явно зафіксовано: `/n-fix` опікується лише структурою проєкту (правила `.cursor/rules/` + `npx @nitra/cursor fix`), а лінт-порушення у самому коді (ESLint/oxlint/jscpd/cspell/knip/sonarjs/stylelint) — поза скоупом і виправляються винятково через `/n-lint`. Кроки 7→6 і 8→7 переномеровано; остаточний пункт 7 додатково нагадує, що лінт-помилки не входять у критерій успіху `/n-fix`. Мета — щоб агент, що виконує `/n-fix`, не плутав свою задачу з `/n-lint` і не запускав важкий `bun run lint` без потреби; те, що діагностує `/n-lint`, виправляється там же, а не дублюється тут.
780
813
 
781
814
  ### Fixed
782
815
 
@@ -788,7 +821,7 @@
788
821
 
789
822
  - **`npm/rules/npm-module/npm-module.mdc`** — переформульовано вимогу про тести й фікстури. Раніше правило вимагало тримати їх **поза** будь-яким шляхом з `"files"` (канонічно — у `npm/tests/`). Тепер тести/фікстури можуть лежати **поруч з кодом** усередині `"files"`-шляхів, але `"files"` обовʼязково має містити **негативні glob-патерни**, що виключають їх із tarball (`!**/*.test.*`, `!**/*.spec.*`, `!**/test-helpers.*`, `!**/fixtures/**`, `!**/__tests__/**`, опційно `!**/*_test.rego`). Це краще відповідає реальному layout пакета (co-located test-файли у `rules/<id>/js/<concern>/`) і прибирає роз'їзд правила з фактичним `npm/package.json`. Версію `.mdc` піднято до `1.12`.
790
823
  - **`npm/rules/npm-module/js/package_structure/check.mjs::checkNoTestsInPublishedFiles`** — текст fail-повідомлення тепер однозначно радить додати негативний glob у `"files"`, без альтернативи «винеси за межі шляхів з "files"». Логіка перевірки (walk positive ∖ negative + класифікація test-style) не змінилась — пере-кваліфіковано лише підказку для агента й людини.
791
- - **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк), **`npm/rules/style-lint/style-lint.mdc`** — розмежовано ролі скілів: `/n-fix` відповідає за **структуру** проєкту (правила `.cursor/rules/` + `npx @nitra/cursor check`), `/n-lint` — за **чистоту коду** (`bun run lint`). Крок 6 у `n-fix` (перебір `lint-js`/`lint-text`/`lint-style`) замінено на одиничний `bun run lint` з делегуванням до `/n-lint` — лінт-логіку (auto-fix, sonarjs-рефакторинг, заборона паралельних запусків ESLint) `n-fix` більше не дублює. У `style-lint.mdc` cross-reference «повний набір `lint-*` (навичка `n-fix`)» оновлено на «`bun run lint` (навичка `/n-lint`)».
824
+ - **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк), **`npm/rules/style-lint/style-lint.mdc`** — розмежовано ролі скілів: `/n-fix` відповідає за **структуру** проєкту (правила `.cursor/rules/` + `npx @nitra/cursor fix`), `/n-lint` — за **чистоту коду** (`bun run lint`). Крок 6 у `n-fix` (перебір `lint-js`/`lint-text`/`lint-style`) замінено на одиничний `bun run lint` з делегуванням до `/n-lint` — лінт-логіку (auto-fix, sonarjs-рефакторинг, заборона паралельних запусків ESLint) `n-fix` більше не дублює. У `style-lint.mdc` cross-reference «повний набір `lint-*` (навичка `n-fix`)» оновлено на «`bun run lint` (навичка `/n-lint`)».
792
825
 
793
826
  ## [1.11.5] - 2026-05-15
794
827
 
@@ -923,11 +956,11 @@
923
956
 
924
957
  ### Changed
925
958
 
926
- - **CLI auto-discovery** підхоплює `check-rego.mjs` і `check-tauri.mjs` через `discoverCheckScripts()` у `bin/n-cursor.js`. Окрема реєстрація не потрібна — будь-який `check-*.mjs` стає доступним через `npx @nitra/cursor check <rule>`.
959
+ - **CLI auto-discovery** підхоплює `check-rego.mjs` і `check-tauri.mjs` через `discoverCheckScripts()` у `bin/n-cursor.js`. Окрема реєстрація не потрібна — будь-який `check-*.mjs` стає доступним через `npx @nitra/cursor fix <rule>`.
927
960
 
928
961
  ### Verified
929
962
 
930
- - **На цьому репо `npx @nitra/cursor check rego` детектує реальні гепи у `.vscode/extensions.json` (немає `tsandall.opa`) і `.vscode/settings.json` (немає `[rego]` блока).** Це true-positive: репо має `rego` у `.n-cursor.json:rules` і містить `.rego` файли, тож канонічний tooling-набір вимагається. Фікс — додати entries у `.vscode/*` згідно `rego.mdc`.
963
+ - **На цьому репо `npx @nitra/cursor fix rego` детектує реальні гепи у `.vscode/extensions.json` (немає `tsandall.opa`) і `.vscode/settings.json` (немає `[rego]` блока).** Це true-positive: репо має `rego` у `.n-cursor.json:rules` і містить `.rego` файли, тож канонічний tooling-набір вимагається. Фікс — додати entries у `.vscode/*` згідно `rego.mdc`.
931
964
 
932
965
  ### Not migrated (explained)
933
966
 
@@ -1083,7 +1116,7 @@
1083
1116
 
1084
1117
  ### Changed
1085
1118
 
1086
- - **AGENTS.md — додано `bunx knip` до секції Commands:** `build-agents-commands.mjs` тепер завжди додає рядок `- **knip (невикористані залежності та експорти)**: \`bunx knip\``після`npx @nitra/cursor check`; оновлено тест (`items.length`3 → 4, перевірка`toContain('bunx knip')`).
1119
+ - **AGENTS.md — додано `bunx knip` до секції Commands:** `build-agents-commands.mjs` тепер завжди додає рядок `- **knip (невикористані залежності та експорти)**: \`bunx knip\``після`npx @nitra/cursor fix`; оновлено тест (`items.length`3 → 4, перевірка`toContain('bunx knip')`).
1087
1120
  - **`knip.json` — `graphql` у `ignoreDependencies`:** повернуто `graphql` до кореневого `ignoreDependencies` (peer-залежність, яку knip фолсово репортить як unused; вимога `js-lint.mdc` / `check-js-lint.mjs`).
1088
1121
 
1089
1122
  ## [1.9.8] - 2026-05-12
@@ -1179,7 +1212,7 @@
1179
1212
 
1180
1213
  ### Changed
1181
1214
 
1182
- - **ga / Plan B (rego-authoritative, повна централізація):** rego-крок переїхав із `lint-ga.mjs` у `check-ga.mjs::check()` як **перший крок**. Раніше `bun run lint-ga` сам викликав 4 per-workflow conftest + 1 batch для `ga.workflow_common`, а `npx @nitra/cursor check ga` цю частину не робив — тепер вся ga-логіка (rego + JS cross-file) в одному `check-ga.check()`. `lint-ga.mjs::runLintGaCli` спрощено: preflight (shellcheck/uv) → actionlint → zizmor → `await checkGa()`. Видалено: `CONFTEST_TARGETS`, `GA_POLICY_DIR`, `runConftestStep`, `runConftestWorkflowCommon` — і непотрібні імпорти `existsSync`/`readdirSync`/`dirname`/`join`/`fileURLToPath`. `runLintGaCli` тепер `async`; `bin/n-cursor.js` оновлено на `await runLintGaCli()`. Тест `lint-ga.test.mjs` оновлено: `await fn()` замість `fn()`. Тест `check-ga.test.mjs::"exit 1 коли shellcheck відсутній"` переведений на точковий виклик експортованої `checkShellcheckInstalled` (бо `withBinRemovedFromPath('shellcheck')` на macOS заодно видаляв `/opt/homebrew/bin` де conftest, ламаючи hard-fail у `runConftestBatch`).
1215
+ - **ga / Plan B (rego-authoritative, повна централізація):** rego-крок переїхав із `lint-ga.mjs` у `check-ga.mjs::check()` як **перший крок**. Раніше `bun run lint-ga` сам викликав 4 per-workflow conftest + 1 batch для `ga.workflow_common`, а `npx @nitra/cursor fix ga` цю частину не робив — тепер вся ga-логіка (rego + JS cross-file) в одному `check-ga.check()`. `lint-ga.mjs::runLintGaCli` спрощено: preflight (shellcheck/uv) → actionlint → zizmor → `await checkGa()`. Видалено: `CONFTEST_TARGETS`, `GA_POLICY_DIR`, `runConftestStep`, `runConftestWorkflowCommon` — і непотрібні імпорти `existsSync`/`readdirSync`/`dirname`/`join`/`fileURLToPath`. `runLintGaCli` тепер `async`; `bin/n-cursor.js` оновлено на `await runLintGaCli()`. Тест `lint-ga.test.mjs` оновлено: `await fn()` замість `fn()`. Тест `check-ga.test.mjs::"exit 1 коли shellcheck відсутній"` переведений на точковий виклик експортованої `checkShellcheckInstalled` (бо `withBinRemovedFromPath('shellcheck')` на macOS заодно видаляв `/opt/homebrew/bin` де conftest, ламаючи hard-fail у `runConftestBatch`).
1183
1216
  - **`check-ga.mjs::checkShellcheckInstalled`:** додано `export` (потрібен для точкового тесту після рефактору).
1184
1217
  - **тестова фікстура `setupCanonicalGaProject` у check-ga.test.mjs:** додано секцію `concurrency` (з канонічними `group` і `cancel-in-progress: true`) у workflow `clean-ga-workflows.yml`, `clean-merged-branch.yml`, `git-ai.yml` — `ga.workflow_common` rego тепер запускається у `check()`, а ці workflow раніше не мали concurrency у фікстурі (правило `lint-ga.yml` уже мало). Це **правильна** реакція: rego-перевірка тепер ловить порушення на тих самих фікстурах, на яких раніше не запускалась.
1185
1218
 
@@ -1312,7 +1345,7 @@
1312
1345
  `redis`, підшляхів `ioredis/...` / `redis/...` і `@redis/*`. Не зачіпає
1313
1346
  сторонні `redis-*` (наприклад, `redis-mock`).
1314
1347
  - `npm/scripts/check-js-bun-redis.mjs` запускає AST-скан по JS/TS-джерелах і
1315
- доступний як `npx @nitra/cursor check js-bun-redis`.
1348
+ доступний як `npx @nitra/cursor fix js-bun-redis`.
1316
1349
  - Rego-полісі `npm/policy/js_bun_redis/package_json/` — заборона
1317
1350
  `ioredis` / `node-redis` / `redis` / `@redis/*` у `dependencies` будь-якого
1318
1351
  `package.json` у дереві; зареєстрована таргетом у
@@ -1502,7 +1535,7 @@
1502
1535
 
1503
1536
  ### Added
1504
1537
 
1505
- - `mdc/rego.mdc` (нова версія 1.1, з 1.0): VS Code-секція з рекомендованим розширенням `tsandall.opa` (LSP від автора OPA: підсвічування, hover, go-to-definition, format-on-save через `opa fmt`), `.vscode/extensions.json` і `.vscode/settings.json` сніпети для `[rego]` (`editor.defaultFormatter: tsandall.opa`, `formatOnSave: true`); опис кроків `lint-rego` (preflight `opa`+`regal`, далі `opa check --strict` і `regal lint`); `package.json`-сніпет зі скриптом `lint-rego`; install-команди (`brew install opa regal` + universal лінки); приклад `.regal/config.yaml`. Раніше файл містив лише placeholder `npx @nitra/cursor check rego`.
1538
+ - `mdc/rego.mdc` (нова версія 1.1, з 1.0): VS Code-секція з рекомендованим розширенням `tsandall.opa` (LSP від автора OPA: підсвічування, hover, go-to-definition, format-on-save через `opa fmt`), `.vscode/extensions.json` і `.vscode/settings.json` сніпети для `[rego]` (`editor.defaultFormatter: tsandall.opa`, `formatOnSave: true`); опис кроків `lint-rego` (preflight `opa`+`regal`, далі `opa check --strict` і `regal lint`); `package.json`-сніпет зі скриптом `lint-rego`; install-команди (`brew install opa regal` + universal лінки); приклад `.regal/config.yaml`. Раніше файл містив лише placeholder `npx @nitra/cursor fix rego`.
1506
1539
 
1507
1540
  ### Changed
1508
1541
 
@@ -1598,7 +1631,7 @@
1598
1631
  - `image` правило розщеплене на два самостійні: **`image-compress`** (валідація `lint-image` / `.gitignore` / залежностей — стиснення raster/SVG через `@nitra/minify-image`) і **`image-avif`** (генерація AVIF-двійників, переписування raster-посилань у `.vue`/`.html` на `.avif`, прибирання AVIF-сиріт). Це дозволяє тримати компресію всюди, а AVIF — лише там, де його підтримка гарантована (адмінки), вимикаючи його для публічних сайтів через `disable-rules: ["image-avif"]` у `.n-cursor.json` чи опт-аут на рівні пакета (`"@nitra/minify-image": { "disable-avif": true }` у `package.json` сайту).
1599
1632
  - `auto-rules.md` / `auto-rules.mjs`: автодетект `image-compress - [bun]` (всюди, де є `package.json`), `image-avif - [vue, image-compress]` (лише для проєктів з `.vue`-файлами і вже активним `image-compress`).
1600
1633
  - Видалено `npm/scripts/check-image.mjs` і `npm/mdc/image.mdc` — їх замінили `check-image-compress.mjs` + `check-image-avif.mjs` і `image-compress.mdc` + `image-avif.mdc`.
1601
- - Канонічний `lint-image` залишається без `--avif` (його перевіряє `image-compress`); `npx @nitra/cursor check image-avif` тепер є самостійною командою для AVIF-pipeline.
1634
+ - Канонічний `lint-image` залишається без `--avif` (його перевіряє `image-compress`); `npx @nitra/cursor fix image-avif` тепер є самостійною командою для AVIF-pipeline.
1602
1635
 
1603
1636
  ### Added
1604
1637
 
@@ -1705,7 +1738,7 @@
1705
1738
 
1706
1739
  ### Changed
1707
1740
 
1708
- - `image` (mdc v1.4 → v1.5): прапорець `--avif` у `lint-image` тепер **заборонений** (інакше `bun run lint` плодив би `.avif` для зображень, що ніде не вживаються); канонічний `lint-image` — `npx @nitra/minify-image --src=. --write`. AVIF-генерацію виконує **виключно** `npx @nitra/cursor check image`. Секцію «AVIF-імпорти у `.vue`» переписано: тепер вона документує триетапну логіку `check image` — (1) запуск `npx @nitra/minify-image --src=. --write --avif`, (2) авто-заміна raster-посилань у `.vue`/`.html` на `.avif` у кожному workspace-пакеті, (3) прибирання AVIF-сиріт (файли `.avif` без жодного посилання у `.vue`/`.html` видаляються — AVIF лишається лише там, де заміна реально вдалася).
1741
+ - `image` (mdc v1.4 → v1.5): прапорець `--avif` у `lint-image` тепер **заборонений** (інакше `bun run lint` плодив би `.avif` для зображень, що ніде не вживаються); канонічний `lint-image` — `npx @nitra/minify-image --src=. --write`. AVIF-генерацію виконує **виключно** `npx @nitra/cursor fix image`. Секцію «AVIF-імпорти у `.vue`» переписано: тепер вона документує триетапну логіку `check image` — (1) запуск `npx @nitra/minify-image --src=. --write --avif`, (2) авто-заміна raster-посилань у `.vue`/`.html` на `.avif` у кожному workspace-пакеті, (3) прибирання AVIF-сиріт (файли `.avif` без жодного посилання у `.vue`/`.html` видаляються — AVIF лишається лише там, де заміна реально вдалася).
1709
1742
  - `check-image.mjs`: `checkLintImageScript` більше не вимагає `--avif`, натомість фейлить за його наявністю; додано `runAvifGeneration` (best-effort `npx ... --avif`, опт-аут через `NITRA_CURSOR_NO_AVIF_RUN=1` для тестів), `cleanupOrphanAvifs` (видаляє `<...>.avif` без живого посилання), `hasAnyRasterImage`, `resolveImagePath`. `checkVueAvifImportsInPackage` тепер не лише валідує, а й переписує raster-посилання на `.avif` (коли AVIF-двійник реально існує на диску); якщо `.avif` нема — фейл, як раніше. Сканування поширено на `.html` файли (раніше було тільки `.vue`).
1710
1743
  - `tests/check-image.test.mjs`: `CANONICAL_LINT_IMAGE` без `--avif`; кейс «без `--avif`» перейменовано/перекинуто на «з забороненим `--avif`»; додано тести на orphan-cleanup (`.avif` без посилань видаляється) та авто-заміну raster-імпорту, коли `.avif`-сусід реально існує.
1711
1744
 
@@ -1848,7 +1881,7 @@
1848
1881
 
1849
1882
  ### Added
1850
1883
 
1851
- - `ga.mdc` (v1.4) / `check-ga.mjs`: нова перевірка локального [`shellcheck`](https://www.shellcheck.net/) у `PATH`. Без нього `actionlint` (`bunx github-actionlint`) мовчки пропускає shell-перевірки в `run:` блоках, тож локальний `bun lint-ga` дає зелений результат, який падає в CI на `ubuntu-latest` (де shellcheck передвстановлений). `npx @nitra/cursor check ga` тепер `fail` з підказкою встановлення (`brew install shellcheck` / `apt-get install -y shellcheck` / `pacman -S shellcheck`).
1884
+ - `ga.mdc` (v1.4) / `check-ga.mjs`: нова перевірка локального [`shellcheck`](https://www.shellcheck.net/) у `PATH`. Без нього `actionlint` (`bunx github-actionlint`) мовчки пропускає shell-перевірки в `run:` блоках, тож локальний `bun lint-ga` дає зелений результат, який падає в CI на `ubuntu-latest` (де shellcheck передвстановлений). `npx @nitra/cursor fix ga` тепер `fail` з підказкою встановлення (`brew install shellcheck` / `apt-get install -y shellcheck` / `pacman -S shellcheck`).
1852
1885
 
1853
1886
  ### Changed
1854
1887
 
@@ -1864,7 +1897,7 @@
1864
1897
 
1865
1898
  ### Added
1866
1899
 
1867
- - `abie.mdc` (v1.16) / `check-abie.mjs`: нова перевірка `.github/actionlint.yaml`. Якщо файл відсутній — `npx @nitra/cursor check abie` створює його з канонічним вмістом (`self-hosted-runner.labels: ['ua', 'dev', 'ru']`); якщо є — звіряє, що в `self-hosted-runner.labels` присутні мітки `ua`, `dev`, `ru` (порядок, інші мітки й формат лапок дозволені). Експортовано `ABIE_REQUIRED_ACTIONLINT_LABELS`, `parseActionlintSelfHostedLabels`, `abieMissingActionlintLabels`.
1900
+ - `abie.mdc` (v1.16) / `check-abie.mjs`: нова перевірка `.github/actionlint.yaml`. Якщо файл відсутній — `npx @nitra/cursor fix abie` створює його з канонічним вмістом (`self-hosted-runner.labels: ['ua', 'dev', 'ru']`); якщо є — звіряє, що в `self-hosted-runner.labels` присутні мітки `ua`, `dev`, `ru` (порядок, інші мітки й формат лапок дозволені). Експортовано `ABIE_REQUIRED_ACTIONLINT_LABELS`, `parseActionlintSelfHostedLabels`, `abieMissingActionlintLabels`.
1868
1901
 
1869
1902
  ## [1.8.163] - 2026-05-01
1870
1903
 
package/README.md CHANGED
@@ -52,11 +52,11 @@
52
52
 
53
53
  - **Структура Kustomize:** спільне виноситься в **`base`**; вміст **base** відповідає тому, як має виглядати середовище **dev**; окремої директорії **`dev/`** немає — за dev відповідає **`base`**. У інших середовищах — тонкі **overlays** (часто лише **`kustomization.yaml`** і patches / оверрайди).
54
54
  - **Namespace** задається в **`kustomization.yaml`** (`namespace:`), а не через **`metadata.namespace`** у кожному ресурсі; окремі patches лише на зміну **namespace** не потрібні.
55
- - У **Deployment** для кожного контейнера: **`resources`** (перевіряє **`npx @nitra/cursor check k8s`**);
55
+ - У **Deployment** для кожного контейнера: **`resources`** (перевіряє **`npx @nitra/cursor fix k8s`**);
56
56
  - Рядки в **base**, які змінюються в overlays, позначайте коментарем на рядку (узгоджено в команді), наприклад: `# буде замінено через kustomize`.
57
57
  - Після перенесення в **`base`** / overlays **видаляйте** застарілі маніфести та каталоги, які більше не потрібні.
58
58
 
59
- Повний текст правил — у **`k8s.mdc`**; programmatic перевірки — у **`npm/rules/k8s/`**: JS-checks у `fix/<concern>/check.mjs`, rego-policies у `policy/<concern>/<name>.rego` (обидва запускаються через `npx @nitra/cursor check k8s`).
59
+ Повний текст правил — у **`k8s.mdc`**; programmatic перевірки — у **`npm/rules/k8s/`**: JS-checks у `js/<concern>/check.mjs`, rego-policies у `policy/<concern>/<name>.rego` (обидва запускаються через `npx @nitra/cursor fix k8s`).
60
60
 
61
61
  ### v8r і власний каталог схем
62
62
 
@@ -66,8 +66,8 @@
66
66
 
67
67
  ```bash
68
68
  npx @nitra/cursor
69
- npx @nitra/cursor check
70
- npx @nitra/cursor check bun ga
69
+ npx @nitra/cursor fix
70
+ npx @nitra/cursor fix bun ga
71
71
  ```
72
72
 
73
73
  Команда `check` запускає programmatic перевірки з каталогу `scripts/` пакету. Якщо в корені репозиторію вже є `.n-cursor.json`, перед перевірками виконується зчитування конфігу — зокрема додається або виправляється поле `$schema`, якщо воно відсутнє або не збігається з очікуваним URL.
@@ -109,13 +109,13 @@ npm/
109
109
 
110
110
  ### Структура одного правила
111
111
 
112
- Кожне правило `npm/rules/<id>/` ділиться за **технологією реалізації** на три сиблінги — `fix/`, `lint/`, `policy/`:
112
+ Кожне правило `npm/rules/<id>/` ділиться за **технологією реалізації** на три сиблінги — `js/`, `lint/`, `policy/`:
113
113
 
114
114
  ```
115
115
  npm/rules/<id>/
116
116
  ├── <id>.mdc # текст правила (після синку — .cursor/rules/n-<id>.mdc)
117
117
  ├── auto.md # умова автоактивації скілу (опційно)
118
- ├── fix/ # JS для `npx @nitra/cursor check`
118
+ ├── js/ # JS для `npx @nitra/cursor fix`
119
119
  │ └── <concern>/
120
120
  │ ├── check.mjs # діагностика — повертає список violations
121
121
  │ ├── check.test.mjs
@@ -123,7 +123,7 @@ npm/rules/<id>/
123
123
  ├── lint/ # JS, що живить `bun run lint-<id>` (для правил з канонічним lint-скриптом)
124
124
  │ ├── lint.mjs # CLI entry для `n-cursor lint-<id>`
125
125
  │ └── run-*.mjs # допоміжні runner-и (shellcheck, v8r тощо)
126
- └── policy/ # rego для `npx @nitra/cursor check`
126
+ └── policy/ # rego для `npx @nitra/cursor fix`
127
127
  └── <concern>/
128
128
  ├── <concern>.rego # правила (`deny contains msg if …`)
129
129
  ├── <concern>_test.rego # юніт-тести (запускає `bun run lint-rego` → conftest verify)
@@ -134,11 +134,11 @@ npm/rules/<id>/
134
134
 
135
135
  | Що реалізує | Канал виклику | Куди |
136
136
  | ------------------------- | ---------------------------------------------- | ------------------- |
137
- | JS-діагностика + автофікс | `npx @nitra/cursor check` (fix-канал) | `fix/<concern>/` |
137
+ | JS-діагностика + автофікс | `npx @nitra/cursor fix` (fix-канал) | `js/<concern>/` |
138
138
  | JS-orchestrator лінту | `bun run lint-<id>` через `n-cursor lint-<id>` | `lint/` |
139
- | Rego-діагностика | `npx @nitra/cursor check` (fix-канал) | `policy/<concern>/` |
139
+ | Rego-діагностика | `npx @nitra/cursor fix` (fix-канал) | `policy/<concern>/` |
140
140
 
141
- `fix/` і `policy/` обидва живлять fix-канал (`npx @nitra/cursor check` запускає і JS-checks, і rego-policies), але **розділені за технологією**: JS у `fix/`, rego у `policy/`. `lint/` тримає лише JS, що оркеструє `bun run lint-<id>`.
141
+ `js/` і `policy/` обидва живлять fix-канал (`npx @nitra/cursor fix` запускає і JS-checks, і rego-policies), але **розділені за технологією**: JS у `js/`, rego у `policy/`. `lint/` тримає лише JS, що оркеструє `bun run lint-<id>`.
142
142
 
143
143
  ## AGENTS.md у проєкті користувача
144
144
 
@@ -165,7 +165,7 @@ npm/rules/<id>/
165
165
 
166
166
  3. Для секції **Skills** використовуйте блок **`{{#skills}}` … `{{/skills}}`** з тим самим `{{name}}`: рядки формуються з каталогів у `.cursor/skills/` (див. також `buildSkillBulletItems` у `bin/n-cursor.js`).
167
167
 
168
- 4. Для секції **Commands** використовуйте **`{{#commands}}` … `{{/commands}}`**: список генерується з кореневого **`package.json`** (поле `scripts` — відомі ключі у фіксованому порядку, плюс додаткові `lint-*`) та завжди доповнюється рядками про **`npx @nitra/cursor`** і **`npx @nitra/cursor check`**. Логіка винесена в **`npm/scripts/build-agents-commands.mjs`**.
168
+ 4. Для секції **Commands** використовуйте **`{{#commands}}` … `{{/commands}}`**: список генерується з кореневого **`package.json`** (поле `scripts` — відомі ключі у фіксованому порядку, плюс додаткові `lint-*`) та завжди доповнюється рядками про **`npx @nitra/cursor`** і **`npx @nitra/cursor fix`**. Логіка винесена в **`npm/scripts/build-agents-commands.mjs`**.
169
169
 
170
170
  5. Після змін у шаблоні перевірте локально: у тестовому репозиторії з `.n-cursor.json` виконайте `npx`/`bunx` на зібраному пакеті або `node npm/bin/n-cursor.js` з кореня того репозиторію і переконайтеся, що **`AGENTS.md`** виглядає як очікується.
171
171
 
package/bin/n-cursor.js CHANGED
@@ -83,14 +83,13 @@ import {
83
83
  import { detectAutoSkills } from '../scripts/auto-skills.mjs'
84
84
  import { runStopHookCli } from '../scripts/claude-stop-hook.mjs'
85
85
  import { discoverCheckRulesFromCursorRules } from '../scripts/utils/discover-check-rules-from-cursor.mjs'
86
- import { discoverCheckableRules } from '../scripts/utils/discover-checkable-rules.mjs'
86
+ import { listRuleIds } from '../scripts/utils/list-rule-ids.mjs'
87
87
  import { ensureNitraCursorInRootDevDependencies } from '../scripts/ensure-nitra-cursor-dev-dependencies.mjs'
88
88
  import { runLintDocker } from '../rules/docker/lint/lint.mjs'
89
89
  import { runLintGaCli } from '../rules/ga/lint/lint.mjs'
90
90
  import { runLintK8s } from '../rules/k8s/lint/lint.mjs'
91
91
  import { runLintRego } from '../rules/rego/lint/lint.mjs'
92
92
  import { runLintTextCli } from '../rules/text/lint/lint.mjs'
93
- import { runRule } from '../scripts/utils/run-rule.mjs'
94
93
  import { syncClaudeConfig } from '../scripts/sync-claude-config.mjs'
95
94
  import { upgradeNitraCursorToLatestAndBunInstall } from '../scripts/upgrade-nitra-cursor-and-install.mjs'
96
95
  import { runRenameYamlExtensionsCli } from './rename-yaml-extensions.mjs'
@@ -974,91 +973,56 @@ function logRemovedManagedItems(title, basePath, names) {
974
973
  }
975
974
 
976
975
  /**
977
- * Знаходить правила, для яких є хоча б щось прогонне: JS-концерн у `rules/<id>/fix/<concern>/check*.mjs`
978
- * або policy-концерн у `rules/<id>/policy/<concern>/target.json`. Делегує у `discoverCheckableRules`
979
- * див. `scripts/utils/discover-checkable-rules.mjs`.
980
- * @returns {import('../scripts/utils/discover-checkable-rules.mjs').CheckableRule[]} опис правил у алфавітному порядку
981
- */
982
- function discoverCheckScripts() {
983
- return discoverCheckableRules(BUNDLED_RULES_DIR)
984
- }
985
-
986
- /**
987
- * Запускає перевірки: без аргументів — за `*.mdc` у `.cursor/rules/`; з аргументами — лише вказані правила.
988
- * Делегує оркестрацію concern-ів (JS-checks + policy через `runConftestBatch`) у `runRule`;
989
- * сам `runChecks` відповідає лише за фільтр id, агрегацію exit-кодів і shared walk-cache на прогон.
990
- * @param {string[]} requestedRules імена правил; порожній масив — брати з `.cursor/rules/*.mdc`
976
+ * Spawn-wrapper для `npx @nitra/cursor fix [<rule>...]`. Один шлях у коді: для кожного правила
977
+ * робить `bun rules/<id>/fix.mjs` як окремий процес. Сам `fix.mjs` читає `.n-cursor.json`,
978
+ * перевіряє whitelist (`runRuleCli`) і друкує per-rule summary.
979
+ *
980
+ * Без аргументів — discover з `.cursor/rules/*.mdc` у проекті-споживачі.
981
+ * @param {string[]} requestedRules імена правил; порожній масив — discovery з `.cursor/rules/`
991
982
  * @returns {Promise<void>}
992
983
  */
993
- async function runChecks(requestedRules) {
994
- const allRules = await discoverCheckScripts()
995
- if (allRules.length === 0) {
996
- console.error('❌ Не знайдено жодного check-скрипта у пакеті')
997
- throw new Error('No check scripts found')
998
- }
999
-
1000
- const root = cwd()
1001
- const legacyConfigPath = join(root, 'nitra-cursor.json')
1002
- if (existsSync(join(root, CONFIG_FILE)) || existsSync(legacyConfigPath)) {
1003
- try {
1004
- await readConfig()
1005
- } catch (error) {
1006
- console.error(`❌ ${error.message}`)
1007
- throw error
1008
- }
984
+ async function runFixCommand(requestedRules) {
985
+ const available = await listRuleIds(BUNDLED_RULES_DIR)
986
+ if (available.length === 0) {
987
+ console.error('❌ Не знайдено жодного правила у пакеті')
988
+ throw new Error('No rules found')
1009
989
  }
1010
990
 
1011
- const available = allRules.map(r => r.id)
1012
- let idsToCheck
991
+ let idsToRun
1013
992
  if (requestedRules.length > 0) {
1014
- idsToCheck = requestedRules
993
+ const unknown = requestedRules.filter(id => !available.includes(id))
994
+ if (unknown.length > 0) {
995
+ console.error(`❌ Невідомі правила: ${unknown.join(', ')}`)
996
+ console.log(` Доступні: ${available.join(', ')}`)
997
+ throw new Error(`Unknown rules: ${unknown.join(', ')}`)
998
+ }
999
+ idsToRun = requestedRules
1015
1000
  } else {
1016
1001
  const mdcFiles = await listProjectRulesMdcFiles()
1017
1002
  if (mdcFiles.length === 0) {
1018
1003
  throw new Error(
1019
- `Немає файлів *.mdc у ${RULES_DIR}/. Запустіть \`npx ${PACKAGE_NAME}\` або вкажіть правила: \`npx ${PACKAGE_NAME} check bun ga\``
1004
+ `Немає файлів *.mdc у ${RULES_DIR}/. Запустіть \`npx ${PACKAGE_NAME}\` або вкажіть правила: \`npx ${PACKAGE_NAME} fix bun ga\``
1020
1005
  )
1021
1006
  }
1022
- idsToCheck = discoverCheckRulesFromCursorRules(available, mdcFiles)
1023
- if (idsToCheck.length === 0) {
1007
+ idsToRun = discoverCheckRulesFromCursorRules(available, mdcFiles)
1008
+ if (idsToRun.length === 0) {
1024
1009
  console.log(
1025
- `\n🔍 ${PACKAGE_NAME} check — у ${RULES_DIR}/ немає правил з programmatic перевіркою ` +
1026
- `(відповідного check-*.mjs або policy/<name>/target.json у пакеті). Нічого не запущено.\n`
1010
+ `\n🔍 ${PACKAGE_NAME} fix — у ${RULES_DIR}/ немає правил з programmatic перевіркою ` +
1011
+ `(відповідного fix.mjs у пакеті). Нічого не запущено.\n`
1027
1012
  )
1028
1013
  return
1029
1014
  }
1030
1015
  }
1031
1016
 
1032
- const unknown = idsToCheck.filter(id => !available.includes(id))
1033
- if (unknown.length > 0) {
1034
- console.error(`❌ Невідомі правила: ${unknown.join(', ')}`)
1035
- console.log(` Доступні: ${available.join(', ')}`)
1036
- throw new Error(`Unknown rules: ${unknown.join(', ')}`)
1037
- }
1038
-
1039
- console.log(`\n🔍 ${PACKAGE_NAME} check — перевірка правил (${idsToCheck.length})\n`)
1040
-
1041
- const ruleMap = new Map(allRules.map(r => [r.id, r]))
1042
- /** @type {Map<string, Promise<string[]>>} shared walk-cache (cross-concern, cross-rule у межах одного прогону) */
1043
- const walkCache = new Map()
1044
1017
  let totalFailed = 0
1045
-
1046
- for (const id of idsToCheck) {
1047
- try {
1048
- const code = await runRule(ruleMap.get(id), BUNDLED_RULES_DIR, walkCache)
1049
- if (code !== 0) totalFailed++
1050
- } catch (error) {
1051
- console.log(` ❌ Помилка виконання: ${error.message}`)
1052
- totalFailed++
1053
- }
1054
- console.log()
1018
+ for (const id of idsToRun) {
1019
+ const fixPath = join(BUNDLED_RULES_DIR, id, 'fix.mjs')
1020
+ const result = spawnSync('bun', [fixPath], { stdio: 'inherit' })
1021
+ if (result.status !== 0) totalFailed++
1055
1022
  }
1056
1023
 
1057
- const passedCount = idsToCheck.length - totalFailed
1058
- console.log(`✨ Результат: ${passedCount}/${idsToCheck.length} правил без зауважень\n`)
1059
-
1060
1024
  if (totalFailed > 0) {
1061
- throw new Error(`${totalFailed} з ${idsToCheck.length} правил мають проблеми`)
1025
+ throw new Error(`${totalFailed} з ${idsToRun.length} правил мають проблеми`)
1062
1026
  }
1063
1027
  }
1064
1028
 
@@ -1257,8 +1221,15 @@ const [command, ...args] = process.argv.slice(2)
1257
1221
  try {
1258
1222
  await ensureNitraCursorInRootDevDependencies(cwd())
1259
1223
  switch (command) {
1224
+ case 'fix': {
1225
+ await runFixCommand(args)
1226
+
1227
+ break
1228
+ }
1260
1229
  case 'check': {
1261
- await runChecks(args)
1230
+ // Backward-compatibility alias. Перейменовано на `fix` у 1.13.84 (узгоджено з ім'ям файла `rules/<id>/fix.mjs`).
1231
+ console.warn(`⚠️ Команда \`check\` deprecated — використовуйте \`fix\` (\`npx ${PACKAGE_NAME} fix [<rule>...]\`)`)
1232
+ await runFixCommand(args)
1262
1233
 
1263
1234
  break
1264
1235
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.13.82",
3
+ "version": "1.13.84",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",