@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
@@ -133,12 +133,12 @@ KVCMS_URL=http://kvcms-hl.ua-apruv.svc.abie-ua.internal:8080
133
133
 
134
134
  `<namespace>` (наприклад `dev-apruv` / `ua-apruv`) — `metadata.name` цільового namespace після kustomize-overlay для відповідного середовища; `<service>` — `metadata.name` headless Service (`-hl`) того сервісу, до якого йде URL.
135
135
 
136
- **Перевірка `fix/env_dns/check.mjs`** сканує всі `*.env` файли, basename яких збігається з `dev.env` / `ua.env` (з провідною крапкою чи без), знаходить **усі** internal URL (`http://<svc>.<ns>.svc.<dns>` — як для Hasura-ендпоінта, так і для KVCMS чи будь-якого іншого) і вимагає, щоб для кожного:
136
+ **Перевірка `js/env_dns/check.mjs`** сканує всі `*.env` файли, basename яких збігається з `dev.env` / `ua.env` (з провідною крапкою чи без), знаходить **усі** internal URL (`http://<svc>.<ns>.svc.<dns>` — як для Hasura-ендпоінта, так і для KVCMS чи будь-якого іншого) і вимагає, щоб для кожного:
137
137
 
138
138
  - DNS-суфікс відповідав env: `abie-dev.internal` / `abie-ua.internal`;
139
139
  - namespace починався з `dev-` / `ua-` відповідно.
140
140
 
141
- Загальне правило про **внутрішній** URL (не публічний домен) для `HASURA_GRAPHQL_ENDPOINT` лишається у **`hasura.mdc`** (для nitra і abie) — `check-hasura.mjs` приймає кластерний DNS-формат `<cluster>.internal`.
141
+ Загальне правило про **внутрішній** URL (не публічний домен) для `HASURA_GRAPHQL_ENDPOINT` лишається у **`hasura.mdc`** (для nitra і abie) — `rules/hasura/fix.mjs` приймає кластерний DNS-формат `<cluster>.internal`.
142
142
 
143
143
  ## `@nitra/abie-docs` у `devDependencies`
144
144
 
@@ -160,7 +160,7 @@ bun add -d @nitra/abie-docs
160
160
 
161
161
  ## Швидкий gate через conftest (Rego)
162
162
 
163
- Підмножину пер-документних правил продубльовано як rego-полісі у **`npm/rules/abie/policy/`** (запускається через **`bun run lint-rego`** для `*_test.rego` юніт-тестів і через **`npx @nitra/cursor check abie`** для прогону по реальних YAML — деталі в **conftest.mdc** / **n-rego.mdc**). JS у **`fix/<concern>/check.mjs`** authoritative — rego тільки швидкий gate для одиничного маніфеста (зокрема через IDE-розширення `tsandall.opa`).
163
+ Підмножину пер-документних правил продубльовано як rego-полісі у **`npm/rules/abie/policy/`** (запускається через **`bun run lint-rego`** для `*_test.rego` юніт-тестів і через **`npx @nitra/cursor fix abie`** для прогону по реальних YAML — деталі в **conftest.mdc** / **n-rego.mdc**). JS у **`js/<concern>/check.mjs`** authoritative — rego тільки швидкий gate для одиничного маніфеста (зокрема через IDE-розширення `tsandall.opa`).
164
164
 
165
165
  Пакети (директорія в **`npm/policy/abie/`** → namespace → що перевіряє):
166
166
 
@@ -170,12 +170,12 @@ bun add -d @nitra/abie-docs
170
170
  - **`clean_merged_ignore_branches/`** → `abie.clean_merged_ignore_branches` — у workflow `.github/workflows/clean-merged-branch.yml` крок з `uses: phpdocker-io/github-actions-delete-abandoned-branches` має `with.ignore_branches`, що містить токени `dev,ua` (case-insensitive). **Цільові файли:** `.github/workflows/clean-merged-branch.yml`.
171
171
  - **`package_json_docs/`** → `abie.package_json_docs` — у кореневому `package.json` `devDependencies` має містити `@nitra/abie-docs` (presence-only, версію не фіксуємо). **Цільові файли:** `package.json`.
172
172
 
173
- Cross-file / FS-логіка лишається у JS-частинах (`fix/<concern>/check.mjs`) — Rego не читає файлову систему й не робить cross-document резолюцію:
173
+ Cross-file / FS-логіка лишається у JS-частинах (`js/<concern>/check.mjs`) — Rego не читає файлову систему й не робить cross-document резолюцію:
174
174
 
175
- - парність HCP↔Deployment у каталозі та modeline `hc.yaml` — `fix/hc_pairing/check.mjs`;
176
- - валідація ua-overlay JSON6902 patches на HTTPRoute + аналіз cross-namespace `backendRefs` у пакетах — `fix/ua_http_route/check.mjs`;
177
- - ua-overlay JSON6902 patch на `Deployment.nodeSelector` (`preem: false`) — `fix/ua_node_selector/check.mjs`;
178
- - env→cluster DNS (`*.dev.env` / `*.ua.env`) — `fix/env_dns/check.mjs`;
179
- - скан артефактів Firebase Hosting у підкаталогах першого рівня — `fix/firebase_hosting/check.mjs`.
175
+ - парність HCP↔Deployment у каталозі та modeline `hc.yaml` — `js/hc_pairing/check.mjs`;
176
+ - валідація ua-overlay JSON6902 patches на HTTPRoute + аналіз cross-namespace `backendRefs` у пакетах — `js/ua_http_route/check.mjs`;
177
+ - ua-overlay JSON6902 patch на `Deployment.nodeSelector` (`preem: false`) — `js/ua_node_selector/check.mjs`;
178
+ - env→cluster DNS (`*.dev.env` / `*.ua.env`) — `js/env_dns/check.mjs`;
179
+ - скан артефактів Firebase Hosting у підкаталогах першого рівня — `js/firebase_hosting/check.mjs`.
180
180
 
181
181
  Точна звірка `targetRef.name` HealthCheckPolicy з суфіксом `-hl` обчислюється з `hcp.metadata.name` і живе у Rego (`abie.health_check_policy`); за конвенцією `hcp.metadata.name` дорівнює `<deployment.name>`, тому окремий cross-file lookup до маніфесту Deployment не потрібен.
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -2,7 +2,7 @@
2
2
  # `spec.template.spec.nodeSelector.preem` зі значенням, що вважається істинним
3
3
  # (boolean `true` або рядок `"true"` без урахування регістру). Overlay ua далі
4
4
  # підміняє селектор JSON6902-патчем на `preem: false`
5
- # (див. `fix/ua_node_selector/check.mjs`).
5
+ # (див. `js/ua_node_selector/check.mjs`).
6
6
  #
7
7
  # Запуск (локально, лише для одного base-YAML з Deployment):
8
8
  # conftest test path/to/k8s/base/deployment.yaml \
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # Cross-file gating: шлях `…/k8s/.../base/…` фільтрується через
13
13
  # `policy/base_deployment_preem/target.json` (glob). Rule-level applies-гейт —
14
- # `fix/applies/check.mjs` (поле `rules` у `.n-cursor.json`).
14
+ # `js/applies/check.mjs` (поле `rules` у `.n-cursor.json`).
15
15
  #
16
16
  # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
17
17
  # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
@@ -18,8 +18,8 @@
18
18
  #
19
19
  # Cross-file gating: glob по `hc.yaml` у k8s-дереві — у
20
20
  # `policy/health_check_policy/target.json`. FS-парність HCP↔Deployment та
21
- # modeline `hc.yaml` — `fix/hc_pairing/check.mjs`. Rule-level applies-гейт —
22
- # `fix/applies/check.mjs`.
21
+ # modeline `hc.yaml` — `js/hc_pairing/check.mjs`. Rule-level applies-гейт —
22
+ # `js/applies/check.mjs`.
23
23
  #
24
24
  # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
25
25
  # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
@@ -8,7 +8,7 @@
8
8
  #
9
9
  # Cross-file gating (саме шлях `…/k8s/.../base/...` визначає, чи застосовувати
10
10
  # правило) задає glob у `policy/http_route_base/target.json`. Тут — лише
11
- # валідація вмісту `spec.hostnames`. Rule-level applies-гейт — `fix/applies/check.mjs`.
11
+ # валідація вмісту `spec.hostnames`. Rule-level applies-гейт — `js/applies/check.mjs`.
12
12
  #
13
13
  # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
14
14
  # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { dirname, relative } from 'node:path'
10
10
 
11
- import { pathHasK8sSegment } from '../../k8s/fix/manifests/check.mjs'
11
+ import { pathHasK8sSegment } from '../../k8s/js/manifests/check.mjs'
12
12
  import { walkDir } from '../../../scripts/utils/walkDir.mjs'
13
13
  import { isDeploymentDoc, readAndParseYamlDocs } from './yaml.mjs'
14
14
 
package/rules/adr/adr.mdc CHANGED
@@ -95,7 +95,7 @@ docs/adr/
95
95
  └── hooks.json # Cursor Agent stop-hooks для тих самих скриптів
96
96
  ```
97
97
 
98
- `.gitignore` у корені проєкту повинен містити базові рядки (`node_modules/`, `dist/`, `*.secret`) і патерни для ADR Stop-hook (**`.claude/hooks/*.log`**, `.claude/hooks/.normalize-state`, `.claude/hooks/.normalize.lock`). Канонічний фрагмент (дописується `npx @nitra/cursor`, коли правило `adr` увімкнене): [.gitignore.snippet](./fix/hooks/template/.gitignore.snippet).
98
+ `.gitignore` у корені проєкту повинен містити базові рядки (`node_modules/`, `dist/`, `*.secret`) і патерни для ADR Stop-hook (**`.claude/hooks/*.log`**, `.claude/hooks/.normalize-state`, `.claude/hooks/.normalize.lock`). Канонічний фрагмент (дописується `npx @nitra/cursor`, коли правило `adr` увімкнене): [.gitignore.snippet](./js/hooks/template/.gitignore.snippet).
99
99
 
100
100
  ## Stop-hook у `.claude/settings.json`
101
101
 
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -116,7 +116,7 @@ async function checkHookScript(reporter, scriptName) {
116
116
  function checkProjectSettings(reporter) {
117
117
  const { pass, fail } = reporter
118
118
  if (existsSync(PROJECT_SETTINGS_PATH)) {
119
- pass(`${PROJECT_SETTINGS_PATH} є (Stop-hook перевіряє npx @nitra/cursor check → adr.settings_json)`)
119
+ pass(`${PROJECT_SETTINGS_PATH} є (Stop-hook перевіряє npx @nitra/cursor fix → adr.settings_json)`)
120
120
  } else {
121
121
  fail(`${PROJECT_SETTINGS_PATH} не існує — запусти \`npx @nitra/cursor\``)
122
122
  }
package/rules/bun/bun.mdc CHANGED
@@ -72,4 +72,4 @@ FROM oven/bun:alpine AS build-env
72
72
 
73
73
  Якщо в **`.n-cursor.json`** у масиві **`rules`** є **`docker`**, у кореневому `package.json` **обов'язково** скрипт **`lint-docker`** (див. **`docker.mdc`**) і рядок **`bun run lint-docker`** у **`lint`**. Якщо є **`k8s`** — **обов'язково** **`lint-k8s`** і **`bun run lint-k8s`** у **`lint`** (див. **`k8s.mdc`**).
74
74
 
75
- **Зворотній інваріант:** якщо правила **немає** в `rules` (або воно явно перенесене в **`disable-rules`**), скрипту **`lint-<id>`** у кореневому `package.json` бути **не може**, і ланцюжок агрегованого **`scripts.lint`** не має містити **`bun run lint-<id>`**. Інакше `bun run lint` падатиме на вимкненому правилі — `n-cursor lint-<id>` ігнорує `.n-cursor.json` і обходить дерево незалежно від `rules`/`disable-rules`. Для скриптів із кількома власниками (як **`lint-image`** — обслуговує і **`image-avif`**, і **`image-compress`**) скрипт лишається дозволеним, поки активний **хоч один** власник; зворотній інваріант тригериться лише коли в `rules` немає **жодного** з них. Перевірка — **`npx @nitra/cursor check bun`**.
75
+ **Зворотній інваріант:** якщо правила **немає** в `rules` (або воно явно перенесене в **`disable-rules`**), скрипту **`lint-<id>`** у кореневому `package.json` бути **не може**, і ланцюжок агрегованого **`scripts.lint`** не має містити **`bun run lint-<id>`**. Інакше `bun run lint` падатиме на вимкненому правилі — `n-cursor lint-<id>` ігнорує `.n-cursor.json` і обходить дерево незалежно від `rules`/`disable-rules`. Для скриптів із кількома власниками (як **`lint-image`** — обслуговує і **`image-avif`**, і **`image-compress`**) скрипт лишається дозволеним, поки активний **хоч один** власник; зворотній інваріант тригериться лише коли в `rules` немає **жодного** з них. Перевірка — **`npx @nitra/cursor fix bun`**.
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -183,7 +183,7 @@ export async function check() {
183
183
  }
184
184
 
185
185
  if (existsSync('bunfig.toml')) {
186
- pass('bunfig.toml є (структуру перевіряє npx @nitra/cursor check → bun.bunfig)')
186
+ pass('bunfig.toml є (структуру перевіряє npx @nitra/cursor fix → bun.bunfig)')
187
187
  } else {
188
188
  fail('Відсутній bunfig.toml — створи з [install] linker = "hoisted" (bun.mdc)')
189
189
  }
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -1,4 +1,4 @@
1
- # Порт перевірки версії `@capacitor/core` з `npm/scripts/check-capacitor.mjs`
1
+ # Порт перевірки версії `@capacitor/core` з `npm/scripts/rules/capacitor/fix.mjs`
2
2
  # (capacitor.mdc) — мінімальна мажорна версія = 8.
3
3
  #
4
4
  # Запуск (локально, у пакеті з Capacitor):
@@ -10,8 +10,8 @@
10
10
  # Підтримує `^8.0.0`, `>=8`, `8.x`, `workspace:*` тощо.
11
11
  #
12
12
  # Цей порт спрощує JS-логіку — повна семантика OR-діапазонів (`a || b`) і нижня
13
- # межа діапазону лишається в JS (`check-capacitor.mjs`: `capacitorVersionRangeMinMajor`).
14
- # JS-перевірка лишилась authoritative й бігає через `npx @nitra/cursor check capacitor`;
13
+ # межа діапазону лишається в JS (`rules/capacitor/fix.mjs`: `capacitorVersionRangeMinMajor`).
14
+ # JS-перевірка лишилась authoritative й бігає через `npx @nitra/cursor fix capacitor`;
15
15
  # ця Rego — швидкий gate для одиничного `package.json` (наприклад через IDE).
16
16
  #
17
17
  # FS-сканування пакетів через workspaces, iOS-специфічна логіка (Podfile), вибір
@@ -10,7 +10,7 @@ alwaysApply: true
10
10
 
11
11
  1. **`version`** у `<ws>/package.json` (або `[project].version` у `pyproject.toml`) → **patch +1** відносно `git show HEAD:<ws>/package.json`, якщо ще не піднято.
12
12
  2. **`CHANGELOG.md`** того workspace → **нова** секція `## [версія] - YYYY-MM-DD` **зверху** (не bullet-и в стару версію).
13
- 3. **`npx @nitra/cursor check changelog`** (у репо `@nitra/cursor`: `bun ./npm/bin/n-cursor.js check changelog`) → exit **`0`**.
13
+ 3. **`npx @nitra/cursor fix changelog`** (у репо `@nitra/cursor`: `bun ./npm/bin/n-cursor.js check changelog`) → exit **`0`**.
14
14
 
15
15
  **Тригер шляхів (приклади):** `npm/**`, `packages/foo/**`, будь-який каталог з власним `package.json` / `pyproject.toml`, куди потрапили правки.
16
16
 
@@ -43,7 +43,7 @@ alwaysApply: true
43
43
 
44
44
  **Вимагають bump + нову секцію CHANGELOG** — усі інші зміни в каталозі workspace (код, rego, правила, скіли, конфіги, тести тощо). Виняток `.cursor/` / `.claude/` **не** поширюється на джерело правил у репо `@nitra/cursor` — воно лежить під `npm/`, тож зміни в ньому далі вимагають bump.
45
45
 
46
- Перевірка програмна (`changelog/fix/consistency/check.mjs`).
46
+ Перевірка програмна (`changelog/js/consistency/check.mjs`).
47
47
 
48
48
  ## Дві моделі бази порівняння
49
49
 
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
package/rules/ci4/ci4.mdc CHANGED
@@ -30,7 +30,7 @@ RAG витягує **фрагменти**, не цілі документи. Т
30
30
 
31
31
  ## Docs-as-Code
32
32
 
33
- Документація живе у Git поруч із кодом, проходить **той самий Code Review**, версіонується і автоматично перевіряється у CI (лінтери Markdown, валідатори посилань, `npx @nitra/cursor check`). Биті посилання й документація, що «не компілюється», — **блокуючий баг**, не косметика.
33
+ Документація живе у Git поруч із кодом, проходить **той самий Code Review**, версіонується і автоматично перевіряється у CI (лінтери Markdown, валідатори посилань, `npx @nitra/cursor fix`). Биті посилання й документація, що «не компілюється», — **блокуючий баг**, не косметика.
34
34
 
35
35
  ## Трасування як документація недетермінованої поведінки
36
36
 
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -7,7 +7,7 @@ alwaysApply: false
7
7
 
8
8
  # Docker — hadolint
9
9
 
10
- Для образів з Docker Hub — **`oven/bun`**, **`alpine`**, **`nginxinc/nginx-unprivileged`**, **`node`** — у **`FROM`** треба вказувати дзеркало GCR, а не pull напряму з Hub: **`mirror.gcr.io/oven/bun`**, **`mirror.gcr.io/library/alpine`**, **`mirror.gcr.io/nginxinc/nginx-unprivileged`**, **`mirror.gcr.io/library/node`**. Перевіряє **`check-docker.mjs`**, деталі в **`npm/rules/docker/fix/lint/docker-mirror.mjs`**.
10
+ Для образів з Docker Hub — **`oven/bun`**, **`alpine`**, **`nginxinc/nginx-unprivileged`**, **`node`** — у **`FROM`** треба вказувати дзеркало GCR, а не pull напряму з Hub: **`mirror.gcr.io/oven/bun`**, **`mirror.gcr.io/library/alpine`**, **`mirror.gcr.io/nginxinc/nginx-unprivileged`**, **`mirror.gcr.io/library/node`**. Перевіряє **`rules/docker/fix.mjs`**, деталі в **`npm/rules/docker/js/lint/docker-mirror.mjs`**.
11
11
 
12
12
  Також Dockerfile/Containerfile **має бути multistage build**: окремий build stage (залежності/компіляція) і окремий runtime stage. У фінальному stage дозволені лише мінімальні базові образи:
13
13
 
@@ -90,33 +90,33 @@ CMD ["./app"]
90
90
 
91
91
  ## Область
92
92
 
93
- - Усі файли з іменем **`Dockerfile`** або **`Dockerfile.*`** (наприклад `Dockerfile.prod`) у репозиторії, крім ігнорованих каталогів (`node_modules`, `.git`, `dist`, …) — як у **`check-docker.mjs`**.
93
+ - Усі файли з іменем **`Dockerfile`** або **`Dockerfile.*`** (наприклад `Dockerfile.prod`) у репозиторії, крім ігнорованих каталогів (`node_modules`, `.git`, `dist`, …) — як у **`rules/docker/fix.mjs`**.
94
94
  - Також скрипт перевірки обробляє **`Containerfile`** та **`Containerfile.*`** (Podman / альтернативні імена), навіть якщо glob правила спрацьовує переважно на `Dockerfile*`.
95
95
 
96
96
  ## lint-docker
97
97
 
98
98
  CLI **`hadolint`** приймає лише **явні шляхи** (`[DOCKERFILE...]` у **`hadolint --help`**); обхід репозиторію робить CLI **`n-cursor lint-docker`** (реалізація — **`npm/rules/docker/js/run.mjs`**).
99
99
 
100
- **Область lint-docker (вужча, ніж `check docker`):** лише файли з іменем **`Dockerfile`** та **`*.Dockerfile`** (суфікс **`.dockerfile`** без урахування регістру, наприклад **`api.Dockerfile`**). Файли **`Dockerfile.prod`**, **`Containerfile`** тощо **не** входять у **`lint-docker`**; їх ловить **`check docker`** (`check-docker.mjs`).
100
+ **Область lint-docker (вужча, ніж `check docker`):** лише файли з іменем **`Dockerfile`** та **`*.Dockerfile`** (суфікс **`.dockerfile`** без урахування регістру, наприклад **`api.Dockerfile`**). Файли **`Dockerfile.prod`**, **`Containerfile`** тощо **не** входять у **`lint-docker`**; їх ловить **`check docker`** (`rules/docker/fix.mjs`).
101
101
 
102
- Обхід: **`walkDir`** з тими самими пропусками каталогів, що й **`check-docker.mjs`**. Виклик **`hadolint`**: **`PATH`**, інакше **`docker run`** — спільна логіка **`npm/rules/docker/fix/lint/docker-hadolint.mjs`**.
102
+ Обхід: **`walkDir`** з тими самими пропусками каталогів, що й **`rules/docker/fix.mjs`**. Виклик **`hadolint`**: **`PATH`**, інакше **`docker run`** — спільна логіка **`npm/rules/docker/js/lint/docker-hadolint.mjs`**.
103
103
 
104
104
  - Канон `package.json#scripts.lint-docker`: [package.json.snippet.json](./policy/package_json/template/package.json.snippet.json)
105
105
 
106
- Якщо правило **`docker`** підключено в **`.n-cursor.json`** (масив **`rules`**), у **кореневому** `package.json` **обов'язково** мають бути скрипт **`lint-docker`** і виклик **`bun run lint-docker`** у агрегованому **`lint`** (див. **`bun.mdc`**). Це перевіряє **`npx @nitra/cursor check bun`**.
106
+ Якщо правило **`docker`** підключено в **`.n-cursor.json`** (масив **`rules`**), у **кореневому** `package.json` **обов'язково** мають бути скрипт **`lint-docker`** і виклик **`bun run lint-docker`** у агрегованому **`lint`** (див. **`bun.mdc`**). Це перевіряє **`npx @nitra/cursor fix bun`**.
107
107
 
108
108
  Додай workflow **`.github/workflows/lint-docker.yml`** (гілки **`dev`** і **`main`**, лише **`.yml`**, узгоджено з **`ga.mdc`**):
109
109
 
110
110
  - Канон: [lint-docker.yml.snippet.yml](./policy/lint_docker_yml/template/lint-docker.yml.snippet.yml)
111
111
 
112
- Узгоджуй версію hadolint **v2.12.0** з **`HADOLINT_IMAGE`** у **`npm/rules/docker/fix/lint/docker-hadolint.mjs`**.
112
+ Узгоджуй версію hadolint **v2.12.0** з **`HADOLINT_IMAGE`** у **`npm/rules/docker/js/lint/docker-hadolint.mjs`**.
113
113
 
114
114
  Кореневий скрипт **`lint`** (див. **`n-bun.mdc`**) **обов'язково** містить **`bun run lint-docker`**, коли в проєкті підключено правило **`docker`**.
115
115
 
116
116
  ## Запуск
117
117
 
118
118
  1. **`bun run lint-docker`** — **`run-docker.mjs`**: **`Dockerfile`** та **`*.Dockerfile`** (див. **`lint-docker`**); у CI встанови hadolint (приклад у workflow).
119
- 2. **`npx @nitra/cursor check docker`** — **`check-docker.mjs`**, виклик hadolint як у **`docker-hadolint.mjs`** (**`PATH`** або **`docker run`** з **`hadolint/hadolint:v2.12.0`**).
119
+ 2. **`npx @nitra/cursor fix docker`** — **`rules/docker/fix.mjs`**, виклик hadolint як у **`docker-hadolint.mjs`** (**`PATH`** або **`docker run`** з **`hadolint/hadolint:v2.12.0`**).
120
120
  3. Кореневий **`.hadolint.yaml`**: вимкнення правил, trusted registries — [документація](https://github.com/hadolint/hadolint#configure). Щоб не додавати **`# hadolint ignore=DL3007`** у кожному **`FROM`** з **`:latest`**, у корені репозиторію задати глобально:
121
121
 
122
122
  ```yaml title=".hadolint.yaml"
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -5,12 +5,12 @@
5
5
  * check docker, не обробляються Dockerfile.*, Containerfile тощо — лише канонічне ім’я
6
6
  * Dockerfile та варіанти виду app.Dockerfile (регістр суфікса не важливий).
7
7
  *
8
- * Виклик hadolint — через ../fix/lint/docker-hadolint.mjs (PATH або docker run).
8
+ * Виклик hadolint — через ../js/lint/docker-hadolint.mjs (PATH або docker run).
9
9
  */
10
10
  import { basename } from 'node:path'
11
11
 
12
12
  import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
13
- import { lintDockerfileWithHadolint, posixRel } from '../fix/lint/docker-hadolint.mjs'
13
+ import { lintDockerfileWithHadolint, posixRel } from '../js/lint/docker-hadolint.mjs'
14
14
  import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
15
15
  import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
16
16
  import { walkDir } from '../../../scripts/utils/walkDir.mjs'
@@ -3,7 +3,7 @@
3
3
  # Канон надходить через --data: { "template": { "snippet": ... } }
4
4
  # Перевіряє ЛИШЕ зміст значення `scripts.lint-docker`, якщо ключ присутній.
5
5
  # Умовну обовʼязковість (правило `docker` у `.n-cursor.json` → `scripts.lint-docker`
6
- # зобовʼязаний існувати) перевіряє `check-bun.mjs` через cross-file логіку.
6
+ # зобовʼязаний існувати) перевіряє `rules/bun/fix.mjs` через cross-file логіку.
7
7
  package docker.package_json
8
8
 
9
9
  import rego.v1
@@ -16,7 +16,7 @@ bun add -d @nitra/efes-docs
16
16
 
17
17
  ## Швидкий gate через conftest (Rego)
18
18
 
19
- Пер-документні перевірки efes — rego-полісі у **`npm/rules/efes/policy/`** (запускається через **`npx @nitra/cursor check efes`**; синтаксичний lint — через **`bun run lint-rego`**). Деталі шаблону — у **conftest.mdc** / **n-rego.mdc**.
19
+ Пер-документні перевірки efes — rego-полісі у **`npm/rules/efes/policy/`** (запускається через **`npx @nitra/cursor fix efes`**; синтаксичний lint — через **`bun run lint-rego`**). Деталі шаблону — у **conftest.mdc** / **n-rego.mdc**.
20
20
 
21
21
  Пакети (директорія в **`npm/rules/efes/policy/`** → namespace → що перевіряє):
22
22
 
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -4,7 +4,7 @@ alwaysApply: true
4
4
  version: '1.0'
5
5
  ---
6
6
 
7
- Правило про **зворотний звʼязок до пакета `@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`. Саме тут видно, що в пакеті недопрацьовано: неоднозначна інструкція, відсутня перевірка, хибне спрацювання, порушення без автофіксу. Ця інформація цінна для розробників пакета, але без явного кроку зникає разом із сесією.
7
+ Правило про **зворотний звʼязок до пакета `@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`. Саме тут видно, що в пакеті недопрацьовано: неоднозначна інструкція, відсутня перевірка, хибне спрацювання, порушення без автофіксу. Ця інформація цінна для розробників пакета, але без явного кроку зникає разом із сесією.
8
8
 
9
9
  ## Коли застосовувати
10
10
 
@@ -17,7 +17,7 @@ version: '1.0'
17
17
  **Тертя** — усе, що ускладнило роботу скілу й стосується самого пакета `@nitra/cursor`, а не коду користувацького проєкту:
18
18
 
19
19
  - неоднозначна чи неповна інструкція в `SKILL.md` або `.mdc`;
20
- - правило вимагає поведінку, яку можна перевірити програмно, але `check-*.mjs` для неї немає;
20
+ - правило вимагає поведінку, яку можна перевірити програмно, але програмної перевірки (`rules/<id>/js/<concern>/check.mjs` або `rules/<id>/policy/<concern>/*.rego`) для неї немає;
21
21
  - хибне спрацювання перевірки (false positive);
22
22
  - порушення, яке правило вимагає виправляти вручну, хоча реальний автофікс можливий;
23
23
  - повторюваний патерн, який варто закодувати в правило чи скіл.
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -2,13 +2,13 @@
2
2
  * CLI-обгортка над канонічним `lint-ga` (ga.mdc): робить preflight на `shellcheck`, `uv` (для `uvx`)
3
3
  * і `conftest` (для rego-полісі у `check-ga`),
4
4
  * тоді послідовно виконує `bunx github-actionlint`, `uvx zizmor --offline --collect=workflows .` і
5
- * делегує до `check-ga.mjs::check()` — там і Rego-частина (через `runConftestBatch`),
5
+ * делегує до `rules/ga/fix.mjs::check()` — там і Rego-частина (через `runConftestBatch`),
6
6
  * і JS cross-file перевірки правил `ga.mdc`.
7
7
  *
8
8
  * Plan B-патерн (rego-authoritative): Rego-полісі (`npm/policy/ga/`) запускає вже сам
9
- * `check-ga.mjs::check()` як перший крок — `lint-ga.mjs` про це не знає. Раніше `lint-ga.mjs` сам
9
+ * `rules/ga/fix.mjs::check()` як перший крок — `lint-ga.mjs` про це не знає. Раніше `lint-ga.mjs` сам
10
10
  * спавнив conftest для `ga.<name>` per-workflow і `ga.workflow_common` (PoC); тепер ця логіка
11
- * централізована у `check-ga.mjs`, тож одне джерело істини, без дублювання між
11
+ * централізована у `rules/ga/fix.mjs`, тож одне джерело істини, без дублювання між
12
12
  * `lint-ga` і `npx \@nitra/cursor check ga`.
13
13
  *
14
14
  * Без preflight `actionlint` (через `bunx github-actionlint`) мовчки пропускає shell-перевірки в
@@ -18,7 +18,7 @@
18
18
  * `uv` потрібен для `uvx zizmor`. Якщо його нема — `uvx zizmor` падає неінформативно («command not
19
19
  * found»); підказка з командою встановлення коротша й корисніша.
20
20
  *
21
- * `conftest` потрібен для `check-ga.mjs::runAllGaRego` (`runConftestBatch`). Без preflight крок
21
+ * `conftest` потрібен для `rules/ga/fix.mjs::runAllGaRego` (`runConftestBatch`). Без preflight крок
22
22
  * check-ga кидає виняток, який глобальний `catch` у `bin/n-cursor.js` раніше ковтав без логу —
23
23
  * локально це виглядало як мовчазний exit 1.
24
24
  *
@@ -26,7 +26,7 @@
26
26
  */
27
27
  import { platform } from 'node:process'
28
28
 
29
- import { check as checkGa } from '../fix/workflows/check.mjs'
29
+ import { check as checkGa } from '../js/workflows/check.mjs'
30
30
  import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
31
31
  import { runLintStep } from '../../../scripts/utils/run-lint-step.mjs'
32
32
  import { withLock } from '../../../scripts/utils/with-lock.mjs'
@@ -137,7 +137,7 @@ function preflight(dep) {
137
137
  * 1) preflight: `shellcheck`, `uv` (для `uvx zizmor`) і `conftest` (для check-ga); відсутній → exit 1;
138
138
  * 2) `bunx github-actionlint`;
139
139
  * 3) `uvx zizmor --offline --collect=workflows .`;
140
- * 4) `check-ga.mjs::check()` — Rego-полісі (батч conftest з `npm/policy/ga/`) + JS cross-file
140
+ * 4) `rules/ga/fix.mjs::check()` — Rego-полісі (батч conftest з `npm/policy/ga/`) + JS cross-file
141
141
  * перевірки правил `ga.mdc`. Це **те саме**, що робить `npx \@nitra/cursor check ga`, тож
142
142
  * `lint-ga` тепер є суперсетом перевірки правила: external-tools + check.
143
143
  *
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Порт `verifyNoDirectBunOrCache`, `verifyNoRunShellLineContinuationBackslash`,
4
4
  # `verifyCheckoutBeforeLocalSetupBunDeps` та `validateConcurrencyOnRoot` з
5
- # `npm/scripts/check-ga.mjs`. На відміну від `lint_ga`/`clean_ga_workflows`/
5
+ # `npm/scripts/rules/ga/fix.mjs`. На відміну від `lint_ga`/`clean_ga_workflows`/
6
6
  # `clean_merged_branch`/`git_ai`, цей пакет не привʼязаний до конкретного
7
7
  # workflow — `conftest test` запускається на кожному файлі окремо з
8
8
  # `--namespace ga.workflow_common`, і `input` — це окремий розпарсений YAML.
@@ -0,0 +1,19 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
6
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
7
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
8
+ */
9
+ export function run(ctx) {
10
+ return runStandardRule(import.meta.dirname, ctx)
11
+ }
12
+
13
+ if (import.meta.main) {
14
+ // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
15
+ // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
16
+ const { runRuleCli } = await import('../../scripts/utils/run-rule-cli.mjs')
17
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
18
+ process.exit(await runRuleCli(import.meta.dirname))
19
+ }
@@ -2,7 +2,7 @@
2
2
  * Пошук tagged template **`gql\`…\``** у джерелах для правила graphql.mdc.
3
3
  *
4
4
  * Для **`.vue`** береться лише вміст `<script>` / `<script setup>` (паралельна реалізація екстрактора;
5
- * аналог у `rules/vue/fix/packages/vue-forbidden-imports.mjs` — модулі не діляться кодом, щоб уникати
5
+ * аналог у `rules/vue/js/packages/vue-forbidden-imports.mjs` — модулі не діляться кодом, щоб уникати
6
6
  * cross-rule імпортів і тримати кожне правило самодостатнім).
7
7
  * Семантику визначає **oxc-parser** (`program`): рекурсивний обхід AST, збіг лише для **Identifier** з іменем **`gql`** як тега шаблону.
8
8
  */