@nitra/cursor 3.22.0 → 3.23.1
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/.pi-template/extensions/n-cursor-adr/docs/index.md +181 -0
- package/AGENTS.template.md +4 -0
- package/CHANGELOG.md +37 -3
- package/bin/docs/n-cursor.md +636 -0
- package/bin/docs/rename-yaml-extensions.md +207 -0
- package/bin/n-cursor.js +30 -3
- package/package.json +1 -1
- package/rules/abie/docs/fix.md +18 -0
- package/rules/abie/js/docs/applies.md +26 -0
- package/rules/abie/js/docs/env_dns.md +32 -0
- package/rules/abie/js/docs/firebase_hosting.md +23 -0
- package/rules/abie/js/docs/hc_pairing.md +35 -0
- package/rules/abie/js/docs/ua_http_route.md +28 -0
- package/rules/abie/js/docs/ua_node_selector.md +28 -0
- package/rules/abie/lib/docs/enabled.md +29 -0
- package/rules/abie/lib/docs/env-dns.md +35 -0
- package/rules/abie/lib/docs/hc-yaml.md +33 -0
- package/rules/abie/lib/docs/http-route.md +44 -0
- package/rules/abie/lib/docs/k8s-tree.md +40 -0
- package/rules/abie/lib/docs/kustomization-patches.md +47 -0
- package/rules/abie/lib/docs/overlay-paths.md +38 -0
- package/rules/abie/lib/docs/yaml.md +29 -0
- package/rules/adr/docs/fix.md +148 -0
- package/rules/adr/js/docs/hooks.md +259 -0
- package/rules/bun/docs/fix.md +156 -0
- package/rules/bun/js/docs/layout.md +393 -0
- package/rules/capacitor/docs/fix.md +121 -0
- package/rules/capacitor/js/docs/platforms.md +295 -0
- package/rules/changelog/changelog.mdc +4 -2
- package/rules/changelog/docs/fix.md +174 -0
- package/rules/changelog/js/consistency.mjs +114 -13
- package/rules/changelog/js/docs/consistency.md +387 -0
- package/rules/changelog/lib/docs/package-manifest.md +210 -0
- package/rules/ci4/docs/fix.md +179 -0
- package/rules/ci4/js/docs/marksman_config.md +128 -0
- package/rules/docker/docker.mdc +8 -3
- package/rules/docker/docs/fix.md +171 -0
- package/rules/docker/js/docs/lint.md +258 -0
- package/rules/docker/lib/docs/docker-hadolint.md +184 -0
- package/rules/docker/lib/docs/docker-mirror.md +247 -0
- package/rules/docker/lib/docs/docker-native-addon.md +170 -0
- package/rules/docker/lib/docs/docker-nginx-user.md +219 -0
- package/rules/docker/lint/docs/lint.md +193 -0
- package/rules/efes/docs/fix.md +203 -0
- package/rules/feedback/docs/fix.md +140 -0
- package/rules/flow/docs/fix.md +152 -0
- package/rules/ga/docs/fix.md +158 -0
- package/rules/ga/js/docs/lint.md +100 -0
- package/rules/ga/js/docs/workflows.md +217 -0
- package/rules/ga/lint/docs/lint.md +209 -0
- package/rules/ga/policy/clean_merged_branch/clean_merged_branch.rego +11 -2
- package/rules/ga/policy/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +3 -4
- package/rules/graphql/docs/fix.md +126 -0
- package/rules/graphql/js/docs/tooling.md +264 -0
- package/rules/graphql/lib/docs/graphql-gql-scan.md +219 -0
- package/rules/hasura/docs/fix.md +120 -0
- package/rules/hasura/hasura.mdc +14 -0
- package/rules/hasura/js/docs/internal_urls.md +326 -0
- package/rules/image-avif/docs/fix.md +132 -0
- package/rules/image-avif/js/docs/avif_generation.md +241 -0
- package/rules/image-compress/docs/fix.md +150 -0
- package/rules/image-compress/js/docs/package_setup.md +191 -0
- package/rules/js-bun-db/docs/fix.md +148 -0
- package/rules/js-bun-db/js/docs/safety.md +231 -0
- package/rules/js-bun-db/js-bun-db.mdc +42 -13
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +347 -0
- package/rules/js-bun-redis/docs/fix.md +123 -0
- package/rules/js-bun-redis/js/docs/imports.md +176 -0
- package/rules/js-bun-redis/lib/docs/redis-imports.md +223 -0
- package/rules/js-lint/docs/fix.md +117 -0
- package/rules/js-lint/js/docs/lint.md +250 -0
- package/rules/js-lint/js/docs/tooling.md +348 -0
- package/rules/js-lint/js/docs/utils_imports.md +207 -0
- package/rules/js-lint-ci/docs/fix.md +154 -0
- package/rules/js-lint-ci/js/docs/lint.md +144 -0
- package/rules/js-mssql/docs/fix.md +128 -0
- package/rules/js-mssql/js/docs/deps.md +263 -0
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +367 -0
- package/rules/js-run/docs/fix.md +144 -0
- package/rules/js-run/js/docs/runtime.md +388 -0
- package/rules/js-run/lib/docs/bunyan-imports.md +117 -0
- package/rules/js-run/lib/docs/check-env-scan.md +433 -0
- package/rules/js-run/lib/docs/conn-file-rules.md +300 -0
- package/rules/js-run/lib/docs/conn-imports-scan.md +204 -0
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +326 -0
- package/rules/k8s/docs/fix.md +129 -0
- package/rules/k8s/js/docs/manifests.md +344 -0
- package/rules/k8s/js/manifests.mjs +6 -2
- package/rules/k8s/k8s.mdc +4 -2
- package/rules/k8s/lint/docs/lint.md +411 -0
- package/rules/k8s/policy/network_policy/template/deployment.snippet.yaml +2 -0
- package/rules/k8s/policy/network_policy/template/stateful-set.snippet.yaml +2 -0
- package/rules/nginx-default-tpl/docs/fix.md +124 -0
- package/rules/nginx-default-tpl/js/docs/template.md +378 -0
- package/rules/npm-module/docs/fix.md +98 -0
- package/rules/npm-module/js/docs/package_structure.md +274 -0
- package/rules/npm-module/js/docs/rule_meta.md +137 -0
- package/rules/npm-module/js/docs/skill_meta.md +190 -0
- package/rules/php/docs/fix.md +107 -0
- package/rules/php/js/docs/tooling.md +152 -0
- package/rules/php/lint/docs/lint.md +215 -0
- package/rules/python/docs/fix.md +163 -0
- package/rules/python/js/docs/applies.md +108 -0
- package/rules/python/js/docs/tooling.md +153 -0
- package/rules/python/lint/docs/lint.md +322 -0
- package/rules/rego/docs/fix.md +121 -0
- package/rules/rego/js/docs/applies.md +174 -0
- package/rules/rego/js/docs/lint.md +118 -0
- package/rules/rego/lint/docs/lint.md +204 -0
- package/rules/release/docs/change.md +185 -0
- package/rules/release/docs/fix.md +119 -0
- package/rules/release/docs/release.md +222 -0
- package/rules/release/lib/docs/aggregate.md +246 -0
- package/rules/release/lib/docs/change-file.md +200 -0
- package/rules/release/lib/docs/fallback.md +203 -0
- package/rules/rust/docs/fix.md +129 -0
- package/rules/rust/js/docs/applies.md +140 -0
- package/rules/rust/lib/docs/has-cargo-toml.md +130 -0
- package/rules/security/docs/fix.md +86 -0
- package/rules/security/js/docs/lint.md +171 -0
- package/rules/security/js/docs/sample_secret.md +190 -0
- package/rules/security/js/docs/trufflehog.md +137 -0
- package/rules/security/js/lint.mjs +9 -1
- package/rules/style-lint/docs/fix.md +155 -0
- package/rules/style-lint/js/docs/lint.md +184 -0
- package/rules/style-lint/js/docs/tooling.md +194 -0
- package/rules/tauri/docs/fix.md +158 -0
- package/rules/tauri/js/docs/cargo_mutants_config.md +168 -0
- package/rules/tauri/js/docs/tooling.md +228 -0
- package/rules/test/coverage/coverage.mjs +15 -3
- package/rules/test/docs/fix.md +132 -0
- package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +138 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +134 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +160 -0
- package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +195 -0
- package/rules/test/js/docs/cargo_mutants_config.md +173 -0
- package/rules/test/js/docs/location.md +136 -0
- package/rules/test/js/docs/no-process-chdir.md +160 -0
- package/rules/test/js/docs/no-relative-fs-path.md +271 -0
- package/rules/test/js/docs/stryker_config.md +152 -0
- package/rules/test/js/docs/vitest-config-pool-forks.md +174 -0
- package/rules/text/docs/fix.md +118 -0
- package/rules/text/js/docs/forbidden-prettier.md +143 -0
- package/rules/text/js/docs/formatting.md +256 -0
- package/rules/text/js/docs/lint.md +122 -0
- package/rules/text/lint/docs/lint.md +220 -0
- package/rules/text/lint/docs/run-dotenv-linter.md +157 -0
- package/rules/text/lint/docs/run-shellcheck.md +212 -0
- package/rules/text/lint/docs/run-v8r.md +197 -0
- package/rules/vue/docs/fix.md +127 -0
- package/rules/vue/js/docs/packages.md +335 -0
- package/rules/vue/lib/docs/vue-forbidden-imports.md +261 -0
- package/rules/worktree/docs/fix.md +161 -0
- package/schemas/rule-meta.json +5 -1
- package/scripts/auto-rules.mjs +7 -4
- package/scripts/coverage-classify/docs/apply.md +202 -0
- package/scripts/coverage-classify/docs/cache.md +203 -0
- package/scripts/coverage-classify/docs/index.md +218 -0
- package/scripts/coverage-classify/docs/prompt.md +132 -0
- package/scripts/coverage-classify/docs/verdict-schema.md +169 -0
- package/scripts/coverage-fix-extract.mjs +122 -0
- package/scripts/coverage-fix.mjs +1 -1
- package/scripts/dispatcher/docs/graph.md +346 -0
- package/scripts/dispatcher/docs/index.md +236 -0
- package/scripts/dispatcher/docs/trace.md +296 -0
- package/scripts/dispatcher/index.mjs +1 -1
- package/scripts/dispatcher/lib/active.mjs +4 -8
- package/scripts/dispatcher/lib/commands.mjs +7 -11
- package/scripts/dispatcher/lib/docs/active.md +348 -0
- package/scripts/dispatcher/lib/docs/artifact.md +232 -0
- package/scripts/dispatcher/lib/docs/budget.md +167 -0
- package/scripts/dispatcher/lib/docs/capability.md +196 -0
- package/scripts/dispatcher/lib/docs/commands.md +210 -0
- package/scripts/dispatcher/lib/docs/events.md +182 -0
- package/scripts/dispatcher/lib/docs/executor.md +190 -0
- package/scripts/dispatcher/lib/docs/flow-lock.md +161 -0
- package/scripts/dispatcher/lib/docs/flow-resolve.md +267 -0
- package/scripts/dispatcher/lib/docs/gate.md +231 -0
- package/scripts/dispatcher/lib/docs/level.md +335 -0
- package/scripts/dispatcher/lib/docs/plan-panel.md +181 -0
- package/scripts/dispatcher/lib/docs/plan.md +200 -0
- package/scripts/dispatcher/lib/docs/planner.md +269 -0
- package/scripts/dispatcher/lib/docs/review.md +255 -0
- package/scripts/dispatcher/lib/docs/reviewer.md +240 -0
- package/scripts/dispatcher/lib/docs/snapshot.md +247 -0
- package/scripts/dispatcher/lib/docs/spec.md +203 -0
- package/scripts/dispatcher/lib/docs/state-store.md +303 -0
- package/scripts/dispatcher/lib/docs/subagent-runner.md +173 -0
- package/scripts/dispatcher/lib/executor.mjs +6 -1
- package/scripts/dispatcher/lib/flow-resolve.mjs +3 -1
- package/scripts/dispatcher/lib/level.mjs +29 -3
- package/scripts/dispatcher/lib/review.mjs +1 -1
- package/scripts/dispatcher/lib/subagent-runner.mjs +5 -3
- package/scripts/docs/auto-rules.md +376 -0
- package/scripts/docs/auto-skills.md +173 -0
- package/scripts/docs/build-agents-commands.md +183 -0
- package/scripts/docs/cli-entry.md +153 -0
- package/scripts/docs/coverage-fix.md +177 -0
- package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +189 -0
- package/scripts/lib/changed-files.mjs +4 -1
- package/scripts/lib/docs/changed-files.md +149 -0
- package/scripts/lib/docs/check-mdc-template-refs.md +222 -0
- package/scripts/lib/docs/check-reporter.md +175 -0
- package/scripts/lib/docs/discover-check-rules-from-cursor.md +157 -0
- package/scripts/lib/docs/discover-checkable-rules.md +165 -0
- package/scripts/lib/docs/ensure-tool.md +254 -0
- package/scripts/lib/docs/generated-markdown.md +275 -0
- package/scripts/lib/docs/gha-workflow.md +326 -0
- package/scripts/lib/docs/inline-template-links.md +303 -0
- package/scripts/lib/docs/list-rule-ids.md +156 -0
- package/scripts/lib/docs/load-cursor-config.md +147 -0
- package/scripts/lib/docs/mirror-parity.md +167 -0
- package/scripts/lib/worktree.mjs +26 -0
- package/scripts/worktree-cli.mjs +12 -2
- package/skills/coverage-fix/SKILL.md +34 -45
- package/skills/docgen/SKILL.md +44 -23
- package/skills/docgen/bench/etalon/firebase_hosting.md +19 -0
- package/skills/docgen/bench/etalon/k8s-tree.md +24 -0
- package/skills/docgen/bench/etalon/overlay-paths.md +24 -0
- package/skills/docgen/js/docgen-ignore.mjs +54 -0
- package/skills/docgen/js/docgen-scan.mjs +37 -21
- package/skills/llm-patch/SKILL.md +23 -2
- package/skills/start-check/SKILL.md +26 -53
- package/skills/start-check/js/check.mjs +211 -0
- package/skills/taze/SKILL.md +9 -3
- package/skills/taze/js/diff.mjs +154 -0
- package/types/bin/n-cursor.d.ts +1 -1
- package/skills/fix-tests/SKILL.md +0 -119
- package/skills/fix-tests/meta.json +0 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# prompt.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `prompt.mjs` — це prompt-builder для скрипта `coverage-classify`, що класифікує вцілілих мутантів зі звіту Stryker через LLM. Файл експонує дві сутності:
|
|
6
|
+
|
|
7
|
+
- статичний рядок `SYSTEM_PROMPT`, який описує LLM правила класифікації та формат JSON-відповіді;
|
|
8
|
+
- функцію `buildUserPrompt(mutant, cwd)`, яка для кожного конкретного мутанта збирає контекстний user-prompt: фрагмент вихідного коду навколо мутації, вміст відповідного тестового файла та дату останньої git-активності.
|
|
9
|
+
|
|
10
|
+
Розділення на статичний `SYSTEM_PROMPT` і динамічний `buildUserPrompt` обґрунтоване стратегією кешування промптів через Anthropic API (`cache_control: ephemeral`) — незмінна частина (системний промпт) кешується між викликами, а змінна (контекст мутанта) формується щоразу заново.
|
|
11
|
+
|
|
12
|
+
Модуль не виконує жодних мережевих викликів — він лише будує текст. Виклик LLM відбувається у викликальному коді (інший модуль `coverage-classify`).
|
|
13
|
+
|
|
14
|
+
## Експорти / API
|
|
15
|
+
|
|
16
|
+
| Експорт | Тип | Призначення |
|
|
17
|
+
| ------------------------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| `SYSTEM_PROMPT` | `string` (named export) | Статичний англомовний системний промпт для LLM-класифікатора мутантів. Містить опис п'яти можливих verdict-категорій (`worth-testing`, `equivalent`, `defensive`, `glue`, `wrapper`), JSON-схему відповіді та інструкції щодо рівня впевненості (`confidence`). |
|
|
19
|
+
| `buildUserPrompt(mutant, cwd)` | `function` (named export) | Будує user-prompt для одного мутанта. |
|
|
20
|
+
|
|
21
|
+
Внутрішня (не експортована) функція:
|
|
22
|
+
|
|
23
|
+
- `extractTestTitles(content)` — допоміжна, витягує заголовки `describe/test/it` з тексту test-файла.
|
|
24
|
+
|
|
25
|
+
Внутрішні константи (не експортуються):
|
|
26
|
+
|
|
27
|
+
- `CONTEXT_LINES = 10` — кількість рядків контексту вище й нижче рядка мутанта при формуванні фрагмента вихідного коду.
|
|
28
|
+
- `TEST_FILE_MAX_LINES = 2000` — поріг розміру test-файла у рядках; якщо більше — у промпт іде лише список title-ів, а не повний текст.
|
|
29
|
+
|
|
30
|
+
## Функції
|
|
31
|
+
|
|
32
|
+
### `extractTestTitles(content)`
|
|
33
|
+
|
|
34
|
+
Внутрішня helper-функція для редукування довгих тестових файлів до списку заголовків.
|
|
35
|
+
|
|
36
|
+
- **Сигнатура**: `extractTestTitles(content: string) => string`
|
|
37
|
+
- **Параметри**:
|
|
38
|
+
- `content` — повний текст test-файла як рядок.
|
|
39
|
+
- **Повертає**: рядок, де кожен запис має формат `describe: <title>` або `test: <title>` / `it: <title>`, з'єднаний через `\n`. Якщо у файлі не знайдено жодного блоку `describe`/`test`/`it` — повертає літерал `(no describe/test blocks found)`.
|
|
40
|
+
- **Алгоритм**: проганяє по `content` глобальний `unicode/multiline` regex `^\s*(describe|test|it)\(['"\`](.+?)['"\`]`, що ловить початки тестових блоків з аргументом у одинарних, подвійних або зворотних лапках. Для кожного match-у формує рядок `<kind>: <title>` і додає до масиву, який в кінці зливається в один рядок.
|
|
41
|
+
- **Side effects**: відсутні (чиста функція).
|
|
42
|
+
- **Обмеження**: regex не аналізує AST, тому коментарі типу `// describe('foo'`) також можуть бути захоплені; для шаблонів промпту це прийнятна апроксимація.
|
|
43
|
+
|
|
44
|
+
### `buildUserPrompt(mutant, cwd)`
|
|
45
|
+
|
|
46
|
+
Основна публічна функція модуля. Збирає markdown-розмічений user-prompt з чотирма секціями: метаінформація про мутант, фрагмент вихідного коду, існуючі тести, дата останньої git-активності файла.
|
|
47
|
+
|
|
48
|
+
- **Сигнатура**: `buildUserPrompt(mutant, cwd: string) => string`, де `mutant` має форму:
|
|
49
|
+
```
|
|
50
|
+
{
|
|
51
|
+
file: string, // шлях до файла відносно cwd
|
|
52
|
+
line: number, // рядок мутації (1-based)
|
|
53
|
+
col: number, // колонка мутації
|
|
54
|
+
mutantType: string, // тип мутанта зі Stryker (наприклад "ConditionalExpression")
|
|
55
|
+
original: string, // оригінальний фрагмент коду
|
|
56
|
+
replacement: string // мутований фрагмент
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
- **Параметри**:
|
|
60
|
+
- `mutant` — об'єкт-опис мутанта, як зазначено вище.
|
|
61
|
+
- `cwd` — абсолютний шлях до кореня проєкту; використовується для побудови абсолютного шляху до файла й як `cwd` для виклику `git`.
|
|
62
|
+
- **Повертає**: markdown-рядок із секціями `# Mutant`, `# Source context (±10 lines)`, `# Existing tests`, `# Recent activity`. Готовий бути переданим у поле `messages[].content` LLM-запиту.
|
|
63
|
+
- **Side effects**:
|
|
64
|
+
- синхронні read-only file system операції: `existsSync`, `readFileSync` для джерельного файла й тестового файла;
|
|
65
|
+
- синхронний виклик процесу `git log -1 --format=%ar -- <absPath>` через `execFileSync` (read-only щодо git-репозиторію).
|
|
66
|
+
- **Обробка помилок / graceful fallback**:
|
|
67
|
+
- якщо джерельний файл не існує — `srcContext = '(source file unavailable)'`;
|
|
68
|
+
- якщо тестовий файл не існує — `existingTests = '(no test file)'`;
|
|
69
|
+
- якщо `git` недоступний, файл untracked або команда падає — `recentActivity = '(no git history)'`. `catch`-блок мовчазний, помилка проковтується (за коментарем `git unavailable or file untracked — keep placeholder`).
|
|
70
|
+
|
|
71
|
+
#### Алгоритм формування секцій
|
|
72
|
+
|
|
73
|
+
1. **Абсолютний шлях**: `absPath = join(cwd, mutant.file)`.
|
|
74
|
+
2. **Source context**:
|
|
75
|
+
- читає файл, розбиває на рядки;
|
|
76
|
+
- обчислює діапазон `[start, end)`, де `start = max(0, mutant.line - 1 - 10)`, `end = min(lines.length, mutant.line + 10)`;
|
|
77
|
+
- вирізає slice, додає до кожного рядка префікс `<absoluteLineNumber>: ` (1-based) і об'єднує через `\n`.
|
|
78
|
+
3. **Existing tests** — шукає файл за конвенцією `dirname(absPath)/tests/<basename без .mjs>.test.mjs`:
|
|
79
|
+
- якщо файл існує і має <= 2000 рядків — вставляє повний вміст;
|
|
80
|
+
- якщо більше — викликає `extractTestTitles(content)` і вставляє лише заголовки тест-блоків.
|
|
81
|
+
4. **Recent activity**: викликає `git log -1 --format=%ar -- <absPath>` з опціями `cwd`, `encoding: 'utf8'`, `stdio: ['ignore', 'pipe', 'ignore']` (stderr глушиться). Trim-ить результат; якщо він непорожній — підставляє у плейсхолдер.
|
|
82
|
+
5. Повертає шаблонний рядок із усіма зібраними секціями.
|
|
83
|
+
|
|
84
|
+
## Залежності
|
|
85
|
+
|
|
86
|
+
### Зовнішні (Node.js builtins)
|
|
87
|
+
|
|
88
|
+
- `node:child_process` — `execFileSync` для виклику `git log`. Прямий виклик бінарника `git` без shell-інтерпретації (аргументи — масив).
|
|
89
|
+
- `node:fs` — `existsSync`, `readFileSync` для синхронного читання джерельних і тестових файлів.
|
|
90
|
+
- `node:path` — `basename`, `dirname`, `join` для роботи зі шляхами.
|
|
91
|
+
|
|
92
|
+
### Внутрішньопроєктні
|
|
93
|
+
|
|
94
|
+
Модуль не імпортує жодних інших модулів проєкту і не має внутрішньопроєктних залежностей.
|
|
95
|
+
|
|
96
|
+
### Очікувані виклики ззовні
|
|
97
|
+
|
|
98
|
+
Файл є частиною комплекту `npm/scripts/coverage-classify/`. Сусідні модулі тієї ж теки (`index.mjs`, `apply.mjs`, `cache.mjs`, `verdict-schema.mjs`) ймовірно імпортують `SYSTEM_PROMPT` і `buildUserPrompt` для побудови запитів до LLM і подальшої обробки verdict-ів. Цей файл сам по собі нічого не виконує — він суто «бібліотечний».
|
|
99
|
+
|
|
100
|
+
## Потік виконання / Використання
|
|
101
|
+
|
|
102
|
+
Типовий сценарій споживання:
|
|
103
|
+
|
|
104
|
+
1. Споживач (наприклад `index.mjs` у тій самій теці) імпортує:
|
|
105
|
+
```
|
|
106
|
+
import { SYSTEM_PROMPT, buildUserPrompt } from './prompt.mjs'
|
|
107
|
+
```
|
|
108
|
+
2. Для кожного survived-мутанта зі Stryker-звіту:
|
|
109
|
+
- формує об'єкт `mutant` із полів звіту;
|
|
110
|
+
- викликає `const userPrompt = buildUserPrompt(mutant, process.cwd())`;
|
|
111
|
+
- відправляє у LLM-API два повідомлення:
|
|
112
|
+
- system: `SYSTEM_PROMPT` (з `cache_control: { type: 'ephemeral' }`),
|
|
113
|
+
- user: `userPrompt`.
|
|
114
|
+
3. LLM повертає JSON-об'єкт за схемою, описаною у `SYSTEM_PROMPT`:
|
|
115
|
+
```
|
|
116
|
+
{
|
|
117
|
+
"verdict": "worth-testing" | "equivalent" | "defensive" | "glue" | "wrapper",
|
|
118
|
+
"confidence": number,
|
|
119
|
+
"reason": string,
|
|
120
|
+
"suggestedTest": string // тільки якщо verdict === "worth-testing"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
4. Викликальний код парсить відповідь (валідація схеми ймовірно в `verdict-schema.mjs`) і застосовує її (`apply.mjs`).
|
|
124
|
+
|
|
125
|
+
### Інваріанти й обмеження
|
|
126
|
+
|
|
127
|
+
- `mutant.file` має бути шляхом відносно `cwd` — інакше абсолютний шлях буде некоректний і обидва файли (джерело й тест) випадуть у fallback-плейсхолдери.
|
|
128
|
+
- Конвенція розташування тестів є жорсткою: `tests/<basename без .mjs>.test.mjs` поряд з джерельним файлом. Інші конвенції (наприклад `__tests__/` або `.spec.mjs`) не підтримуються — для них `existingTests` буде `(no test file)`.
|
|
129
|
+
- Розширення `.mjs` зашите у `basename(absPath, '.mjs')`. Для файлів інших розширень (`.js`, `.ts`, `.vue`) `basename` залишить розширення в результаті, тому шлях до тестів стане некоректним.
|
|
130
|
+
- `CONTEXT_LINES = 10` і `TEST_FILE_MAX_LINES = 2000` — внутрішні константи, не конфігуруються параметрами.
|
|
131
|
+
- `git log` запускається синхронно — для великої кількості мутантів це може бути bottleneck.
|
|
132
|
+
- Усі операції синхронні; модуль безпечний для послідовного використання, але не оптимізований під concurrent-доступ (хоча сам по собі stateless).
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# verdict-schema.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `verdict-schema.mjs` визначає контракт даних для відповіді LLM-класифікатора в межах інструменту `coverage-classify`. Класифікатор приймає рішення про те, як трактувати вцілілого мутанта (surviving mutant) після прогону мутаційного тестування: чи варто на нього писати тест, чи він поведінково еквівалентний, чи це захисна гілка для неможливого стану, чи це склейка/обгортка, що покривається інтеграційними тестами.
|
|
6
|
+
|
|
7
|
+
Файл розв'язує дві задачі:
|
|
8
|
+
|
|
9
|
+
1. Декларує **Zod-схему** `VerdictSchema`, якій має відповідати JSON-об'єкт-вердикт від LLM.
|
|
10
|
+
2. Надає утиліту `parseVerdict`, яка приймає сирий текст відповіді LLM, витягує з нього перший знайдений JSON-блок, парсить його і валідовує за схемою.
|
|
11
|
+
|
|
12
|
+
Призначення схеми — стабілізувати взаємодію з LLM: навіть якщо LLM повертає вердикт у вигляді тексту з преамбулою чи поясненнями, модуль робить «liberal-in, strict-out» — толерантно витягує JSON-острівець, а далі застосовує жорстку валідацію (категорія, межі впевненості, мінімальна осмисленість пояснення).
|
|
13
|
+
|
|
14
|
+
Категорії вердикту (`verdict`):
|
|
15
|
+
|
|
16
|
+
- `worth-testing` — pure logic / реальні гілки, варто писати юніт-тест.
|
|
17
|
+
- `equivalent` — мутант поведінково еквівалентний оригіналу, він не killable.
|
|
18
|
+
- `defensive` — гілка для impossible state (захисний код), не killable.
|
|
19
|
+
- `glue` — CLI entry / обгортка `runStandardRule` тощо; покривається інтеграційними тестами.
|
|
20
|
+
- `wrapper` — тонкий `spawn`/`fetch`-обгортка; покривається інтеграційними тестами.
|
|
21
|
+
|
|
22
|
+
## Експорти / API
|
|
23
|
+
|
|
24
|
+
Модуль експортує два символи (обидва — іменовані експорти ES modules):
|
|
25
|
+
|
|
26
|
+
| Символ | Тип | Призначення |
|
|
27
|
+
| --------------- | --------------------------- | ---------------------------------------------------- |
|
|
28
|
+
| `VerdictSchema` | `ZodObject` | Схема валідації для verdict-об'єкта LLM. |
|
|
29
|
+
| `parseVerdict` | `function(rawText: string)` | Парсер raw-text відповіді LLM у валідований verdict. |
|
|
30
|
+
|
|
31
|
+
### `VerdictSchema`
|
|
32
|
+
|
|
33
|
+
Z-об'єкт зі строго визначеними полями:
|
|
34
|
+
|
|
35
|
+
- `verdict` — `z.enum(['worth-testing', 'equivalent', 'defensive', 'glue', 'wrapper'])`. Обов'язкове. Будь-яке інше значення відхиляється.
|
|
36
|
+
- `confidence` — `z.number().min(0).max(1)`. Обов'язкове. Дробове число в діапазоні `[0, 1]`, де `0` — повна невпевненість, `1` — повна впевненість LLM у вердикті.
|
|
37
|
+
- `reason` — `z.string().min(20).max(500)`. Обов'язкове. Текстове пояснення довжиною від 20 до 500 символів — мінімум змушує LLM аргументувати, максимум — обмежує балакучість.
|
|
38
|
+
- `suggestedTest` — `z.string().max(300).optional()`. Опціональне. Текстова підказка/начерк тесту довжиною до 300 символів; за домовленістю заповнюється переважно для категорії `worth-testing`.
|
|
39
|
+
|
|
40
|
+
Поля поза цим переліком не описано як заборонені на рівні схеми; за замовчуванням Zod пропускає невідомі ключі без помилки, але вони не з'являться в результаті типізації, що використовує цей модуль. Якщо в майбутньому потрібен strict-режим, його можна додати через `.strict()`.
|
|
41
|
+
|
|
42
|
+
### `parseVerdict(rawText)`
|
|
43
|
+
|
|
44
|
+
Високорівнева функція-фасад: «витягни JSON з тексту LLM і провалідуй».
|
|
45
|
+
|
|
46
|
+
## Функції
|
|
47
|
+
|
|
48
|
+
### `parseVerdict(rawText)`
|
|
49
|
+
|
|
50
|
+
Сигнатура:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
function parseVerdict(rawText: string): {
|
|
54
|
+
verdict: 'worth-testing' | 'equivalent' | 'defensive' | 'glue' | 'wrapper',
|
|
55
|
+
confidence: number,
|
|
56
|
+
reason: string,
|
|
57
|
+
suggestedTest?: string
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Параметри:
|
|
62
|
+
|
|
63
|
+
- `rawText` — `string`. Сирий текст, повернений LLM. Може містити довільний preamble/postamble навколо JSON-блоку (пояснення, markdown-загортки тощо). Очікується, що в тексті є рівно один корисний JSON-об'єкт-вердикт.
|
|
64
|
+
|
|
65
|
+
Повертає:
|
|
66
|
+
|
|
67
|
+
- Обʼєкт verdict, який пройшов валідацію `VerdictSchema`. Тип повернення відповідає схемі (див. вище).
|
|
68
|
+
|
|
69
|
+
Side effects:
|
|
70
|
+
|
|
71
|
+
- Жодних. Функція чиста: не пише в файлову систему, не звертається до мережі, не модифікує параметри.
|
|
72
|
+
|
|
73
|
+
Алгоритм:
|
|
74
|
+
|
|
75
|
+
1. Знайти позицію першого символу `{` через `rawText.indexOf('{')` → `jsonStart`.
|
|
76
|
+
2. Знайти позицію останнього `}` через `rawText.lastIndexOf('}')` → `jsonEnd`.
|
|
77
|
+
3. Якщо хоча б один з індексів дорівнює `-1` — кинути `Error('No JSON object found in LLM response')`.
|
|
78
|
+
4. Інакше — вирізати підрядок `rawText.slice(jsonStart, jsonEnd + 1)` (включно з обома фігурними дужками) та віддати у `JSON.parse`.
|
|
79
|
+
5. Результат парсингу передати у `VerdictSchema.parse(...)` і повернути.
|
|
80
|
+
|
|
81
|
+
Виключення / помилки:
|
|
82
|
+
|
|
83
|
+
- `Error('No JSON object found in LLM response')` — якщо в тексті немає жодної з фігурних дужок (`{` або `}`).
|
|
84
|
+
- `SyntaxError` (від `JSON.parse`) — якщо вирізаний фрагмент не є валідним JSON. Наприклад, через зайвий текст усередині `{...}`, який LLM могла додати між дужками.
|
|
85
|
+
- `ZodError` (від `VerdictSchema.parse`) — якщо JSON валідний, але не відповідає схемі: невідома категорія `verdict`, `confidence` поза `[0, 1]`, `reason` коротший за 20 символів або довший за 500, `suggestedTest` довший за 300 символів, відсутнє обов'язкове поле тощо.
|
|
86
|
+
|
|
87
|
+
Поведінкові нюанси, важливі для викликача:
|
|
88
|
+
|
|
89
|
+
- Стратегія «перший `{` … останній `}`» свідомо толерантна: дозволяє LLM писати щось ось так: `Here's the verdict: { ... } Hope it helps.` Однак якщо LLM повертає **кілька** JSON-обʼєктів, функція ризикує склеїти їх у невалідний фрагмент — це очікувано і впирається у валідацію JSON.
|
|
90
|
+
- Функція не намагається «латати» некоректний JSON (немає trailing-comma-cleanup, немає markdown-fence-strip). Помилки прокидаються догори викликача — там і місце для retry / fallback-логіки.
|
|
91
|
+
- У разі `ZodError` повідомлення зазвичай містить читабельний шлях до невалідного поля, що зручно для логування при debug LLM-промпта.
|
|
92
|
+
|
|
93
|
+
## Залежності
|
|
94
|
+
|
|
95
|
+
Зовнішні:
|
|
96
|
+
|
|
97
|
+
- [`zod`](https://www.npmjs.com/package/zod) — рантайм-валідатор схем. Імпортується як `import { z } from 'zod'`. Версія керується кореневим `package.json` робочого простору `npm/`.
|
|
98
|
+
|
|
99
|
+
Внутрішні:
|
|
100
|
+
|
|
101
|
+
- Немає. Модуль не імпортує нічого з власного проєкту і не залежить від інших файлів `coverage-classify`.
|
|
102
|
+
|
|
103
|
+
Стандартна бібліотека / середовище:
|
|
104
|
+
|
|
105
|
+
- `JSON.parse` — глобальний API JavaScript runtime.
|
|
106
|
+
- `String.prototype.indexOf` / `lastIndexOf` / `slice` — стандартні методи рядків.
|
|
107
|
+
|
|
108
|
+
Цільове середовище: Node-сумісний рантайм (Node.js / Bun) із підтримкою ES Modules — файл написано як `.mjs`.
|
|
109
|
+
|
|
110
|
+
## Потік виконання / Використання
|
|
111
|
+
|
|
112
|
+
### Як модуль вписується в `coverage-classify`
|
|
113
|
+
|
|
114
|
+
Інструмент `coverage-classify` працює за такою послідовністю (типова):
|
|
115
|
+
|
|
116
|
+
1. Зчитати список вцілілих мутантів із результатів мутаційного тестування.
|
|
117
|
+
2. Для кожного мутанта зібрати контекст (фрагмент коду, місце змін) та згенерувати промпт для LLM.
|
|
118
|
+
3. Виконати запит до LLM і отримати raw-text відповідь.
|
|
119
|
+
4. **Викликати `parseVerdict(rawText)`** із цього модуля, щоб отримати типізований verdict.
|
|
120
|
+
5. Зберегти verdict у кеш / звіт (`apply.mjs`, `cache.mjs`) і застосувати дії: для `worth-testing` згенерувати TODO/тести, для решти — позначити мутант відповідною категорією.
|
|
121
|
+
|
|
122
|
+
Таким чином, `verdict-schema.mjs` — це межа між «світом LLM» (нечіткий текст) і «світом інструменту» (структуровані дані).
|
|
123
|
+
|
|
124
|
+
### Приклад використання
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
import { parseVerdict, VerdictSchema } from './verdict-schema.mjs'
|
|
128
|
+
|
|
129
|
+
// 1) Парсимо raw-відповідь LLM
|
|
130
|
+
const rawLLM = `
|
|
131
|
+
The mutant is in a defensive branch. Here is the verdict:
|
|
132
|
+
{
|
|
133
|
+
"verdict": "defensive",
|
|
134
|
+
"confidence": 0.92,
|
|
135
|
+
"reason": "The condition guards an impossible state when the input list is empty.",
|
|
136
|
+
"suggestedTest": ""
|
|
137
|
+
}
|
|
138
|
+
Thanks!
|
|
139
|
+
`
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const verdict = parseVerdict(rawLLM)
|
|
143
|
+
// verdict.verdict === 'defensive'
|
|
144
|
+
// verdict.confidence === 0.92
|
|
145
|
+
console.log(verdict)
|
|
146
|
+
} catch (err) {
|
|
147
|
+
// 'No JSON object found in LLM response' | SyntaxError | ZodError
|
|
148
|
+
console.error('LLM verdict invalid:', err.message)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 2) Якщо в нас уже є об'єкт (наприклад, з кешу) — валідуємо безпосередньо через схему
|
|
152
|
+
const cached = { verdict: 'glue', confidence: 1, reason: 'CLI entry point only, integration covers.' }
|
|
153
|
+
const ok = VerdictSchema.parse(cached) // кине ZodError, якщо не відповідає
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Граничні випадки
|
|
157
|
+
|
|
158
|
+
- Порожній рядок → `indexOf('{') === -1` → кидаємо `'No JSON object found in LLM response'`.
|
|
159
|
+
- Рядок без `}` (LLM обірвалась) → `lastIndexOf('}') === -1` → та сама помилка.
|
|
160
|
+
- LLM повернула markdown-fence (` ```json ... ``` `) навколо JSON → `parseVerdict` витягне саме JSON-острів між першим `{` і останнім `}`, fence ігнорується.
|
|
161
|
+
- LLM повернула `confidence: 1.5` → `ZodError` (порушено `max(1)`).
|
|
162
|
+
- LLM повернула `verdict: 'unknown'` → `ZodError` (не входить у `z.enum([...])`).
|
|
163
|
+
- LLM повернула `reason` коротшим за 20 символів → `ZodError` (`min(20)`). Це навмисний захист від відповідей-однословів типу `"ok"`.
|
|
164
|
+
|
|
165
|
+
### Рекомендації для викликача
|
|
166
|
+
|
|
167
|
+
- Обгортайте виклик `parseVerdict` у `try/catch` і за помилки робіть retry з посиленим промптом (наприклад, з нагадуванням про схему) або падайте у fallback-категорію.
|
|
168
|
+
- Не зберігайте у кеш `rawText` як вердикт — зберігайте лише провалідований об'єкт (результат `parseVerdict`); це підтримує інваріант «у кеші тільки валідні дані».
|
|
169
|
+
- Якщо в майбутньому з'являться нові категорії — оновлюйте `z.enum` тут, інакше LLM-вердикти з новими значеннями будуть відхилятися.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `n-cursor coverage-fix index|slice` — read-only витяг вцілілих мутантів із
|
|
3
|
+
* `COVERAGE.md` для скілу `n-coverage-fix`.
|
|
4
|
+
*
|
|
5
|
+
* Мотивація: `COVERAGE.md` може важити мегабайти (секція `## Вцілілі мутанти`
|
|
6
|
+
* з JSON-блоком на сотні файлів). Якщо цей файл читає LLM-оркестратор, він
|
|
7
|
+
* спалює сотні тисяч токенів лише на парсинг. Натомість важкий парсинг несе цей
|
|
8
|
+
* скрипт (для JS — мілісекунди, 0 токенів), а агенту віддається рівно потрібна
|
|
9
|
+
* порція:
|
|
10
|
+
* - `index` — крихітний `[{file, mutants}]` для рішення про фан-аут;
|
|
11
|
+
* - `slice --file <path>` — промпт лише для одного файлу (контекст ±3 рядки),
|
|
12
|
+
* рівно під когнітивне навантаження одного субагента.
|
|
13
|
+
*
|
|
14
|
+
* Команда read-only: лише парсить наявний `COVERAGE.md`, нічого не мутує і не
|
|
15
|
+
* перезапускає Stryker (тож не входить у root-guard).
|
|
16
|
+
*/
|
|
17
|
+
import { readFile } from 'node:fs/promises'
|
|
18
|
+
import { join } from 'node:path'
|
|
19
|
+
|
|
20
|
+
import { buildFixPrompt } from './coverage-fix.mjs'
|
|
21
|
+
|
|
22
|
+
/** Заголовок секції вцілілих мутантів у COVERAGE.md (контракт із renderMarkdown). */
|
|
23
|
+
const SURVIVED_SECTION = '## Вцілілі мутанти'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Огорожа json-блоку: ≥3 бектики, далі `json` і решта рядка до `\n`. Довжина
|
|
27
|
+
* захоплюється в групу 1 — renderMarkdown пише 3, але oxfmt підвищує до 4+, коли
|
|
28
|
+
* сам JSON-вміст містить ``` (типово для original/replacement мутантів).
|
|
29
|
+
*/
|
|
30
|
+
const FENCE_OPEN_RE = /(`{3,})json[^\n]*\n/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Витягує JSON-масив вцілілих мутантів із тексту COVERAGE.md: знаходить секцію
|
|
34
|
+
* `## Вцілілі мутанти`, перший огороджений ` ```json ` блок під нею і парсить.
|
|
35
|
+
* @param {string} md повний текст COVERAGE.md
|
|
36
|
+
* @returns {import('./coverage-fix.mjs').SurvivedFileGroup[]} групи вцілілих по файлах (порожньо, якщо секції/блоку немає або JSON невалідний)
|
|
37
|
+
*/
|
|
38
|
+
export function parseSurvivedBlock(md) {
|
|
39
|
+
const sectionAt = md.indexOf(SURVIVED_SECTION)
|
|
40
|
+
if (sectionAt === -1) return []
|
|
41
|
+
const after = md.slice(sectionAt)
|
|
42
|
+
const open = after.match(FENCE_OPEN_RE)
|
|
43
|
+
if (!open) return []
|
|
44
|
+
const fence = open[1]
|
|
45
|
+
const bodyStart = open.index + open[0].length
|
|
46
|
+
const rest = after.slice(bodyStart)
|
|
47
|
+
// Закриття — рядок із тих самих бектиків. Усередині JSON реальних переводів
|
|
48
|
+
// рядка немає (JSON.stringify екранує їх як `\n`), тож `\n<fence>` унікально
|
|
49
|
+
// позначає кінець блоку навіть якщо значення містять бектики.
|
|
50
|
+
const closeAt = rest.indexOf(`\n${fence}`)
|
|
51
|
+
const json = closeAt === -1 ? rest : rest.slice(0, closeAt)
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(json)
|
|
54
|
+
return Array.isArray(parsed) ? parsed : []
|
|
55
|
+
} catch {
|
|
56
|
+
return []
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Читає `COVERAGE.md` із кореня проєкту і повертає структуровані групи вцілілих.
|
|
62
|
+
* @param {string} cwd корінь проєкту
|
|
63
|
+
* @returns {Promise<import('./coverage-fix.mjs').SurvivedFileGroup[]>} групи вцілілих по файлах
|
|
64
|
+
*/
|
|
65
|
+
export async function readSurvived(cwd) {
|
|
66
|
+
let md
|
|
67
|
+
try {
|
|
68
|
+
md = await readFile(join(cwd, 'COVERAGE.md'), 'utf8')
|
|
69
|
+
} catch {
|
|
70
|
+
return []
|
|
71
|
+
}
|
|
72
|
+
return parseSurvivedBlock(md)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Згортає групи вцілілих у компактний index `[{file, mutants}]`.
|
|
77
|
+
* @param {import('./coverage-fix.mjs').SurvivedFileGroup[]} survived групи вцілілих
|
|
78
|
+
* @returns {Array<{file:string, mutants:number}>} файл → кількість вцілілих мутантів
|
|
79
|
+
*/
|
|
80
|
+
export function buildIndex(survived) {
|
|
81
|
+
return survived
|
|
82
|
+
.filter(group => group && typeof group.file === 'string' && Array.isArray(group.mutants))
|
|
83
|
+
.map(group => ({ file: group.file, mutants: group.mutants.length }))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const USAGE = 'Usage: n-cursor coverage-fix <index | slice --file <path>>'
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* CLI: `index` друкує компактний JSON-масив, `slice --file <path>` — промпт для
|
|
90
|
+
* одного файлу. Обидва read-only (читають лише COVERAGE.md).
|
|
91
|
+
* @param {string[]} args аргументи після `coverage-fix`
|
|
92
|
+
* @param {string} [cwd] корінь проєкту (ін'єкція для тестів)
|
|
93
|
+
* @returns {Promise<number>} exit code
|
|
94
|
+
*/
|
|
95
|
+
export async function runCoverageFixCli(args, cwd = process.cwd()) {
|
|
96
|
+
const sub = args[0]
|
|
97
|
+
const survived = await readSurvived(cwd)
|
|
98
|
+
|
|
99
|
+
if (sub === 'index') {
|
|
100
|
+
process.stdout.write(`${JSON.stringify(buildIndex(survived))}\n`)
|
|
101
|
+
return 0
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (sub === 'slice') {
|
|
105
|
+
const flagAt = args.indexOf('--file')
|
|
106
|
+
const file = flagAt === -1 ? undefined : args[flagAt + 1]
|
|
107
|
+
if (!file) {
|
|
108
|
+
console.error(USAGE)
|
|
109
|
+
return 1
|
|
110
|
+
}
|
|
111
|
+
const group = survived.find(g => g && g.file === file)
|
|
112
|
+
if (!group) {
|
|
113
|
+
console.error(`✗ Файл не знайдено серед вцілілих мутантів: ${file}`)
|
|
114
|
+
return 1
|
|
115
|
+
}
|
|
116
|
+
process.stdout.write(`${await buildFixPrompt([group], cwd)}\n`)
|
|
117
|
+
return 0
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.error(USAGE)
|
|
121
|
+
return 1
|
|
122
|
+
}
|
package/scripts/coverage-fix.mjs
CHANGED
|
@@ -54,7 +54,7 @@ export async function fixSurvivedMutants(survived, projectRoot) {
|
|
|
54
54
|
* @param {string} projectRoot корінь проєкту
|
|
55
55
|
* @returns {Promise<string>} текст rich-промпту
|
|
56
56
|
*/
|
|
57
|
-
async function buildFixPrompt(survived, projectRoot) {
|
|
57
|
+
export async function buildFixPrompt(survived, projectRoot) {
|
|
58
58
|
const sections = []
|
|
59
59
|
|
|
60
60
|
for (const { file, mutants, exampleTest } of survived) {
|