@nitra/cursor 1.27.3 → 1.27.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.
Files changed (43) hide show
  1. package/.claude-template/hooks/capture-decisions.sh +1 -1
  2. package/.claude-template/hooks/normalize-decisions.sh +1 -1
  3. package/.pi-template/extensions/n-cursor-adr/tsconfig.json +1 -0
  4. package/CHANGELOG.md +61 -32
  5. package/bin/n-cursor.js +2 -2
  6. package/package.json +1 -1
  7. package/rules/bun/bun.mdc +1 -1
  8. package/rules/bun/policy/package_json/package_json.rego +14 -4
  9. package/rules/changelog/js/consistency.mjs +1 -1
  10. package/rules/image-avif/js/avif_generation.mjs +2 -2
  11. package/rules/js-lint/js-lint.mdc +1 -1
  12. package/rules/js-mssql/js/deps.mjs +1 -1
  13. package/rules/k8s/js/manifests.mjs +19 -19
  14. package/rules/k8s/k8s.mdc +9 -9
  15. package/rules/k8s/policy/network_policy/network_policy.rego +5 -5
  16. package/rules/tauri/js/cargo_mutants_config.mjs +3 -3
  17. package/rules/tauri/tauri.mdc +2 -2
  18. package/rules/test/coverage/coverage.mjs +4 -4
  19. package/rules/test/js/cargo_mutants_config.mjs +2 -2
  20. package/rules/test/js/data/cargo_mutants_config/mutants.toml.baseline +1 -1
  21. package/rules/test/js/data/stryker_config/stryker.config.baseline.mjs +1 -1
  22. package/rules/test/js/stryker_config.mjs +3 -3
  23. package/rules/test/test.mdc +5 -5
  24. package/rules/text/js/forbidden-prettier.mjs +59 -0
  25. package/rules/text/js/formatting.mjs +1 -4
  26. package/rules/text/policy/package_json/package_json.rego +16 -0
  27. package/rules/text/text.mdc +1 -1
  28. package/rules/vue/vue.mdc +1 -1
  29. package/schemas/v8r-catalog.json +6 -0
  30. package/scripts/coverage-fix.mjs +12 -12
  31. package/scripts/lib/run-lint-cli.mjs +5 -5
  32. package/scripts/lib/run-lint-step.mjs +1 -1
  33. package/scripts/lib/run-rule.mjs +1 -1
  34. package/scripts/lib/timing-summary.mjs +3 -3
  35. package/scripts/post-tool-use-fix.mjs +4 -4
  36. package/scripts/sync-claude-config.mjs +2 -2
  37. package/scripts/utils/ensure-gitignore-entries.mjs +2 -2
  38. package/scripts/utils/resolve-cargo-manifest.mjs +1 -1
  39. package/scripts/utils/resolve-js-root.mjs +1 -1
  40. package/scripts/utils/walkDir.mjs +2 -2
  41. package/skills/coverage-fix/SKILL.md +15 -12
  42. package/skills/fix-tests/SKILL.md +13 -13
  43. /package/rules/k8s/policy/network_policy/template/{statefulset.snippet.yaml → stateful-set.snippet.yaml} +0 -0
@@ -19,6 +19,12 @@
19
19
  "description": "Каталог схем Schema Store (v8r-catalog.json у пакеті)",
20
20
  "url": "https://json.schemastore.org/schema-catalog.json",
21
21
  "fileMatch": ["npm/schemas/v8r-catalog.json"]
22
+ },
23
+ {
24
+ "name": "tsconfig",
25
+ "description": "TypeScript config для pi extension templates, які Schema Store не матчить через вкладений/прихований шлях",
26
+ "url": "https://json.schemastore.org/tsconfig.json",
27
+ "fileMatch": [".pi/extensions/*/tsconfig.json", "npm/.pi-template/extensions/*/tsconfig.json"]
22
28
  }
23
29
  ]
24
30
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `n-cursor coverage --fix`: запускає Claude Code агента для написання тестів
3
- * по вижилих мутантах Stryker. Агент отримує список мутантів з контекстом
4
- * (file, line, оригінальний код, вижилий варіант, тип мутації) і самостійно
3
+ * по вцілілих мутантах Stryker. Агент отримує список мутантів з контекстом
4
+ * (file, line, оригінальний код, вцілілий варіант, тип мутації) і самостійно
5
5
  * знаходить або створює відповідні test-файли.
6
6
  *
7
7
  * Залежить від `@anthropic-ai/claude-agent-sdk` (dependencies у npm/package.json).
@@ -15,8 +15,8 @@ import { join } from 'node:path'
15
15
  */
16
16
 
17
17
  /**
18
- * Запускає Claude Code агента для написання тестів по вижилих мутантах.
19
- * @param {SurvivedFileGroup[]} survived вижилі мутанти, згруповані по файлах
18
+ * Запускає Claude Code агента для написання тестів по вцілілих мутантах.
19
+ * @param {SurvivedFileGroup[]} survived вцілілі мутанти, згруповані по файлах
20
20
  * @param {string} projectRoot абсолютний шлях до кореня проєкту
21
21
  * @returns {Promise<void>}
22
22
  */
@@ -28,7 +28,7 @@ export async function fixSurvivedMutants(survived, projectRoot) {
28
28
  }
29
29
 
30
30
  const prompt = await buildFixPrompt(survived, projectRoot)
31
- console.log(`\n🤖 coverage --fix: запускаю агента для ${totalMutants} вижилих мутантів...\n`)
31
+ console.log(`\n🤖 coverage --fix: запускаю агента для ${totalMutants} вцілілих мутантів...\n`)
32
32
 
33
33
  // Dynamic import: @anthropic-ai/claude-agent-sdk завантажується лише при --fix,
34
34
  // щоб не гальмувати звичайний coverage-прогін за відсутності пакету.
@@ -48,9 +48,9 @@ export async function fixSurvivedMutants(survived, projectRoot) {
48
48
  }
49
49
 
50
50
  /**
51
- * Формує rich-промпт для агента: список вижилих мутантів згрупований по файлах,
51
+ * Формує rich-промпт для агента: список вцілілих мутантів згрупований по файлах,
52
52
  * з контекстом ±3 рядки навколо кожного мутанта з source-файлу.
53
- * @param {SurvivedFileGroup[]} survived групи вижилих мутантів по файлах
53
+ * @param {SurvivedFileGroup[]} survived групи вцілілих мутантів по файлах
54
54
  * @param {string} projectRoot корінь проєкту
55
55
  * @returns {Promise<string>} текст rich-промпту
56
56
  */
@@ -66,7 +66,7 @@ async function buildFixPrompt(survived, projectRoot) {
66
66
  // файл може бути недоступним — пропускаємо контекст, але продовжуємо
67
67
  }
68
68
 
69
- const mutantDescs = mutants
69
+ const mutantDescriptions = mutants
70
70
  .map(m => {
71
71
  const ctxStart = Math.max(0, m.line - 4)
72
72
  const ctxEnd = Math.min(srcLines.length, m.line + 3)
@@ -89,15 +89,15 @@ async function buildFixPrompt(survived, projectRoot) {
89
89
  ? `\n\nПриклад тесту з \`${exampleTest.testFile}\`:\n\`\`\`js\n${exampleTest.code}\n\`\`\``
90
90
  : ''
91
91
 
92
- sections.push(`### \`${file}\`${exampleSection}\n${mutantDescs}`)
92
+ sections.push(`### \`${file}\`${exampleSection}\n${mutantDescriptions}`)
93
93
  }
94
94
 
95
95
  return [
96
- 'Твоє завдання — написати unit-тести, що вбивають наступні вижилі мутанти Stryker.',
96
+ 'Твоє завдання — написати unit-тести, що вбивають наступні вцілілі мутанти Stryker.',
97
97
  'Для кожного мутанта: знайди або створи відповідний test-файл, додай тест-кейс,',
98
- 'що явно перевіряє цю гілку/умову і провалиться якщо код замінити на "вижилий варіант".',
98
+ 'що явно перевіряє цю гілку/умову і провалиться якщо код замінити на "вцілілий варіант".',
99
99
  '',
100
- '## Вижилі мутанти',
100
+ '## Вцілілі мутанти',
101
101
  '',
102
102
  ...sections,
103
103
  '',
@@ -1,8 +1,8 @@
1
1
  /**
2
- * `n-cursor lint` — оркестратор лінт-ланцюжка з тайменгом на кожен крок.
2
+ * `n-cursor lint` — оркестратор лінт-ланцюжка з вимірюванням часу на кожен крок.
3
3
  *
4
4
  * Замість агрегатора `bun run lint-ga && bun run lint-js && ... && oxfmt .` у кореневому
5
- * `package.json` (де child-процеси анонімні і час кожного не видно), цей орекстратор:
5
+ * `package.json` (де child-процеси анонімні і час кожного не видно), цей оркестратор:
6
6
  *
7
7
  * - читає `scripts` з кореневого `package.json`,
8
8
  * - бере **присутні** ключі з фіксованого списку `LINT_SCRIPTS` (відсутні мовчки пропускає),
@@ -14,7 +14,7 @@
14
14
  *
15
15
  * Список + порядок зумисне фіксований: збігається з канонічним ланцюжком, що його раніше
16
16
  * тримав root `package.json`. Динамічний discovery (`scripts/^lint-/`) дав би непередбачуваний
17
- * порядок і небажану інтерпретацію кастомних `lint-*` користувача.
17
+ * порядок і небажану інтерпретацію власних `lint-*` користувача.
18
18
  *
19
19
  * `oxfmt` — окремий рядок поза префіксом `lint-`, ставиться в кінець (як було у `lint`).
20
20
  */
@@ -72,9 +72,9 @@ function readRootScripts(root) {
72
72
  */
73
73
 
74
74
  /**
75
- * Виконує лінт-ланцюжок з тайменгом. Повертає exit-код, не кидає винятків (для прямого
75
+ * Виконує лінт-ланцюжок з вимірюванням часу. Повертає exit-код, не кидає винятків (для прямого
76
76
  * присвоєння у `process.exitCode`).
77
- * @param {RunLintCliOptions} [options] DI для тестів (мокаємо spawn / fs / clock)
77
+ * @param {RunLintCliOptions} [options] DI для тестів (підміняємо spawn / fs / clock)
78
78
  * @returns {number} 0 = успіх, ненульовий = code першого впалого скрипта, або 1 при структурних проблемах
79
79
  */
80
80
  export function runLintCli(options = {}) {
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process'
11
11
  import { resolveCmd } from '../utils/resolve-cmd.mjs'
12
12
 
13
13
  /**
14
- * Запускає один крок lint-обгортки: резолвить `cmd` у PATH і `spawnSync` із успадкованим stdio.
14
+ * Запускає один крок lint-обгортки: визначає `cmd` у PATH і `spawnSync` із успадкованим stdio.
15
15
  * @param {string} title заголовок для логу (наприклад `actionlint`)
16
16
  * @param {string} cmd ім'я команди (`bunx`, `uvx`, `npx`, …)
17
17
  * @param {string[]} args аргументи команди
@@ -54,7 +54,7 @@ async function evaluateAppliesGate(bundledRulesDir, rule) {
54
54
 
55
55
  /**
56
56
  * Запускає одну policy-полісі через `runConftestBatch`. Створює локальний репортер,
57
- * читає `target.json`, резолвить файли, фіксує fail/pass — і повертає exit-код.
57
+ * читає `target.json`, визначає файли, фіксує fail/pass — і повертає exit-код.
58
58
  * @param {string} bundledRulesDir абсолютний `rules/`
59
59
  * @param {string} ruleId id правила
60
60
  * @param {string} concernName імʼя полісі (= підкаталог у `policy/`)
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Формат таблиці-резюме часу виконання для оркестраторів `fix` / `lint`.
2
+ * Формат таблиці-резюме часу виконання для orchestrator `fix` / `lint`.
3
3
  *
4
4
  * Дві спільні точки використання:
5
5
  * - `runFixCommand` у `bin/n-cursor.js` — після прогону всіх `rules/<id>/fix.mjs`.
6
6
  * - `runLintCli` у `scripts/lib/run-lint-cli.mjs` — після прогону `lint-*` скриптів з кореневого `package.json`.
7
7
  *
8
8
  * Чиста функція без I/O — повертає готовий рядок (з фінальним `\n`), друк — на стороні виклику.
9
- * Час виводиться як `<ціла>.<десята>s`, навіть для субсекундних інтервалів — щоб одиниця була стабільна.
9
+ * Час виводиться як `<ціла>.<десята>s`, навіть для коротших за секунду інтервалів — щоб одиниця була стабільна.
10
10
  *
11
11
  * Маркер `❌` на рядку — якщо `ok === false`.
12
12
  * @typedef {{ id: string, ms: number, ok: boolean }} TimingEntry
@@ -40,7 +40,7 @@ export function formatDurationMs(ms) {
40
40
  * total <sum>
41
41
  * ```
42
42
  *
43
- * Ширина колонки id вирівнюється під найдовший id у списку. Мінімальна ширина riski — 14
43
+ * Ширина колонки id вирівнюється під найдовший id у списку. Мінімальна ширина risk — 14
44
44
  * (узгоджено з типовою довжиною заголовків `fix-js-lint` / `lint-security`).
45
45
  * @param {string} title заголовок таблиці (наприклад, `Fix timing` або `Lint timing`)
46
46
  * @param {TimingEntry[]} timings записи в порядку запуску — друкуються як є, не сортуються
@@ -6,9 +6,9 @@
6
6
  *
7
7
  * Контракт:
8
8
  * - stdin Claude Code: JSON із `tool_input.file_path` (відносний шлях зміненого файла);
9
- * - exit 0, якщо файл не маршрутизується (PostToolUse не блокує turn у будь-якому випадку,
9
+ * - exit 0, якщо файл не має маршрут (PostToolUse не блокує turn у будь-якому випадку,
10
10
  * але ми лишаємо exit-код прозорим — для діагностики);
11
- * - інакше spawn `npx --no @nitra/cursor fix <rules…>` із пробрасуванням exit-коду.
11
+ * - інакше spawn `npx --no @nitra/cursor fix <rules…>` із передаванням exit-коду.
12
12
  *
13
13
  * Маршрути впорядковані від найбільш специфічного до загального; перший збіг — переможець.
14
14
  * `docs/adr/**\/*.md` свідомо повертає `[]`: ADR-нормалізація вже покривається async
@@ -83,7 +83,7 @@ async function readStdin() {
83
83
 
84
84
  /**
85
85
  * Дістає `tool_input.file_path` зі stdin JSON Claude Code. Невалідний JSON
86
- * або відсутнє поле → `null` (не помилка: дехто з тулів — напр. Bash — не пише `file_path`).
86
+ * або відсутнє поле → `null` (не помилка: дехто з інструментів — напр. Bash — не пише `file_path`).
87
87
  * @param {string} stdinJson сирий вміст stdin
88
88
  * @returns {string | null} відносний шлях або `null`
89
89
  */
@@ -102,7 +102,7 @@ function extractFilePath(stdinJson) {
102
102
 
103
103
  /**
104
104
  * Точка входу. Викликається з `bin/n-cursor.js` коли argv[0] === `post-tool-use-fix`.
105
- * Параметри ін'єктовні для тестів: `stdinJson` обходить read від `process.stdin`,
105
+ * Параметри доступні для інʼєкції для тестів: `stdinJson` обходить read від `process.stdin`,
106
106
  * `spawnFn` — заміна `node:child_process.spawn` (повертає EventEmitter-сумісний об'єкт).
107
107
  * @param {{ stdinJson?: string, spawnFn?: typeof spawn }} [options] параметри для тестів (ін'єкція stdin/spawn)
108
108
  * @returns {Promise<number>} exit code (0 — пропущено / fix ОК; інше — exit-код `fix`)
@@ -467,7 +467,7 @@ export async function removeOrphanAdrHookLib(projectRoot) {
467
467
  * перезаписується. Якщо bundled template відсутній (legacy-версії пакета без `.pi-template/`)
468
468
  * або в ньому немає `index.ts` — повертаємо `{written: false}` без помилки.
469
469
  *
470
- * Розширення поверх `index.ts` (tsconfig тощо) потрібні, бо `.pi/extensions/` синкається як є
470
+ * Розширення поверх `index.ts` (tsconfig тощо) потрібні, бо `.pi/extensions/` синхронізується як є
471
471
  * у проєкти-споживачі, а IDE/TS-сервер мусить резолвити `node:*` модулі без додаткових
472
472
  * project-wide конфігів.
473
473
  * @param {string} projectRoot корінь проєкту-споживача
@@ -637,7 +637,7 @@ export async function syncClaudeConfig({ projectRoot, bundledPackageRoot, enable
637
637
  ? await syncAdrNormalizeHookScript(projectRoot, templateDir)
638
638
  : { written: false, path: '' }
639
639
  // Lib-файли мають сенс лише з активним хоча б одним ADR-хуком — без caller'а
640
- // нікому source-ити; при вимкненому правилі прибираємо орфан-теку.
640
+ // нікому source-ити; при вимкненому правилі прибираємо осиротілу-теку.
641
641
  const adrHookLibEntries = includeAdrHook
642
642
  ? await syncAdrHookLibScripts(projectRoot, templateDir)
643
643
  : (await removeOrphanAdrHookLib(projectRoot), [])
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Idempotent append-only оновлювач `.gitignore` у корені проєкту. Перевіряє,
2
+ * Idempotent append-only модуль оновлення `.gitignore` у корені проєкту. Перевіряє,
3
3
  * чи задані entries уже присутні (точне співпадіння рядка після `trim`); відсутні
4
- * дописує під header-комент, не порушуючи решту файлу. Якщо `.gitignore` немає —
4
+ * дописує під header-коментар, не порушуючи решту файлу. Якщо `.gitignore` немає —
5
5
  * створюється з заданими entries + header.
6
6
  *
7
7
  * Викликається з test-концерну `stryker_config` (gitignore Stryker temp dirs).
@@ -2,7 +2,7 @@
2
2
  * Резолвить шлях до Cargo.toml у проєкті: cwd/Cargo.toml або в одному з
3
3
  * workspace-підкаталогів (з підтримкою Tauri-патерну `<workspace>/src-tauri/`).
4
4
  * Спільна утиліта для coverage-провайдера rust і test-концерну cargo_mutants_config.
5
- * Повертає null (а не throw) щоб callsite-и могли gracefully skip-нути.
5
+ * Повертає null (а не throw) щоб callsite-и могли gracefully skip-пропустити.
6
6
  */
7
7
  import { existsSync } from 'node:fs'
8
8
  import { readFile } from 'node:fs/promises'
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Резолвить корінь JS-коду в проєкті: для workspace-projects — перший workspace
3
- * (наприклад `app/` у mlmail), для single-package — корінь cwd. Спільна утиліта
3
+ * (наприклад `app/` у mail app), для single-package — корінь cwd. Спільна утиліта
4
4
  * для coverage-провайдера js-lint і test-концерну stryker_config (DRY).
5
5
  */
6
6
  import { existsSync } from 'node:fs'
@@ -42,7 +42,7 @@ function isIgnoredDir(dirAbsPosix, ignorePosix) {
42
42
  * @param {string} dir абсолютний шлях
43
43
  * @param {(filePath: string) => void} onFile виклик для кожного файлу
44
44
  * @param {string[]} [ignorePaths] шляхи каталогів (відносні від cwd або абсолютні), що повністю виключаються з обходу
45
- * @returns {Promise<void>} резолвиться по завершенню обходу
45
+ * @returns {Promise<void>} визначається по завершенню обходу
46
46
  */
47
47
  export async function walkDir(dir, onFile, ignorePaths = []) {
48
48
  const ignorePosix = ignorePaths.map(p => toAbsPosix(p))
@@ -54,7 +54,7 @@ export async function walkDir(dir, onFile, ignorePaths = []) {
54
54
  * @param {string} dir абсолютний шлях каталогу для обходу
55
55
  * @param {(filePath: string) => void} onFile колбек, що викликається для кожного звичайного файлу
56
56
  * @param {string[]} ignorePosix вже нормалізовані абсолютні posix-шляхи ігнорованих каталогів
57
- * @returns {Promise<void>} резолвиться по завершенню рекурсії
57
+ * @returns {Promise<void>} визначається по завершенню рекурсії
58
58
  */
59
59
  async function walkDirInner(dir, onFile, ignorePosix) {
60
60
  if (ignorePosix.length > 0 && isIgnoredDir(toAbsPosix(dir), ignorePosix)) return
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: n-coverage-fix
3
3
  description: >-
4
- Автономна команда: запускає n-cursor coverage → читає вижилих мутантів → ітеративно пише тести до конвергенції (max 3 ітерації)
4
+ Автономна команда: запускає n-cursor coverage → читає вцілілих мутантів → ітеративно пише тести до конвергенції (max 3 ітерації)
5
5
  ---
6
6
 
7
7
  # n-coverage-fix — підвищення mutation score
@@ -36,21 +36,21 @@ n-cursor coverage
36
36
  bun run coverage
37
37
  ```
38
38
 
39
- Ця команда генерує `COVERAGE.md`. Якщо є survived mutants — COVERAGE.md матиме секцію `## Вижилі мутанти` з JSON-блоком.
39
+ Ця команда генерує `COVERAGE.md`. Якщо є survived mutants — COVERAGE.md матиме секцію `## Вцілілі мутанти` з JSON-блоком.
40
40
 
41
- ### Крок 2: Перевір вижилих
41
+ ### Крок 2: Перевір вцілілих
42
42
 
43
- Прочитай `COVERAGE.md`. Знайди секцію `## Вижилі мутанти`. Знайди фенсований блок ` ```json ` і розпарси JSON-масив.
43
+ Прочитай `COVERAGE.md`. Знайди секцію `## Вцілілі мутанти`. Знайди огороджений блок ` ```json ` і розбери JSON-масив.
44
44
 
45
45
  Якщо секція відсутня або масив порожній — зупинись:
46
46
 
47
47
  ```
48
- ✓ Жодних вижилих мутантів — mutation score повний. Coverage завершено.
48
+ ✓ Жодних вцілілих мутантів — mutation score повний. Coverage завершено.
49
49
  ```
50
50
 
51
51
  Запам'ятай `prevCount = масив.length`.
52
52
 
53
- ### Крок 3: Для кожного файлу — спауни Agent
53
+ ### Крок 3: Для кожного файлу — запускає Agent
54
54
 
55
55
  Згрупуй мутанти по полю `file`. Для кожної групи:
56
56
 
@@ -68,8 +68,8 @@ bun run coverage
68
68
  **3b. Сформуй промпт для Agent:**
69
69
 
70
70
  ```
71
- Тобі дані вижилі мутанти зі Stryker для файлу `<file>`.
72
- Ці мутанти вижили бо наявні тести НЕ вловили конкретні зміни коду.
71
+ Тобі дані вцілілі мутанти зі Stryker для файлу `<file>`.
72
+ Ці мутанти вціліли, бо наявні тести НЕ вловили конкретні зміни коду.
73
73
 
74
74
  **Вихідний код** (`<file>`):
75
75
  \`\`\`
@@ -81,7 +81,7 @@ bun run coverage
81
81
  <зміст test-файлу або "файл ще не існує">
82
82
  \`\`\`
83
83
 
84
- **Вижилі мутанти** (кожен — зміна коду що НЕ вловлена):
84
+ **Вцілілі мутанти** (кожен — зміна коду що НЕ вловлена):
85
85
  <для кожного мутанта:>
86
86
  - Рядок <line>, колонка <col>: `<original>` → `<replacement>` (тип: <mutantType>)
87
87
 
@@ -111,21 +111,24 @@ bun test
111
111
  n-cursor coverage
112
112
  ```
113
113
 
114
- Прочитай новий `COVERAGE.md`. Розпарси JSON-масив вижилих.
114
+ Прочитай новий `COVERAGE.md`. Розбери JSON-масив вцілілих.
115
115
  `newCount = новий масив.length`
116
116
 
117
117
  **Рішення:**
118
118
 
119
119
  - `newCount < prevCount` AND iterations < 3 → повтор з Кроку 2 з оновленим масивом
120
120
  - `newCount >= prevCount` → конвергенція:
121
+
121
122
  ```
122
123
  ✓ Конвергенція: mutation score більше не покращується.
123
- Було вижилих: <prevCount>, стало: <newCount>.
124
+ Було вцілілих: <prevCount>, стало: <newCount>.
124
125
  ```
126
+
125
127
  - iterations == 3 → зупинись:
128
+
126
129
  ```
127
130
  ⚠️ Досягнуто максимум ітерацій (3).
128
- Вижило: <newCount> мутантів. Деякі можуть бути невбивними (dead code, external state).
131
+ Вціліло: <newCount> мутантів. Деякі можуть бути стійкими (dead code, external state).
129
132
  ```
130
133
 
131
134
  ## Конвергенція — нормальний результат
@@ -1,31 +1,31 @@
1
1
  ---
2
2
  name: n-fix-tests
3
3
  description: >-
4
- Ітеративно дописати тести щоб підвищити mutation score — читає вижилі мутанти з COVERAGE.md і запускає агент до конвергенції
4
+ Ітеративно дописати тести щоб підвищити mutation score — читає вцілілі мутанти з COVERAGE.md і запускає агент до конвергенції
5
5
  ---
6
6
 
7
7
  # n-fix-tests — підвищення mutation score
8
8
 
9
9
  ## Мета
10
10
 
11
- Читає структурований JSON-блок вижилих мутантів з `COVERAGE.md` і ітеративно дописує тести що їх вловлюють. Зупиняється коли score перестає покращуватись (конвергенція).
11
+ Читає структурований JSON-блок вцілілих мутантів з `COVERAGE.md` і ітеративно дописує тести що їх вловлюють. Зупиняється коли score перестає покращуватись (конвергенція).
12
12
 
13
13
  ## Передумови
14
14
 
15
- - У `COVERAGE.md` є секція `## Вижилі мутанти` з JSON-блоком
15
+ - У `COVERAGE.md` є секція `## Вцілілі мутанти` з JSON-блоком
16
16
  - Залежності встановлені (`bun i`)
17
17
  - `bun run coverage` (або `n-cursor coverage`) доступний
18
18
 
19
19
  ## Workflow
20
20
 
21
- ### Крок 1: Зчитай вижилих мутантів
21
+ ### Крок 1: Зчитай вцілілих мутантів
22
22
 
23
- Прочитай `COVERAGE.md`. Знайди секцію `## Вижилі мутанти`. Знайди фенсований блок ` ```json ` у цій секції і розпарси JSON-масив.
23
+ Прочитай `COVERAGE.md`. Знайди секцію `## Вцілілі мутанти`. Знайди огороджений блок ` ```json ` у цій секції і розбери JSON-масив.
24
24
 
25
25
  Якщо секція відсутня або масив порожній — зупинись з повідомленням:
26
- `✓ Жодних вижилих мутантів — mutation score повний`
26
+ `✓ Жодних вцілілих мутантів — mutation score повний`
27
27
 
28
- Запамʼятай поточну кількість вижилих: `prevCount = масив.length`
28
+ Запамʼятай поточну кількість вцілілих: `prevCount = масив.length`
29
29
 
30
30
  ### Крок 2: Знайди test-команду і coverage-команду
31
31
 
@@ -41,7 +41,7 @@ description: >-
41
41
  1. `scripts["coverage"]` з `package.json` → виклик: `bun run coverage`
42
42
  2. fallback: `n-cursor coverage`
43
43
 
44
- ### Крок 3: Для кожного файлу — спауни Agent
44
+ ### Крок 3: Для кожного файлу — запускає Agent
45
45
 
46
46
  Згрупуй мутанти по полю `file`. Для кожної групи виконай:
47
47
 
@@ -61,8 +61,8 @@ description: >-
61
61
  **3b. Сформуй промпт для Agent:**
62
62
 
63
63
  ```
64
- Тобі дані вижилі мутанти зі Stryker для файлу `<file>`.
65
- Ці мутанти вижили тому що наявні тести НЕ вловили конкретні зміни коду.
64
+ Тобі дані вцілілі мутанти зі Stryker для файлу `<file>`.
65
+ Ці мутанти вціліли, тому що наявні тести НЕ вловили конкретні зміни коду.
66
66
 
67
67
  **Вихідний код** (`<file>`):
68
68
  \`\`\`
@@ -74,7 +74,7 @@ description: >-
74
74
  <зміст test-файлу або "файл ще не існує">
75
75
  \`\`\`
76
76
 
77
- **Вижилі мутанти** (кожен — зміна коду що НЕ вловлена):
77
+ **Вцілілі мутанти** (кожен — зміна коду що НЕ вловлена):
78
78
  <для кожного мутанта:>
79
79
  - Рядок <line>, колонка <col>: `<original>` → `<replacement>` (тип мутації: <mutantType>)
80
80
 
@@ -105,14 +105,14 @@ bun test # або test-команда з кроку 2
105
105
  bun run coverage # або coverage-команда з кроку 2
106
106
  ```
107
107
 
108
- Прочитай новий `COVERAGE.md`, знайди і розпарси JSON-масив вижилих.
108
+ Прочитай новий `COVERAGE.md`, знайди і розбери JSON-масив вцілілих.
109
109
  `newCount = новий масив.length`
110
110
 
111
111
  **Рішення:**
112
112
 
113
113
  - Якщо `newCount < prevCount` → повтор з Кроку 1 з оновленим масивом
114
114
  - Якщо `newCount >= prevCount` → зупинись:
115
- `✓ Конвергенція: mutation score більше не покращується. Вижило: <newCount> мутантів.`
115
+ `✓ Конвергенція: mutation score більше не покращується. Вціліло: <newCount> мутантів.`
116
116
 
117
117
  ## Зупинка після конвергенції
118
118