@nitra/cursor 1.8.38 → 1.8.41

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/README.md CHANGED
@@ -85,10 +85,11 @@ CLI автоматично (команда завантаження правил
85
85
  ```
86
86
  npm/
87
87
  ├── AGENTS.template.md # шаблон AGENTS.md для цільових репозиторіїв (потрапляє в npm-архів)
88
- ├── mdc/ # cursor-правила
88
+ ├── mdc/ # cursor-правила (без префікса n-; після синку — .cursor/rules/n-<id>.mdc)
89
89
  │ ├── js-format.mdc
90
90
  │ ├── npm-module.mdc
91
91
  │ └── text.mdc
92
+ ├── skills/ # skills (каталоги <id>/; після синку — .cursor/skills/n-<id>/)
92
93
  └── bin/
93
94
  └── n-cursor.js # CLI-скрипт
94
95
  ```
package/bin/n-cursor.js CHANGED
@@ -24,8 +24,9 @@
24
24
  * `github-actions/` пакету при кожному успішному синку (workflows з правил ga / js-lint / text).
25
25
  *
26
26
  * Skills копіюються з npm/skills пакету лише для id з масиву «skills» у .n-cursor.json
27
- * (у JSON — без префікса, каталоги в проєкті n-<id>, як і для правил). Якщо ключа skills
28
- * немає, за замовчуванням підтягуються всі bundled skills з префіксом n- у пакеті.
27
+ * (у JSON — без префікса, як імена файлів у mdc/ без n-). У пакеті джерело — каталоги
28
+ * skills/<id>/ (без префікса); у проєкті .cursor/skills/n-<id>/ (префікс n-, як n-*.mdc).
29
+ * Якщо ключа skills немає, за замовчуванням підтягуються всі підкаталоги skills/ (лише імена без префікса n-).
29
30
  * Зайві каталоги n-* у .cursor/skills, яких немає у списку, видаляються.
30
31
  *
31
32
  * Якщо в корені є package.json і в ньому ще немає \@nitra/cursor у devDependencies (і не оголошено
@@ -87,7 +88,7 @@ async function discoverBundledRuleNames() {
87
88
  }
88
89
 
89
90
  /**
90
- * Імена skills (без префікса n-) з каталогу skills пакету — лише директорії n-*
91
+ * Імена skills (id без префікса n-) з каталогу skills пакету — лише підкаталоги `<id>/` без префікса n-
91
92
  * @returns {Promise<string[]>} відсортовані id
92
93
  */
93
94
  async function discoverBundledSkillNames() {
@@ -96,8 +97,8 @@ async function discoverBundledSkillNames() {
96
97
  }
97
98
  const entries = await readdir(BUNDLED_SKILLS_DIR, { withFileTypes: true })
98
99
  return entries
99
- .filter(e => e.isDirectory() && e.name.startsWith(RULE_PREFIX))
100
- .map(e => e.name.slice(RULE_PREFIX.length))
100
+ .filter(e => e.isDirectory() && !e.name.startsWith('.') && !e.name.startsWith(RULE_PREFIX))
101
+ .map(e => e.name)
101
102
  .toSorted((a, b) => a.localeCompare(b))
102
103
  }
103
104
 
@@ -233,28 +234,13 @@ function normalizeSkillId(skillName) {
233
234
  return s
234
235
  }
235
236
 
236
- /** Legacy id у `.n-cursor.json` → поточний bundled id (каталог `n-<id>` у пакеті) */
237
- const LEGACY_SKILL_ID_MAP = {
238
- 'fix-cursor': 'fix'
239
- }
240
-
241
- /**
242
- * Поточний id skill для шляхів у пакеті та `.cursor/skills`
243
- * @param {string} skillName елемент масиву skills або ім'я каталогу
244
- * @returns {string} canonical id без префікса n-
245
- */
246
- function canonicalSkillId(skillName) {
247
- const id = normalizeSkillId(skillName)
248
- return LEGACY_SKILL_ID_MAP[id] ?? id
249
- }
250
-
251
237
  /**
252
238
  * Ім'я керованого каталогу skill у .cursor/skills (префікс n-)
253
- * @param {string} skillId id без префікса
239
+ * @param {string} skillId id без префікса (або з префіксом n- у конфігу — нормалізується)
254
240
  * @returns {string} наприклад n-fix
255
241
  */
256
242
  function managedSkillDirName(skillId) {
257
- return `${RULE_PREFIX}${canonicalSkillId(skillId)}`
243
+ return `${RULE_PREFIX}${normalizeSkillId(skillId)}`
258
244
  }
259
245
 
260
246
  /**
@@ -445,7 +431,7 @@ async function syncClaudeMd(configRules, configSkills) {
445
431
  lines.push('', '## Skills', '')
446
432
  const skillsRoot = join(cwd(), SKILLS_DIR)
447
433
  for (const skillId of configSkills) {
448
- const id = canonicalSkillId(skillId)
434
+ const id = normalizeSkillId(skillId)
449
435
  const dirName = managedSkillDirName(skillId)
450
436
  const skillMdPath = join(skillsRoot, dirName, 'SKILL.md')
451
437
  let desc = ''
@@ -495,7 +481,7 @@ async function syncAgentsMd(configSkills) {
495
481
  }
496
482
 
497
483
  /**
498
- * Копіює лише skills зі списку configSkills (каталоги n-* у пакеті)
484
+ * Копіює лише skills зі списку configSkills (джерело: skills/<id>/ у пакеті)
499
485
  * @param {string[]} configSkills id без префікса n-
500
486
  * @returns {Promise<{ success: number, fail: number }>} лічильники успішних і невдалих копіювань
501
487
  */
@@ -511,13 +497,13 @@ async function syncSkills(configSkills) {
511
497
  let fail = 0
512
498
 
513
499
  for (const skillId of configSkills) {
514
- const id = canonicalSkillId(skillId)
515
- const dirName = managedSkillDirName(skillId)
516
- const srcDir = join(BUNDLED_SKILLS_DIR, dirName)
517
- const destDir = join(skillsRoot, dirName)
500
+ const id = normalizeSkillId(skillId)
501
+ const srcDir = join(BUNDLED_SKILLS_DIR, id)
502
+ const destDirName = managedSkillDirName(skillId)
503
+ const destDir = join(skillsRoot, destDirName)
518
504
 
519
505
  if (existsSync(srcDir)) {
520
- process.stdout.write(` ⬇ ${id} → ${SKILLS_DIR}/${dirName} ... `)
506
+ process.stdout.write(` ⬇ ${id} → ${SKILLS_DIR}/${destDirName} ... `)
521
507
  try {
522
508
  await mkdir(destDir, { recursive: true })
523
509
  const files = await readdir(srcDir)
@@ -533,9 +519,9 @@ async function syncSkills(configSkills) {
533
519
  fail++
534
520
  }
535
521
  } else {
536
- process.stdout.write(` ⬇ ${id} → ${SKILLS_DIR}/${dirName} ... `)
522
+ process.stdout.write(` ⬇ ${id} → ${SKILLS_DIR}/${destDirName} ... `)
537
523
  console.log(`❌`)
538
- console.error(` Немає каталогу в пакеті: ${dirName}`)
524
+ console.error(` Немає каталогу в пакеті: skills/${id}`)
539
525
  fail++
540
526
  }
541
527
  }
@@ -560,9 +546,9 @@ async function syncCommands(configSkills) {
560
546
  let fail = 0
561
547
 
562
548
  for (const skillId of configSkills) {
563
- const id = canonicalSkillId(skillId)
564
- const dirName = managedSkillDirName(skillId)
565
- const srcSkillMd = join(BUNDLED_SKILLS_DIR, dirName, 'SKILL.md')
549
+ const id = normalizeSkillId(skillId)
550
+ const srcSkillMd = join(BUNDLED_SKILLS_DIR, id, 'SKILL.md')
551
+ const destDirName = managedSkillDirName(skillId)
566
552
  const destFile = join(commandsDir, `${RULE_PREFIX}${id}.md`)
567
553
 
568
554
  process.stdout.write(` ⬇ ${id} → ${COMMANDS_DIR}/${RULE_PREFIX}${id}.md ... `)
@@ -572,7 +558,7 @@ async function syncCommands(configSkills) {
572
558
  const descRaw = extractSkillDescription(raw)
573
559
  const desc = descRaw ? skillDescriptionSafeForMarkdownInline(descRaw) : ''
574
560
  const header = desc ? `# ${RULE_PREFIX}${id} — ${desc}\n\n` : ''
575
- const body = `${header}Виконай інструкції зі скілу \`.cursor/skills/${dirName}/SKILL.md\`.\n`
561
+ const body = `${header}Виконай інструкції зі скілу \`.cursor/skills/${destDirName}/SKILL.md\`.\n`
576
562
  await writeFile(destFile, body, 'utf8')
577
563
  console.log(`✅`)
578
564
  success++
@@ -583,7 +569,7 @@ async function syncCommands(configSkills) {
583
569
  }
584
570
  } else {
585
571
  console.log(`❌`)
586
- console.error(` Немає SKILL.md у пакеті: ${dirName}`)
572
+ console.error(` Немає SKILL.md у пакеті: skills/${id}`)
587
573
  fail++
588
574
  }
589
575
  }
@@ -600,7 +586,7 @@ async function removeOrphanManagedCommandFiles(commandsDir, configSkills) {
600
586
  if (!existsSync(commandsDir)) {
601
587
  return []
602
588
  }
603
- const expected = new Set(configSkills.map(s => `${RULE_PREFIX}${canonicalSkillId(s)}.md`))
589
+ const expected = new Set(configSkills.map(s => `${RULE_PREFIX}${normalizeSkillId(s)}.md`))
604
590
  const names = await readdir(commandsDir)
605
591
  const removed = []
606
592
  for (const name of names) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.38",
3
+ "version": "1.8.41",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "skills": {
23
23
  "type": "array",
24
- "description": "Ідентифікатори skills без префікса n- (каталог .cursor/skills). Якщо відсутній, CLI доповнить списком skills з пакету.",
24
+ "description": "Ідентифікатори skills без префікса n- (у пакеті — підкаталог skills/<id>/, у проєкті після синку — .cursor/skills/n-<id>/). Якщо відсутній, CLI доповнить списком skills з пакету.",
25
25
  "items": {
26
26
  "type": "string",
27
27
  "minLength": 1
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: n-abie-kustomize
3
+ description: >-
4
+ Трансформація дерев k8s у структуру Kustomize (base + overlays): dev → base, без окремої dev/
5
+ version: '1.0'
6
+ ---
7
+
8
+ Трансформуй директорії, щоб виділити спільне за допомогою kustomize. За основу беремо все, що в середовищі dev, і саме в такому вигляді з dev воно має стати **base**; якщо вже є base і немає dev — це нормально, рухайся далі.
9
+
10
+ У інших середовищах має бути лише `kustomization.yaml` і зміни через оверрайди.
11
+
12
+ У **base** у всіх ресурсів (окрім `base/kustomization.yaml`) має бути namespace **dev**.
13
+
14
+ Окремої директорії **dev** не має бути — за середовище dev відповідає **base**.
15
+
16
+ README має бути в директорії **k8s**.
17
+
18
+ Рядки в маніфестах у **base**, які змінюватимуться в інших середовищах, позначай коментарем на тому самому рядку: `# буде замінено через kustomize`.
19
+
20
+ Патчів лише на namespace не роби — namespace задається в `kustomization.yaml`.
21
+
22
+ Застарілі файли прибирай.
23
+
24
+ У всіх Deployment має бути `imagePullPolicy: Always`.
25
+
26
+ Для overlays **ru** та **ua** `namespace` задавай у `kustomization.yaml` (без окремих patch лише на зміну namespace). Деталі — **n-k8s** / **abie** у `.cursor/rules/`, якщо ці правила увімкнені в проєкті.
@@ -1,86 +0,0 @@
1
- ---
2
- name: n-mdc-check
3
- description: >-
4
- Проаналізувати правило в npm/mdc і перенести максимум перевірюваної логіки в check-{id}.mjs;
5
- залишити в .mdc лише те, що не автоматизується або служить контекстом для агента
6
- ---
7
-
8
- # n-mdc-check — від правила до скрипта
9
-
10
- Навичка для роботи з правилами пакета `@nitra/cursor`: **перевірювані критерії** мають жити в **`npm/scripts/check-<id>.mjs`**, а **`npm/mdc/<id>.mdc`** (і дзеркало **`.cursor/rules/n-<id>.mdc`**) — бути **коротким орієнтиром**: навіщо правило, як виправляти порушення, яка команда підтверджує відповідність.
11
-
12
- Канонічні вимоги до скриптів, тестів і AST — **`.cursor/rules/scripts.mdc`**.
13
-
14
- ## Коли застосовувати
15
-
16
- - Додали або змінили вимоги в **`npm/mdc/<id>.mdc`** (або локальному **`n-<id>.mdc`**).
17
- - У правилі багато «має містити», «заборонено», точних фрагментів файлів — і агенти повторюють перевірку вручну.
18
- - Потрібно зменшити обсяг `.mdc` і уникнути роз’їзду тексту й фактичної перевірки.
19
-
20
- ## Ідентифікатор правила
21
-
22
- - Файл правила в пакеті: **`npm/mdc/<id>.mdc`** → скрипт: **`npm/scripts/check-<id>.mjs`**, команда CLI: **`npx @nitra/cursor check <id>`**.
23
- - CLI підхоплює всі **`check-*.mjs`** з каталогу `scripts` пакета; окремої реєстрації не потрібно.
24
- - Якщо правило згадане в **`AGENTS.md`**, для нього доречна programmatic перевірка — має існувати відповідний **`check-<id>.mjs`** (коли вимоги формалізовані).
25
-
26
- ## Workflow
27
-
28
- ### 1. Базова лінія
29
-
30
- ```bash
31
- npx @nitra/cursor check <id>
32
- ```
33
-
34
- Зафіксуй поточний вивід (якщо скрипт уже є).
35
-
36
- ### 2. Розбір тексту правила
37
-
38
- Прочитай **`npm/mdc/<id>.mdc`** повністю. Для кожної вимоги виріши:
39
-
40
- | Тип | Куди |
41
- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
42
- | Перевірювана структура (файли, поля JSON/YAML, наявність ключів, заборонені шляхи) | **`check-<id>.mjs`** |
43
- | Семантика JS/TS у файлах | **`check-<id>.mjs`** через **Oxc AST** (`oxc-parser`), не «сліпі» regex по всьому файлу |
44
- | Вміст у Vue SFC / MDX / Astro | Спочатку **виділи** валідний JS/TS-фрагмент, потім AST; regex — лише для ізоляції блоків |
45
- | Не-JS конфіги, сирі workflow | Текстовий/структурний парсинг або обґрунтований regex; у JSDoc коротко **чому** не AST |
46
- | Смак, архітектура, «навіщо так», поради без однозначного критерію | Залиш у **`.mdc`** |
47
-
48
- ### 3. Скрипт
49
-
50
- - **Новий** `check-<id>.mjs`: орієнтуйся на наявні файли в **`npm/scripts/`** (наприклад **`check-bun.mjs`**) — стиль **`fail` / `pass`**, **`export async function check()`**, exit code **0 / 1**.
51
- - **На початку файлу** (перед `import`) — **багаторядковий** верхній JSDoc **українською**: що перевіряє файл; між смисловими блоками — рядок `*`; перші рядки без службових префіксів — одразу зрозуміло призначення.
52
- - **JSDoc** до експортованих функцій і нетривіальних внутрішніх функцій.
53
- - Повідомлення **`fail`**: конкретно, що не так і як виправити (як у інших check-скриптах).
54
- - Залежність **`oxc-parser`** не додавай у корінь споживача — вона в **`dependencies`** пакета **`@nitra/cursor`** (див. **dev-dep** / **scripts.mdc**).
55
-
56
- ### 4. Тести
57
-
58
- Якщо логіка нетривіальна або її легко зламати — додай **`npm/tests/check-<id>.test.mjs`** (або розшир наявні тести). Після змін:
59
-
60
- ```bash
61
- cd npm && bun test
62
- ```
63
-
64
- ### 5. Спрощення `.mdc`
65
-
66
- - Прибери з правила **дубль** детальних умов, які тепер у скрипті; залиш **короткий зміст**, мотивацію, посилання на файли/конвенції.
67
- - Потрібно зберегти (або додати) секцію **«Перевірка»** з **`npx @nitra/cursor check <id>`** (або повним ім’ям правила з `AGENTS.md`).
68
- - Якщо оновлюєш пакетне правило, **синхронно** онови дзеркало **`.cursor/rules/n-<id>.mdc`**, щоб текст не розходився (як прийнято в цьому репозиторії).
69
-
70
- ### 6. Верифікація та версія пакета
71
-
72
- ```bash
73
- npx @nitra/cursor check <id>
74
- ```
75
-
76
- Після змін у **`npm/`** (у тому числі `skills/`, `scripts/`, `mdc/`) підвищ **patch**-версію в **`npm/package.json`** на **один** крок відносно вже запланованого релізу (див. **n-npm-module**).
77
-
78
- ## Антипатерни
79
-
80
- - Залишати в `.mdc` великі «еталонні» YAML/JSON, якщо перевірка може читати очікувану структуру з репозиторію або константи в скрипті.
81
- - Оновлювати лише текст правила без оновлення **`check-<id>.mjs`**, коли для правила вже є скрипт або з’явилась нова перевірювана умова.
82
- - Дублювати однакову логіку в кількох check-скриптах замість спільної утиліти в **`npm/scripts/utils/`**.
83
-
84
- ## Команда в чаті
85
-
86
- `/n-mdc-check` — застосуй цей workflow до правила з поточного контексту або до `<id>`, який вкаже користувач.
File without changes