@nitra/cursor 1.13.82 → 1.13.83

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 (113) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +5 -5
  3. package/bin/n-cursor.js +16 -21
  4. package/package.json +1 -1
  5. package/rules/abie/abie.mdc +8 -8
  6. package/rules/abie/fix.mjs +15 -0
  7. package/rules/abie/policy/base_deployment_preem/base_deployment_preem.rego +2 -2
  8. package/rules/abie/policy/health_check_policy/health_check_policy.rego +2 -2
  9. package/rules/abie/policy/http_route_base/http_route_base.rego +1 -1
  10. package/rules/abie/utils/k8s-tree.mjs +1 -1
  11. package/rules/adr/adr.mdc +1 -1
  12. package/rules/adr/fix.mjs +15 -0
  13. package/rules/bun/fix.mjs +15 -0
  14. package/rules/capacitor/fix.mjs +15 -0
  15. package/rules/changelog/changelog.mdc +1 -1
  16. package/rules/changelog/fix.mjs +15 -0
  17. package/rules/ci4/fix.mjs +15 -0
  18. package/rules/docker/docker.mdc +3 -3
  19. package/rules/docker/fix.mjs +15 -0
  20. package/rules/docker/lint/lint.mjs +2 -2
  21. package/rules/efes/fix.mjs +15 -0
  22. package/rules/feedback/fix.mjs +15 -0
  23. package/rules/ga/fix.mjs +15 -0
  24. package/rules/ga/lint/lint.mjs +1 -1
  25. package/rules/graphql/fix.mjs +15 -0
  26. package/rules/graphql/{fix → js}/tooling/graphql-gql-scan.mjs +1 -1
  27. package/rules/hasura/fix.mjs +15 -0
  28. package/rules/hasura/policy/svc_hl/svc_hl.rego +1 -1
  29. package/rules/image-avif/fix.mjs +15 -0
  30. package/rules/image-compress/fix.mjs +15 -0
  31. package/rules/js-bun-db/fix.mjs +15 -0
  32. package/rules/js-bun-redis/fix.mjs +15 -0
  33. package/rules/js-bun-redis/policy/package_json/package_json.rego +1 -1
  34. package/rules/js-lint/fix.mjs +15 -0
  35. package/rules/js-lint/{fix → js}/tooling/check.mjs +3 -3
  36. package/rules/js-lint/{fix → js}/tooling/rebuild-oxlint-canonical.mjs +1 -1
  37. package/rules/js-lint/js-lint.mdc +2 -2
  38. package/rules/js-mssql/fix.mjs +15 -0
  39. package/rules/js-run/fix.mjs +15 -0
  40. package/rules/k8s/fix.mjs +15 -0
  41. package/rules/k8s/k8s.mdc +1 -1
  42. package/rules/nginx-default-tpl/fix.mjs +15 -0
  43. package/rules/nginx-default-tpl/{fix → js}/template/check.mjs +1 -1
  44. package/rules/npm-module/fix.mjs +15 -0
  45. package/rules/npm-module/{fix → js}/package_structure/check.mjs +1 -1
  46. package/rules/php/fix.mjs +15 -0
  47. package/rules/rego/fix.mjs +15 -0
  48. package/rules/security/fix.mjs +15 -0
  49. package/rules/security/security.mdc +2 -2
  50. package/rules/style-lint/fix.mjs +15 -0
  51. package/rules/tauri/fix.mjs +15 -0
  52. package/rules/test/fix.mjs +15 -0
  53. package/rules/test/test.mdc +1 -1
  54. package/rules/text/fix.mjs +15 -0
  55. package/rules/vue/fix.mjs +15 -0
  56. package/rules/vue/vue.mdc +1 -1
  57. package/scripts/auto-rules.mjs +3 -3
  58. package/scripts/sync-claude-config.mjs +2 -2
  59. package/scripts/utils/ast-scan-utils.mjs +3 -3
  60. package/scripts/utils/discover-checkable-rules.mjs +30 -18
  61. package/scripts/utils/list-rule-ids.mjs +23 -0
  62. package/scripts/utils/run-rule.mjs +7 -7
  63. package/scripts/utils/run-standard-rule.mjs +34 -0
  64. package/scripts/utils/walk-cache.mjs +24 -0
  65. package/scripts/utils/workspaces.mjs +1 -1
  66. /package/rules/abie/{fix → js}/applies/check.mjs +0 -0
  67. /package/rules/abie/{fix → js}/env_dns/check.mjs +0 -0
  68. /package/rules/abie/{fix → js}/firebase_hosting/check.mjs +0 -0
  69. /package/rules/abie/{fix → js}/hc_pairing/check.mjs +0 -0
  70. /package/rules/abie/{fix → js}/ua_http_route/check.mjs +0 -0
  71. /package/rules/abie/{fix → js}/ua_node_selector/check.mjs +0 -0
  72. /package/rules/adr/{fix → js}/hooks/check.mjs +0 -0
  73. /package/rules/adr/{fix → js}/hooks/template/.gitignore.snippet +0 -0
  74. /package/rules/bun/{fix → js}/layout/check.mjs +0 -0
  75. /package/rules/capacitor/{fix → js}/platforms/check.mjs +0 -0
  76. /package/rules/changelog/{fix → js}/consistency/check.mjs +0 -0
  77. /package/rules/changelog/{fix → js}/consistency/package-manifest.mjs +0 -0
  78. /package/rules/docker/{fix → js}/lint/check.mjs +0 -0
  79. /package/rules/docker/{fix → js}/lint/docker-hadolint.mjs +0 -0
  80. /package/rules/docker/{fix → js}/lint/docker-mirror.mjs +0 -0
  81. /package/rules/ga/{fix → js}/workflows/check.mjs +0 -0
  82. /package/rules/graphql/{fix → js}/tooling/check.mjs +0 -0
  83. /package/rules/hasura/{fix → js}/internal_urls/check.mjs +0 -0
  84. /package/rules/image-avif/{fix → js}/avif_generation/check.mjs +0 -0
  85. /package/rules/image-compress/{fix → js}/package_setup/check.mjs +0 -0
  86. /package/rules/js-bun-db/{fix → js}/safety/bun-sql-scan.mjs +0 -0
  87. /package/rules/js-bun-db/{fix → js}/safety/check.mjs +0 -0
  88. /package/rules/js-bun-redis/{fix → js}/imports/check.mjs +0 -0
  89. /package/rules/js-lint/{fix → js}/tooling/knip-canonical.json +0 -0
  90. /package/rules/js-lint/{fix → js}/tooling/oxlint-canonical-skeleton.json +0 -0
  91. /package/rules/js-lint/{fix → js}/tooling/oxlint-canonical.json +0 -0
  92. /package/rules/js-lint/{fix → js}/tooling/oxlint-rules.tsv +0 -0
  93. /package/rules/js-mssql/{fix → js}/deps/check.mjs +0 -0
  94. /package/rules/js-mssql/{fix → js}/deps/mssql-pool-scan.mjs +0 -0
  95. /package/rules/js-run/{fix → js}/runtime/bunyan-imports.mjs +0 -0
  96. /package/rules/js-run/{fix → js}/runtime/check-env-scan.mjs +0 -0
  97. /package/rules/js-run/{fix → js}/runtime/check.mjs +0 -0
  98. /package/rules/js-run/{fix → js}/runtime/conn-file-rules.mjs +0 -0
  99. /package/rules/js-run/{fix → js}/runtime/conn-imports-scan.mjs +0 -0
  100. /package/rules/js-run/{fix → js}/runtime/promise-settimeout-scan.mjs +0 -0
  101. /package/rules/k8s/{fix → js}/kubescape_exceptions/template/.kubescape-exceptions.json.snippet.json +0 -0
  102. /package/rules/k8s/{fix → js}/manifests/check.mjs +0 -0
  103. /package/rules/php/{fix → js}/tooling/check.mjs +0 -0
  104. /package/rules/rego/{fix → js}/applies/check.mjs +0 -0
  105. /package/rules/security/{fix → js}/sample_secret/check.mjs +0 -0
  106. /package/rules/security/{fix → js}/trufflehog/check.mjs +0 -0
  107. /package/rules/security/{fix → js}/trufflehog/template/.trufflehog-exclude.snippet.txt +0 -0
  108. /package/rules/style-lint/{fix → js}/tooling/check.mjs +0 -0
  109. /package/rules/tauri/{fix → js}/tooling/check.mjs +0 -0
  110. /package/rules/test/{fix → js}/location/check.mjs +0 -0
  111. /package/rules/text/{fix → js}/formatting/check.mjs +0 -0
  112. /package/rules/vue/{fix → js}/packages/check.mjs +0 -0
  113. /package/rules/vue/{fix → js}/packages/vue-forbidden-imports.mjs +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@
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.83] - 2026-05-23
8
+
9
+ ### Changed
10
+
11
+ - **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/` (за технологією, не функцією).
12
+ - **Локальна логіка в `fix.mjs` заборонена** — розширення поведінки правил тільки через опції в `RuleContext` (зараз: `walkCache`; зарезервовано на майбутнє: `skipMdcRefs`, `skipApplies`, `onlyConcerns`). Простір варіацій повністю описано в `RuleContext` JSDoc; convention-drift виключений на рівні дизайну.
13
+ - **Shared `walkCache`** як module-level singleton у `scripts/utils/walk-cache.mjs` (`getOrCreateWalkCache` + `resetWalkCache` для тестів). CLI створює один cache на прогон і прокидає через ctx до всіх concerns.
14
+ - **Нові 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).
15
+ - **Нові тести:** `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.
16
+
17
+ ### Breaking
18
+
19
+ - **Для зовнішніх інтеграторів, що пишуть власні правила:** каталог `rules/<id>/fix/<concern>/check.mjs` перейменовано на `rules/<id>/js/<concern>/check.mjs`; додатково потрібен файл `rules/<id>/fix.mjs` з канонічним вмістом (див. будь-яке вбудоване правило для шаблону). CLI більше не запустить правило без `fix.mjs`.
20
+
21
+ ### Notes
22
+
23
+ - Зворотна сумісність CLI: `npx @nitra/cursor check` та `npx @nitra/cursor check abie` працюють як раніше.
24
+ - 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`.
25
+
7
26
  ## [1.13.82] - 2026-05-23
8
27
 
9
28
  ### Changed
package/README.md CHANGED
@@ -56,7 +56,7 @@
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 check k8s`).
60
60
 
61
61
  ### v8r і власний каталог схем
62
62
 
@@ -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 check`
119
119
  │ └── <concern>/
120
120
  │ ├── check.mjs # діагностика — повертає список violations
121
121
  │ ├── check.test.mjs
@@ -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 check` (fix-канал) | `js/<concern>/` |
138
138
  | JS-orchestrator лінту | `bun run lint-<id>` через `n-cursor lint-<id>` | `lint/` |
139
139
  | Rego-діагностика | `npx @nitra/cursor check` (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 check` запускає і JS-checks, і rego-policies), але **розділені за технологією**: JS у `js/`, rego у `policy/`. `lint/` тримає лише JS, що оркеструє `bun run lint-<id>`.
142
142
 
143
143
  ## AGENTS.md у проєкті користувача
144
144
 
package/bin/n-cursor.js CHANGED
@@ -83,14 +83,14 @@ 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'
93
+ import { getOrCreateWalkCache } from '../scripts/utils/walk-cache.mjs'
94
94
  import { syncClaudeConfig } from '../scripts/sync-claude-config.mjs'
95
95
  import { upgradeNitraCursorToLatestAndBunInstall } from '../scripts/upgrade-nitra-cursor-and-install.mjs'
96
96
  import { runRenameYamlExtensionsCli } from './rename-yaml-extensions.mjs'
@@ -973,26 +973,17 @@ function logRemovedManagedItems(title, basePath, names) {
973
973
  }
974
974
  }
975
975
 
976
- /**
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
976
  /**
987
977
  * Запускає перевірки: без аргументів — за `*.mdc` у `.cursor/rules/`; з аргументами — лише вказані правила.
988
- * Делегує оркестрацію concern-ів (JS-checks + policy через `runConftestBatch`) у `runRule`;
989
- * сам `runChecks` відповідає лише за фільтр id, агрегацію exit-кодів і shared walk-cache на прогон.
978
+ * Перебирає правила через `listRuleIds`, для кожного робить dynamic `import('<rules>/<id>/fix.mjs')`
979
+ * і викликає `mod.run({ walkCache })`. Сам `runChecks` відповідає лише за фільтр id, агрегацію
980
+ * exit-кодів і shared walk-cache на прогон.
990
981
  * @param {string[]} requestedRules імена правил; порожній масив — брати з `.cursor/rules/*.mdc`
991
982
  * @returns {Promise<void>}
992
983
  */
993
984
  async function runChecks(requestedRules) {
994
- const allRules = await discoverCheckScripts()
995
- if (allRules.length === 0) {
985
+ const available = await listRuleIds(BUNDLED_RULES_DIR)
986
+ if (available.length === 0) {
996
987
  console.error('❌ Не знайдено жодного check-скрипта у пакеті')
997
988
  throw new Error('No check scripts found')
998
989
  }
@@ -1008,7 +999,6 @@ async function runChecks(requestedRules) {
1008
999
  }
1009
1000
  }
1010
1001
 
1011
- const available = allRules.map(r => r.id)
1012
1002
  let idsToCheck
1013
1003
  if (requestedRules.length > 0) {
1014
1004
  idsToCheck = requestedRules
@@ -1023,7 +1013,7 @@ async function runChecks(requestedRules) {
1023
1013
  if (idsToCheck.length === 0) {
1024
1014
  console.log(
1025
1015
  `\n🔍 ${PACKAGE_NAME} check — у ${RULES_DIR}/ немає правил з programmatic перевіркою ` +
1026
- `(відповідного check-*.mjs або policy/<name>/target.json у пакеті). Нічого не запущено.\n`
1016
+ `(відповідного fix.mjs у пакеті). Нічого не запущено.\n`
1027
1017
  )
1028
1018
  return
1029
1019
  }
@@ -1038,14 +1028,19 @@ async function runChecks(requestedRules) {
1038
1028
 
1039
1029
  console.log(`\n🔍 ${PACKAGE_NAME} check — перевірка правил (${idsToCheck.length})\n`)
1040
1030
 
1041
- const ruleMap = new Map(allRules.map(r => [r.id, r]))
1042
1031
  /** @type {Map<string, Promise<string[]>>} shared walk-cache (cross-concern, cross-rule у межах одного прогону) */
1043
- const walkCache = new Map()
1032
+ const walkCache = getOrCreateWalkCache()
1044
1033
  let totalFailed = 0
1045
1034
 
1046
1035
  for (const id of idsToCheck) {
1047
1036
  try {
1048
- const code = await runRule(ruleMap.get(id), BUNDLED_RULES_DIR, walkCache)
1037
+ const fixPath = join(BUNDLED_RULES_DIR, id, 'fix.mjs')
1038
+ // eslint-disable-next-line no-unsanitized/method -- id з whitelist'у listRuleIds (readdir + existsSync), fixPath не з зовнішнього input
1039
+ const mod = await import(fixPath)
1040
+ if (typeof mod.run !== 'function') {
1041
+ throw new TypeError(`${id}: rules/${id}/fix.mjs не експортує run()`)
1042
+ }
1043
+ const code = await mod.run({ walkCache })
1049
1044
  if (code !== 0) totalFailed++
1050
1045
  } catch (error) {
1051
1046
  console.log(` ❌ Помилка виконання: ${error.message}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.13.82",
3
+ "version": "1.13.83",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -133,7 +133,7 @@ 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-` відповідно.
@@ -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 check 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,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -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,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -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,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -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`**. Перевіряє **`check-docker.mjs`**, деталі в **`npm/rules/docker/js/lint/docker-mirror.mjs`**.
11
11
 
12
12
  Також Dockerfile/Containerfile **має бути multistage build**: окремий build stage (залежності/компіляція) і окремий runtime stage. У фінальному stage дозволені лише мінімальні базові образи:
13
13
 
@@ -99,7 +99,7 @@ CLI **`hadolint`** приймає лише **явні шляхи** (`[DOCKERFILE
99
99
 
100
100
  **Область lint-docker (вужча, ніж `check docker`):** лише файли з іменем **`Dockerfile`** та **`*.Dockerfile`** (суфікс **`.dockerfile`** без урахування регістру, наприклад **`api.Dockerfile`**). Файли **`Dockerfile.prod`**, **`Containerfile`** тощо **не** входять у **`lint-docker`**; їх ловить **`check docker`** (`check-docker.mjs`).
101
101
 
102
- Обхід: **`walkDir`** з тими самими пропусками каталогів, що й **`check-docker.mjs`**. Виклик **`hadolint`**: **`PATH`**, інакше **`docker run`** — спільна логіка **`npm/rules/docker/fix/lint/docker-hadolint.mjs`**.
102
+ Обхід: **`walkDir`** з тими самими пропусками каталогів, що й **`check-docker.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
 
@@ -109,7 +109,7 @@ CLI **`hadolint`** приймає лише **явні шляхи** (`[DOCKERFILE
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
 
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -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'
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -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'
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -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
  */
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -8,7 +8,7 @@
8
8
  # conftest test hasura/k8s/base/svc-hl.yaml -p npm/rules/hasura/policy/svc_hl \
9
9
  # --namespace hasura.svc_hl
10
10
  #
11
- # Cross-file (`HASURA_GRAPHQL_ENDPOINT` ↔ YAML) — `fix/internal_urls/check.mjs`.
11
+ # Cross-file (`HASURA_GRAPHQL_ENDPOINT` ↔ YAML) — `js/internal_urls/check.mjs`.
12
12
  package hasura.svc_hl
13
13
 
14
14
  import rego.v1
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }
@@ -0,0 +1,15 @@
1
+ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
2
+
3
+ /**
4
+ * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
5
+ * @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
6
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
7
+ */
8
+ export function run(ctx) {
9
+ return runStandardRule(import.meta.dirname, ctx)
10
+ }
11
+
12
+ if (import.meta.main) {
13
+ // eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
14
+ process.exit(await run())
15
+ }