@nitra/cursor 1.9.5 → 1.9.6

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,12 @@
4
4
 
5
5
  Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
6
6
 
7
+ ## [1.9.6] - 2026-05-12
8
+
9
+ ### Changed
10
+
11
+ - **js-lint — ігнорувати `.claude/worktrees/` для jscpd і всіх лінтів:** правило `js-lint.mdc` (v1.18) тепер документує, що каталог `.claude/worktrees/` (робочі копії, які Claude Code створює через superpowers-skill `using-git-worktrees`) має бути виключений з лінт-перевірок. Канонічне місце — `.gitignore` (паралельні воркті — це за визначенням не-комітні робочі копії; `gitignore: true` у `.jscpd.json` уже є, тож запис у `.gitignore` каскадно вимикає сканування). Як страховку на випадок запуску jscpd без `gitignore: true` рекомендовано додати `.claude/worktrees/**` у `ignore` `.jscpd.json` — приклад у правилі оновлено. Без цього `bunx jscpd .` фіксує дзеркальні «клони» між кореневим репо і його worktree-копією у `.claude/worktrees/<name>/…`.
12
+
7
13
  ## [1.9.5] - 2026-05-12
8
14
 
9
15
  ### Changed
@@ -18,7 +24,7 @@
18
24
 
19
25
  ### Removed
20
26
 
21
- - **graphql — вимога `scripts.dump-schema` у `package.json` прибрана:** правило `graphql.mdc` більше не вимагає канонічний скрипт `dump-schema` (раніше — `bunx graphqurl http://localhost:4040/v1/graphql -H 'X-Hasura-Admin-Secret: secret' --introspect > schema.graphql`) у корені проєкту за наявності gql tagged template literals. У `.mdc` відповідну буліт-точку та JSON-фрагмент видалено; фраза про «стандартний спосіб оновлення локальної `schema.graphql`» теж прибрана з підсумкового речення. Каталог `npm/policy/graphql/` (єдиний файл `package_json/package_json.rego` з deny-правилами на відсутність/неканонічний `scripts.dump-schema`) видалено повністю. Запис реєстру `graphql.package_json` (policyDir `graphql`, rule `graphql`, single `package.json`) прибрано з `npm/scripts/lint-conftest.mjs` (заголовок секції перейменовано — `graphql` вилучено). JSDoc-преамбулу `npm/scripts/check-graphql.mjs` оновлено: видалено абзац про rego-порт перевірки `dump-schema` і згадку `scripts.dump-schema` з докстрингу `check()`. Сам JS-чек і так не торкався `package.json` — після видалення rego-полісі ніяких runtime-перевірок `dump-schema` не лишається. У кореневому `package.json` репо cursor скрипт `dump-schema` теж видалено, оскільки тримати його як shim без правила немає сенсу.
27
+ - **graphql — вимога `scripts.dump-schema` у `package.json` прибрана:** правило `graphql.mdc` більше не вимагає канонічний скрипт `dump-schema` (раніше — `bunx graphqurl http://localhost:4040/v1/graphql -H 'X-Hasura-Admin-Secret: secret' --introspect > schema.graphql`) у корені проєкту за наявності gql tagged template literals. У `.mdc` відповідну буліт-точку та JSON-фрагмент видалено; фраза про «стандартний спосіб оновлення локальної `schema.graphql`» теж прибрана з підсумкового речення. Каталог `npm/policy/graphql/` (єдиний файл `package_json/package_json.rego` з deny-правилами на відсутність/неканонічний `scripts.dump-schema`) видалено повністю. Запис реєстру `graphql.package_json` (policyDir `graphql`, rule `graphql`, single `package.json`) прибрано з `npm/scripts/lint-conftest.mjs` (заголовок секції перейменовано — `graphql` вилучено). JSDoc-преамбулу `npm/scripts/check-graphql.mjs` оновлено: видалено абзац про rego-порт перевірки `dump-schema` і згадку `scripts.dump-schema` з JSDoc функції `check()`. Сам JS-чек і так не торкався `package.json` — після видалення rego-полісі ніяких runtime-перевірок `dump-schema` не лишається. У кореневому `package.json` репо cursor скрипт `dump-schema` теж видалено, оскільки тримати його як shim без правила немає сенсу.
22
28
 
23
29
  ## [1.9.3] - 2026-05-11
24
30
 
package/mdc/js-lint.mdc CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Перевірка JavaScript коду
3
3
  alwaysApply: true
4
- version: '1.17'
4
+ version: '1.18'
5
5
  ---
6
6
 
7
7
  **oxlint**, **ESLint**, **jscpd**. У скрипті **`lint-js`** і в CI — **`bunx oxlint`**, **`bunx eslint`**, **`bunx jscpd`** (у CI без **`--fix`** для oxlint/eslint — див. приклад workflow нижче). Без **prettier** і **@nitra/prettier-config**. У **`devDependencies`** має бути **`@nitra/eslint-config` мінімум `^3.9.2`** (з **3.8.0** правило `no-restricted-syntax` забороняє `for...in`; з **3.9.2** у `getConfig` вбудовано ignore для **`**/adr/**`** — ADR-документи не валідуються ESLint, локально цей glob додавати не потрібно; також транзитивно йде **`@e18e/eslint-plugin`** для oxlint); пакет **`@e18e/eslint-plugin`** окремо не додавай. Пакети oxlint/eslint/jscpd не додавай без потреби монорепо.
@@ -43,7 +43,9 @@ version: '1.17'
43
43
  }
44
44
  ```
45
45
 
46
- У корені проєкту має бути `.jscpd.json`. Мінімум: увімкнути облік `.gitignore`, ненульовий код виходу при знаходженні клонів, консольний звіт. За потреби додай `ignore` (дзеркальні каталоги, шаблони) та `minLines`, щоб відсікти дрібні збіги:
46
+ У корені проєкту має бути `.jscpd.json`. Мінімум: увімкнути облік `.gitignore`, ненульовий код виходу при знаходженні клонів, консольний звіт. За потреби додай `ignore` (дзеркальні каталоги, шаблони) та `minLines`, щоб відсікти дрібні збіги.
47
+
48
+ Каталог `.claude/worktrees/` (робочі копії, які Claude Code створює через **superpowers:using-git-worktrees**) має ігноруватися: додай його у кореневий `.gitignore` (це штатне місце для не-комітних робочих копій), а в `.jscpd.json` додай `.claude/worktrees/**` у `ignore` як страховку на випадок запуску без `gitignore: true`. Без цього jscpd сканує паралельну копію репо в worktree і фіксує самозбіги між дзеркальними файлами.
47
49
 
48
50
  ```json title=".jscpd.json"
49
51
  {
@@ -51,10 +53,14 @@ version: '1.17'
51
53
  "exitCode": 1,
52
54
  "reporters": ["console"],
53
55
  "minLines": 25,
54
- "ignore": ["**/dist/**"]
56
+ "ignore": [".claude/worktrees/**", "**/dist/**"]
55
57
  }
56
58
  ```
57
59
 
60
+ ```text title=".gitignore (фрагмент)"
61
+ .claude/worktrees/
62
+ ```
63
+
58
64
  ## jscpd: рефакторинг і структура
59
65
 
60
66
  Коли **jscpd** знаходить клони, спочатку зменшуй дублювання кодом, а не конфігом.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.9.5",
3
+ "version": "1.9.6",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -80,6 +80,13 @@ const TEST_FRAMEWORK_MODULES = new Set([
80
80
  'tape'
81
81
  ])
82
82
 
83
+ /** Символи у glob-сегменті, які треба екранувати для RegExp (без `*` / `?` — їх обробляємо окремо). */
84
+ const REGEX_SPECIAL_IN_GLOB = new Set(['.', '+', '^', '$', '{', '}', '(', ')', '|', '[', ']', '\\'])
85
+
86
+ /** Збіги для post-обробки glob → regex після злиття сегментів через `/` (див. `globToRegex`). */
87
+ const GLOBSTAR_LEADING_RE = /^__GLOBSTAR__\//u
88
+ const GLOBSTAR_TRAILING_RE = /\/__GLOBSTAR__$/u
89
+
83
90
  /**
84
91
  * Чи є під `npm/src` хоча б один `.js` (рекурсивно).
85
92
  * @param {string[]} [ignorePaths] абсолютні шляхи каталогів, повністю виключених з обходу
@@ -338,13 +345,13 @@ function checkPublishWorkflow(passFn, failFn) {
338
345
  }
339
346
 
340
347
  /**
341
- * Перетворює glob-патерн (як у npm `files`) у анкоровану `RegExp`. Підтримує
342
- * globstar (нуль або більше сегментів), `*` (символи без `/`) і `?` (один
343
- * символ без `/`). Не підтримує brace-expansion і class `[…]` — у негативних
344
- * патернах `files` цього достатньо для практичних випадків (приклад:
345
- * negation з префіксом `!` і двома зірочками поряд з `_test.rego`).
348
+ * Перетворює glob-патерн (як у npm `files`) у `RegExp` з якорями `^` / `$`.
349
+ * Підтримує globstar (нуль або більше сегментів), `*` (символи без `/`) і `?`
350
+ * (один символ без `/`). Не підтримує brace-expansion і class `[…]` — у
351
+ * негативних патернах `files` цього достатньо для практичних випадків
352
+ * (приклад: negation з префіксом `!` і двома зірочками поряд з `_test.rego`).
346
353
  * @param {string} glob posix-шлях у glob-нотації
347
- * @returns {RegExp} регулярка, анкорована з обох боків
354
+ * @returns {RegExp} `RegExp` з якорями `^` / `$`
348
355
  */
349
356
  export function globToRegex(glob) {
350
357
  const parts = glob.split('/')
@@ -354,16 +361,16 @@ export function globToRegex(glob) {
354
361
  for (const c of p) {
355
362
  if (c === '*') out += '[^/]*'
356
363
  else if (c === '?') out += '[^/]'
357
- else if ('.+^${}()|[]\\'.includes(c)) out += `\\${c}`
364
+ else if (REGEX_SPECIAL_IN_GLOB.has(c)) out += `\\${c}`
358
365
  else out += c
359
366
  }
360
367
  return out
361
368
  })
362
369
  let re = tokens.join('/')
363
- re = re.replace(/\/__GLOBSTAR__\//gu, '(?:/.*/|/)')
364
- re = re.replace(/^__GLOBSTAR__\//u, '(?:.*/)?')
365
- re = re.replace(/\/__GLOBSTAR__$/u, '(?:/.*)?')
366
- re = re.replace(/__GLOBSTAR__/gu, '.*')
370
+ re = re.replaceAll('/__GLOBSTAR__/', '(?:/.*/|/)')
371
+ re = re.replace(GLOBSTAR_LEADING_RE, '(?:.*/)?')
372
+ re = re.replace(GLOBSTAR_TRAILING_RE, '(?:/.*)?')
373
+ re = re.replaceAll('__GLOBSTAR__', '.*')
367
374
  return new RegExp(`^${re}$`, 'u')
368
375
  }
369
376
 
@@ -449,7 +456,7 @@ export function findTestFrameworkImport(content, virtualPath) {
449
456
  */
450
457
  export async function classifyPublishedFileAsTest(relPath) {
451
458
  const segments = relPath.split('/')
452
- const base = segments[segments.length - 1]
459
+ const base = segments.at(-1)
453
460
  const dirs = segments.slice(0, -1)
454
461
  const testDir = dirs.find(seg => TEST_DIR_NAMES.has(seg.toLowerCase()))
455
462
  if (testDir) return `test-style каталог "${testDir}/"`
@@ -482,7 +489,7 @@ async function checkNoTestsInPublishedFiles(pass, fail) {
482
489
  if (reason) violations.push({ file: rel, reason })
483
490
  }
484
491
  if (violations.length === 0) {
485
- pass(`npm/: усі ${files.length} опублікованих файли без тестів/фікстур`)
492
+ pass(`npm/: усі ${files.length} опублікованих файли без тестів і fixtures`)
486
493
  return
487
494
  }
488
495
  for (const v of violations) {