@nitra/cursor 1.8.197 → 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 +18 -0
- package/bin/n-cursor.js +33 -1
- package/mdc/image-avif.mdc +2 -2
- package/mdc/image-compress.mdc +4 -2
- package/package.json +1 -1
- package/scripts/auto-rules.mjs +41 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@
|
|
|
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
|
+
|
|
18
|
+
## [1.8.198] - 2026-05-07
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `image-compress` (mdc v1.0 → v1.1): мінімум `@nitra/minify-image` піднято з **3.2.0** до **3.3.1**. У `3.3.1` upstream CLI порівнює sha1 raster-сорсу зі збереженим у `.n-minify-image.tsv` і автоматично перегенеровує `<source>.avif` при зміні контенту оригіналу — раніше stale `.avif` лишався поки розробник не видаляв його вручну. Додано пояснювальний абзац у правило.
|
|
23
|
+
- `image-avif` (mdc v1.0 → v1.1): крок 1 (`npx @nitra/minify-image --src=. --write --avif`) явно требує ≥ 3.3.1 і документує, що sha1-перевірка для регенерації застарілого AVIF тепер живе у CLI; `@nitra/cursor` цю логіку **не дублює**.
|
|
24
|
+
|
|
7
25
|
## [1.8.197] - 2026-05-07
|
|
8
26
|
|
|
9
27
|
### 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 {
|
|
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/mdc/image-avif.mdc
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: AVIF-двійники для raster-зображень з ув'язуванням у .vue/.html
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.1'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
AVIF-двійники (`<name>.<ext>.avif`) генерує **виключно** `npx @nitra/cursor check image-avif` — у `lint-image` прапорець `--avif` заборонений (це валідує правило `image-compress`). Перевірка робить три кроки в порядку:
|
|
8
8
|
|
|
9
|
-
1. Запускає `npx @nitra/minify-image --src=. --write --avif` — генерує `<name>.<ext>.avif` поряд з кожним PNG/JPEG/GIF.
|
|
9
|
+
1. Запускає `npx @nitra/minify-image --src=. --write --avif` (≥ **3.3.1**) — генерує `<name>.<ext>.avif` поряд з кожним PNG/JPEG/GIF. **Перегенерація при оновленні оригіналу:** з 3.3.1 CLI порівнює sha1 кожного raster-сорсу зі збереженим у `.n-minify-image.tsv` і автоматично перезаписує `<source>.avif`, якщо оригінал відредагували після останнього прогону. `@nitra/cursor` цю логіку не дублює — sha1-кеш живе всередині `@nitra/minify-image`.
|
|
10
10
|
2. Сканує `.vue` (а також `.html`) файли в кожному workspace-пакеті (root + workspaces) і автоматично переписує raster-посилання на AVIF-двійник у двох формах:
|
|
11
11
|
- **Імпорт-пов'язані** — `import x from '...png|jpg|jpeg|gif'` (далі `:src="x"` у шаблоні);
|
|
12
12
|
- **Прямі статичні** — `<img src="...png" />` у `<template>` (Vite перетворює такий шлях на asset-імпорт на етапі збірки, тож вимога та сама).
|
package/mdc/image-compress.mdc
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Оптимізація raster/SVG через @nitra/minify-image у локальному lint
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.1'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
CLI [`@nitra/minify-image`](https://www.npmjs.com/package/@nitra/minify-image) (≥ **3.
|
|
7
|
+
CLI [`@nitra/minify-image`](https://www.npmjs.com/package/@nitra/minify-image) (≥ **3.3.1**) запускається через `npx` (як `markdownlint-cli2` у text.mdc) і **не** додається в `dependencies` / `devDependencies`. Канонічний `lint-image` — авто-оптимізація з прапорцем `--write`: стискає raster/SVG на місці. **AVIF-генерація (`--avif`) у `lint-image` заборонена** — її виконує окреме правило `image-avif` (`npx @nitra/cursor check image-avif`), яке заодно прибирає AVIF-сироти. Split-cache робить повторні прогони дешевими — і локально, і після `git clone`.
|
|
8
|
+
|
|
9
|
+
Мінімум `3.3.1` важливий для правила `image-avif`: починаючи з цієї версії, CLI порівнює sha1 raster-сорсу зі збереженим у `.n-minify-image.tsv` і **перегенеровує `<source>.avif`** при будь-якій зміні контенту оригіналу (раніше stale `.avif` лишався, поки розробник не видаляв його вручну).
|
|
8
10
|
|
|
9
11
|
Перевірка лише локальна — у CI `lint-image` не запускаємо (sharp/svgo тягнуть бінарні залежності, цінність на ubuntu-runner-ах нижча за час прогону). Окремий workflow `lint-image.yml` створювати не треба.
|
|
10
12
|
|
package/package.json
CHANGED
package/scripts/auto-rules.mjs
CHANGED
|
@@ -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]
|