@nitra/cursor 1.8.171 → 1.8.177

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.
@@ -4,20 +4,25 @@
4
4
 
5
5
  Path-scoped нагадування для агента: підвантажується автоматично, коли редагуємо файли під `npm/`.
6
6
 
7
- ## Перед коміт-релевантними змінами в `npm/`
7
+ ## Перед PR з коміт-релевантними змінами в `npm/`
8
8
 
9
9
  1. Підвищ `version` у `npm/package.json` (build-bump, не більше одного кроку відносно `HEAD`).
10
10
  2. Додай запис у `npm/CHANGELOG.md` форматом Keep a Changelog: `## [версія] - YYYY-MM-DD` + секції `### Added/Changed/Fixed/Removed`.
11
+ 3. Переконайся, що `"CHANGELOG.md"` є в масиві `files` у `npm/package.json` (правило `changelog`).
11
12
 
12
- Без обох пунктів `npx @nitra/cursor check npm-module` падає, а `Stop` hook блокує завершення ходу.
13
+ Логіка PR-scoped: bump і запис достатньо зробити **один раз — як суму по всьому PR** (порівняння йде з гілкою `dev`), а не на кожен коміт.
14
+
15
+ Без оновленого CHANGELOG `npx @nitra/cursor check changelog` падає, а `Stop` hook блокує завершення ходу.
13
16
 
14
17
  ## Перевірка локально
15
18
 
16
19
  ```bash
20
+ npx @nitra/cursor check changelog
17
21
  npx @nitra/cursor check npm-module
18
22
  ```
19
23
 
20
24
  ## Джерело правил
21
25
 
22
- - `.cursor/rules/n-npm-module.mdc` — повний текст правила
23
- - `npm/scripts/check-npm-module.mjs` — алгоритм перевірки
26
+ - `.cursor/rules/n-changelog.mdc` — правило про CHANGELOG (PR-scoped, для всіх воркспейсів)
27
+ - `.cursor/rules/n-npm-module.mdc` — правило публікації пакета (типи, hk, npm-publish workflow)
28
+ - `npm/scripts/check-changelog.mjs`, `npm/scripts/check-npm-module.mjs` — алгоритми перевірки
package/CHANGELOG.md CHANGED
@@ -4,6 +4,53 @@
4
4
 
5
5
  Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
6
6
 
7
+ ## [1.8.177] - 2026-05-05
8
+
9
+ ### Changed
10
+
11
+ - `changelog` (mdc v2.0): тепер дві моделі бази порівняння на рівні воркспейсу. **npm-published** (`name` + `files` + не `private: true`) — порівняння з опублікованою версією через `npm view <name> version` (git не задіяний; покриває кейс прямих комітів у `main` поза PR-flow). **local-only** (приватні / без `files`) — PR-scoped через `git merge-base <dev> HEAD`, що коректно обробляє: feature-гілку (видно лише унікальні коміти), `main` після merge `dev → main` (diff порожній → правило мовчить), direct-commit на `main` поза PR (ловиться як зміна, що потребує bump). Якщо реєстр недосяжний (офлайн / пакет не публікувався) — fail-safe pass, щоб локальна розробка не блокувалась.
12
+ - `check-changelog.mjs`: повний рефактор. Експорт `check(opts?)` з опційним `getPublishedVersion` для підстановки в тестах (CLI калить без аргументів — використовується дефолтний `npm view`-виклик з 10s таймаутом). Класифікація воркспейсів через `isNpmPublishable(pkg)`; для published — `checkPublishedWorkspace`, для local-only — окрема `runLocalOnlyChecks` із власною skip-логікою (no-git / on dev / no dev ref / no merge-base) і `resolveMergeBase(baseRef)` через `git merge-base`. Спільна `verifyChangelogEntry` для обох режимів.
13
+ - `n-changelog.mdc` / `mdc/changelog.mdc` (v1.1 → 2.0): переписано під дві моделі з прикладами кейсів.
14
+ - Тести `check-changelog.test.mjs`: 16 кейсів (раніше 11) — npm-mode (sync / out-of-sync / no CHANGELOG / no entry / files без `CHANGELOG.md` / offline), local-only skip-логіка, merge-base сценарії (feature-гілка, `main` після merge `dev → main`, direct-commit на `main`), змішаний режим.
15
+
16
+ ## [1.8.176] - 2026-05-05
17
+
18
+ ### Changed
19
+
20
+ - `changelog` стало єдиним правилом про CHANGELOG для всіх воркспейсів — включно з `npm/`. У `check-npm-module.mjs` прибрано `checkChangelog()` (і константу `CHANGELOG_PATH`); відповідну секцію `## CHANGELOG` видалено з `mdc/npm-module.mdc` (v1.9). Логіка перевірки `npm/CHANGELOG.md` лишилася незмінна за наповненням, але тепер вона PR-scoped (порівняння з `dev`), тож на feature-гілці bump і запис достатньо зробити **один раз — як суму по PR**, без bump-шуму в проміжних комітах.
21
+ - `check-changelog.mjs`: додано перевірку `files`-масиву — якщо `<ws>/package.json` його оголошує, у ньому має бути `"CHANGELOG.md"` (приватні воркспейси без `files` цей пункт пропускають). Прибрано `SKIP_WORKSPACE = 'npm'` — `npm/` тепер у звичайному циклі. Хелпер `readPackageJsonOrNull` об'єднує читання `package.json` (раніше було два окремі читачі — `version` і `files`).
22
+ - `auto-rules.mjs` / `auto-rules.md`: `changelog` переведено на `AUTO_RULE_DEPENDENCIES = ['bun']` (раніше — пряма умова `packageJsonExists`); тепер послідовно з рештою правил.
23
+ - `npm/.claude-template/npm-CLAUDE.md` (і згенерований `npm/CLAUDE.md`): оновлено — посилається на `n-changelog.mdc`, явно згадує `files: ["CHANGELOG.md"]`, наголошує на PR-scoped логіці.
24
+ - Тести `check-changelog.test.mjs`: кейс `npm/ пропускається` замінено на `npm/ перевіряється з files=["CHANGELOG.md"]`; додано окремий кейс fail при `files` без `CHANGELOG.md`.
25
+
26
+ ## [1.8.175] - 2026-05-05
27
+
28
+ ### Added
29
+
30
+ - `k8s.mdc` / `check-k8s.mjs`: у маршрутах Gateway API (**HTTPRoute**, **GRPCRoute**, **TCPRoute**, **TLSRoute**, **UDPRoute**, група `gateway.networking.k8s.io`) забороняється поле `namespace` у `spec.rules[*].backendRefs[*]` (і однини `backendRef`), якщо його значення збігається з `metadata.namespace` самого маршруту. За замовчуванням Gateway API резолвить backend у тому ж namespace, що й маршрут — дублювання у `backendRef` мертве й заважає Kustomize-overlay, що міняє namespace маршруту. Cross-namespace backendRef (з відмінним `namespace`) правило не торкається. Експортовано `collectGatewayApiRouteBackendRefsWithRedundantNamespace(spec, routeNs)`; перевіряється усередині існуючого `failIfGatewayRouteUsesNonHeadlessService` (той самий обхід дерева, що й для headless-перевірки). Додано приклад «погано/добре» у `k8s.mdc` і відповідні юніт-тести.
31
+
32
+ ## [1.8.174] - 2026-05-05
33
+
34
+ ### Added
35
+
36
+ - Нове правило `changelog` (`mdc/changelog.mdc` + `scripts/check-changelog.mjs`): для «звичайних» Bun-монорепо проєктів вимагає, щоб у кожному workspace, який змінився відносно базової гілки `dev`, у поточному PR було підвищено `version` у `<ws>/package.json` і додано запис `## [version] - YYYY-MM-DD` у `<ws>/CHANGELOG.md` (Keep a Changelog 1.1.0). Перевірка PR-scoped: на самій гілці `dev` пропускається; на feature-гілці bump і запис достатньо зробити **один раз — як суму по всьому PR**, без бамп-шуму в проміжних комітах. Воркспейс `npm/` пропускається — його CHANGELOG покриває окреме правило `npm-module`. У `auto-rules.md` / `auto-rules.mjs` `changelog` додано до автодетекту з умовою «у корені є `package.json`» і до `AUTO_RULE_ORDER` між `capacitor` і `docker`.
37
+
38
+ ### Added
39
+
40
+ - `.n-cursor.json` поле `ignore` (`schemas/n-cursor.json`): тепер не лише сигнал для AI, а й керує обходом усіх `check-*.mjs` / `run-*.mjs` — перелічені каталоги повністю виключаються з `walkDir`, як `node_modules` чи `.git`. Дозволяє безпечно тримати vendored Helm-чарти, генеровані маніфести, legacy-дерева у репо без false-positive’ів від check-скриптів. Розширено опис у схемі (стандартні виключення додавати не треба) і README отримав секцію «Виключення цілих дерев».
41
+ - `scripts/utils/load-cursor-config.mjs`: нова утиліта `loadCursorIgnorePaths(root)` — читає поле `ignore` з `.n-cursor.json` і нормалізує до абсолютних posix-шляхів без trailing-slash; пропускає не-рядки та порожні елементи; повертає `[]`, якщо файлу/поля нема або JSON невалідний.
42
+ - `scripts/utils/walkDir.mjs`: третій аргумент `ignorePaths` (за замовчуванням `[]`) — каталоги, які пропускаються разом з усім вмістом. Збіг — за повним шляхом (точний або з префіксом `/`), а не за basename, тож `postgres-master-test/` не пропускається коли в ignore лише `postgres-master/`. Стандартні пропуски (`node_modules`, `.git`, `dist`, `coverage`, `.turbo`, `.next`) працюють як раніше.
43
+
44
+ ### Changed
45
+
46
+ - Усі скрипти, що обходять FS через `walkDir`, тепер на початку `check()` зчитують `loadCursorIgnorePaths(root)` і передають третім аргументом: `check-abie`, `check-docker`, `check-graphql`, `check-hasura`, `check-image`, `check-js-bun-db`, `check-js-mssql`, `check-js-run`, `check-k8s`, `check-nginx-default-tpl`, `check-npm-module`, `check-vue`, плюс `run-docker`, `run-k8s` і `rename-yaml-extensions`. Wrapper-функції (`findDockerfilePaths`, `findK8sYamlFiles`, `findLintDockerfilePaths`, `findK8sRoots`, `findDefaultConfTemplatePaths`, `migrateDefaultTplConfFiles`) отримали опційний параметр `ignorePaths` для прозорого пробросу.
47
+
48
+ ## [1.8.172] - 2026-05-04
49
+
50
+ ### Changed
51
+
52
+ - `auto-rules.md` / `auto-rules.mjs`: правило `php` тепер автоувімкається за наявністю `composer.json` у корені, а не за будь-яким `*.php` файлом у дереві. Прибрано константу `PHP_RE`, факт `hasPhpSource` і його збір у `updateFileFacts`/`collectAutoRuleFacts`; натомість у `detectAutoRulesAndSkills` додано прапорець `composerJsonExists` (за аналогією з `packageJsonExists` / `npmDirExists`).
53
+
7
54
  ## [1.8.171] - 2026-05-04
8
55
 
9
56
  ### Removed
package/README.md CHANGED
@@ -30,6 +30,20 @@
30
30
 
31
31
  Щоб використовувати конкретну версію правил, оновіть залежність `@nitra/cursor` у проєкті (`bun add -d @nitra/cursor@<версія>` тощо). Поле `version` у `.n-cursor.json`, якщо воно лишилось у старих конфігах, **ігнорується**.
32
32
 
33
+ ### Виключення цілих дерев — поле `ignore`
34
+
35
+ Поле `ignore` у `.n-cursor.json` — список директорій (posix-шляхи відносно кореня репозиторію), які CLI повністю пропускає під час обходу: жоден `check-*.mjs` не сканує і не валідує файли всередині них, а агент не редагує/не створює/не видаляє там файли. Стандартні виключення (`node_modules`, `.git`, `dist`, `coverage`, `.turbo`, `.next`) працюють завжди — додавати їх у `ignore` не потрібно.
36
+
37
+ Типові кандидати: vendored Helm-чарти, генеровані маніфести, legacy-дерева, які не підтягуються під поточні правила:
38
+
39
+ ```json
40
+ {
41
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/n-cursor.json",
42
+ "rules": ["k8s"],
43
+ "ignore": ["dremio/dev/dremio_v2", "postgres-master"]
44
+ }
45
+ ```
46
+
33
47
  ### Правило `k8s` і Kustomize
34
48
 
35
49
  У цільовому репозиторії з маніфестами під **`**/k8s`** дотримуйтесь **`mdc/k8s.mdc`** з пакету (після синку — `.cursor/rules/n-k8s.mdc`або копія з`node_modules/@nitra/cursor/mdc/k8s.mdc`).
package/bin/auto-rules.md CHANGED
@@ -12,6 +12,8 @@ bun - якщо в корені проекту є package.json
12
12
 
13
13
  capacitor - якщо в проекті є хоч один файл capacitor.config.json
14
14
 
15
+ changelog - [bun]
16
+
15
17
  docker - якщо в проекті є хоч один Dockerfile
16
18
 
17
19
  ga - якщо присутня директорія .github/workflows
@@ -36,7 +38,7 @@ nginx-default-tpl - якщо присутній хоч один файл з пе
36
38
 
37
39
  npm-module - якщо в корені присутня директорія npm
38
40
 
39
- php - якщо присутній хоч один php файл
41
+ php - якщо в корені є composer.json
40
42
 
41
43
  style-lint - якщо присутній хоч один vue або css файл
42
44
 
@@ -0,0 +1,64 @@
1
+ ---
2
+ description: CHANGELOG.md в кожному workspace, з двома моделями бази порівняння
3
+ alwaysApply: true
4
+ version: '2.0'
5
+ ---
6
+
7
+ Bun monorepo: у кожному workspace із кореневого `package.json.workspaces` (плюс кореневий пакет, плюс `npm/`) має бути власний **`CHANGELOG.md`**. Спільного на репозиторій змісту змін **не існує** — кожен пакет веде свій. Правило `npm-module` відповідає лише за публікацію типів і workflow, а CHANGELOG — за цим правилом.
8
+
9
+ ## Дві моделі бази порівняння
10
+
11
+ Правило за **`<ws>/package.json`** автоматично визначає режим перевірки:
12
+
13
+ ### npm-published воркспейс
14
+
15
+ Якщо в `<ws>/package.json` є непорожнє `name`, **не** `private: true` і оголошено масив `files` — workspace публікується в npm. База — **опублікована версія в реєстрі** (`npm view <name> version`):
16
+
17
+ 1. Якщо локальна `version` дорівнює опублікованій — ще нічого не зрелізнуто, перевірка мовчить.
18
+ 2. Якщо локальна `version` відрізняється від опублікованої — потрібен запис у `<ws>/CHANGELOG.md` для локальної версії (формат `## [версія] - YYYY-MM-DD`) і `"CHANGELOG.md"` у `files`.
19
+ 3. Якщо реєстр недосяжний (офлайн / пакет ще не публікувався) — fail-safe pass із поясненням, щоб локальна розробка не блокувалася.
20
+
21
+ Git у цьому режимі не використовується — порівнюється поточний стан робочої копії з тим, що насправді в npm. Це покриває кейс «прямі коміти в `main` поза PR-flow» автоматично, бо неопубліковані зміни одразу видно.
22
+
23
+ ### local-only воркспейс
24
+
25
+ Якщо workspace приватний (`private: true`) або без `files` (apps, services, internal-only пакети) — база = **гілка `dev`**, точніше `git merge-base <dev> HEAD`:
26
+
27
+ 1. На самій гілці `dev` правило не активне.
28
+ 2. На feature-гілці merge-base = точка розгалуження від `dev` → видно лише унікальні коміти цієї гілки. Bump + запис у `CHANGELOG.md` потрібні **раз на весь PR — як сума по гілці**, без bump-шуму в проміжних комітах.
29
+ 3. На `main` після merge `dev → main` merge-base = поточний `dev` → diff порожній → правило мовчить.
30
+ 4. Direct-commit на `main` поза PR-flow ловиться як зміна, що потребує bump + запис у `CHANGELOG.md`.
31
+
32
+ Якщо не git-репо, або `dev`/`origin/dev` не існує — local-only перевірка пропускається.
33
+
34
+ ## Формат CHANGELOG.md
35
+
36
+ [Keep a Changelog 1.1.0](https://keepachangelog.com/uk/1.1.0/), мова — українська, новіші версії зверху.
37
+
38
+ ```md title="<ws>/CHANGELOG.md"
39
+ # Changelog
40
+
41
+ Усі помітні зміни цього пакета документуються тут.
42
+
43
+ Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
44
+
45
+ ## [1.2.3] - 2026-05-05
46
+
47
+ ### Added
48
+
49
+ - ...
50
+
51
+ ### Changed
52
+
53
+ - ...
54
+
55
+ ### Fixed
56
+
57
+ - ...
58
+ ```
59
+
60
+ Секції — підмножина `### Added`, `### Changed`, `### Fixed`, `### Removed` (одна або кілька).
61
+
62
+ ## Перевірка
63
+
64
+ `npx @nitra/cursor check changelog`
package/mdc/k8s.mdc CHANGED
@@ -214,6 +214,41 @@ spec:
214
214
 
215
215
  **Точні умови та повідомлення `fail`** — верхній JSDoc **`npm/scripts/check-k8s.mjs`**.
216
216
 
217
+ ### Gateway API: не дублюй namespace у `backendRef`
218
+
219
+ У маршрутах Gateway API (**HTTPRoute**, **GRPCRoute**, **TCPRoute**, **TLSRoute**, **UDPRoute**) у `spec.rules[*].backendRefs[*]` **не** додавай поле **`namespace`**, якщо його значення збігається з **`metadata.namespace`** самого маршруту. За замовчуванням Gateway API резолвить backend у тому ж namespace, що й маршрут, тож такий рядок — мертвий: він плутає під час перенесень між середовищами і ламається мовчки, якщо overlay змінює namespace маршруту через Kustomize, а в backendRef залишився старий рядок. Прибери поле — поведінка не зміниться. **`check k8s`** падає на такому збігу.
220
+
221
+ ```yaml
222
+ # ❌ погано — namespace дублює metadata.namespace маршруту
223
+ apiVersion: gateway.networking.k8s.io/v1
224
+ kind: HTTPRoute
225
+ metadata:
226
+ name: admin-site
227
+ namespace: dev-b2b
228
+ spec:
229
+ rules:
230
+ - backendRefs:
231
+ - name: auth-hl
232
+ namespace: dev-b2b # ← прибери
233
+ port: 8080
234
+ ```
235
+
236
+ ```yaml
237
+ # ✅ добре — namespace лише в metadata
238
+ apiVersion: gateway.networking.k8s.io/v1
239
+ kind: HTTPRoute
240
+ metadata:
241
+ name: admin-site
242
+ namespace: dev-b2b
243
+ spec:
244
+ rules:
245
+ - backendRefs:
246
+ - name: auth-hl
247
+ port: 8080
248
+ ```
249
+
250
+ Якщо backend **дійсно** живе в іншому namespace — поле **`namespace`** у `backendRef` обов'язкове (і потрібен `ReferenceGrant` у тому namespace); правило цього випадку не торкається.
251
+
217
252
  ## ConfigMap: ім'я збігається з Deployment
218
253
 
219
254
  Якщо в `k8s/base/` є **`configmap.yaml`** і **Deployment**, і цей Deployment посилається рівно на **один** ConfigMap — `metadata.name` ConfigMap має збігатися з `metadata.name` Deployment. Точні умови перевірки — **`check-k8s.mjs`**.
@@ -474,6 +509,28 @@ patches:
474
509
  preem: "false"
475
510
  ```
476
511
 
512
+ ### `patches[].target`: лише `kind` і `name`
513
+
514
+ У `patches[].target` залишай **тільки** **`kind`** і **`name`** — поля **`group`** і **`version`** прибирай. Kustomize резолвить ціль за GVK+name; `group`/`version` — звужувальні фільтри, потрібні лише за реальної колізії `kind+name` між різними API-групами або версіями. У межах одного namespace apiserver зберігає об'єкт у єдиному storage-GVK, тож для звичайних маніфестів така колізія неможлива, і `group`/`version` у `target` — мертвий шум, який ламається мовчки під час змін API (наприклад, перехід `v1beta1` → `v1`).
515
+
516
+ ```yaml
517
+ # ❌ зайві group / version
518
+ patches:
519
+ - target:
520
+ group: gateway.networking.k8s.io
521
+ version: v1beta1
522
+ kind: Gateway
523
+ name: gw
524
+
525
+ # ✅
526
+ patches:
527
+ - target:
528
+ kind: Gateway
529
+ name: gw
530
+ ```
531
+
532
+ **Виняток:** залишай `group` / `version`, лише якщо в дереві overlay реально співіснують ресурси з однаковими `kind`+`name`, але різними API-групами/версіями (наприклад, дві CRD з одним `kind`). У такому разі вкажи мінімальний набір полів, потрібний для дисамбігуації.
533
+
477
534
  ## Перевірка
478
535
 
479
536
  **`npx @nitra/cursor check k8s`** — програмні критерії в **JSDoc на початку** **`npm/scripts/check-k8s.mjs`**. Якщо під **`k8s`** немає **`*.yaml`** — крок пропущено. Канон **`$schema`** для редактора — розділ **«Визначення схеми YAML`** нижче.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Оформлення репозиторію для npm модуля
3
3
  alwaysApply: true
4
- version: '1.8'
4
+ version: '1.9'
5
5
  ---
6
6
 
7
7
  Bun monorepo: workspace **`npm/`**, кореневий **`package.json`**, **`.github/workflows/`**; опційно **`demo/`**.
@@ -51,11 +51,7 @@ bunx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly
51
51
 
52
52
  ## CHANGELOG
53
53
 
54
- Разом із підвищенням **build**-версії в **`npm/package.json`** оновлюй **`npm/CHANGELOG.md`** додавай новий запис із номером версії та коротким описом змін у модулі. Без оновлення `CHANGELOG.md` зміни в `npm/` зливати в `main` не можна.
55
-
56
- Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/) (новіші версії зверху, мова — українська). Кожен запис починається з рядка `## [версія] - YYYY-MM-DD` і має одну або кілька секцій: `### Added`, `### Changed`, `### Fixed`, `### Removed`.
57
-
58
- Файл **`CHANGELOG.md`** має бути в масиві **`files`** у **`npm/package.json`**, щоб публікувався разом із пакетом.
54
+ Окреме правило **`changelog`** ([changelog.mdc](changelog.mdc)) вимагає `npm/CHANGELOG.md` із записом для поточної версії (Keep a Changelog) і присутність `"CHANGELOG.md"` у масиві `files` у `npm/package.json`. Логіка PR-scoped (сума по гілці vs `dev`).
59
55
 
60
56
  ## npm publish
61
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.171",
3
+ "version": "1.8.177",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "ignore": {
47
47
  "type": "array",
48
- "description": "Директорії, у яких заборонено будь-які модифікації файлів (AI не редагує, не видаляє, не створює файли). Шляхи відносно кореня репозиторію. Наприклад: [\"packages/vendor\", \"packages/generated\"].",
48
+ "description": "Директорії, що повністю виключаються з обходу check-скриптів CLI (npx @nitra/cursor check ...) і AI-модифікацій (AI не редагує, не видаляє, не створює файли). Шляхи відносно кореня репозиторію (posix). Приклади: vendored Helm-чарти, генеровані маніфести, legacy-дерева. Стандартні виключення (node_modules, .git, dist, coverage, .turbo, .next) застосовуються завжди — додавати їх не треба.",
49
49
  "items": {
50
50
  "type": "string",
51
51
  "minLength": 1
@@ -26,6 +26,7 @@ export const AUTO_RULE_ORDER = Object.freeze([
26
26
  'abie',
27
27
  'bun',
28
28
  'capacitor',
29
+ 'changelog',
29
30
  'docker',
30
31
  'ga',
31
32
  'graphql',
@@ -54,6 +55,7 @@ export const AUTO_SKILL_ORDER = Object.freeze(['abie-kustomize', 'fix', 'lint'])
54
55
  */
55
56
  export const AUTO_RULE_DEPENDENCIES = Object.freeze(
56
57
  /** @type {Record<string, readonly string[]>} */ ({
58
+ changelog: Object.freeze(['bun']),
57
59
  image: Object.freeze(['vue'])
58
60
  })
59
61
  )
@@ -63,7 +65,6 @@ const HASURA_CONFIG_MARKER = 'metadata_directory: metadata'
63
65
  const JS_LIKE_RE = /\.(?:mjs|cjs|js|jsx|ts|tsx)$/iu
64
66
  const STYLE_RE = /\.(?:css|vue)$/iu
65
67
  const VUE_RE = /\.vue$/iu
66
- const PHP_RE = /\.php$/iu
67
68
  const NGINX_DEFAULT_FILES = new Set(['default.conf.template', 'default.conf', 'nginx.conf'])
68
69
  const IGNORED_DIR_NAMES = new Set(['node_modules', '.git', '.next', '.turbo'])
69
70
  const DEFAULT_DISABLED_LIST = Object.freeze([])
@@ -245,7 +246,6 @@ function updateDirFacts(dirName, facts) {
245
246
  * hasDockerfile: boolean,
246
247
  * hasJsLikeSource: boolean,
247
248
  * hasNginxDefaultTplFile: boolean,
248
- * hasPhpSource: boolean,
249
249
  * hasVueOrCssSource: boolean,
250
250
  * hasVueSource: boolean
251
251
  * }} facts агреговані факти
@@ -267,9 +267,6 @@ function updateFileFacts(fileName, relPath, facts) {
267
267
  if (VUE_RE.test(relPath)) {
268
268
  facts.hasVueSource = true
269
269
  }
270
- if (PHP_RE.test(relPath)) {
271
- facts.hasPhpSource = true
272
- }
273
270
  if (STYLE_RE.test(relPath)) {
274
271
  facts.hasVueOrCssSource = true
275
272
  }
@@ -452,7 +449,6 @@ export function isMonorepoPackage(packageJson) {
452
449
  * hasK8sDir: boolean,
453
450
  * hasNginxDefaultTplFile: boolean,
454
451
  * hasTempoDir: boolean,
455
- * hasPhpSource: boolean,
456
452
  * hasVueSource: boolean,
457
453
  * hasVueOrCssSource: boolean
458
454
  * }>} агреговані факти
@@ -469,7 +465,6 @@ export async function collectAutoRuleFacts(root) {
469
465
  hasK8sDir: false,
470
466
  hasNginxDefaultTplFile: false,
471
467
  hasTempoDir: false,
472
- hasPhpSource: false,
473
468
  hasVueSource: false,
474
469
  hasVueOrCssSource: false
475
470
  }
@@ -556,6 +551,7 @@ export async function detectAutoRulesAndSkills({
556
551
 
557
552
  const packageJsonExists = existsSync(join(root, 'package.json'))
558
553
  const npmDirExists = existsSync(join(root, 'npm'))
554
+ const composerJsonExists = existsSync(join(root, 'composer.json'))
559
555
  const repositoryUrl = getRepositoryUrl(
560
556
  packageJsonParsed && typeof packageJsonParsed === 'object' && !Array.isArray(packageJsonParsed)
561
557
  ? /** @type {Record<string, unknown>} */ (packageJsonParsed).repository
@@ -612,7 +608,7 @@ export async function detectAutoRulesAndSkills({
612
608
  { enabled: facts.hasK8sDir, id: 'k8s' },
613
609
  { enabled: facts.hasNginxDefaultTplFile, id: 'nginx-default-tpl' },
614
610
  { enabled: npmDirExists, id: 'npm-module' },
615
- { enabled: facts.hasPhpSource, id: 'php' },
611
+ { enabled: composerJsonExists, id: 'php' },
616
612
  { enabled: facts.hasVueOrCssSource, id: 'style-lint' }
617
613
  ]
618
614
  for (const item of autoRuleChecks) {
@@ -47,6 +47,7 @@ import { parseAllDocuments } from 'yaml'
47
47
  import { pathHasK8sSegment, ruKustomizationHasHealthCheckDeletePatch } from './check-k8s.mjs'
48
48
  import { createCheckReporter } from './utils/check-reporter.mjs'
49
49
  import { flattenWorkflowSteps, getStepUses, parseWorkflowYaml } from './utils/gha-workflow.mjs'
50
+ import { loadCursorIgnorePaths } from './utils/load-cursor-config.mjs'
50
51
  import { walkDir } from './utils/walkDir.mjs'
51
52
 
52
53
  const CONFIG_FILE = '.n-cursor.json'
@@ -385,18 +386,22 @@ export function ignoreBranchesIncludesRequired(ignoreBranches, required) {
385
386
  * @param {string} root корінь репозиторію
386
387
  * @returns {Promise<string[]>} відсортовані шляхи
387
388
  */
388
- async function findK8sYamlFiles(root) {
389
+ async function findK8sYamlFiles(root, ignorePaths = []) {
389
390
  /** @type {string[]} */
390
391
  const out = []
391
- await walkDir(root, p => {
392
- if (!pathHasK8sSegment(p)) {
393
- return
394
- }
395
- if (!YAML_EXTENSION_RE.test(p)) {
396
- return
397
- }
398
- out.push(p)
399
- })
392
+ await walkDir(
393
+ root,
394
+ p => {
395
+ if (!pathHasK8sSegment(p)) {
396
+ return
397
+ }
398
+ if (!YAML_EXTENSION_RE.test(p)) {
399
+ return
400
+ }
401
+ out.push(p)
402
+ },
403
+ ignorePaths
404
+ )
400
405
  return [...out].toSorted((a, b) => a.localeCompare(b))
401
406
  }
402
407
 
@@ -2088,7 +2093,8 @@ export async function check() {
2088
2093
  await ensureNoFirebaseHostingArtifacts(root, pass, fail)
2089
2094
  await checkCleanMergedBranch(root, pass, fail)
2090
2095
 
2091
- const yamlFiles = await findK8sYamlFiles(root)
2096
+ const ignorePaths = await loadCursorIgnorePaths(root)
2097
+ const yamlFiles = await findK8sYamlFiles(root, ignorePaths)
2092
2098
  const deploymentDirs = await collectDeploymentDirs(root, yamlFiles, fail)
2093
2099
 
2094
2100
  if (deploymentDirs.size > 0) {