@nitra/cursor 1.13.83 → 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.
- package/.claude-template/commands/n-check.md +2 -2
- package/CHANGELOG.md +41 -27
- package/README.md +10 -10
- package/bin/n-cursor.js +34 -58
- package/package.json +1 -1
- package/rules/abie/abie.mdc +2 -2
- package/rules/abie/fix.mjs +5 -1
- package/rules/adr/fix.mjs +5 -1
- package/rules/adr/js/hooks/check.mjs +1 -1
- package/rules/bun/bun.mdc +1 -1
- package/rules/bun/fix.mjs +5 -1
- package/rules/bun/js/layout/check.mjs +1 -1
- package/rules/capacitor/fix.mjs +5 -1
- package/rules/capacitor/policy/package_json/package_json.rego +3 -3
- package/rules/changelog/changelog.mdc +1 -1
- package/rules/changelog/fix.mjs +5 -1
- package/rules/ci4/ci4.mdc +1 -1
- package/rules/ci4/fix.mjs +5 -1
- package/rules/docker/docker.mdc +6 -6
- package/rules/docker/fix.mjs +5 -1
- package/rules/docker/policy/package_json/package_json.rego +1 -1
- package/rules/efes/efes.mdc +1 -1
- package/rules/efes/fix.mjs +5 -1
- package/rules/feedback/feedback.mdc +2 -2
- package/rules/feedback/fix.mjs +5 -1
- package/rules/ga/fix.mjs +5 -1
- package/rules/ga/lint/lint.mjs +5 -5
- package/rules/ga/policy/workflow_common/workflow_common.rego +1 -1
- package/rules/graphql/fix.mjs +5 -1
- package/rules/graphql/policy/vscode_extensions/vscode_extensions.rego +2 -2
- package/rules/hasura/fix.mjs +5 -1
- package/rules/image-avif/fix.mjs +5 -1
- package/rules/image-avif/image-avif.mdc +1 -1
- package/rules/image-avif/js/avif_generation/check.mjs +1 -1
- package/rules/image-compress/fix.mjs +5 -1
- package/rules/image-compress/js/package_setup/check.mjs +1 -1
- package/rules/js-bun-db/fix.mjs +5 -1
- package/rules/js-bun-redis/fix.mjs +5 -1
- package/rules/js-lint/fix.mjs +5 -1
- package/rules/js-lint/js/tooling/check.mjs +2 -2
- package/rules/js-lint/js-lint.mdc +1 -1
- package/rules/js-mssql/fix.mjs +5 -1
- package/rules/js-mssql/policy/package_json/package_json.rego +2 -2
- package/rules/js-run/fix.mjs +5 -1
- package/rules/js-run/js/runtime/check.mjs +3 -3
- package/rules/k8s/fix.mjs +5 -1
- package/rules/k8s/js/manifests/check.mjs +1 -1
- package/rules/k8s/k8s.mdc +12 -12
- package/rules/k8s/lint/lint.mjs +2 -2
- package/rules/k8s/policy/base_kustomization/base_kustomization.rego +3 -3
- package/rules/k8s/policy/base_manifest/base_manifest.rego +2 -2
- package/rules/k8s/policy/gateway/gateway.rego +2 -2
- package/rules/k8s/policy/hasura_configmap/hasura_configmap.rego +3 -3
- package/rules/k8s/policy/hasura_httproute/hasura_httproute.rego +1 -1
- package/rules/k8s/policy/hpa_pdb/hpa_pdb.rego +1 -1
- package/rules/k8s/policy/kustomization/kustomization.rego +2 -2
- package/rules/k8s/policy/manifest/manifest.rego +4 -4
- package/rules/k8s/policy/svc_hl_yaml/svc_hl_yaml.rego +2 -2
- package/rules/k8s/policy/svc_yaml/svc_yaml.rego +2 -2
- package/rules/nginx-default-tpl/fix.mjs +5 -1
- package/rules/nginx-default-tpl/policy/vscode_extensions/vscode_extensions.rego +2 -2
- package/rules/nginx-default-tpl/policy/vscode_settings/vscode_settings.rego +1 -1
- package/rules/npm-module/fix.mjs +5 -1
- package/rules/npm-module/js/package_structure/check.mjs +2 -2
- package/rules/php/fix.mjs +5 -1
- package/rules/php/js/tooling/check.mjs +2 -2
- package/rules/rego/fix.mjs +5 -1
- package/rules/security/fix.mjs +5 -1
- package/rules/security/security.mdc +1 -1
- package/rules/style-lint/fix.mjs +5 -1
- package/rules/style-lint/js/tooling/check.mjs +2 -2
- package/rules/tauri/fix.mjs +5 -1
- package/rules/tauri/js/tooling/check.mjs +1 -1
- package/rules/tauri/policy/vscode_extensions/vscode_extensions.rego +2 -2
- package/rules/test/fix.mjs +5 -1
- package/rules/test/test.mdc +1 -1
- package/rules/text/fix.mjs +5 -1
- package/rules/text/js/formatting/check.mjs +2 -2
- package/rules/text/text.mdc +1 -1
- package/rules/vue/fix.mjs +5 -1
- package/rules/vue/js/packages/check.mjs +1 -1
- package/rules/vue/policy/package_json/package_json.rego +1 -1
- package/rules/vue/vue.mdc +1 -1
- package/schemas/n-cursor.json +1 -1
- package/scripts/build-agents-commands.mjs +1 -1
- package/scripts/claude-stop-hook.mjs +1 -1
- package/scripts/utils/discover-check-rules-from-cursor.mjs +1 -1
- package/scripts/utils/read-n-cursor-config-lite.mjs +59 -0
- package/scripts/utils/run-rule-cli.mjs +37 -0
- package/skills/fix/SKILL.md +5 -5
- package/skills/lint/SKILL.md +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: >-
|
|
3
|
-
Запустити всі програмні перевірки правил (`npx @nitra/cursor
|
|
3
|
+
Запустити всі програмні перевірки правил (`npx @nitra/cursor fix`)
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# n-check
|
|
7
7
|
|
|
8
|
-
Запусти `npx @nitra/cursor
|
|
8
|
+
Запусти `npx @nitra/cursor fix` і пройдися по результатах.
|
|
9
9
|
|
|
10
10
|
- Якщо є помилки — виправи відповідно до правила, на яке вказує перевірка.
|
|
11
11
|
- Якщо все чисто — підтверди коротким повідомленням і переходь до наступного кроку.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.13.84] - 2026-05-23
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **CLI команда `check` перейменована на `fix`** (узгоджено з ім'ям файла `rules/<id>/fix.mjs`). `npx @nitra/cursor fix [<rule>...]` — новий канонічний формат. Команда `check` залишається як deprecated alias з warning'ом — буде видалена в наступній major-версії.
|
|
12
|
+
- **CLI стає spawn-wrapper:** замість inline dynamic import у `runChecks`, `fix [<rule>...]` тепер просто послідовно спавнить `bun rules/<id>/fix.mjs` per rule (один шлях у коді — `fix.mjs` як єдина авторитативна точка входу). Discovery з `.cursor/rules/*.mdc` без аргументів зберігається.
|
|
13
|
+
- **`rules/<id>/fix.mjs` отримує standalone-режим:** блок `if (import.meta.main)` тепер делегує новій утиліті `runRuleCli`, яка читає `.n-cursor.json` (через light reader), перевіряє whitelist + друкує per-rule summary. `bun rules/<id>/fix.mjs` тепер повний еквівалент `npx @nitra/cursor fix <id>`.
|
|
14
|
+
- **Документація переписана:** всі `npx @nitra/cursor check <rule>` у `.mdc`, `.cursor/rules/`, `README.md`, skills, JSDoc pass-повідомленнях оновлено на `fix`. Один формат у документації; CLI alias `check` лишається тільки для backward compatibility.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`scripts/utils/run-rule-cli.mjs`** — standalone runner з config-loading + summary; використовується `fix.mjs::main` блоком.
|
|
19
|
+
- **`scripts/utils/read-n-cursor-config-lite.mjs`** — мінімальний read-only `.n-cursor.json` reader (без auto-detection / sync — це окрема справа CLI). API: `readNCursorConfigLite()`, `isRuleEnabled(config, ruleId)`. Open-by-default: якщо файл відсутній — правило вважається активним (для debug).
|
|
20
|
+
|
|
7
21
|
## [1.13.83] - 2026-05-23
|
|
8
22
|
|
|
9
23
|
### Changed
|
|
@@ -20,7 +34,7 @@
|
|
|
20
34
|
|
|
21
35
|
### Notes
|
|
22
36
|
|
|
23
|
-
- Зворотна сумісність CLI: `npx @nitra/cursor
|
|
37
|
+
- Зворотна сумісність CLI: `npx @nitra/cursor fix` та `npx @nitra/cursor fix abie` працюють як раніше.
|
|
24
38
|
- Use-cases: `bun npm/rules/abie/fix.mjs` (debug); `bun npm/rules/${{ matrix.rule }}/fix.mjs` (CI per-rule jobs); IDE Run-button на `fix.mjs`.
|
|
25
39
|
|
|
26
40
|
## [1.13.82] - 2026-05-23
|
|
@@ -33,7 +47,7 @@
|
|
|
33
47
|
- `rules/test/fix/location/check.mjs` — перевіряє **лише `*.test.mjs`**, `*_test.rego` свідомо виключено з область перевірки (зафіксовано у docstring).
|
|
34
48
|
- Додано test-case у `rules/test/fix/location/tests/check.test.mjs`: `*_test.rego` поряд із полісі НЕ є порушенням.
|
|
35
49
|
- **Відкат переміщення `*_test.rego`**: 69 файлів, які раніше було помилково перенесено у `policy/<concern>/tests/<name>_test.rego`, повернуто у `policy/<concern>/<name>_test.rego` через `git mv`. Порожні `tests/` піддиректорії під `policy/` видалено.
|
|
36
|
-
- **`npx @nitra/cursor
|
|
50
|
+
- **`npx @nitra/cursor fix test`** охоплює лише JS-тести: «✅ Всі 77 файлів *.test.mjs у каталозі tests/». Rego-тести продовжують перевірятись через `conftest verify` у правилі `rego`.
|
|
37
51
|
|
|
38
52
|
## [1.13.81] - 2026-05-23
|
|
39
53
|
|
|
@@ -61,7 +75,7 @@
|
|
|
61
75
|
- Ручні фіксапи 4 тестів із HERE/`..` path patterns (sync-setup-bun-deps-action, inline-template-links, rules/adr/fix/hooks, rules/abie/utils/enabled) — додано додатковий `..`, бо тести стали на рівень глибше.
|
|
62
76
|
- `package.json#files` негативні globs (`!**/*.test.mjs`, `!**/__fixtures__/**`, `!**/fixtures/**`) працюють рекурсивно — без змін.
|
|
63
77
|
- **77 тестів** проходять у новому layout (76 існуючих + 1 нового правила): `bun test` 843 pass / 2 fail (обидва — pre-existing `with-lock` issues, не пов'язані).
|
|
64
|
-
- `npx @nitra/cursor
|
|
78
|
+
- `npx @nitra/cursor fix test` → `✅ Всі 77 файлів *.test.mjs у каталозі tests/ (test.mdc)`.
|
|
65
79
|
|
|
66
80
|
## [1.13.79] - 2026-05-23
|
|
67
81
|
|
|
@@ -215,7 +229,7 @@
|
|
|
215
229
|
|
|
216
230
|
### Added
|
|
217
231
|
|
|
218
|
-
- Нове `alwaysApply`-правило **`feedback`** ([feedback.mdc](rules/feedback/feedback.mdc)) — ефемерний канал зворотного звʼязку до пакета `@nitra/cursor`. Виконуючи будь-який скіл пакета (`n-lint`, `n-fix`, `n-taze`, `n-adr-normalize`, `n-llm-patch`, `n-publish-telegram`, `mdc-check`), агент проходить крізь `.cursor/rules/`, `SKILL.md` і `npx @nitra/cursor
|
|
232
|
+
- Нове `alwaysApply`-правило **`feedback`** ([feedback.mdc](rules/feedback/feedback.mdc)) — ефемерний канал зворотного звʼязку до пакета `@nitra/cursor`. Виконуючи будь-який скіл пакета (`n-lint`, `n-fix`, `n-taze`, `n-adr-normalize`, `n-llm-patch`, `n-publish-telegram`, `mdc-check`), агент проходить крізь `.cursor/rules/`, `SKILL.md` і `npx @nitra/cursor fix` — і бачить «тертя»: неоднозначні інструкції, відсутні `check-*.mjs`, false positive, порушення без автофіксу, повторювані патерни. Правило вимагає наприкінці скілу, **після** основного резюме, додати у відповідь чату секцію `## 🔧 Покращення @nitra/cursor` з пунктами за схемою `target` (`rule`/`skill`/`check`) · `id` · `kind` (`ambiguous-doc`/`missing-check`/`false-positive`/`no-autofix`/`recurring-pattern`) · `evidence` · `suggestion`. Резюме **навмисно ефемерне** — живе лише у відповіді чату: правило забороняє запис файлів/чернеток, GitHub issue/PR і редагування самого пакета; розробник, читаючи відповідь, сам вирішує, чи переносити пункт у пакет. Якщо тертя не було — секція повністю пропускається. Правило чисто документаційне (як `ci4`), `check-*.mjs` не має, бо поведінка агента програмно не верифікується. Зачеплено: новий каталог [rules/feedback/](rules/feedback/) з `feedback.mdc` (`version: '1.0'`), додано `"feedback"` у `rules` кореневого `.n-cursor.json` — після синку правило копіюється як `.cursor/rules/n-feedback.mdc` і потрапляє в `AGENTS.md`.
|
|
219
233
|
- `check security`: новий concern **`security.sample_secret`** — placeholder фейкових credential-значень у прикладних файлах має бути `sample-secret`, а не bare `secret`. Причина: `sample-secret` містить підрядок `sample` із вшитого списку `DefaultFalsePositives` TruffleHog і відсіюється сканером гарантовано та незалежно від версії; bare `secret` наразі ігнорується лише тому, що випадково присутнє у словнику `fp_words.txt` — крихка поведінка, що залежить від версії інструмента. [check.mjs](rules/security/fix/sample_secret/check.mjs) обходить дерево, відбирає прикладні файли (basename із суфіксом `.example`/`.sample`/`.template`/`.dist` чи infix `.example.`/`.sample.`/`.template.`, а також усе всередині каталогів `fixtures`/`fixture`/`__fixtures__`) і порядково шукає `secret` у позиції значення — одразу після `=`, `:` або `=>` з опційними лапками; імена ключів (`client_secret`, `JWT_SECRET`) не чіпаються, бо матч прив'язаний до значення. Решта файлів не сканується — там `secret` майже завжди частина реального коду. Скан текстовий (regex, не AST/Rego): прикладні файли — різнорідні конфіги (`.env`, YAML, JSON, TOML, plain `.dist`) без єдиного AST, а відбір файлів потребує обходу дерева. Зачеплено: [check.mjs](rules/security/fix/sample_secret/check.mjs) і [check.test.mjs](rules/security/fix/sample_secret/check.test.mjs) (новий concern + 9 тестів), [security.mdc](rules/security/security.mdc) (нова секція «Placeholder для секретів — `sample-secret`» та секція «Перевірка»). Bump `security.mdc` `2.0` → `2.1`.
|
|
220
234
|
|
|
221
235
|
## [1.13.57] - 2026-05-19
|
|
@@ -685,14 +699,14 @@
|
|
|
685
699
|
- **`tauri`** (`1.0 → 1.1`) — `globs: "**/src-tauri/**,**/tauri.conf.json"`
|
|
686
700
|
- **`js-lint`** (`1.21 → 1.22`) — `globs: "**/{.oxlintrc.json,eslint.config.js,.jscpd.json,knip.json,package.json},**/*.{js,mjs,cjs,jsx,ts,tsx}"`
|
|
687
701
|
- **`js-run`** (`1.7 → 1.8`) — `globs: "**/package.json,**/jsconfig.json,**/src/**/*.{js,mjs,cjs,ts,tsx}"`
|
|
688
|
-
- **Мотивація:** усі 9 правил мають повне покриття `npx @nitra/cursor
|
|
702
|
+
- **Мотивація:** усі 9 правил мають повне покриття `npx @nitra/cursor fix <rule>` (JS-перевірка + Rego policy). Тримати їх `alwaysApply: true` без потреби палить контекст AI у сесіях, де редагується непов'язаний код. Помилка → check ловить → AI виправляє — той самий цикл, що для `security@1.12.1` і `changelog`/`image-compress`/`php`/`vue`.
|
|
689
703
|
- **Залишено `alwaysApply: true`** — `text` (cross-cutting cspell-словник, апостроф), `adr` (про процес capture/normalize hooks), `ci4` (0 програмних чекерів — без AI-контексту правило мертве), `abie` (має JS `applies`-гейт, у не-abie репо мовчить; файли розкидані).
|
|
690
704
|
|
|
691
705
|
## [1.12.1] - 2026-05-17
|
|
692
706
|
|
|
693
707
|
### Changed
|
|
694
708
|
|
|
695
|
-
- **`npm/rules/security/security.mdc`** — `alwaysApply: true` → `alwaysApply: false` + `globs: "**/.gitleaks.toml,**/package.json,**/.github/workflows/**/*.yml"`. AI-контекст правила тепер підвантажується лише при роботі з релевантними файлами (за зразком `changelog`/`image-compress`/`php`), а не на кожен турн. Програмна валідація через `npx @nitra/cursor
|
|
709
|
+
- **`npm/rules/security/security.mdc`** — `alwaysApply: true` → `alwaysApply: false` + `globs: "**/.gitleaks.toml,**/package.json,**/.github/workflows/**/*.yml"`. AI-контекст правила тепер підвантажується лише при роботі з релевантними файлами (за зразком `changelog`/`image-compress`/`php`), а не на кожен турн. Програмна валідація через `npx @nitra/cursor fix security` залишається завжди увімкненою (через `auto.md = завжди`) і ловить помилки незалежно від AI-контексту. Версія frontmatter `1.0` → `1.1`.
|
|
696
710
|
- **Мотивація:** правило має повне покриття перевіркою (Rego + JS-check); тримати його `alwaysApply: true` не дає AI додаткової цінності понад те, що `check security` ловить програмно — лише марно займає контекстне вікно при роботі з кодом, не повʼязаним з конфігурацією security.
|
|
697
711
|
|
|
698
712
|
## [1.12.0] - 2026-05-16
|
|
@@ -719,7 +733,7 @@
|
|
|
719
733
|
|
|
720
734
|
### Removed
|
|
721
735
|
|
|
722
|
-
- **`npm/package.json#devDependencies`** — повторно видалено `@nitra/cursor: ^1.11.16` self-reference, який повернувся в коміті `8ae6e9e auto adr` (автоматичний stop-hook fix). Той самий блок уже прибирали в `1.11.14` (див. запис нижче) — потрапив назад через автофікс. `npx @nitra/cursor
|
|
736
|
+
- **`npm/package.json#devDependencies`** — повторно видалено `@nitra/cursor: ^1.11.16` self-reference, який повернувся в коміті `8ae6e9e auto adr` (автоматичний stop-hook fix). Той самий блок уже прибирали в `1.11.14` (див. запис нижче) — потрапив назад через автофікс. `npx @nitra/cursor fix npm-module` знову зелений.
|
|
723
737
|
|
|
724
738
|
## [1.11.16] - 2026-05-16
|
|
725
739
|
|
|
@@ -739,36 +753,36 @@
|
|
|
739
753
|
|
|
740
754
|
### Removed
|
|
741
755
|
|
|
742
|
-
- **`npm/package.json#devDependencies`** — повністю видалено блок (містив лише self-reference `@nitra/cursor: ^1.11.9`). `npx @nitra/cursor
|
|
756
|
+
- **`npm/package.json#devDependencies`** — повністю видалено блок (містив лише self-reference `@nitra/cursor: ^1.11.9`). `npx @nitra/cursor fix npm-module` зафіксував порушення: `devDependencies` не публікуються користувачам пакета, але інструменти, що **потрібні** для розробки пакета, мають жити в кореневому `package.json` (у workspace-root) як `@nitra/cursor: workspace:*` (там уже є). Self-reference у `npm/package.json` лишався з попередньої практики, але **публікувався** у npm-tarball (хоч і ігнорувався установником, оскільки лізе у nested deps), забруднюючи метадані пакета.
|
|
743
757
|
- **`knip.json#workspaces.npm.ignoreDependencies: ["@nitra/cursor"]`** — workaround, доданий у 1.11.13 для приховання knip-violation на self-reference, тепер не потрібен (першопричина прибрана). Знято, щоб конфіг лишався чистим.
|
|
744
758
|
|
|
745
759
|
## [1.11.13] - 2026-05-16
|
|
746
760
|
|
|
747
761
|
### Fixed
|
|
748
762
|
|
|
749
|
-
- **`npm/rules/{bun,image-compress,js-bun-redis,js-run,php,style-lint,text}/fix/<concern>/check.mjs`** — escape `@nitra` як `\@nitra` у JSDoc-блоках (`/** … */`), де `npx @nitra/cursor
|
|
763
|
+
- **`npm/rules/{bun,image-compress,js-bun-redis,js-run,php,style-lint,text}/fix/<concern>/check.mjs`** — escape `@nitra` як `\@nitra` у JSDoc-блоках (`/** … */`), де `npx @nitra/cursor fix` стояв всередині backticks. ESLint-плагін `jsdoc/escape-inline-tags` парсив `@nitra` як інлайн-тег (false-positive у backticks) і видавав 8 warnings. Виправлення — escape-символ `\` перед `@`, як уже зроблено в інших місцях коду (CHANGELOG 1.11.5 для `js-run`). Pass-повідомлення та `//`-коментарі поза JSDoc не зачіпало — там парсер не активний.
|
|
750
764
|
- **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк) — заголовок секції перейменовано з **«Скоуп»** на **«Scope»**, бо cspell флагав «Скоуп» як unknown word. Англійський «Scope» зрозумілий і не вимагає розширення словника. Тіло секції без змін.
|
|
751
765
|
|
|
752
766
|
## [1.11.12] - 2026-05-15
|
|
753
767
|
|
|
754
768
|
### Removed
|
|
755
769
|
|
|
756
|
-
- **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 3 реструктуризації: dual-mode підтримка `js/` (legacy) прибрана. Після завершення масового переїзду у 1.11.10 (всі 26 правил у `rules/<id>/fix/`) інфраструктура `n-cursor
|
|
770
|
+
- **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 3 реструктуризації: dual-mode підтримка `js/` (legacy) прибрана. Після завершення масового переїзду у 1.11.10 (всі 26 правил у `rules/<id>/fix/`) інфраструктура `n-cursor fix` тепер сканує **тільки** `rules/<id>/fix/<concern>/check*.mjs`. Конкретно: (1) у `discoverCheckableRules` видалено `listJsConcerns(js/, 'js')`-виклик, утиліту `mergeJsConcerns` (fatal на дублікат `js/`+`fix/`) і поле `rootDir` у `JsConcern`-типі; (2) у `run-rule.mjs::resolveJsCheckPath` `concern.rootDir ?? 'js'` замінено на хардкод `'fix'`; (3) JSDoc на початку обох файлів і на `evaluateAppliesGate` оновлено з `js/applies/check.mjs` на `fix/applies/check.mjs`; (4) коментар на `discoverCheckScripts` у `npm/bin/n-cursor.js` оновлено — згадку legacy `js/check.mjs` прибрано. Жодне правило в `rules/` не торкається — лише сканер.
|
|
757
771
|
- **`npm/scripts/utils/discover-checkable-rules.test.mjs`**, **`npm/scripts/utils/run-rule.test.mjs`** — прибрано тести dual-mode: `правило з тільки JS-концерном у legacy js/`, `правило з різними концернами у js/ і fix/`, `дублікат концерну в js/ і fix/ — fatal`, `пропускає js/utils/ як концерн`, `концерн з rootDir="fix"`, `концерн без rootDir (legacy-тести) fallback до js/`, `applies-гейт у fix/applies/`. Додано: `legacy js/-структура ігнорується (concern у js/<name>/ не підхоплюється)` — гарантує, що випадковий залишок `js/`-дерева у правилі не виконається, та `правило з кількома JS-концернами в fix/ — всі присутні, відсортовані`. Тестовий хелпер `addJsConcern` / `writeConcernJs` — за замовчуванням пишуть у `fix/` без параметра rootDir.
|
|
758
772
|
|
|
759
773
|
## [1.11.11] - 2026-05-15
|
|
760
774
|
|
|
761
775
|
### Removed
|
|
762
776
|
|
|
763
|
-
- **`npm/scripts/lint-conftest.mjs`** — скрипт видалено повністю. Його єдина функція — ітерувати policy-концерни через `discoverCheckableRules` і запускати `runConftestBatch` на реальних файлах — **повністю дублювала** `npx @nitra/cursor
|
|
777
|
+
- **`npm/scripts/lint-conftest.mjs`** — скрипт видалено повністю. Його єдина функція — ітерувати policy-концерни через `discoverCheckableRules` і запускати `runConftestBatch` на реальних файлах — **повністю дублювала** `npx @nitra/cursor fix` (CHANGELOG 1.11.5: «`bun.bunfig`, `text.cspell`, `npm_module.npm_publish_yml` тепер прогоняються через CLI `check <id>` без додаткового `bun run lint-conftest`»). Окремий канал залишався лише як IDE-fast-feedback, але через одне джерело правди (`target.json` поруч з `.rego`) другий entry-point не дає нічого нового. Кореневий `package.json` оновлено: скрипт `lint-conftest` прибрано, ланцюжок `lint` тепер `bun run lint-rego && bun run lint-js && …` (без `lint-conftest`).
|
|
764
778
|
|
|
765
779
|
### Changed
|
|
766
780
|
|
|
767
|
-
- **`npm/README.md`** — секція «Структура пакету» переписана під поточний layout (`rules/<id>/<id>.mdc` замість застарілих `mdc/`). Додано підсекцію **«Структура одного правила»** з принципом fix/lint/policy: технологія реалізації визначає директорію — JS для `npx @nitra/cursor
|
|
781
|
+
- **`npm/README.md`** — секція «Структура пакету» переписана під поточний layout (`rules/<id>/<id>.mdc` замість застарілих `mdc/`). Додано підсекцію **«Структура одного правила»** з принципом fix/lint/policy: технологія реалізації визначає директорію — JS для `npx @nitra/cursor fix` у `fix/<concern>/`, JS для `bun run lint-<id>` у `lint/`, rego для `npx @nitra/cursor fix` у `policy/<concern>/`. Решта `mdc/`-посилань у README також виправлені на `rules/`.
|
|
768
782
|
- **`.cursor/rules/conftest.mdc`** — крок 5 у workflow «нова перевірка» переписано: окремої реєстрації нового rego-пакета в TARGETS більше не потрібно (TARGETS видалено разом із `lint-conftest.mjs`); `discoverCheckableRules` автоматично підхоплює пакет за наявності `target.json` поруч з `.rego`.
|
|
769
783
|
- **`.cursor/rules/scripts.mdc`** — згадку `lint-conftest.mjs` прибрано зі списку «крос-правильної інфраструктури» у `npm/scripts/`.
|
|
770
|
-
- **`npm/rules/abie/abie.mdc`** (cross-reference) — `npx @nitra/cursor lint-conftest` → `npx @nitra/cursor
|
|
771
|
-
- **`npm/rules/**/fix/<concern>/check.mjs`** (10 файлів) та **`npm/rules/**/policy/<concern>/<name>.rego`** (7 файлів) — у коментарях і `pass()`-повідомленнях `bun run lint-conftest` замінено на `npx @nitra/cursor
|
|
784
|
+
- **`npm/rules/abie/abie.mdc`** (cross-reference) — `npx @nitra/cursor lint-conftest` → `npx @nitra/cursor fix abie`; `npm/policy/abie/` → `npm/rules/abie/policy/`; `check-abie.mjs` → `fix/<concern>/check.mjs`.
|
|
785
|
+
- **`npm/rules/**/fix/<concern>/check.mjs`** (10 файлів) та **`npm/rules/**/policy/<concern>/<name>.rego`** (7 файлів) — у коментарях і `pass()`-повідомленнях `bun run lint-conftest` замінено на `npx @nitra/cursor fix` (структурна валідація живить fix-канал; окремого `lint-conftest`-каналу більше немає). Для conditional rego-полісі без `target.json` (ті, що не auto-discoverable) текст коментарів переформульовано — замість «глобально у `lint-conftest` НЕ реєструється» тепер «без `target.json` поруч (не auto-discoverable через `n-cursor fix`)».
|
|
772
786
|
|
|
773
787
|
## [1.11.10] - 2026-05-15
|
|
774
788
|
|
|
@@ -782,7 +796,7 @@
|
|
|
782
796
|
|
|
783
797
|
### Changed
|
|
784
798
|
|
|
785
|
-
- **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 1 реструктуризації `rules/<id>/js/` → `rules/<id>/{fix,lint}/`: інфраструктура `n-cursor
|
|
799
|
+
- **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 1 реструктуризації `rules/<id>/js/` → `rules/<id>/{fix,lint}/`: інфраструктура `n-cursor fix` тепер **dual-mode** — сканує JS-концерни одночасно у `rules/<id>/js/<concern>/` (legacy) і `rules/<id>/fix/<concern>/` (новий формат). Кожен знайдений концерн штампується полем `rootDir: 'js' | 'fix'`; `runRule` використовує його для побудови шляху імпорту через `resolveJsCheckPath`. Концерн з однаковим іменем у обох каталогах одного правила — fatal-помилка з підказкою «заверши міграцію цього концерну у fix/ і видали `js/<name>/`», щоб не лишалось напіввиконаних move-ів. `utils/` пропускається в обох коренях. Жодне правило ще не переїхало у фазі 1 — це лише підготовка інфраструктури; для зворотної сумісності `resolveJsCheckPath` має fallback `rootDir ?? 'js'`, тож тести, що збирають `jsConcerns` вручну без `rootDir`, продовжують працювати без змін. CLI-точки входу `n-cursor lint-X` (статичні `import` у `npm/bin/n-cursor.js:79-83`) переїдуть пізніше — у фазах 2/3 (move + оновлення imports).
|
|
786
800
|
- **`npm/scripts/utils/discover-checkable-rules.test.mjs`**, **`npm/scripts/utils/run-rule.test.mjs`** — додано покриття нового `fix/`-кореня: окремі тести на discovery концерну у `fix/`, mix `js/`+`fix/` різних концернів одного правила, fatal на дублікат, пропуск `fix/utils/`, runRule з `rootDir: 'fix'`, applies-гейт у `fix/applies/`, та fallback на `js/` для концернів без `rootDir` (зворотна сумісність із наявними тестовими фікстурами).
|
|
787
801
|
|
|
788
802
|
## [1.11.8] - 2026-05-15
|
|
@@ -795,7 +809,7 @@
|
|
|
795
809
|
|
|
796
810
|
### Changed
|
|
797
811
|
|
|
798
|
-
- **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк) — `/n-fix` більше **не запускає** `bun run lint` і **не делегує** до `/n-lint`. Крок 6 (`bun run lint` з делегуванням, доданий у 1.11.6) повністю видалено; замість нього на початку SKILL.md додано секцію **«Scope»**, де явно зафіксовано: `/n-fix` опікується лише структурою проєкту (правила `.cursor/rules/` + `npx @nitra/cursor
|
|
812
|
+
- **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк) — `/n-fix` більше **не запускає** `bun run lint` і **не делегує** до `/n-lint`. Крок 6 (`bun run lint` з делегуванням, доданий у 1.11.6) повністю видалено; замість нього на початку SKILL.md додано секцію **«Scope»**, де явно зафіксовано: `/n-fix` опікується лише структурою проєкту (правила `.cursor/rules/` + `npx @nitra/cursor fix`), а лінт-порушення у самому коді (ESLint/oxlint/jscpd/cspell/knip/sonarjs/stylelint) — поза скоупом і виправляються винятково через `/n-lint`. Кроки 7→6 і 8→7 переномеровано; остаточний пункт 7 додатково нагадує, що лінт-помилки не входять у критерій успіху `/n-fix`. Мета — щоб агент, що виконує `/n-fix`, не плутав свою задачу з `/n-lint` і не запускав важкий `bun run lint` без потреби; те, що діагностує `/n-lint`, виправляється там же, а не дублюється тут.
|
|
799
813
|
|
|
800
814
|
### Fixed
|
|
801
815
|
|
|
@@ -807,7 +821,7 @@
|
|
|
807
821
|
|
|
808
822
|
- **`npm/rules/npm-module/npm-module.mdc`** — переформульовано вимогу про тести й фікстури. Раніше правило вимагало тримати їх **поза** будь-яким шляхом з `"files"` (канонічно — у `npm/tests/`). Тепер тести/фікстури можуть лежати **поруч з кодом** усередині `"files"`-шляхів, але `"files"` обовʼязково має містити **негативні glob-патерни**, що виключають їх із tarball (`!**/*.test.*`, `!**/*.spec.*`, `!**/test-helpers.*`, `!**/fixtures/**`, `!**/__tests__/**`, опційно `!**/*_test.rego`). Це краще відповідає реальному layout пакета (co-located test-файли у `rules/<id>/js/<concern>/`) і прибирає роз'їзд правила з фактичним `npm/package.json`. Версію `.mdc` піднято до `1.12`.
|
|
809
823
|
- **`npm/rules/npm-module/js/package_structure/check.mjs::checkNoTestsInPublishedFiles`** — текст fail-повідомлення тепер однозначно радить додати негативний glob у `"files"`, без альтернативи «винеси за межі шляхів з "files"». Логіка перевірки (walk positive ∖ negative + класифікація test-style) не змінилась — пере-кваліфіковано лише підказку для агента й людини.
|
|
810
|
-
- **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк), **`npm/rules/style-lint/style-lint.mdc`** — розмежовано ролі скілів: `/n-fix` відповідає за **структуру** проєкту (правила `.cursor/rules/` + `npx @nitra/cursor
|
|
824
|
+
- **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк), **`npm/rules/style-lint/style-lint.mdc`** — розмежовано ролі скілів: `/n-fix` відповідає за **структуру** проєкту (правила `.cursor/rules/` + `npx @nitra/cursor fix`), `/n-lint` — за **чистоту коду** (`bun run lint`). Крок 6 у `n-fix` (перебір `lint-js`/`lint-text`/`lint-style`) замінено на одиничний `bun run lint` з делегуванням до `/n-lint` — лінт-логіку (auto-fix, sonarjs-рефакторинг, заборона паралельних запусків ESLint) `n-fix` більше не дублює. У `style-lint.mdc` cross-reference «повний набір `lint-*` (навичка `n-fix`)» оновлено на «`bun run lint` (навичка `/n-lint`)».
|
|
811
825
|
|
|
812
826
|
## [1.11.5] - 2026-05-15
|
|
813
827
|
|
|
@@ -942,11 +956,11 @@
|
|
|
942
956
|
|
|
943
957
|
### Changed
|
|
944
958
|
|
|
945
|
-
- **CLI auto-discovery** підхоплює `check-rego.mjs` і `check-tauri.mjs` через `discoverCheckScripts()` у `bin/n-cursor.js`. Окрема реєстрація не потрібна — будь-який `check-*.mjs` стає доступним через `npx @nitra/cursor
|
|
959
|
+
- **CLI auto-discovery** підхоплює `check-rego.mjs` і `check-tauri.mjs` через `discoverCheckScripts()` у `bin/n-cursor.js`. Окрема реєстрація не потрібна — будь-який `check-*.mjs` стає доступним через `npx @nitra/cursor fix <rule>`.
|
|
946
960
|
|
|
947
961
|
### Verified
|
|
948
962
|
|
|
949
|
-
- **На цьому репо `npx @nitra/cursor
|
|
963
|
+
- **На цьому репо `npx @nitra/cursor fix rego` детектує реальні гепи у `.vscode/extensions.json` (немає `tsandall.opa`) і `.vscode/settings.json` (немає `[rego]` блока).** Це true-positive: репо має `rego` у `.n-cursor.json:rules` і містить `.rego` файли, тож канонічний tooling-набір вимагається. Фікс — додати entries у `.vscode/*` згідно `rego.mdc`.
|
|
950
964
|
|
|
951
965
|
### Not migrated (explained)
|
|
952
966
|
|
|
@@ -1102,7 +1116,7 @@
|
|
|
1102
1116
|
|
|
1103
1117
|
### Changed
|
|
1104
1118
|
|
|
1105
|
-
- **AGENTS.md — додано `bunx knip` до секції Commands:** `build-agents-commands.mjs` тепер завжди додає рядок `- **knip (невикористані залежності та експорти)**: \`bunx knip\``після`npx @nitra/cursor
|
|
1119
|
+
- **AGENTS.md — додано `bunx knip` до секції Commands:** `build-agents-commands.mjs` тепер завжди додає рядок `- **knip (невикористані залежності та експорти)**: \`bunx knip\``після`npx @nitra/cursor fix`; оновлено тест (`items.length`3 → 4, перевірка`toContain('bunx knip')`).
|
|
1106
1120
|
- **`knip.json` — `graphql` у `ignoreDependencies`:** повернуто `graphql` до кореневого `ignoreDependencies` (peer-залежність, яку knip фолсово репортить як unused; вимога `js-lint.mdc` / `check-js-lint.mjs`).
|
|
1107
1121
|
|
|
1108
1122
|
## [1.9.8] - 2026-05-12
|
|
@@ -1198,7 +1212,7 @@
|
|
|
1198
1212
|
|
|
1199
1213
|
### Changed
|
|
1200
1214
|
|
|
1201
|
-
- **ga / Plan B (rego-authoritative, повна централізація):** rego-крок переїхав із `lint-ga.mjs` у `check-ga.mjs::check()` як **перший крок**. Раніше `bun run lint-ga` сам викликав 4 per-workflow conftest + 1 batch для `ga.workflow_common`, а `npx @nitra/cursor
|
|
1215
|
+
- **ga / Plan B (rego-authoritative, повна централізація):** rego-крок переїхав із `lint-ga.mjs` у `check-ga.mjs::check()` як **перший крок**. Раніше `bun run lint-ga` сам викликав 4 per-workflow conftest + 1 batch для `ga.workflow_common`, а `npx @nitra/cursor fix ga` цю частину не робив — тепер вся ga-логіка (rego + JS cross-file) в одному `check-ga.check()`. `lint-ga.mjs::runLintGaCli` спрощено: preflight (shellcheck/uv) → actionlint → zizmor → `await checkGa()`. Видалено: `CONFTEST_TARGETS`, `GA_POLICY_DIR`, `runConftestStep`, `runConftestWorkflowCommon` — і непотрібні імпорти `existsSync`/`readdirSync`/`dirname`/`join`/`fileURLToPath`. `runLintGaCli` тепер `async`; `bin/n-cursor.js` оновлено на `await runLintGaCli()`. Тест `lint-ga.test.mjs` оновлено: `await fn()` замість `fn()`. Тест `check-ga.test.mjs::"exit 1 коли shellcheck відсутній"` переведений на точковий виклик експортованої `checkShellcheckInstalled` (бо `withBinRemovedFromPath('shellcheck')` на macOS заодно видаляв `/opt/homebrew/bin` де conftest, ламаючи hard-fail у `runConftestBatch`).
|
|
1202
1216
|
- **`check-ga.mjs::checkShellcheckInstalled`:** додано `export` (потрібен для точкового тесту після рефактору).
|
|
1203
1217
|
- **тестова фікстура `setupCanonicalGaProject` у check-ga.test.mjs:** додано секцію `concurrency` (з канонічними `group` і `cancel-in-progress: true`) у workflow `clean-ga-workflows.yml`, `clean-merged-branch.yml`, `git-ai.yml` — `ga.workflow_common` rego тепер запускається у `check()`, а ці workflow раніше не мали concurrency у фікстурі (правило `lint-ga.yml` уже мало). Це **правильна** реакція: rego-перевірка тепер ловить порушення на тих самих фікстурах, на яких раніше не запускалась.
|
|
1204
1218
|
|
|
@@ -1331,7 +1345,7 @@
|
|
|
1331
1345
|
`redis`, підшляхів `ioredis/...` / `redis/...` і `@redis/*`. Не зачіпає
|
|
1332
1346
|
сторонні `redis-*` (наприклад, `redis-mock`).
|
|
1333
1347
|
- `npm/scripts/check-js-bun-redis.mjs` запускає AST-скан по JS/TS-джерелах і
|
|
1334
|
-
доступний як `npx @nitra/cursor
|
|
1348
|
+
доступний як `npx @nitra/cursor fix js-bun-redis`.
|
|
1335
1349
|
- Rego-полісі `npm/policy/js_bun_redis/package_json/` — заборона
|
|
1336
1350
|
`ioredis` / `node-redis` / `redis` / `@redis/*` у `dependencies` будь-якого
|
|
1337
1351
|
`package.json` у дереві; зареєстрована таргетом у
|
|
@@ -1521,7 +1535,7 @@
|
|
|
1521
1535
|
|
|
1522
1536
|
### Added
|
|
1523
1537
|
|
|
1524
|
-
- `mdc/rego.mdc` (нова версія 1.1, з 1.0): VS Code-секція з рекомендованим розширенням `tsandall.opa` (LSP від автора OPA: підсвічування, hover, go-to-definition, format-on-save через `opa fmt`), `.vscode/extensions.json` і `.vscode/settings.json` сніпети для `[rego]` (`editor.defaultFormatter: tsandall.opa`, `formatOnSave: true`); опис кроків `lint-rego` (preflight `opa`+`regal`, далі `opa check --strict` і `regal lint`); `package.json`-сніпет зі скриптом `lint-rego`; install-команди (`brew install opa regal` + universal лінки); приклад `.regal/config.yaml`. Раніше файл містив лише placeholder `npx @nitra/cursor
|
|
1538
|
+
- `mdc/rego.mdc` (нова версія 1.1, з 1.0): VS Code-секція з рекомендованим розширенням `tsandall.opa` (LSP від автора OPA: підсвічування, hover, go-to-definition, format-on-save через `opa fmt`), `.vscode/extensions.json` і `.vscode/settings.json` сніпети для `[rego]` (`editor.defaultFormatter: tsandall.opa`, `formatOnSave: true`); опис кроків `lint-rego` (preflight `opa`+`regal`, далі `opa check --strict` і `regal lint`); `package.json`-сніпет зі скриптом `lint-rego`; install-команди (`brew install opa regal` + universal лінки); приклад `.regal/config.yaml`. Раніше файл містив лише placeholder `npx @nitra/cursor fix rego`.
|
|
1525
1539
|
|
|
1526
1540
|
### Changed
|
|
1527
1541
|
|
|
@@ -1617,7 +1631,7 @@
|
|
|
1617
1631
|
- `image` правило розщеплене на два самостійні: **`image-compress`** (валідація `lint-image` / `.gitignore` / залежностей — стиснення raster/SVG через `@nitra/minify-image`) і **`image-avif`** (генерація AVIF-двійників, переписування raster-посилань у `.vue`/`.html` на `.avif`, прибирання AVIF-сиріт). Це дозволяє тримати компресію всюди, а AVIF — лише там, де його підтримка гарантована (адмінки), вимикаючи його для публічних сайтів через `disable-rules: ["image-avif"]` у `.n-cursor.json` чи опт-аут на рівні пакета (`"@nitra/minify-image": { "disable-avif": true }` у `package.json` сайту).
|
|
1618
1632
|
- `auto-rules.md` / `auto-rules.mjs`: автодетект `image-compress - [bun]` (всюди, де є `package.json`), `image-avif - [vue, image-compress]` (лише для проєктів з `.vue`-файлами і вже активним `image-compress`).
|
|
1619
1633
|
- Видалено `npm/scripts/check-image.mjs` і `npm/mdc/image.mdc` — їх замінили `check-image-compress.mjs` + `check-image-avif.mjs` і `image-compress.mdc` + `image-avif.mdc`.
|
|
1620
|
-
- Канонічний `lint-image` залишається без `--avif` (його перевіряє `image-compress`); `npx @nitra/cursor
|
|
1634
|
+
- Канонічний `lint-image` залишається без `--avif` (його перевіряє `image-compress`); `npx @nitra/cursor fix image-avif` тепер є самостійною командою для AVIF-pipeline.
|
|
1621
1635
|
|
|
1622
1636
|
### Added
|
|
1623
1637
|
|
|
@@ -1724,7 +1738,7 @@
|
|
|
1724
1738
|
|
|
1725
1739
|
### Changed
|
|
1726
1740
|
|
|
1727
|
-
- `image` (mdc v1.4 → v1.5): прапорець `--avif` у `lint-image` тепер **заборонений** (інакше `bun run lint` плодив би `.avif` для зображень, що ніде не вживаються); канонічний `lint-image` — `npx @nitra/minify-image --src=. --write`. AVIF-генерацію виконує **виключно** `npx @nitra/cursor
|
|
1741
|
+
- `image` (mdc v1.4 → v1.5): прапорець `--avif` у `lint-image` тепер **заборонений** (інакше `bun run lint` плодив би `.avif` для зображень, що ніде не вживаються); канонічний `lint-image` — `npx @nitra/minify-image --src=. --write`. AVIF-генерацію виконує **виключно** `npx @nitra/cursor fix image`. Секцію «AVIF-імпорти у `.vue`» переписано: тепер вона документує триетапну логіку `check image` — (1) запуск `npx @nitra/minify-image --src=. --write --avif`, (2) авто-заміна raster-посилань у `.vue`/`.html` на `.avif` у кожному workspace-пакеті, (3) прибирання AVIF-сиріт (файли `.avif` без жодного посилання у `.vue`/`.html` видаляються — AVIF лишається лише там, де заміна реально вдалася).
|
|
1728
1742
|
- `check-image.mjs`: `checkLintImageScript` більше не вимагає `--avif`, натомість фейлить за його наявністю; додано `runAvifGeneration` (best-effort `npx ... --avif`, опт-аут через `NITRA_CURSOR_NO_AVIF_RUN=1` для тестів), `cleanupOrphanAvifs` (видаляє `<...>.avif` без живого посилання), `hasAnyRasterImage`, `resolveImagePath`. `checkVueAvifImportsInPackage` тепер не лише валідує, а й переписує raster-посилання на `.avif` (коли AVIF-двійник реально існує на диску); якщо `.avif` нема — фейл, як раніше. Сканування поширено на `.html` файли (раніше було тільки `.vue`).
|
|
1729
1743
|
- `tests/check-image.test.mjs`: `CANONICAL_LINT_IMAGE` без `--avif`; кейс «без `--avif`» перейменовано/перекинуто на «з забороненим `--avif`»; додано тести на orphan-cleanup (`.avif` без посилань видаляється) та авто-заміну raster-імпорту, коли `.avif`-сусід реально існує.
|
|
1730
1744
|
|
|
@@ -1867,7 +1881,7 @@
|
|
|
1867
1881
|
|
|
1868
1882
|
### Added
|
|
1869
1883
|
|
|
1870
|
-
- `ga.mdc` (v1.4) / `check-ga.mjs`: нова перевірка локального [`shellcheck`](https://www.shellcheck.net/) у `PATH`. Без нього `actionlint` (`bunx github-actionlint`) мовчки пропускає shell-перевірки в `run:` блоках, тож локальний `bun lint-ga` дає зелений результат, який падає в CI на `ubuntu-latest` (де shellcheck передвстановлений). `npx @nitra/cursor
|
|
1884
|
+
- `ga.mdc` (v1.4) / `check-ga.mjs`: нова перевірка локального [`shellcheck`](https://www.shellcheck.net/) у `PATH`. Без нього `actionlint` (`bunx github-actionlint`) мовчки пропускає shell-перевірки в `run:` блоках, тож локальний `bun lint-ga` дає зелений результат, який падає в CI на `ubuntu-latest` (де shellcheck передвстановлений). `npx @nitra/cursor fix ga` тепер `fail` з підказкою встановлення (`brew install shellcheck` / `apt-get install -y shellcheck` / `pacman -S shellcheck`).
|
|
1871
1885
|
|
|
1872
1886
|
### Changed
|
|
1873
1887
|
|
|
@@ -1883,7 +1897,7 @@
|
|
|
1883
1897
|
|
|
1884
1898
|
### Added
|
|
1885
1899
|
|
|
1886
|
-
- `abie.mdc` (v1.16) / `check-abie.mjs`: нова перевірка `.github/actionlint.yaml`. Якщо файл відсутній — `npx @nitra/cursor
|
|
1900
|
+
- `abie.mdc` (v1.16) / `check-abie.mjs`: нова перевірка `.github/actionlint.yaml`. Якщо файл відсутній — `npx @nitra/cursor fix abie` створює його з канонічним вмістом (`self-hosted-runner.labels: ['ua', 'dev', 'ru']`); якщо є — звіряє, що в `self-hosted-runner.labels` присутні мітки `ua`, `dev`, `ru` (порядок, інші мітки й формат лапок дозволені). Експортовано `ABIE_REQUIRED_ACTIONLINT_LABELS`, `parseActionlintSelfHostedLabels`, `abieMissingActionlintLabels`.
|
|
1887
1901
|
|
|
1888
1902
|
## [1.8.163] - 2026-05-01
|
|
1889
1903
|
|
package/README.md
CHANGED
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
|
|
53
53
|
- **Структура Kustomize:** спільне виноситься в **`base`**; вміст **base** відповідає тому, як має виглядати середовище **dev**; окремої директорії **`dev/`** немає — за dev відповідає **`base`**. У інших середовищах — тонкі **overlays** (часто лише **`kustomization.yaml`** і patches / оверрайди).
|
|
54
54
|
- **Namespace** задається в **`kustomization.yaml`** (`namespace:`), а не через **`metadata.namespace`** у кожному ресурсі; окремі patches лише на зміну **namespace** не потрібні.
|
|
55
|
-
- У **Deployment** для кожного контейнера: **`resources`** (перевіряє **`npx @nitra/cursor
|
|
55
|
+
- У **Deployment** для кожного контейнера: **`resources`** (перевіряє **`npx @nitra/cursor fix k8s`**);
|
|
56
56
|
- Рядки в **base**, які змінюються в overlays, позначайте коментарем на рядку (узгоджено в команді), наприклад: `# буде замінено через kustomize`.
|
|
57
57
|
- Після перенесення в **`base`** / overlays **видаляйте** застарілі маніфести та каталоги, які більше не потрібні.
|
|
58
58
|
|
|
59
|
-
Повний текст правил — у **`k8s.mdc`**; programmatic перевірки — у **`npm/rules/k8s/`**: JS-checks у `js/<concern>/check.mjs`, rego-policies у `policy/<concern>/<name>.rego` (обидва запускаються через `npx @nitra/cursor
|
|
59
|
+
Повний текст правил — у **`k8s.mdc`**; programmatic перевірки — у **`npm/rules/k8s/`**: JS-checks у `js/<concern>/check.mjs`, rego-policies у `policy/<concern>/<name>.rego` (обидва запускаються через `npx @nitra/cursor fix k8s`).
|
|
60
60
|
|
|
61
61
|
### v8r і власний каталог схем
|
|
62
62
|
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
68
|
npx @nitra/cursor
|
|
69
|
-
npx @nitra/cursor
|
|
70
|
-
npx @nitra/cursor
|
|
69
|
+
npx @nitra/cursor fix
|
|
70
|
+
npx @nitra/cursor fix bun ga
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Команда `check` запускає programmatic перевірки з каталогу `scripts/` пакету. Якщо в корені репозиторію вже є `.n-cursor.json`, перед перевірками виконується зчитування конфігу — зокрема додається або виправляється поле `$schema`, якщо воно відсутнє або не збігається з очікуваним URL.
|
|
@@ -115,7 +115,7 @@ npm/
|
|
|
115
115
|
npm/rules/<id>/
|
|
116
116
|
├── <id>.mdc # текст правила (після синку — .cursor/rules/n-<id>.mdc)
|
|
117
117
|
├── auto.md # умова автоактивації скілу (опційно)
|
|
118
|
-
├── js/ # JS для `npx @nitra/cursor
|
|
118
|
+
├── js/ # JS для `npx @nitra/cursor fix`
|
|
119
119
|
│ └── <concern>/
|
|
120
120
|
│ ├── check.mjs # діагностика — повертає список violations
|
|
121
121
|
│ ├── check.test.mjs
|
|
@@ -123,7 +123,7 @@ npm/rules/<id>/
|
|
|
123
123
|
├── lint/ # JS, що живить `bun run lint-<id>` (для правил з канонічним lint-скриптом)
|
|
124
124
|
│ ├── lint.mjs # CLI entry для `n-cursor lint-<id>`
|
|
125
125
|
│ └── run-*.mjs # допоміжні runner-и (shellcheck, v8r тощо)
|
|
126
|
-
└── policy/ # rego для `npx @nitra/cursor
|
|
126
|
+
└── policy/ # rego для `npx @nitra/cursor fix`
|
|
127
127
|
└── <concern>/
|
|
128
128
|
├── <concern>.rego # правила (`deny contains msg if …`)
|
|
129
129
|
├── <concern>_test.rego # юніт-тести (запускає `bun run lint-rego` → conftest verify)
|
|
@@ -134,11 +134,11 @@ npm/rules/<id>/
|
|
|
134
134
|
|
|
135
135
|
| Що реалізує | Канал виклику | Куди |
|
|
136
136
|
| ------------------------- | ---------------------------------------------- | ------------------- |
|
|
137
|
-
| JS-діагностика + автофікс | `npx @nitra/cursor
|
|
137
|
+
| JS-діагностика + автофікс | `npx @nitra/cursor fix` (fix-канал) | `js/<concern>/` |
|
|
138
138
|
| JS-orchestrator лінту | `bun run lint-<id>` через `n-cursor lint-<id>` | `lint/` |
|
|
139
|
-
| Rego-діагностика | `npx @nitra/cursor
|
|
139
|
+
| Rego-діагностика | `npx @nitra/cursor fix` (fix-канал) | `policy/<concern>/` |
|
|
140
140
|
|
|
141
|
-
`js/` і `policy/` обидва живлять fix-канал (`npx @nitra/cursor
|
|
141
|
+
`js/` і `policy/` обидва живлять fix-канал (`npx @nitra/cursor fix` запускає і JS-checks, і rego-policies), але **розділені за технологією**: JS у `js/`, rego у `policy/`. `lint/` тримає лише JS, що оркеструє `bun run lint-<id>`.
|
|
142
142
|
|
|
143
143
|
## AGENTS.md у проєкті користувача
|
|
144
144
|
|
|
@@ -165,7 +165,7 @@ npm/rules/<id>/
|
|
|
165
165
|
|
|
166
166
|
3. Для секції **Skills** використовуйте блок **`{{#skills}}` … `{{/skills}}`** з тим самим `{{name}}`: рядки формуються з каталогів у `.cursor/skills/` (див. також `buildSkillBulletItems` у `bin/n-cursor.js`).
|
|
167
167
|
|
|
168
|
-
4. Для секції **Commands** використовуйте **`{{#commands}}` … `{{/commands}}`**: список генерується з кореневого **`package.json`** (поле `scripts` — відомі ключі у фіксованому порядку, плюс додаткові `lint-*`) та завжди доповнюється рядками про **`npx @nitra/cursor`** і **`npx @nitra/cursor
|
|
168
|
+
4. Для секції **Commands** використовуйте **`{{#commands}}` … `{{/commands}}`**: список генерується з кореневого **`package.json`** (поле `scripts` — відомі ключі у фіксованому порядку, плюс додаткові `lint-*`) та завжди доповнюється рядками про **`npx @nitra/cursor`** і **`npx @nitra/cursor fix`**. Логіка винесена в **`npm/scripts/build-agents-commands.mjs`**.
|
|
169
169
|
|
|
170
170
|
5. Після змін у шаблоні перевірте локально: у тестовому репозиторії з `.n-cursor.json` виконайте `npx`/`bunx` на зібраному пакеті або `node npm/bin/n-cursor.js` з кореня того репозиторію і переконайтеся, що **`AGENTS.md`** виглядає як очікується.
|
|
171
171
|
|
package/bin/n-cursor.js
CHANGED
|
@@ -90,7 +90,6 @@ 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 { getOrCreateWalkCache } from '../scripts/utils/walk-cache.mjs'
|
|
94
93
|
import { syncClaudeConfig } from '../scripts/sync-claude-config.mjs'
|
|
95
94
|
import { upgradeNitraCursorToLatestAndBunInstall } from '../scripts/upgrade-nitra-cursor-and-install.mjs'
|
|
96
95
|
import { runRenameYamlExtensionsCli } from './rename-yaml-extensions.mjs'
|
|
@@ -974,86 +973,56 @@ function logRemovedManagedItems(title, basePath, names) {
|
|
|
974
973
|
}
|
|
975
974
|
|
|
976
975
|
/**
|
|
977
|
-
*
|
|
978
|
-
*
|
|
979
|
-
*
|
|
980
|
-
*
|
|
981
|
-
*
|
|
976
|
+
* Spawn-wrapper для `npx @nitra/cursor fix [<rule>...]`. Один шлях у коді: для кожного правила
|
|
977
|
+
* робить `bun rules/<id>/fix.mjs` як окремий процес. Сам `fix.mjs` читає `.n-cursor.json`,
|
|
978
|
+
* перевіряє whitelist (`runRuleCli`) і друкує per-rule summary.
|
|
979
|
+
*
|
|
980
|
+
* Без аргументів — discover з `.cursor/rules/*.mdc` у проекті-споживачі.
|
|
981
|
+
* @param {string[]} requestedRules імена правил; порожній масив — discovery з `.cursor/rules/`
|
|
982
982
|
* @returns {Promise<void>}
|
|
983
983
|
*/
|
|
984
|
-
async function
|
|
984
|
+
async function runFixCommand(requestedRules) {
|
|
985
985
|
const available = await listRuleIds(BUNDLED_RULES_DIR)
|
|
986
986
|
if (available.length === 0) {
|
|
987
|
-
console.error('❌ Не знайдено жодного
|
|
988
|
-
throw new Error('No
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
const root = cwd()
|
|
992
|
-
const legacyConfigPath = join(root, 'nitra-cursor.json')
|
|
993
|
-
if (existsSync(join(root, CONFIG_FILE)) || existsSync(legacyConfigPath)) {
|
|
994
|
-
try {
|
|
995
|
-
await readConfig()
|
|
996
|
-
} catch (error) {
|
|
997
|
-
console.error(`❌ ${error.message}`)
|
|
998
|
-
throw error
|
|
999
|
-
}
|
|
987
|
+
console.error('❌ Не знайдено жодного правила у пакеті')
|
|
988
|
+
throw new Error('No rules found')
|
|
1000
989
|
}
|
|
1001
990
|
|
|
1002
|
-
let
|
|
991
|
+
let idsToRun
|
|
1003
992
|
if (requestedRules.length > 0) {
|
|
1004
|
-
|
|
993
|
+
const unknown = requestedRules.filter(id => !available.includes(id))
|
|
994
|
+
if (unknown.length > 0) {
|
|
995
|
+
console.error(`❌ Невідомі правила: ${unknown.join(', ')}`)
|
|
996
|
+
console.log(` Доступні: ${available.join(', ')}`)
|
|
997
|
+
throw new Error(`Unknown rules: ${unknown.join(', ')}`)
|
|
998
|
+
}
|
|
999
|
+
idsToRun = requestedRules
|
|
1005
1000
|
} else {
|
|
1006
1001
|
const mdcFiles = await listProjectRulesMdcFiles()
|
|
1007
1002
|
if (mdcFiles.length === 0) {
|
|
1008
1003
|
throw new Error(
|
|
1009
|
-
`Немає файлів *.mdc у ${RULES_DIR}/. Запустіть \`npx ${PACKAGE_NAME}\` або вкажіть правила: \`npx ${PACKAGE_NAME}
|
|
1004
|
+
`Немає файлів *.mdc у ${RULES_DIR}/. Запустіть \`npx ${PACKAGE_NAME}\` або вкажіть правила: \`npx ${PACKAGE_NAME} fix bun ga\``
|
|
1010
1005
|
)
|
|
1011
1006
|
}
|
|
1012
|
-
|
|
1013
|
-
if (
|
|
1007
|
+
idsToRun = discoverCheckRulesFromCursorRules(available, mdcFiles)
|
|
1008
|
+
if (idsToRun.length === 0) {
|
|
1014
1009
|
console.log(
|
|
1015
|
-
`\n🔍 ${PACKAGE_NAME}
|
|
1010
|
+
`\n🔍 ${PACKAGE_NAME} fix — у ${RULES_DIR}/ немає правил з programmatic перевіркою ` +
|
|
1016
1011
|
`(відповідного fix.mjs у пакеті). Нічого не запущено.\n`
|
|
1017
1012
|
)
|
|
1018
1013
|
return
|
|
1019
1014
|
}
|
|
1020
1015
|
}
|
|
1021
1016
|
|
|
1022
|
-
const unknown = idsToCheck.filter(id => !available.includes(id))
|
|
1023
|
-
if (unknown.length > 0) {
|
|
1024
|
-
console.error(`❌ Невідомі правила: ${unknown.join(', ')}`)
|
|
1025
|
-
console.log(` Доступні: ${available.join(', ')}`)
|
|
1026
|
-
throw new Error(`Unknown rules: ${unknown.join(', ')}`)
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
console.log(`\n🔍 ${PACKAGE_NAME} check — перевірка правил (${idsToCheck.length})\n`)
|
|
1030
|
-
|
|
1031
|
-
/** @type {Map<string, Promise<string[]>>} shared walk-cache (cross-concern, cross-rule у межах одного прогону) */
|
|
1032
|
-
const walkCache = getOrCreateWalkCache()
|
|
1033
1017
|
let totalFailed = 0
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
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 })
|
|
1044
|
-
if (code !== 0) totalFailed++
|
|
1045
|
-
} catch (error) {
|
|
1046
|
-
console.log(` ❌ Помилка виконання: ${error.message}`)
|
|
1047
|
-
totalFailed++
|
|
1048
|
-
}
|
|
1049
|
-
console.log()
|
|
1018
|
+
for (const id of idsToRun) {
|
|
1019
|
+
const fixPath = join(BUNDLED_RULES_DIR, id, 'fix.mjs')
|
|
1020
|
+
const result = spawnSync('bun', [fixPath], { stdio: 'inherit' })
|
|
1021
|
+
if (result.status !== 0) totalFailed++
|
|
1050
1022
|
}
|
|
1051
1023
|
|
|
1052
|
-
const passedCount = idsToCheck.length - totalFailed
|
|
1053
|
-
console.log(`✨ Результат: ${passedCount}/${idsToCheck.length} правил без зауважень\n`)
|
|
1054
|
-
|
|
1055
1024
|
if (totalFailed > 0) {
|
|
1056
|
-
throw new Error(`${totalFailed} з ${
|
|
1025
|
+
throw new Error(`${totalFailed} з ${idsToRun.length} правил мають проблеми`)
|
|
1057
1026
|
}
|
|
1058
1027
|
}
|
|
1059
1028
|
|
|
@@ -1252,8 +1221,15 @@ const [command, ...args] = process.argv.slice(2)
|
|
|
1252
1221
|
try {
|
|
1253
1222
|
await ensureNitraCursorInRootDevDependencies(cwd())
|
|
1254
1223
|
switch (command) {
|
|
1224
|
+
case 'fix': {
|
|
1225
|
+
await runFixCommand(args)
|
|
1226
|
+
|
|
1227
|
+
break
|
|
1228
|
+
}
|
|
1255
1229
|
case 'check': {
|
|
1256
|
-
|
|
1230
|
+
// Backward-compatibility alias. Перейменовано на `fix` у 1.13.84 (узгоджено з ім'ям файла `rules/<id>/fix.mjs`).
|
|
1231
|
+
console.warn(`⚠️ Команда \`check\` deprecated — використовуйте \`fix\` (\`npx ${PACKAGE_NAME} fix [<rule>...]\`)`)
|
|
1232
|
+
await runFixCommand(args)
|
|
1257
1233
|
|
|
1258
1234
|
break
|
|
1259
1235
|
}
|
package/package.json
CHANGED
package/rules/abie/abie.mdc
CHANGED
|
@@ -138,7 +138,7 @@ KVCMS_URL=http://kvcms-hl.ua-apruv.svc.abie-ua.internal:8080
|
|
|
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) — `
|
|
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
|
|
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
|
|
package/rules/abie/fix.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
|
|
5
|
+
* Library mode: викликається CLI orchestration через `import + run(ctx)`.
|
|
5
6
|
* @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
|
|
6
7
|
* @returns {Promise<number>} 0 — OK, 1 — порушення
|
|
7
8
|
*/
|
|
@@ -10,6 +11,9 @@ export function run(ctx) {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
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')
|
|
13
17
|
// eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
|
|
14
|
-
process.exit(await
|
|
18
|
+
process.exit(await runRuleCli(import.meta.dirname))
|
|
15
19
|
}
|
package/rules/adr/fix.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { runStandardRule } from '../../scripts/utils/run-standard-rule.mjs'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
|
|
5
|
+
* Library mode: викликається CLI orchestration через `import + run(ctx)`.
|
|
5
6
|
* @param {import('../../scripts/utils/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
|
|
6
7
|
* @returns {Promise<number>} 0 — OK, 1 — порушення
|
|
7
8
|
*/
|
|
@@ -10,6 +11,9 @@ export function run(ctx) {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
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')
|
|
13
17
|
// eslint-disable-next-line unicorn/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
|
|
14
|
-
process.exit(await
|
|
18
|
+
process.exit(await runRuleCli(import.meta.dirname))
|
|
15
19
|
}
|