@nitra/cursor 1.13.83 → 1.13.85
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 +56 -27
- package/README.md +10 -10
- package/bin/n-cursor.js +40 -60
- 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/lint/lint.mjs +10 -3
- 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 +12 -5
- 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/rego/lint/lint.mjs +12 -2
- 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/lint/lint.mjs +9 -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/scripts/utils/run-standard-rule.mjs +12 -3
- package/scripts/utils/with-lock.mjs +2 -2
- 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,35 @@
|
|
|
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.85] - 2026-05-23
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`withLock` розгорнуто на всі важкі CLI-команди:** додано серіалізацію + дедуп у `lint-rego`, `lint-text`, `lint-k8s`, `lint-docker` за тим самим зразком, що `lint-ga` (приватна `runLint<Foo>Steps()` + публічна `runLint<Foo>Cli = () => withLock('lint-<rule>', …)`).
|
|
12
|
+
- **`fix`-лок переїхав у `runStandardRule`:** замість зовнішньої обгортки навколо `runFixCommand` у `bin/n-cursor.js`, `withLock('fix-<ruleId>')` тепер всередині `scripts/utils/run-standard-rule.mjs`. Кожен `rules/<id>/fix.mjs` отримує лок «безкоштовно» через делегацію; `npx @nitra/cursor fix`, прямий `bun rules/<id>/fix.mjs` і `run(ctx)`-композиція проходять через одну точку. Per-rule гранулярність — різні правила паралельно, однакові серіалізуються.
|
|
13
|
+
- **`runLintRego` тепер async** (наслідок обгортки), додано окремий export `runLintRegoSteps(cwd)` для тестів — щоб не дедупувати проти попереднього прогону, який лишив cached result у `node_modules/.cache/n-cursor/lint-rego/`.
|
|
14
|
+
- **`.cursor/rules/scripts.mdc` 1.8 → 1.9:** додано канонічну секцію «Серіалізація важких CLI-команд: `withLock`» з патерном інтеграції, таблицею ключів і red flags.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Тест `withLock integration > serializes parallel calls` падав через дедуп (обидва виклики бачили однаковий fingerprint і другий пропускав). Тест явно вимикає дедуп через `getFingerprint: () => null` — окремо тестується серіалізація, окремо дедуп.
|
|
19
|
+
- Тест `runLintTextCli` після обгортки повертає Promise; `withIsolatedPath` тепер `await fn()`.
|
|
20
|
+
- JSDoc-тип `withLock` opts розширено `getFingerprint?` (вже використовувався у runtime, але був відсутній у сигнатурі — TS видавав error 2353).
|
|
21
|
+
|
|
22
|
+
## [1.13.84] - 2026-05-23
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **CLI команда `check` перейменована на `fix`** (узгоджено з ім'ям файла `rules/<id>/fix.mjs`). `npx @nitra/cursor fix [<rule>...]` — новий канонічний формат. Команда `check` залишається як deprecated alias з warning'ом — буде видалена в наступній major-версії.
|
|
27
|
+
- **CLI стає spawn-wrapper:** замість inline dynamic import у `runChecks`, `fix [<rule>...]` тепер просто послідовно спавнить `bun rules/<id>/fix.mjs` per rule (один шлях у коді — `fix.mjs` як єдина авторитативна точка входу). Discovery з `.cursor/rules/*.mdc` без аргументів зберігається.
|
|
28
|
+
- **`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>`.
|
|
29
|
+
- **Документація переписана:** всі `npx @nitra/cursor check <rule>` у `.mdc`, `.cursor/rules/`, `README.md`, skills, JSDoc pass-повідомленнях оновлено на `fix`. Один формат у документації; CLI alias `check` лишається тільки для backward compatibility.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **`scripts/utils/run-rule-cli.mjs`** — standalone runner з config-loading + summary; використовується `fix.mjs::main` блоком.
|
|
34
|
+
- **`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).
|
|
35
|
+
|
|
7
36
|
## [1.13.83] - 2026-05-23
|
|
8
37
|
|
|
9
38
|
### Changed
|
|
@@ -20,7 +49,7 @@
|
|
|
20
49
|
|
|
21
50
|
### Notes
|
|
22
51
|
|
|
23
|
-
- Зворотна сумісність CLI: `npx @nitra/cursor
|
|
52
|
+
- Зворотна сумісність CLI: `npx @nitra/cursor fix` та `npx @nitra/cursor fix abie` працюють як раніше.
|
|
24
53
|
- 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
54
|
|
|
26
55
|
## [1.13.82] - 2026-05-23
|
|
@@ -33,7 +62,7 @@
|
|
|
33
62
|
- `rules/test/fix/location/check.mjs` — перевіряє **лише `*.test.mjs`**, `*_test.rego` свідомо виключено з область перевірки (зафіксовано у docstring).
|
|
34
63
|
- Додано test-case у `rules/test/fix/location/tests/check.test.mjs`: `*_test.rego` поряд із полісі НЕ є порушенням.
|
|
35
64
|
- **Відкат переміщення `*_test.rego`**: 69 файлів, які раніше було помилково перенесено у `policy/<concern>/tests/<name>_test.rego`, повернуто у `policy/<concern>/<name>_test.rego` через `git mv`. Порожні `tests/` піддиректорії під `policy/` видалено.
|
|
36
|
-
- **`npx @nitra/cursor
|
|
65
|
+
- **`npx @nitra/cursor fix test`** охоплює лише JS-тести: «✅ Всі 77 файлів *.test.mjs у каталозі tests/». Rego-тести продовжують перевірятись через `conftest verify` у правилі `rego`.
|
|
37
66
|
|
|
38
67
|
## [1.13.81] - 2026-05-23
|
|
39
68
|
|
|
@@ -61,7 +90,7 @@
|
|
|
61
90
|
- Ручні фіксапи 4 тестів із HERE/`..` path patterns (sync-setup-bun-deps-action, inline-template-links, rules/adr/fix/hooks, rules/abie/utils/enabled) — додано додатковий `..`, бо тести стали на рівень глибше.
|
|
62
91
|
- `package.json#files` негативні globs (`!**/*.test.mjs`, `!**/__fixtures__/**`, `!**/fixtures/**`) працюють рекурсивно — без змін.
|
|
63
92
|
- **77 тестів** проходять у новому layout (76 існуючих + 1 нового правила): `bun test` 843 pass / 2 fail (обидва — pre-existing `with-lock` issues, не пов'язані).
|
|
64
|
-
- `npx @nitra/cursor
|
|
93
|
+
- `npx @nitra/cursor fix test` → `✅ Всі 77 файлів *.test.mjs у каталозі tests/ (test.mdc)`.
|
|
65
94
|
|
|
66
95
|
## [1.13.79] - 2026-05-23
|
|
67
96
|
|
|
@@ -215,7 +244,7 @@
|
|
|
215
244
|
|
|
216
245
|
### Added
|
|
217
246
|
|
|
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
|
|
247
|
+
- Нове `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
248
|
- `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
249
|
|
|
221
250
|
## [1.13.57] - 2026-05-19
|
|
@@ -685,14 +714,14 @@
|
|
|
685
714
|
- **`tauri`** (`1.0 → 1.1`) — `globs: "**/src-tauri/**,**/tauri.conf.json"`
|
|
686
715
|
- **`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
716
|
- **`js-run`** (`1.7 → 1.8`) — `globs: "**/package.json,**/jsconfig.json,**/src/**/*.{js,mjs,cjs,ts,tsx}"`
|
|
688
|
-
- **Мотивація:** усі 9 правил мають повне покриття `npx @nitra/cursor
|
|
717
|
+
- **Мотивація:** усі 9 правил мають повне покриття `npx @nitra/cursor fix <rule>` (JS-перевірка + Rego policy). Тримати їх `alwaysApply: true` без потреби палить контекст AI у сесіях, де редагується непов'язаний код. Помилка → check ловить → AI виправляє — той самий цикл, що для `security@1.12.1` і `changelog`/`image-compress`/`php`/`vue`.
|
|
689
718
|
- **Залишено `alwaysApply: true`** — `text` (cross-cutting cspell-словник, апостроф), `adr` (про процес capture/normalize hooks), `ci4` (0 програмних чекерів — без AI-контексту правило мертве), `abie` (має JS `applies`-гейт, у не-abie репо мовчить; файли розкидані).
|
|
690
719
|
|
|
691
720
|
## [1.12.1] - 2026-05-17
|
|
692
721
|
|
|
693
722
|
### Changed
|
|
694
723
|
|
|
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
|
|
724
|
+
- **`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
725
|
- **Мотивація:** правило має повне покриття перевіркою (Rego + JS-check); тримати його `alwaysApply: true` не дає AI додаткової цінності понад те, що `check security` ловить програмно — лише марно займає контекстне вікно при роботі з кодом, не повʼязаним з конфігурацією security.
|
|
697
726
|
|
|
698
727
|
## [1.12.0] - 2026-05-16
|
|
@@ -719,7 +748,7 @@
|
|
|
719
748
|
|
|
720
749
|
### Removed
|
|
721
750
|
|
|
722
|
-
- **`npm/package.json#devDependencies`** — повторно видалено `@nitra/cursor: ^1.11.16` self-reference, який повернувся в коміті `8ae6e9e auto adr` (автоматичний stop-hook fix). Той самий блок уже прибирали в `1.11.14` (див. запис нижче) — потрапив назад через автофікс. `npx @nitra/cursor
|
|
751
|
+
- **`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
752
|
|
|
724
753
|
## [1.11.16] - 2026-05-16
|
|
725
754
|
|
|
@@ -739,36 +768,36 @@
|
|
|
739
768
|
|
|
740
769
|
### Removed
|
|
741
770
|
|
|
742
|
-
- **`npm/package.json#devDependencies`** — повністю видалено блок (містив лише self-reference `@nitra/cursor: ^1.11.9`). `npx @nitra/cursor
|
|
771
|
+
- **`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
772
|
- **`knip.json#workspaces.npm.ignoreDependencies: ["@nitra/cursor"]`** — workaround, доданий у 1.11.13 для приховання knip-violation на self-reference, тепер не потрібен (першопричина прибрана). Знято, щоб конфіг лишався чистим.
|
|
744
773
|
|
|
745
774
|
## [1.11.13] - 2026-05-16
|
|
746
775
|
|
|
747
776
|
### Fixed
|
|
748
777
|
|
|
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
|
|
778
|
+
- **`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
779
|
- **`npm/skills/fix/SKILL.md`** (+`.cursor/skills/n-fix/SKILL.md` синк) — заголовок секції перейменовано з **«Скоуп»** на **«Scope»**, бо cspell флагав «Скоуп» як unknown word. Англійський «Scope» зрозумілий і не вимагає розширення словника. Тіло секції без змін.
|
|
751
780
|
|
|
752
781
|
## [1.11.12] - 2026-05-15
|
|
753
782
|
|
|
754
783
|
### Removed
|
|
755
784
|
|
|
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
|
|
785
|
+
- **`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
786
|
- **`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
787
|
|
|
759
788
|
## [1.11.11] - 2026-05-15
|
|
760
789
|
|
|
761
790
|
### Removed
|
|
762
791
|
|
|
763
|
-
- **`npm/scripts/lint-conftest.mjs`** — скрипт видалено повністю. Його єдина функція — ітерувати policy-концерни через `discoverCheckableRules` і запускати `runConftestBatch` на реальних файлах — **повністю дублювала** `npx @nitra/cursor
|
|
792
|
+
- **`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
793
|
|
|
765
794
|
### Changed
|
|
766
795
|
|
|
767
|
-
- **`npm/README.md`** — секція «Структура пакету» переписана під поточний layout (`rules/<id>/<id>.mdc` замість застарілих `mdc/`). Додано підсекцію **«Структура одного правила»** з принципом fix/lint/policy: технологія реалізації визначає директорію — JS для `npx @nitra/cursor
|
|
796
|
+
- **`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
797
|
- **`.cursor/rules/conftest.mdc`** — крок 5 у workflow «нова перевірка» переписано: окремої реєстрації нового rego-пакета в TARGETS більше не потрібно (TARGETS видалено разом із `lint-conftest.mjs`); `discoverCheckableRules` автоматично підхоплює пакет за наявності `target.json` поруч з `.rego`.
|
|
769
798
|
- **`.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
|
|
799
|
+
- **`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`.
|
|
800
|
+
- **`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
801
|
|
|
773
802
|
## [1.11.10] - 2026-05-15
|
|
774
803
|
|
|
@@ -782,7 +811,7 @@
|
|
|
782
811
|
|
|
783
812
|
### Changed
|
|
784
813
|
|
|
785
|
-
- **`npm/scripts/utils/discover-checkable-rules.mjs`**, **`npm/scripts/utils/run-rule.mjs`** — фаза 1 реструктуризації `rules/<id>/js/` → `rules/<id>/{fix,lint}/`: інфраструктура `n-cursor
|
|
814
|
+
- **`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
815
|
- **`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
816
|
|
|
788
817
|
## [1.11.8] - 2026-05-15
|
|
@@ -795,7 +824,7 @@
|
|
|
795
824
|
|
|
796
825
|
### Changed
|
|
797
826
|
|
|
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
|
|
827
|
+
- **`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
828
|
|
|
800
829
|
### Fixed
|
|
801
830
|
|
|
@@ -807,7 +836,7 @@
|
|
|
807
836
|
|
|
808
837
|
- **`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
838
|
- **`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
|
|
839
|
+
- **`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
840
|
|
|
812
841
|
## [1.11.5] - 2026-05-15
|
|
813
842
|
|
|
@@ -942,11 +971,11 @@
|
|
|
942
971
|
|
|
943
972
|
### Changed
|
|
944
973
|
|
|
945
|
-
- **CLI auto-discovery** підхоплює `check-rego.mjs` і `check-tauri.mjs` через `discoverCheckScripts()` у `bin/n-cursor.js`. Окрема реєстрація не потрібна — будь-який `check-*.mjs` стає доступним через `npx @nitra/cursor
|
|
974
|
+
- **CLI auto-discovery** підхоплює `check-rego.mjs` і `check-tauri.mjs` через `discoverCheckScripts()` у `bin/n-cursor.js`. Окрема реєстрація не потрібна — будь-який `check-*.mjs` стає доступним через `npx @nitra/cursor fix <rule>`.
|
|
946
975
|
|
|
947
976
|
### Verified
|
|
948
977
|
|
|
949
|
-
- **На цьому репо `npx @nitra/cursor
|
|
978
|
+
- **На цьому репо `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
979
|
|
|
951
980
|
### Not migrated (explained)
|
|
952
981
|
|
|
@@ -1102,7 +1131,7 @@
|
|
|
1102
1131
|
|
|
1103
1132
|
### Changed
|
|
1104
1133
|
|
|
1105
|
-
- **AGENTS.md — додано `bunx knip` до секції Commands:** `build-agents-commands.mjs` тепер завжди додає рядок `- **knip (невикористані залежності та експорти)**: \`bunx knip\``після`npx @nitra/cursor
|
|
1134
|
+
- **AGENTS.md — додано `bunx knip` до секції Commands:** `build-agents-commands.mjs` тепер завжди додає рядок `- **knip (невикористані залежності та експорти)**: \`bunx knip\``після`npx @nitra/cursor fix`; оновлено тест (`items.length`3 → 4, перевірка`toContain('bunx knip')`).
|
|
1106
1135
|
- **`knip.json` — `graphql` у `ignoreDependencies`:** повернуто `graphql` до кореневого `ignoreDependencies` (peer-залежність, яку knip фолсово репортить як unused; вимога `js-lint.mdc` / `check-js-lint.mjs`).
|
|
1107
1136
|
|
|
1108
1137
|
## [1.9.8] - 2026-05-12
|
|
@@ -1198,7 +1227,7 @@
|
|
|
1198
1227
|
|
|
1199
1228
|
### Changed
|
|
1200
1229
|
|
|
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
|
|
1230
|
+
- **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
1231
|
- **`check-ga.mjs::checkShellcheckInstalled`:** додано `export` (потрібен для точкового тесту після рефактору).
|
|
1203
1232
|
- **тестова фікстура `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
1233
|
|
|
@@ -1331,7 +1360,7 @@
|
|
|
1331
1360
|
`redis`, підшляхів `ioredis/...` / `redis/...` і `@redis/*`. Не зачіпає
|
|
1332
1361
|
сторонні `redis-*` (наприклад, `redis-mock`).
|
|
1333
1362
|
- `npm/scripts/check-js-bun-redis.mjs` запускає AST-скан по JS/TS-джерелах і
|
|
1334
|
-
доступний як `npx @nitra/cursor
|
|
1363
|
+
доступний як `npx @nitra/cursor fix js-bun-redis`.
|
|
1335
1364
|
- Rego-полісі `npm/policy/js_bun_redis/package_json/` — заборона
|
|
1336
1365
|
`ioredis` / `node-redis` / `redis` / `@redis/*` у `dependencies` будь-якого
|
|
1337
1366
|
`package.json` у дереві; зареєстрована таргетом у
|
|
@@ -1521,7 +1550,7 @@
|
|
|
1521
1550
|
|
|
1522
1551
|
### Added
|
|
1523
1552
|
|
|
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
|
|
1553
|
+
- `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
1554
|
|
|
1526
1555
|
### Changed
|
|
1527
1556
|
|
|
@@ -1617,7 +1646,7 @@
|
|
|
1617
1646
|
- `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
1647
|
- `auto-rules.md` / `auto-rules.mjs`: автодетект `image-compress - [bun]` (всюди, де є `package.json`), `image-avif - [vue, image-compress]` (лише для проєктів з `.vue`-файлами і вже активним `image-compress`).
|
|
1619
1648
|
- Видалено `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
|
|
1649
|
+
- Канонічний `lint-image` залишається без `--avif` (його перевіряє `image-compress`); `npx @nitra/cursor fix image-avif` тепер є самостійною командою для AVIF-pipeline.
|
|
1621
1650
|
|
|
1622
1651
|
### Added
|
|
1623
1652
|
|
|
@@ -1724,7 +1753,7 @@
|
|
|
1724
1753
|
|
|
1725
1754
|
### Changed
|
|
1726
1755
|
|
|
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
|
|
1756
|
+
- `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
1757
|
- `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
1758
|
- `tests/check-image.test.mjs`: `CANONICAL_LINT_IMAGE` без `--avif`; кейс «без `--avif`» перейменовано/перекинуто на «з забороненим `--avif`»; додано тести на orphan-cleanup (`.avif` без посилань видаляється) та авто-заміну raster-імпорту, коли `.avif`-сусід реально існує.
|
|
1730
1759
|
|
|
@@ -1867,7 +1896,7 @@
|
|
|
1867
1896
|
|
|
1868
1897
|
### Added
|
|
1869
1898
|
|
|
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
|
|
1899
|
+
- `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
1900
|
|
|
1872
1901
|
### Changed
|
|
1873
1902
|
|
|
@@ -1883,7 +1912,7 @@
|
|
|
1883
1912
|
|
|
1884
1913
|
### Added
|
|
1885
1914
|
|
|
1886
|
-
- `abie.mdc` (v1.16) / `check-abie.mjs`: нова перевірка `.github/actionlint.yaml`. Якщо файл відсутній — `npx @nitra/cursor
|
|
1915
|
+
- `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
1916
|
|
|
1888
1917
|
## [1.8.163] - 2026-05-01
|
|
1889
1918
|
|
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,60 @@ 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
|
+
*
|
|
982
|
+
* Серіалізація паралельних запусків — per-rule, всередині `runStandardRule` (`withLock('fix-<id>')`).
|
|
983
|
+
* На рівні `runFixCommand` локу нема: різні набори правил можуть прогресувати незалежно,
|
|
984
|
+
* а однакові правила серіалізуються в spawn'ах нижче.
|
|
985
|
+
* @param {string[]} requestedRules імена правил; порожній масив — discovery з `.cursor/rules/`
|
|
982
986
|
* @returns {Promise<void>}
|
|
983
987
|
*/
|
|
984
|
-
async function
|
|
988
|
+
async function runFixCommand(requestedRules) {
|
|
985
989
|
const available = await listRuleIds(BUNDLED_RULES_DIR)
|
|
986
990
|
if (available.length === 0) {
|
|
987
|
-
console.error('❌ Не знайдено жодного
|
|
988
|
-
throw new Error('No
|
|
991
|
+
console.error('❌ Не знайдено жодного правила у пакеті')
|
|
992
|
+
throw new Error('No rules found')
|
|
989
993
|
}
|
|
990
994
|
|
|
991
|
-
|
|
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
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
let idsToCheck
|
|
995
|
+
let idsToRun
|
|
1003
996
|
if (requestedRules.length > 0) {
|
|
1004
|
-
|
|
997
|
+
const unknown = requestedRules.filter(id => !available.includes(id))
|
|
998
|
+
if (unknown.length > 0) {
|
|
999
|
+
console.error(`❌ Невідомі правила: ${unknown.join(', ')}`)
|
|
1000
|
+
console.log(` Доступні: ${available.join(', ')}`)
|
|
1001
|
+
throw new Error(`Unknown rules: ${unknown.join(', ')}`)
|
|
1002
|
+
}
|
|
1003
|
+
idsToRun = requestedRules
|
|
1005
1004
|
} else {
|
|
1006
1005
|
const mdcFiles = await listProjectRulesMdcFiles()
|
|
1007
1006
|
if (mdcFiles.length === 0) {
|
|
1008
1007
|
throw new Error(
|
|
1009
|
-
`Немає файлів *.mdc у ${RULES_DIR}/. Запустіть \`npx ${PACKAGE_NAME}\` або вкажіть правила: \`npx ${PACKAGE_NAME}
|
|
1008
|
+
`Немає файлів *.mdc у ${RULES_DIR}/. Запустіть \`npx ${PACKAGE_NAME}\` або вкажіть правила: \`npx ${PACKAGE_NAME} fix bun ga\``
|
|
1010
1009
|
)
|
|
1011
1010
|
}
|
|
1012
|
-
|
|
1013
|
-
if (
|
|
1011
|
+
idsToRun = discoverCheckRulesFromCursorRules(available, mdcFiles)
|
|
1012
|
+
if (idsToRun.length === 0) {
|
|
1014
1013
|
console.log(
|
|
1015
|
-
`\n🔍 ${PACKAGE_NAME}
|
|
1014
|
+
`\n🔍 ${PACKAGE_NAME} fix — у ${RULES_DIR}/ немає правил з programmatic перевіркою ` +
|
|
1016
1015
|
`(відповідного fix.mjs у пакеті). Нічого не запущено.\n`
|
|
1017
1016
|
)
|
|
1018
1017
|
return
|
|
1019
1018
|
}
|
|
1020
1019
|
}
|
|
1021
1020
|
|
|
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
1021
|
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()
|
|
1022
|
+
for (const id of idsToRun) {
|
|
1023
|
+
const fixPath = join(BUNDLED_RULES_DIR, id, 'fix.mjs')
|
|
1024
|
+
const result = spawnSync('bun', [fixPath], { stdio: 'inherit' })
|
|
1025
|
+
if (result.status !== 0) totalFailed++
|
|
1050
1026
|
}
|
|
1051
1027
|
|
|
1052
|
-
const passedCount = idsToCheck.length - totalFailed
|
|
1053
|
-
console.log(`✨ Результат: ${passedCount}/${idsToCheck.length} правил без зауважень\n`)
|
|
1054
|
-
|
|
1055
1028
|
if (totalFailed > 0) {
|
|
1056
|
-
throw new Error(`${totalFailed} з ${
|
|
1029
|
+
throw new Error(`${totalFailed} з ${idsToRun.length} правил мають проблеми`)
|
|
1057
1030
|
}
|
|
1058
1031
|
}
|
|
1059
1032
|
|
|
@@ -1252,8 +1225,15 @@ const [command, ...args] = process.argv.slice(2)
|
|
|
1252
1225
|
try {
|
|
1253
1226
|
await ensureNitraCursorInRootDevDependencies(cwd())
|
|
1254
1227
|
switch (command) {
|
|
1228
|
+
case 'fix': {
|
|
1229
|
+
await runFixCommand(args)
|
|
1230
|
+
|
|
1231
|
+
break
|
|
1232
|
+
}
|
|
1255
1233
|
case 'check': {
|
|
1256
|
-
|
|
1234
|
+
// Backward-compatibility alias. Перейменовано на `fix` у 1.13.84 (узгоджено з ім'ям файла `rules/<id>/fix.mjs`).
|
|
1235
|
+
console.warn(`⚠️ Команда \`check\` deprecated — використовуйте \`fix\` (\`npx ${PACKAGE_NAME} fix [<rule>...]\`)`)
|
|
1236
|
+
await runFixCommand(args)
|
|
1257
1237
|
|
|
1258
1238
|
break
|
|
1259
1239
|
}
|
|
@@ -1282,7 +1262,7 @@ try {
|
|
|
1282
1262
|
}
|
|
1283
1263
|
case 'lint-rego': {
|
|
1284
1264
|
// Канонічний lint-rego: preflight opa/regal → opa check --strict → regal lint → conftest verify (опц.).
|
|
1285
|
-
process.exitCode = runLintRego()
|
|
1265
|
+
process.exitCode = await runLintRego()
|
|
1286
1266
|
|
|
1287
1267
|
break
|
|
1288
1268
|
}
|
|
@@ -1300,7 +1280,7 @@ try {
|
|
|
1300
1280
|
}
|
|
1301
1281
|
case 'lint-text': {
|
|
1302
1282
|
// Канонічний lint-text: cspell → run-shellcheck → markdownlint-cli2 --fix → run-v8r (text.mdc).
|
|
1303
|
-
process.exitCode = runLintTextCli()
|
|
1283
|
+
process.exitCode = await runLintTextCli()
|
|
1304
1284
|
|
|
1305
1285
|
break
|
|
1306
1286
|
}
|
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
|
|