@nitra/cursor 1.13.89 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/package.json +1 -1
  3. package/rules/abie/abie.mdc +8 -8
  4. package/rules/abie/js/{applies/check.mjs → applies.mjs} +2 -2
  5. package/rules/abie/js/{env_dns/check.mjs → env_dns.mjs} +3 -3
  6. package/rules/abie/js/{firebase_hosting/check.mjs → firebase_hosting.mjs} +1 -1
  7. package/rules/abie/js/{hc_pairing/check.mjs → hc_pairing.mjs} +4 -4
  8. package/rules/abie/js/{ua_http_route/check.mjs → ua_http_route.mjs} +6 -6
  9. package/rules/abie/js/{ua_node_selector/check.mjs → ua_node_selector.mjs} +5 -5
  10. package/rules/abie/policy/base_deployment_preem/base_deployment_preem.rego +2 -2
  11. package/rules/abie/policy/health_check_policy/health_check_policy.rego +2 -2
  12. package/rules/abie/policy/http_route_base/http_route_base.rego +1 -1
  13. package/rules/abie/utils/enabled.mjs +1 -1
  14. package/rules/abie/utils/k8s-tree.mjs +1 -1
  15. package/rules/adr/js/{hooks/check.mjs → hooks.mjs} +1 -1
  16. package/rules/bun/js/{layout/check.mjs → layout.mjs} +1 -1
  17. package/rules/capacitor/js/{platforms/check.mjs → platforms.mjs} +1 -1
  18. package/rules/changelog/changelog.mdc +1 -1
  19. package/rules/changelog/js/{consistency/check.mjs → consistency.mjs} +2 -2
  20. package/rules/changelog/{js/consistency → utils}/package-manifest.mjs +1 -1
  21. package/rules/docker/js/{lint/check.mjs → lint.mjs} +5 -5
  22. package/rules/docker/lint/lint.mjs +1 -1
  23. package/rules/docker/{js/lint → utils}/docker-hadolint.mjs +1 -1
  24. package/rules/feedback/feedback.mdc +1 -1
  25. package/rules/ga/js/{workflows/check.mjs → workflows.mjs} +5 -5
  26. package/rules/ga/lint/lint.mjs +1 -1
  27. package/rules/graphql/js/{tooling/check.mjs → tooling.mjs} +5 -5
  28. package/rules/hasura/js/{internal_urls/check.mjs → internal_urls.mjs} +4 -4
  29. package/rules/hasura/policy/svc_hl/svc_hl.rego +1 -1
  30. package/rules/image-avif/js/{avif_generation/check.mjs → avif_generation.mjs} +5 -5
  31. package/rules/image-compress/js/{package_setup/check.mjs → package_setup.mjs} +1 -1
  32. package/rules/js-bun-db/js/{safety/check.mjs → safety.mjs} +5 -5
  33. package/rules/js-bun-db/{js/safety → utils}/bun-sql-scan.mjs +1 -1
  34. package/rules/js-bun-redis/js/{imports/check.mjs → imports.mjs} +4 -4
  35. package/rules/js-bun-redis/policy/package_json/package_json.rego +1 -1
  36. package/rules/js-lint/js/{tooling/check.mjs → tooling.mjs} +8 -4
  37. package/rules/js-lint/js-lint.mdc +11 -1
  38. package/rules/js-lint/{js/tooling → utils}/rebuild-oxlint-canonical.mjs +2 -2
  39. package/rules/js-mssql/js/{deps/check.mjs → deps.mjs} +5 -5
  40. package/rules/js-mssql/{js/deps → utils}/mssql-pool-scan.mjs +1 -1
  41. package/rules/js-run/js/{runtime/check.mjs → runtime.mjs} +10 -10
  42. package/rules/js-run/{js/runtime → utils}/bunyan-imports.mjs +1 -1
  43. package/rules/js-run/{js/runtime → utils}/check-env-scan.mjs +1 -1
  44. package/rules/js-run/{js/runtime → utils}/conn-file-rules.mjs +1 -1
  45. package/rules/js-run/{js/runtime → utils}/conn-imports-scan.mjs +1 -1
  46. package/rules/js-run/{js/runtime → utils}/promise-settimeout-scan.mjs +1 -1
  47. package/rules/k8s/js/{manifests/check.mjs → manifests.mjs} +4 -4
  48. package/rules/k8s/k8s.mdc +1 -1
  49. package/rules/nginx-default-tpl/js/{template/check.mjs → template.mjs} +5 -5
  50. package/rules/npm-module/js/{package_structure/check.mjs → package_structure.mjs} +4 -4
  51. package/rules/php/js/{tooling/check.mjs → tooling.mjs} +1 -1
  52. package/rules/rego/js/{applies/check.mjs → applies.mjs} +3 -3
  53. package/rules/security/js/{sample_secret/check.mjs → sample_secret.mjs} +2 -2
  54. package/rules/security/js/{trufflehog/check.mjs → trufflehog.mjs} +3 -3
  55. package/rules/security/security.mdc +2 -2
  56. package/rules/style-lint/js/{tooling/check.mjs → tooling.mjs} +1 -1
  57. package/rules/tauri/js/{tooling/check.mjs → tooling.mjs} +2 -2
  58. package/rules/test/js/{location/check.mjs → location.mjs} +3 -3
  59. package/rules/text/js/{formatting/check.mjs → formatting.mjs} +2 -2
  60. package/rules/vue/js/{packages/check.mjs → packages.mjs} +5 -5
  61. package/scripts/auto-rules.mjs +3 -3
  62. package/scripts/sync-claude-config.mjs +1 -1
  63. package/scripts/utils/discover-checkable-rules.mjs +20 -27
  64. package/scripts/utils/inline-template-links.mjs +1 -1
  65. package/scripts/utils/run-rule.mjs +18 -23
  66. /package/rules/adr/js/{hooks/template → templates/hooks}/.gitignore.snippet +0 -0
  67. /package/rules/docker/{js/lint → utils}/docker-mirror.mjs +0 -0
  68. /package/rules/graphql/{js/tooling → utils}/graphql-gql-scan.mjs +0 -0
  69. /package/rules/js-lint/js/{tooling → data/tooling}/knip-canonical.json +0 -0
  70. /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-canonical-skeleton.json +0 -0
  71. /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-canonical.json +0 -0
  72. /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-rules.tsv +0 -0
  73. /package/rules/k8s/js/{kubescape_exceptions/template → templates/kubescape_exceptions}/.kubescape-exceptions.json.snippet.json +0 -0
  74. /package/rules/security/js/{trufflehog/template → templates/trufflehog}/.trufflehog-exclude.snippet.txt +0 -0
  75. /package/rules/vue/{js/packages → utils}/vue-forbidden-imports.mjs +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,33 @@
4
4
 
5
5
  Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
6
6
 
7
+ ## [1.14.0] - 2026-05-24
8
+
9
+ ### Changed (BREAKING)
10
+
11
+ - **Flat концерн-лейаут:** кожен JS-концерн правила тепер один файл `npm/rules/<rule>/js/<concern>.mjs` замість вкладеного `js/<concern>/check.mjs`. Tests — у `js/tests/<concern>.test.mjs` (single) або `js/tests/<concern>/<name>.test.mjs` (multi+fixtures). Templates — у `js/templates/<concern>/`. Data (json/tsv) — у `js/data/<concern>/`. Helpers (cross-concern і concern-private) — у `<rule>/utils/<helper>.mjs` peer до `js/` (existing convention з `abie/utils/`).
12
+ - **`JsConcern.files` removed:** один файл на concern, поле більше не потрібне. `runRule` обчислює шлях як `<rule>/js/<concern.name>.mjs`; `resolveJsCheckPath` тепер `(bundledRulesDir, ruleId, concern)` без `fileName`.
13
+ - **`CHECK_FILENAME_RE` і `TEST_SUFFIX` removed:** discovery більше не використовує regex `check-*.mjs` — `listJsConcerns` фільтрує `*.mjs` без `.test.mjs` (підкаталоги скіпаються через `!isFile()`).
14
+ - **`scripts/sync-claude-config.mjs::ADR_GITIGNORE_SNIPPET_REL`** змінено: `rules/adr/js/hooks/template/.gitignore.snippet` → `rules/adr/js/templates/hooks/.gitignore.snippet`.
15
+ - **`scripts/utils/inline-template-links.mjs::TEMPLATE_SEGMENT_RE`** розширено з `/\/template\//` до `/\/templates?\//` — підтримує і `js/templates/` (нова конвенція), і `policy/<concern>/template/` (існуюча).
16
+
17
+ ### Breaking (для зовнішніх інтеграторів)
18
+
19
+ - Каталог `npm/rules/<rule>/js/<concern>/check.mjs` тепер `npm/rules/<rule>/js/<concern>.mjs`. Tests → `js/tests/`, templates → `js/templates/`, data → `js/data/` (усе всередині `js/`); helpers → `<rule>/utils/<helper>.mjs` (peer до `js/`, як `abie/utils/`). Імпорти helpers з concern-файлів: `from '../utils/<helper>.mjs'`. Міграційний скрипт у git-історії — комміт `refactor(rules): flat layout js/<concern>.mjs (міграційний move)`.
20
+
21
+ ### Notes
22
+
23
+ - Convention для helper-імен: namespace-префікс (`<rule>-` або `<concern>-`) робить колізії у плоскому `utils/` неможливими (як уже робить abie: `k8s-tree`, `kustomization-patches`; docker: `docker-mirror`; vue: `vue-forbidden-imports`).
24
+ - Шпаргалка імпорт-шляхів у `.cursor/rules/scripts.mdc` (1.10 → 1.11).
25
+ - `.cursor/rules/conftest.mdc` — алгоритм Rego-first переписаний під flat-layout.
26
+ - Канонічні `security.mdc` і `k8s.mdc` markdown-лінки на template-файли оновлені (`./js/templates/<concern>/`).
27
+
28
+ ## [1.13.90] - 2026-05-24
29
+
30
+ ### Added
31
+
32
+ - **`js-lint` 1.23 → 1.24 — конвенція `utils/` vs `lib/`:** додано секцію «Структура спільних модулів». `utils/` — низькорівневі generic helpers без домену (могли б жити окремим npm-пакетом); `lib/` — внутрішні модулі з доменним state/конфігом/side effects. Канонічні назви лише ці дві — не `shared/`, не `common/`. Дзеркало `.cursor/rules/n-js-lint.mdc` оновлено.
33
+
7
34
  ## [1.13.89] - 2026-05-23
8
35
 
9
36
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.13.89",
3
+ "version": "1.14.0",
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
- **Перевірка `js/env_dns/check.mjs`** сканує всі `*.env` файли, basename яких збігається з `dev.env` / `ua.env` (з провідною крапкою чи без), знаходить **усі** internal URL (`http://<svc>.<ns>.svc.<dns>` — як для Hasura-ендпоінта, так і для KVCMS чи будь-якого іншого) і вимагає, щоб для кожного:
136
+ **Перевірка `js/env_dns.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 fix abie`** для прогону по реальних YAML — деталі в **conftest.mdc** / **n-rego.mdc**). JS у **`js/<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>.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-частинах (`js/<concern>/check.mjs`) — Rego не читає файлову систему й не робить cross-document резолюцію:
173
+ Cross-file / FS-логіка лишається у JS-частинах (`js/<concern>.mjs`) — Rego не читає файлову систему й не робить cross-document резолюцію:
174
174
 
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`.
175
+ - парність HCP↔Deployment у каталозі та modeline `hc.yaml` — `js/hc_pairing.mjs`;
176
+ - валідація ua-overlay JSON6902 patches на HTTPRoute + аналіз cross-namespace `backendRefs` у пакетах — `js/ua_http_route.mjs`;
177
+ - ua-overlay JSON6902 patch на `Deployment.nodeSelector` (`preem: false`) — `js/ua_node_selector.mjs`;
178
+ - env→cluster DNS (`*.dev.env` / `*.ua.env`) — `js/env_dns.mjs`;
179
+ - скан артефактів Firebase Hosting у підкаталогах першого рівня — `js/firebase_hosting.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 не потрібен.
@@ -3,9 +3,9 @@
3
3
  * Якщо повертає `false` — CLI пропускає всі концерни (JS і policy) цього правила.
4
4
  * `check()` друкує тільки context-pass; решта концернів роблять справжню роботу.
5
5
  */
6
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
6
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
7
7
 
8
- import { isAbieRuleEnabled } from '../../utils/enabled.mjs'
8
+ import { isAbieRuleEnabled } from '../utils/enabled.mjs'
9
9
 
10
10
  /**
11
11
  * @returns {Promise<boolean>} `true` — правило застосовне; `false` — пропустити
@@ -9,10 +9,10 @@
9
9
  import { readFile } from 'node:fs/promises'
10
10
  import { basename, relative } from 'node:path'
11
11
 
12
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
13
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
12
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
13
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
14
14
 
15
- import { abieEnvNameFromBasename, collectAbieEnvFiles, validateAbieEnvInternalUrls } from '../../utils/env-dns.mjs'
15
+ import { abieEnvNameFromBasename, collectAbieEnvFiles, validateAbieEnvInternalUrls } from '../utils/env-dns.mjs'
16
16
 
17
17
  /**
18
18
  * @returns {Promise<number>} результат
@@ -7,7 +7,7 @@ import { existsSync } from 'node:fs'
7
7
  import { readdir } from 'node:fs/promises'
8
8
  import { join } from 'node:path'
9
9
 
10
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
10
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
11
11
 
12
12
  const SKIP_TOP_DIR_NAMES = new Set(['.git', 'node_modules'])
13
13
 
@@ -10,11 +10,11 @@ import { existsSync } from 'node:fs'
10
10
  import { readFile } from 'node:fs/promises'
11
11
  import { relative } from 'node:path'
12
12
 
13
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
14
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
13
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
14
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
15
15
 
16
- import { validateAbieHcModeline } from '../../utils/hc-yaml.mjs'
17
- import { collectDeploymentDirs, findK8sYamlFiles } from '../../utils/k8s-tree.mjs'
16
+ import { validateAbieHcModeline } from '../utils/hc-yaml.mjs'
17
+ import { collectDeploymentDirs, findK8sYamlFiles } from '../utils/k8s-tree.mjs'
18
18
 
19
19
  /**
20
20
  * @returns {Promise<number>} результат
@@ -10,20 +10,20 @@
10
10
  import { readFile } from 'node:fs/promises'
11
11
  import { relative } from 'node:path'
12
12
 
13
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
14
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
13
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
14
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
15
15
 
16
- import { analyzeAbieSharedBackendRefsInPackageK8s } from '../../utils/http-route.mjs'
17
- import { findK8sYamlFiles } from '../../utils/k8s-tree.mjs'
16
+ import { analyzeAbieSharedBackendRefsInPackageK8s } from '../utils/http-route.mjs'
17
+ import { findK8sYamlFiles } from '../utils/k8s-tree.mjs'
18
18
  import {
19
19
  getCombinedNginxRunPatchTextFromKustomization,
20
20
  validateAbieNginxRunHttpRoutePatches
21
- } from '../../utils/kustomization-patches.mjs'
21
+ } from '../utils/kustomization-patches.mjs'
22
22
  import {
23
23
  abiePackageDirFromK8sOverlay,
24
24
  abieOverlayRequiresHttpRouteByVite,
25
25
  isUaKustomizationPath
26
- } from '../../utils/overlay-paths.mjs'
26
+ } from '../utils/overlay-paths.mjs'
27
27
 
28
28
  /**
29
29
  * @returns {Promise<number>} результат
@@ -8,12 +8,12 @@
8
8
  import { readFile } from 'node:fs/promises'
9
9
  import { relative } from 'node:path'
10
10
 
11
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
12
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
11
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
12
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
13
13
 
14
- import { collectDeploymentDirs, findK8sYamlFiles } from '../../utils/k8s-tree.mjs'
15
- import { kustomizationHasAbieDeploymentNodeSelectorPatch } from '../../utils/kustomization-patches.mjs'
16
- import { abieOverlayK8sTreeHasDeployment, isUaKustomizationPath } from '../../utils/overlay-paths.mjs'
14
+ import { collectDeploymentDirs, findK8sYamlFiles } from '../utils/k8s-tree.mjs'
15
+ import { kustomizationHasAbieDeploymentNodeSelectorPatch } from '../utils/kustomization-patches.mjs'
16
+ import { abieOverlayK8sTreeHasDeployment, isUaKustomizationPath } from '../utils/overlay-paths.mjs'
17
17
 
18
18
  /**
19
19
  * @returns {Promise<number>} результат
@@ -2,7 +2,7 @@
2
2
  # `spec.template.spec.nodeSelector.preem` зі значенням, що вважається істинним
3
3
  # (boolean `true` або рядок `"true"` без урахування регістру). Overlay ua далі
4
4
  # підміняє селектор JSON6902-патчем на `preem: false`
5
- # (див. `js/ua_node_selector/check.mjs`).
5
+ # (див. `js/ua_node_selector.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
- # `js/applies/check.mjs` (поле `rules` у `.n-cursor.json`).
14
+ # `js/applies.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` — `js/hc_pairing/check.mjs`. Rule-level applies-гейт —
22
- # `js/applies/check.mjs`.
21
+ # modeline `hc.yaml` — `js/hc_pairing.mjs`. Rule-level applies-гейт —
22
+ # `js/applies.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-гейт — `js/applies/check.mjs`.
11
+ # валідація вмісту `spec.hostnames`. Rule-level applies-гейт — `js/applies.mjs`.
12
12
  #
13
13
  # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
14
14
  # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Rule-level applies-гейт abie: чи `.n-cursor.json:rules` містить `abie`.
3
- * Використовується `js/applies/check.mjs` як `applies()`-експорт — якщо false,
3
+ * Використовується `js/applies.mjs` як `applies()`-експорт — якщо false,
4
4
  * CLI пропускає всі концерни правила (включно з policy).
5
5
  */
6
6
  import { existsSync } from 'node:fs'
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { dirname, relative } from 'node:path'
10
10
 
11
- import { pathHasK8sSegment } from '../../k8s/js/manifests/check.mjs'
11
+ import { pathHasK8sSegment } from '../../k8s/js/manifests.mjs'
12
12
  import { walkDir } from '../../../scripts/utils/walkDir.mjs'
13
13
  import { isDeploymentDoc, readAndParseYamlDocs } from './yaml.mjs'
14
14
 
@@ -24,7 +24,7 @@ import { delimiter, dirname, join } from 'node:path'
24
24
  import { env } from 'node:process'
25
25
  import { fileURLToPath } from 'node:url'
26
26
 
27
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
27
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
28
28
 
29
29
  /** Один hook-артефакт: bash-скрипт + його лог-файл, які перевіряємо однотипно. */
30
30
  const HOOK_ARTIFACTS = /** @type {const} */ ([
@@ -20,7 +20,7 @@
20
20
  import { existsSync } from 'node:fs'
21
21
  import { readFile } from 'node:fs/promises'
22
22
 
23
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
23
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
24
24
 
25
25
  /** Розділювач токенів у `scripts.lint` (послідовність пробільних символів). */
26
26
  const WHITESPACE_RE = /\s+/u
@@ -25,7 +25,7 @@ import { existsSync } from 'node:fs'
25
25
  import { readdir, readFile } from 'node:fs/promises'
26
26
  import { join, relative } from 'node:path'
27
27
 
28
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
28
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
29
29
 
30
30
  /** Мінімальна допустима мажорна версія Capacitor (capacitor.mdc) */
31
31
  const MIN_CAPACITOR_MAJOR = 8
@@ -43,7 +43,7 @@ alwaysApply: true
43
43
 
44
44
  **Вимагають bump + нову секцію CHANGELOG** — усі інші зміни в каталозі workspace (код, rego, правила, скіли, конфіги, тести тощо). Виняток `.cursor/` / `.claude/` **не** поширюється на джерело правил у репо `@nitra/cursor` — воно лежить під `npm/`, тож зміни в ньому далі вимагають bump.
45
45
 
46
- Перевірка програмна (`changelog/js/consistency/check.mjs`).
46
+ Перевірка програмна (`changelog/js/consistency.mjs`).
47
47
 
48
48
  ## Дві моделі бази порівняння
49
49
 
@@ -22,13 +22,13 @@ import { readFile } from 'node:fs/promises'
22
22
  import { join } from 'node:path'
23
23
  import { promisify } from 'node:util'
24
24
 
25
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
25
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
26
26
  import {
27
27
  getMonorepoProjectRootDirs,
28
28
  manifestFilePath,
29
29
  parsePyprojectFields,
30
30
  readPackageManifest
31
- } from './package-manifest.mjs'
31
+ } from '../utils/package-manifest.mjs'
32
32
 
33
33
  const execFileAsync = promisify(execFile)
34
34
 
@@ -8,7 +8,7 @@ import { dirname, join, relative } from 'node:path'
8
8
 
9
9
  import { parse as parseToml } from 'smol-toml'
10
10
 
11
- import { getMonorepoPackageRootDirs, isIgnoredWorkspaceRoot } from '../../../../scripts/utils/workspaces.mjs'
11
+ import { getMonorepoPackageRootDirs, isIgnoredWorkspaceRoot } from '../../../scripts/utils/workspaces.mjs'
12
12
 
13
13
  /**
14
14
  * @typedef {'npm' | 'python'} PackageKind
@@ -30,11 +30,11 @@
30
30
  import { readFile } from 'node:fs/promises'
31
31
  import { basename } from 'node:path'
32
32
 
33
- import { getMirrorGcrHint, getFromImageToken } from './docker-mirror.mjs'
34
- import { lintDockerfileWithHadolint, posixRel } from './docker-hadolint.mjs'
35
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
36
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
37
- import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
33
+ import { getMirrorGcrHint, getFromImageToken } from '../utils/docker-mirror.mjs'
34
+ import { lintDockerfileWithHadolint, posixRel } from '../utils/docker-hadolint.mjs'
35
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
36
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
37
+ import { walkDir } from '../../../scripts/utils/walkDir.mjs'
38
38
 
39
39
  const NEWLINE_RE = /\r?\n/
40
40
  const BUN_INSTALL_RE = /\bbun\s+(?:install|i)\b/iu
@@ -13,7 +13,7 @@
13
13
  import { basename } from 'node:path'
14
14
 
15
15
  import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
16
- import { lintDockerfileWithHadolint, posixRel } from '../js/lint/docker-hadolint.mjs'
16
+ import { lintDockerfileWithHadolint, posixRel } from '../utils/docker-hadolint.mjs'
17
17
  import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
18
18
  import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
19
19
  import { walkDir } from '../../../scripts/utils/walkDir.mjs'
@@ -8,7 +8,7 @@
8
8
  import { spawnSync } from 'node:child_process'
9
9
  import { relative, sep } from 'node:path'
10
10
 
11
- import { resolveCmd } from '../../../../scripts/utils/resolve-cmd.mjs'
11
+ import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
12
12
 
13
13
  /** Тег образу для резервного запуску (узгоджуй з docker.mdc). */
14
14
  export const HADOLINT_IMAGE = 'hadolint/hadolint:v2.12.0'
@@ -17,7 +17,7 @@ version: '1.0'
17
17
  **Тертя** — усе, що ускладнило роботу скілу й стосується самого пакета `@nitra/cursor`, а не коду користувацького проєкту:
18
18
 
19
19
  - неоднозначна чи неповна інструкція в `SKILL.md` або `.mdc`;
20
- - правило вимагає поведінку, яку можна перевірити програмно, але програмної перевірки (`rules/<id>/js/<concern>/check.mjs` або `rules/<id>/policy/<concern>/*.rego`) для неї немає;
20
+ - правило вимагає поведінку, яку можна перевірити програмно, але програмної перевірки (`rules/<id>/js/<concern>.mjs` або `rules/<id>/policy/<concern>/*.rego`) для неї немає;
21
21
  - хибне спрацювання перевірки (false positive);
22
22
  - порушення, яке правило вимагає виправляти вручну, хоча реальний автофікс можливий;
23
23
  - повторюваний патерн, який варто закодувати в правило чи скіл.
@@ -20,11 +20,11 @@ import { execFileSync } from 'node:child_process'
20
20
  import { basename, dirname, join } from 'node:path'
21
21
  import { fileURLToPath } from 'node:url'
22
22
 
23
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
24
- import { eventPathsIncludeExact, parseWorkflowYaml } from '../../../../scripts/utils/gha-workflow.mjs'
25
- import { resolveCmd } from '../../../../scripts/utils/resolve-cmd.mjs'
26
- import { runConftestBatch } from '../../../../scripts/utils/run-conftest-batch.mjs'
27
- import { loadTemplate } from '../../../../scripts/utils/template.mjs'
23
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
24
+ import { eventPathsIncludeExact, parseWorkflowYaml } from '../../../scripts/utils/gha-workflow.mjs'
25
+ import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
26
+ import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
27
+ import { loadTemplate } from '../../../scripts/utils/template.mjs'
28
28
 
29
29
  const HERE = dirname(fileURLToPath(import.meta.url))
30
30
  const GA_POLICY_DIR = join(HERE, '..', '..', 'policy')
@@ -29,7 +29,7 @@
29
29
  */
30
30
  import { platform } from 'node:process'
31
31
 
32
- import { check as checkGa } from '../js/workflows/check.mjs'
32
+ import { check as checkGa } from '../js/workflows.mjs'
33
33
  import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
34
34
  import { runLintStep } from '../../../scripts/utils/run-lint-step.mjs'
35
35
  import { runStandardLint } from '../../../scripts/utils/run-standard-lint.mjs'
@@ -10,15 +10,15 @@ import { existsSync } from 'node:fs'
10
10
  import { readFile } from 'node:fs/promises'
11
11
  import { relative } from 'node:path'
12
12
 
13
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
13
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
14
14
  import {
15
15
  isGqlScanSourceFile,
16
16
  shouldSkipFileForGqlScan,
17
17
  sourceFileHasGqlTaggedTemplate
18
- } from './graphql-gql-scan.mjs'
19
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
20
- import { runConftestBatch } from '../../../../scripts/utils/run-conftest-batch.mjs'
21
- import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
18
+ } from '../utils/graphql-gql-scan.mjs'
19
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
20
+ import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
21
+ import { walkDir } from '../../../scripts/utils/walkDir.mjs'
22
22
 
23
23
  /** Очікуваний файл GraphQL Config у корені (graphql.mdc). */
24
24
  export const GRAPHQL_RC_FILENAME = '.graphqlrc.yml'
@@ -28,10 +28,10 @@ import { basename, join, relative } from 'node:path'
28
28
 
29
29
  import { parseAllDocuments } from 'yaml'
30
30
 
31
- import { getRepositoryUrl } from '../../../../scripts/auto-rules.mjs'
32
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
33
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
34
- import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
31
+ import { getRepositoryUrl } from '../../../scripts/auto-rules.mjs'
32
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
33
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
34
+ import { walkDir } from '../../../scripts/utils/walkDir.mjs'
35
35
 
36
36
  const NITRA_REPOSITORY_URL_MARKER = 'https://github.com/nitra/'
37
37
  const ABIE_REPOSITORY_URL_MARKER = 'https://github.com/abinbevefes/'
@@ -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) — `js/internal_urls/check.mjs`.
11
+ # Cross-file (`HASURA_GRAPHQL_ENDPOINT` ↔ YAML) — `js/internal_urls.mjs`.
12
12
  package hasura.svc_hl
13
13
 
14
14
  import rego.v1
@@ -30,11 +30,11 @@ import { join, relative } from 'node:path'
30
30
  import { spawnSync } from 'node:child_process'
31
31
  import { env } from 'node:process'
32
32
 
33
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
34
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
35
- import { resolveCmd } from '../../../../scripts/utils/resolve-cmd.mjs'
36
- import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
37
- import { getMonorepoPackageRootDirs } from '../../../../scripts/utils/workspaces.mjs'
33
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
34
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
35
+ import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
36
+ import { walkDir } from '../../../scripts/utils/walkDir.mjs'
37
+ import { getMonorepoPackageRootDirs } from '../../../scripts/utils/workspaces.mjs'
38
38
 
39
39
  /** Імʼя CLI-пакета, який генерує AVIF. */
40
40
  const MINIFY_PACKAGE_NAME = '@nitra/minify-image'
@@ -19,7 +19,7 @@
19
19
  import { existsSync } from 'node:fs'
20
20
  import { readFile } from 'node:fs/promises'
21
21
 
22
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
22
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
23
23
 
24
24
  /** Імʼя committed-кешу (sha1 + originalSize + size) у `@nitra/minify-image` ≥ 3.2.0. */
25
25
  const HASH_CACHE_FILENAME = '.n-minify-image.tsv'
@@ -33,7 +33,7 @@ import { existsSync } from 'node:fs'
33
33
  import { readFile } from 'node:fs/promises'
34
34
  import { join, relative } from 'node:path'
35
35
 
36
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
36
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
37
37
  import {
38
38
  findBunSqlPerRequestConnectionInText,
39
39
  findBunSqlPgLeftoverCallInText,
@@ -48,10 +48,10 @@ import {
48
48
  isBunSqlScanSourceFile,
49
49
  textHasBunSqlImport,
50
50
  textHasPgLibImport
51
- } from './bun-sql-scan.mjs'
52
- import { findAllPackageJsonPaths } from '../../../../scripts/utils/find-package-json-paths.mjs'
53
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
54
- import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
51
+ } from '../utils/bun-sql-scan.mjs'
52
+ import { findAllPackageJsonPaths } from '../../../scripts/utils/find-package-json-paths.mjs'
53
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
54
+ import { walkDir } from '../../../scripts/utils/walkDir.mjs'
55
55
 
56
56
  // Дешеві pre-filter regex'и для AST-сканера LISTEN/NOTIFY: уникаємо парсингу
57
57
  // файлів, у яких ніяких сигналів немає. Винесено в модульний скоуп, щоб не
@@ -27,7 +27,7 @@ import {
27
27
  parseProgramOrNull,
28
28
  templateQuasisText,
29
29
  walkAstWithAncestors
30
- } from '../../../../scripts/utils/ast-scan-utils.mjs'
30
+ } from '../../../scripts/utils/ast-scan-utils.mjs'
31
31
 
32
32
  const SOURCE_FILE_RE = /\.([cm]?[jt]sx?)$/u
33
33
  const BUN_SQL_IMPORT_RE = /\bimport\s*\{[\s\S]*?\b(sql|SQL)\b[\s\S]*?\}\s*from\s*["']bun["']/u
@@ -14,14 +14,14 @@ import { existsSync } from 'node:fs'
14
14
  import { readFile } from 'node:fs/promises'
15
15
  import { join, relative } from 'node:path'
16
16
 
17
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
18
- import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
17
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
18
+ import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
19
19
  import {
20
20
  findRedisImportsInText,
21
21
  isRedisScanSourceFile,
22
22
  shouldSkipFileForRedisScan
23
- } from '../../../../scripts/utils/redis-imports.mjs'
24
- import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
23
+ } from '../../../scripts/utils/redis-imports.mjs'
24
+ import { walkDir } from '../../../scripts/utils/walkDir.mjs'
25
25
 
26
26
  /**
27
27
  * Збирає абсолютні шляхи JS/TS джерел у репозиторії для скану заборонених redis-імпортів.
@@ -3,7 +3,7 @@
3
3
  # Канон надходить через --data: { "template": { "deny": ... } }
4
4
  # Структура --data сформована з template/package.json.deny.json.
5
5
  # AST-скан коду (`import`/`require`/dynamic `import()` тих самих пакетів)
6
- # лишається у `js-bun-redis/js/imports/check.mjs`.
6
+ # лишається у `js-bun-redis/js/imports.mjs`.
7
7
  package js_bun_redis.package_json
8
8
 
9
9
  import rego.v1
@@ -2,7 +2,7 @@
2
2
  * Перевіряє лінт JavaScript за правилом js-lint.mdc.
3
3
  *
4
4
  * Flat ESLint з getConfig і ignore для auto-imports,
5
- * `.oxlintrc.json` має збігатися з каноном oxlint у пакеті (`npm/rules/js-lint/js/tooling/oxlint-canonical.json`):
5
+ * `.oxlintrc.json` має збігатися з каноном oxlint у пакеті (`npm/rules/js-lint/js/data/tooling/oxlint-canonical.json`):
6
6
  * plugins, jsPlugins, categories, усі правила з канону (додаткові записи в `rules` дозволені), settings, env,
7
7
  * globals, ignorePatterns. Також перевіряє workspace `package.json` на `type: "module"`
8
8
  * і `engines`, workflow-дубль у `lint.yml`, `knip.json` autofill і застарілі `.eslintrc*`.
@@ -15,17 +15,21 @@ import { copyFile, readFile } from 'node:fs/promises'
15
15
  import { dirname, join } from 'node:path'
16
16
  import { fileURLToPath } from 'node:url'
17
17
 
18
- import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
18
+ import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
19
19
 
20
20
  /** Шлях до канонічного oxlint JSON у цьому пакеті (для перевірки та тестів). */
21
21
  export const OXLINT_CANONICAL_JSON_PATH = join(
22
22
  dirname(fileURLToPath(import.meta.url)),
23
+ 'data',
24
+ 'tooling',
23
25
  'oxlint-canonical.json'
24
26
  )
25
27
 
26
28
  /** Шлях до канонічного knip JSON у цьому пакеті — копіюється у корінь проєкту-споживача, якщо відсутній. */
27
29
  export const KNIP_CANONICAL_JSON_PATH = join(
28
30
  dirname(fileURLToPath(import.meta.url)),
31
+ 'data',
32
+ 'tooling',
29
33
  'knip-canonical.json'
30
34
  )
31
35
 
@@ -154,7 +158,7 @@ export function verifyOxlintRcAgainstCanonical(cfg, canonical) {
154
158
 
155
159
  if (!deepEqualOxlintCanonical(actual, expected)) {
156
160
  failures.push(
157
- `.oxlintrc.json: поле "${key}" має збігатися з каноном пакета @nitra/cursor (npm/rules/js-lint/js/tooling/oxlint-canonical.json)`
161
+ `.oxlintrc.json: поле "${key}" має збігатися з каноном пакета @nitra/cursor (npm/rules/js-lint/js/data/tooling/oxlint-canonical.json)`
158
162
  )
159
163
  }
160
164
  }
@@ -384,7 +388,7 @@ async function checkKnipConfig(passFn, failFn) {
384
388
  return
385
389
  }
386
390
  await copyFile(KNIP_CANONICAL_JSON_PATH, 'knip.json')
387
- passFn('knip.json створено з канонічного npm/rules/js-lint/js/tooling/knip-canonical.json (js-lint.mdc)')
391
+ passFn('knip.json створено з канонічного npm/rules/js-lint/js/data/tooling/knip-canonical.json (js-lint.mdc)')
388
392
  }
389
393
 
390
394
  /**