@nitra/cursor 1.8.198 → 1.8.199

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/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@
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.199] - 2026-05-07
8
+
9
+ ### Added
10
+
11
+ - `auto-rules.mjs`: автоматична міграція застарілих rule-id у `.n-cursor.json` через карту `RULE_MIGRATIONS`. Перший зареєстрований запис — `image` → `image-compress` + `image-avif` (split з 1.8.197). Застосовується і до `rules`, і до `disable-rules`, з дедуплікацією. CLI `n-cursor.js` логує `📦 Авто-міграція .n-cursor.json: image → image-compress, image-avif` перед нормалізацією, потім записує оновлений конфіг (як і раніше — лише якщо вміст реально змінився).
12
+ - `tests/auto-rules.test.mjs`: тести `migrateRuleIds` (порядок, дедуплікація, no-op для актуальних id), `detectLegacyRuleIds`, `mergeConfigWithAutoDetected` з legacy `image` у `rules`/`disable-rules`/конфлікті з `image-compress`.
13
+
14
+ ### Changed
15
+
16
+ - `n-cursor.js`: розширено імпорт з `auto-rules.mjs` (`detectLegacyRuleIds`, `RULE_MIGRATIONS`); виокремлено хелпер `logRuleMigrationsIfAny` (читає сирий конфіг, виводить пояснення, не мутує — мутацію виконує `migrateRuleIds` усередині `mergeConfigWithAutoDetected`). Завдяки цьому `npx @nitra/cursor` сам перебиває `image` на пару наступників — користувачу не треба руками правити `.n-cursor.json`.
17
+
7
18
  ## [1.8.198] - 2026-05-07
8
19
 
9
20
  ### Changed
package/bin/n-cursor.js CHANGED
@@ -56,7 +56,13 @@ import { cwd } from 'node:process'
56
56
  import { fileURLToPath } from 'node:url'
57
57
 
58
58
  import { buildAgentsCommandBulletItems } from '../scripts/build-agents-commands.mjs'
59
- import { detectAutoRulesAndSkills, mergeConfigWithAutoDetected, normalizeIdList } from '../scripts/auto-rules.mjs'
59
+ import {
60
+ detectAutoRulesAndSkills,
61
+ detectLegacyRuleIds,
62
+ mergeConfigWithAutoDetected,
63
+ normalizeIdList,
64
+ RULE_MIGRATIONS
65
+ } from '../scripts/auto-rules.mjs'
60
66
  import { runStopHookCli } from '../scripts/claude-stop-hook.mjs'
61
67
  import { ensureNitraCursorInRootDevDependencies } from '../scripts/ensure-nitra-cursor-dev-dependencies.mjs'
62
68
  import { runLintGaCli } from '../scripts/lint-ga.mjs'
@@ -301,6 +307,7 @@ async function readConfig(paths = {}) {
301
307
  } catch {
302
308
  throw new Error(`Невірний JSON у файлі ${CONFIG_FILE}`)
303
309
  }
310
+ logRuleMigrationsIfAny(config)
304
311
  const normalized = await normalizeConfigWithAutoRules(config)
305
312
  if (JSON.stringify(normalized) !== JSON.stringify(config)) {
306
313
  await writeFile(configPath, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
@@ -309,6 +316,31 @@ async function readConfig(paths = {}) {
309
316
  return normalized
310
317
  }
311
318
 
319
+ /**
320
+ * Якщо у `rules` чи `disable-rules` є застарілі rule-id з `RULE_MIGRATIONS`,
321
+ * виводить пояснювальний лог про автоматичну заміну (саму заміну виконує
322
+ * `migrateRuleIds` у `mergeConfigWithAutoDetected` — тут лише користувацька комунікація).
323
+ * @param {Record<string, unknown>} parsedConfig сирий обʼєкт `.n-cursor.json` після `JSON.parse`
324
+ * @returns {void}
325
+ */
326
+ function logRuleMigrationsIfAny(parsedConfig) {
327
+ /** @type {Set<string>} */
328
+ const seen = new Set()
329
+ for (const key of /** @type {const} */ (['rules', 'disable-rules'])) {
330
+ const list = parsedConfig[key]
331
+ if (!Array.isArray(list)) continue
332
+ const legacy = detectLegacyRuleIds(normalizeIdList(list))
333
+ for (const id of legacy) seen.add(id)
334
+ }
335
+ if (seen.size === 0) return
336
+ console.log(`📦 Авто-міграція ${CONFIG_FILE}:`)
337
+ for (const id of seen) {
338
+ const replacement = RULE_MIGRATIONS[id].join(', ')
339
+ console.log(` • ${id} → ${replacement}`)
340
+ }
341
+ console.log('')
342
+ }
343
+
312
344
  /**
313
345
  * Витягує чисте ім'я файлу правила (без шляху, але зберігає .mdc)
314
346
  * "npm/mdc/text.mdc" → "text.mdc"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.198",
3
+ "version": "1.8.199",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -49,6 +49,45 @@ export const AUTO_RULE_ORDER = Object.freeze([
49
49
  /** Порядок автододавання skills відповідно до `auto-rules.md`. */
50
50
  export const AUTO_SKILL_ORDER = Object.freeze(['abie-kustomize', 'fix', 'lint'])
51
51
 
52
+ /**
53
+ * Карта міграції застарілих rule-id у `.n-cursor.json` на актуальні.
54
+ * Застосовується автоматично при читанні конфігу (як для `rules`, так і для `disable-rules`).
55
+ * Приклад: `image` → `image-compress` + `image-avif` (правило розщеплене у 1.8.197).
56
+ */
57
+ export const RULE_MIGRATIONS = Object.freeze(
58
+ /** @type {Record<string, readonly string[]>} */ ({
59
+ image: Object.freeze(['image-compress', 'image-avif'])
60
+ })
61
+ )
62
+
63
+ /**
64
+ * Розгортає застарілі rule-id у списку згідно з `RULE_MIGRATIONS`. Зберігає порядок,
65
+ * дедуплікує. Чистий хелпер: не мутує вхід, не логує.
66
+ * @param {string[]} ids нормалізований список id (як з `normalizeIdList`)
67
+ * @returns {string[]} список з legacy-id, заміненими на нові; решта без змін
68
+ */
69
+ export function migrateRuleIds(ids) {
70
+ /** @type {string[]} */
71
+ const out = []
72
+ for (const id of ids) {
73
+ const replacement = Object.hasOwn(RULE_MIGRATIONS, id) ? RULE_MIGRATIONS[id] : [id]
74
+ for (const newId of replacement) {
75
+ if (!out.includes(newId)) out.push(newId)
76
+ }
77
+ }
78
+ return out
79
+ }
80
+
81
+ /**
82
+ * Повертає лише ті legacy rule-id зі списку, для яких є запис у `RULE_MIGRATIONS`.
83
+ * Використовується для людинозрозумілого логування міграції при синхронізації CLI.
84
+ * @param {string[]} ids нормалізований список id
85
+ * @returns {string[]} legacy id, які потребуватимуть заміни у `migrateRuleIds`
86
+ */
87
+ export function detectLegacyRuleIds(ids) {
88
+ return ids.filter(id => Object.hasOwn(RULE_MIGRATIONS, id))
89
+ }
90
+
52
91
  /**
53
92
  * Граф залежностей між правилами (`auto-rules.md` синтаксис `rule - [other]`).
54
93
  * Ключ варто автододати, коли всі правила-залежності вже додані до конфігу — щоб
@@ -649,9 +688,9 @@ export async function detectAutoRulesAndSkills({
649
688
  * @returns {{ rules: string[], skills: string[] } & Record<string, unknown>} новий нормалізований конфіг
650
689
  */
651
690
  export function mergeConfigWithAutoDetected({ config, detectedRules, detectedSkills }) {
652
- const existingRules = normalizeIdList(config.rules)
691
+ const existingRules = migrateRuleIds(normalizeIdList(config.rules))
653
692
  const existingSkills = normalizeIdList(config.skills)
654
- const disableRules = normalizeIdList(config['disable-rules'])
693
+ const disableRules = migrateRuleIds(normalizeIdList(config['disable-rules']))
655
694
  const disableSkills = normalizeIdList(config['disable-skills'])
656
695
 
657
696
  const rules = [...existingRules]