@7n/rules 1.7.3 → 1.7.5

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
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.7.5] - 2026-07-16
4
+
5
+ ### Fixed
6
+
7
+ - npm: підняти нижню межу @7n/llm-lib до ^2.7.0 (skills-cli.mjs імпортує ./acp, доданий лише у 2.7.0 — старіші 2.x без цього subpath ламали npx @7n/rules з ERR_PACKAGE_PATH_NOT_EXPORTED)
8
+
9
+ ## [1.7.4] - 2026-07-16
10
+
11
+ ### Fixed
12
+
13
+ - lint не бачить worktree-чекаутів (.worktrees/, .claude/worktrees/): виключені у walkDir, delta-списку змінених файлів і js/eslint (ESLint+oxlint)
14
+
3
15
  ## [1.7.3] - 2026-07-16
4
16
 
5
17
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/rules",
3
- "version": "1.7.3",
3
+ "version": "1.7.5",
4
4
  "description": "CLI еталонних правил і skills (префікс n-): синк у репозиторій, дельта-lint, конформність",
5
5
  "keywords": [
6
6
  "cli",
@@ -63,7 +63,7 @@
63
63
  "rename-yaml-extensions": "bun ./bin/n-rules.js rename-yaml-extensions"
64
64
  },
65
65
  "dependencies": {
66
- "@7n/llm-lib": "^2.0.0",
66
+ "@7n/llm-lib": "^2.7.0",
67
67
  "@7n/mt": "^0.5.1",
68
68
  "@zed-industries/agent-client-protocol": "^0.4.5",
69
69
  "ajv": "^8.20.0",
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: main.mjs
4
4
  resource: npm/rules/js/eslint/main.mjs
5
5
  docgen:
6
- crc: 2d36631f
6
+ crc: 0d2a5e02
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 100
9
9
  issues: judge:inaccurate:0.99
@@ -32,4 +32,4 @@ lint — проводить статичний аналіз коду (пофай
32
32
 
33
33
  **warnIgnored: false.** ESLint конструюється з `warnIgnored: false` — файли з delta-списку, що матчать ignore-патерни `eslint.config.js` (наприклад, синковані `.pi/extensions/**` чи згенеровані `npm/types/**`), не рахуються порушеннями.
34
34
 
35
- **Діагностика крашу oxlint.** Якщо oxlint завершився помилкою і json не розпарсено, у повідомлення DetectorError включаються exit-код і хвости stderr/stdoutінакше на CI причина (відсутній jsPlugin, конфіг, OOM) невидима.
35
+ **Worktree-чекаути ігноруються.** Обидва інструменти виключають `.worktrees/**` і `.claude/worktrees/**` (копії репо від сесійних git-worktree, яких споживацький конфіг зазвичай не виключає): ESLint через global ignores у `overrideConfig`, oxlintчерез `--ignore-pattern`. Діє і у full-режимі, і для явно переданих файлів.
@@ -8,6 +8,7 @@ import { spawnSync } from 'node:child_process'
8
8
  import { ESLint } from 'eslint'
9
9
 
10
10
  import { addedLinesByFile } from '../../../scripts/lib/diff-added-lines.mjs'
11
+ import { WORKTREE_CHECKOUT_GLOBS } from '../../../scripts/utils/walkDir.mjs'
11
12
  import { classifyFindings, eslintResultsToFindings, parseOxlint } from '../lint-findings/main.mjs'
12
13
 
13
14
  const JS_EXT_RE = /\.(?:mjs|cjs|js|jsx|ts|tsx|vue)$/u
@@ -55,12 +56,18 @@ function toViolation(f, cwd, severity) {
55
56
  * @returns {Promise<Array<{ file: string, line: number, rule: string, message: string, tool: string }>>} зібрані знахідки oxlint+eslint
56
57
  */
57
58
  async function collectFindings(js, cwd) {
58
- // warnIgnored:false — файли з delta, що матчать ignore-патерни конфігу, не є порушеннями
59
- const eslint = new ESLint({ cwd, warnIgnored: false })
59
+ // warnIgnored:false — файли з delta, що матчать ignore-патерни конфігу, не є порушеннями.
60
+ // overrideConfig лише з ignores global ignores: worktree-чекаути (.worktrees/,
61
+ // .claude/worktrees/) — копії репо, споживацький eslint-конфіг їх не виключає.
62
+ const eslint = new ESLint({ cwd, warnIgnored: false, overrideConfig: { ignores: WORKTREE_CHECKOUT_GLOBS } })
60
63
  const esResults = await eslint.lintFiles(js === null ? [cwd] : js.map(f => resolve(cwd, f)))
61
64
  const es = eslintResultsToFindings(esResults)
62
65
 
63
- const oxArgs = js === null ? ['oxlint', '--format=json'] : ['oxlint', '--format=json', ...js]
66
+ const worktreeIgnoreArgs = WORKTREE_CHECKOUT_GLOBS.map(g => `--ignore-pattern=${g}`)
67
+ const oxArgs =
68
+ js === null
69
+ ? ['oxlint', '--format=json', ...worktreeIgnoreArgs]
70
+ : ['oxlint', '--format=json', ...worktreeIgnoreArgs, ...js]
64
71
  const oxRes = runOxlintJson(oxArgs, cwd)
65
72
  const ox = parseOxlint(oxRes.stdout)
66
73
  if (ox === null && oxRes.status !== 0) {
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: sync-claude-config.mjs
4
4
  resource: npm/scripts/sync-claude-config.mjs
5
5
  docgen:
6
- crc: 177ad3ea
6
+ crc: 1ae220d3
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 85
9
9
  ---
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { spawnSync } from 'node:child_process'
9
9
 
10
+ import { isWorktreeCheckoutPath } from '../utils/walkDir.mjs'
11
+
10
12
  /**
11
13
  * @param {string[]} args аргументи git
12
14
  * @param {string} cwd корінь
@@ -29,7 +31,18 @@ function gitLines(args, cwd) {
29
31
  export function collectChangedFiles(cwd = process.cwd()) {
30
32
  const modified = gitLines(['diff', 'HEAD', '--name-only', '--diff-filter=ACMR'], cwd)
31
33
  const untracked = gitLines(['ls-files', '--others', '--exclude-standard'], cwd)
32
- return [...new Set([...modified, ...untracked])]
34
+ return dropWorktreeCheckouts([...new Set([...modified, ...untracked])])
35
+ }
36
+
37
+ /**
38
+ * Прибирає шляхи всередині worktree-чекаутів (`.worktrees/`, `.claude/worktrees/`):
39
+ * це повні копії репо (сесійні worktree Claude/агентів), а не робочий код, і в
40
+ * споживацьких репо вони можуть бути не gitignored — git тоді віддає їх як untracked.
41
+ * @param {string[]} paths relative-posix шляхи
42
+ * @returns {string[]} шляхи без worktree-чекаутів
43
+ */
44
+ function dropWorktreeCheckouts(paths) {
45
+ return paths.filter(p => !isWorktreeCheckoutPath(p))
33
46
  }
34
47
 
35
48
  /**
@@ -79,5 +92,5 @@ export function collectChangedFilesSince(base, cwd = process.cwd()) {
79
92
  }
80
93
  const changed = gitLines(['diff', base, '--name-only', '--diff-filter=ACMR'], cwd)
81
94
  const untracked = gitLines(['ls-files', '--others', '--exclude-standard'], cwd)
82
- return [...new Set([...changed, ...untracked])]
95
+ return dropWorktreeCheckouts([...new Set([...changed, ...untracked])])
83
96
  }
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: changed-files.mjs
4
4
  resource: npm/scripts/lib/changed-files.mjs
5
5
  docgen:
6
- crc: 792d3942
6
+ crc: 483db255
7
7
  score: 100
8
8
  ---
9
9
 
@@ -27,6 +27,8 @@ collectChangedFilesSince Збирає змінені та незакомічен
27
27
 
28
28
  ## Гарантії поведінки
29
29
 
30
+ - Обидва збирачі відкидають шляхи всередині worktree-чекаутів (`.worktrees/`, `.claude/worktrees/`): це повні копії репо (сесійні git-worktree Claude/агентів), а не робочий код; у споживацьких репо вони можуть бути не gitignored і інакше потрапляли б у delta-список як untracked.
31
+
30
32
  - Read-only: файл не виконує операцій запису у файлову систему.
31
33
  - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
32
34
  - Не звертається до мережі.
@@ -3,29 +3,31 @@ type: JS Module
3
3
  title: walkDir.mjs
4
4
  resource: npm/scripts/utils/walkDir.mjs
5
5
  docgen:
6
- crc: f205f003
6
+ crc: 6f26e08f
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 100
9
9
  ---
10
10
 
11
- Публічна функція `walkDir` здійснює рекурсивний пошук файлів у вказаному каталозі. Вона обходить файлову систему, ігноруючи каталоги `.git` та `node_modules`. Знаходячи кожен файл, вона передає його повний шлях у колбек для подальшої обробки. Компонент є read-only, тобто не виконує записів у файлову систему чи бази даних. При роботі з файловою системою він перехоплює помилки, забезпечуючи безпечну роботу без викидання винятків.
11
+ Публічна функція `walkDir` здійснює рекурсивний пошук файлів у вказаному каталозі. Вона обходить файлову систему, ігноруючи каталоги `.git`, `node_modules` та worktree-чекаути (`.worktrees/`, `.claude/worktrees/` — повні копії репо від сесійних git-worktree Claude/агентів). Знаходячи кожен файл, вона передає його повний шлях у колбек для подальшої обробки. Компонент є read-only, тобто не виконує записів у файлову систему чи бази даних. При роботі з файловою системою він перехоплює помилки, забезпечуючи безпечну роботу без викидання винятків.
12
12
 
13
13
  ## Поведінка
14
14
 
15
15
  1. Викликається функція walkDir для початку рекурсивного обходу каталогу.
16
16
  2. Система розшифровує вхідний шлях до кореня обходу.
17
17
  3. Система формує додаткові правила ігнорування на основі наданих шляхів.
18
- 4. Система завжди ігнорує каталоги .git та node_modules.
18
+ 4. Система завжди ігнорує каталоги .git, node_modules і worktree-чекаути (.worktrees/, .claude/worktrees/) на будь-якій глибині.
19
19
  5. Система виконує пошук усіх файлів у каталозі, застосовуючи правила ігнорування, включаючи ті, що визначені в .gitignore.
20
20
  6. У разі виникнення помилки під час пошуку, процес обходу припиняється без генерації винятку.
21
21
  7. Для кожного знайденого файлу система викликає наданий колбек, передаючи йому повний абсолютний шлях до цього файлу.
22
22
 
23
23
  ## Публічний API
24
24
 
25
- walkDir — рекурсивно переглядає файли та папки, ігноруючи ті, що вказані у файлі `.gitignore`.
25
+ - walkDir — рекурсивно переглядає файли та папки, ігноруючи ті, що вказані у файлі `.gitignore`.
26
+ - isWorktreeCheckoutPath — предикат для відносного posix-шляху: чи лежить він усередині worktree-чекаута (`.worktrees/` або `.claude/worktrees/`). Для фільтрації git-списків, що не проходять через walkDir (наприклад, delta-список змінених файлів).
27
+ - ALWAYS_IGNORE, WORKTREE_CHECKOUT_GLOBS — експортовані glob-константи безумовних пропусків обходу.
26
28
 
27
29
  ## Гарантії поведінки
28
30
 
29
31
  - Read-only: не виконує операцій запису (ФС/БД).
30
32
  - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
31
- - Свідомо пропускає шляхи: `.git`, `node_modules`.
33
+ - Свідомо пропускає шляхи: `.git`, `node_modules`, `.worktrees/`, `.claude/worktrees/`.
@@ -2,9 +2,26 @@
2
2
  import { join, relative, resolve, sep } from 'node:path'
3
3
  import { globby } from 'globby'
4
4
 
5
+ // Сесійні git-worktree чекаути (Claude/агенти): повні копії репо, не робочий код.
6
+ // Споживацькі репо часто не мають цих шляхів у .gitignore, тож без safety net
7
+ // lint-обхід бачив би дубль усього дерева.
8
+ export const WORKTREE_CHECKOUT_GLOBS = ['**/.worktrees/**', '**/.claude/worktrees/**']
9
+
5
10
  // .git ніколи не потрапляє в .gitignore — пропускаємо завжди.
6
11
  // node_modules — safety net: проєкт може не мати .gitignore або запускатись поза git-репо.
7
- export const ALWAYS_IGNORE = ['.git/**', 'node_modules/**']
12
+ export const ALWAYS_IGNORE = ['.git/**', 'node_modules/**', ...WORKTREE_CHECKOUT_GLOBS]
13
+
14
+ const WORKTREE_CHECKOUT_RE = /(?:^|\/)(?:\.worktrees|\.claude\/worktrees)\//u
15
+
16
+ /**
17
+ * Чи лежить відносний posix-шлях усередині worktree-чекаута (`.worktrees/` або
18
+ * `.claude/worktrees/`). Для фільтрації git-списків, що не проходять через walkDir.
19
+ * @param {string} relPath відносний posix-шлях від кореня репо.
20
+ * @returns {boolean} true, якщо шлях у worktree-чекауті.
21
+ */
22
+ export function isWorktreeCheckoutPath(relPath) {
23
+ return WORKTREE_CHECKOUT_RE.test(relPath)
24
+ }
8
25
 
9
26
  /**
10
27
  * Прибирає всі кінцеві `/` без regex-бектрекінгу.