@7n/rules 1.49.13 → 1.49.15
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 +13 -0
- package/package.json +2 -2
- package/rules/release/docs/index.md +0 -3
- package/rules/release/docs/release.md +10 -6
- package/rules/test/coverage/fix-worker.mjs +3 -1
- package/rules/test/coverage/main.mjs +1 -1
- package/scripts/lib/lint-surface/run-fix.mjs +11 -3
- package/skills/git-reconcile/js/docs/orchestrate.md +28 -44
- package/skills/git-reconcile/js/orchestrate.mjs +28 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.49.15] - 2026-07-27
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- refresh canonical mutation results after generated coverage tests
|
|
8
|
+
|
|
9
|
+
## [1.49.14] - 2026-07-27
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- release: @7n/rules@1.49.9
|
|
14
|
+
|
|
3
15
|
## [1.49.13] - 2026-07-26
|
|
4
16
|
|
|
5
17
|
### Fixed
|
|
6
18
|
|
|
19
|
+
- Виправлено фактичний шлях worktree, setup failure і spawnSync-діагностику в git-reconcile
|
|
7
20
|
- pass coverage mutation verdict feedback to the next ladder rung
|
|
8
21
|
|
|
9
22
|
## [1.49.12] - 2026-07-26
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@7n/rules",
|
|
3
|
-
"version": "1.49.
|
|
3
|
+
"version": "1.49.15",
|
|
4
4
|
"description": "CLI еталонних правил і skills (префікс n-): синк у репозиторій, дельта-lint, конформність",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"rename-yaml-extensions": "bun ./bin/n-rules.js rename-yaml-extensions"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@7n/llm-lib": "2.9.
|
|
68
|
+
"@7n/llm-lib": "2.9.8",
|
|
69
69
|
"@7n/mt": "^0.5.1",
|
|
70
70
|
"@zed-industries/agent-client-protocol": "^0.4.5",
|
|
71
71
|
"ajv": "^8.20.0",
|
|
@@ -4,10 +4,7 @@ title: npm/rules/release
|
|
|
4
4
|
resource: npm/rules/release/
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# npm/rules/release
|
|
8
|
-
|
|
9
7
|
| Файл | Тип |
|
|
10
8
|
| ------------------------- | --------- |
|
|
11
9
|
| [change.mjs](change.md) | JS Module |
|
|
12
|
-
| [main.mjs](main.md) | JS Module |
|
|
13
10
|
| [release.mjs](release.md) | JS Module |
|
|
@@ -3,7 +3,7 @@ type: JS Module
|
|
|
3
3
|
title: release.mjs
|
|
4
4
|
resource: npm/rules/release/release.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 496b51f4
|
|
7
7
|
model: openai-codex/gpt-5.4-mini
|
|
8
8
|
tier: cloud-min
|
|
9
9
|
score: 100
|
|
@@ -12,18 +12,22 @@ docgen:
|
|
|
12
12
|
|
|
13
13
|
## Огляд
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
`release` агрегує per-workspace change-файли у version-bump і CHANGELOG, комітить результат, ставить тег `<name>@<version>` та видаляє використані change-файли. Запускається у CI на `main` за `n-rules-release-design`, варіант A, і сам нічого не публікує.
|
|
16
|
+
|
|
17
|
+
`runReleaseCli` — CLI wrapper для запуску релізного процесу. Він потрібен, щоб ініціювати `release` із командного рядка.
|
|
16
18
|
|
|
17
19
|
## Поведінка
|
|
18
20
|
|
|
19
|
-
`release`
|
|
21
|
+
`release` послідовно обходить workspaces, збирає change-файли з їхніх директорій, визначає новий bump, оновлює версію в маніфесті, дописує секцію в CHANGELOG і прибирає використані change-файли. Якщо для пакета немає явних change-файлів, але є коміти, він все одно формує релізний запис на основі цього джерела змін.
|
|
22
|
+
|
|
23
|
+
Результат `release` — список фактично релізнутих workspace-ів із новими версіями; цей список далі йде в commit-back і створення анотованих тегів `\<name>@\<version>`. Якщо релізу для workspace нема, він не потрапляє до вихідного списку й не отримує тег.
|
|
20
24
|
|
|
21
|
-
`runReleaseCli`
|
|
25
|
+
`runReleaseCli` лише запускає `release` і передає в GitHub Actions перелік workspace-ів, для яких справді з’явилася нова версія.
|
|
22
26
|
|
|
23
27
|
## Публічний API
|
|
24
28
|
|
|
25
|
-
- release — агрегує per-workspace change-файли у version-bump і CHANGELOG,
|
|
26
|
-
- runReleaseCli — CLI-entry для запуску `release
|
|
29
|
+
- release — агрегує per-workspace change-файли у version-bump і CHANGELOG, комітить зміни, ставить тег `<name>@<version>` та видаляє use-up change-файли; спирається на package.json.
|
|
30
|
+
- runReleaseCli — CLI-entry point для ручного запуску `release` без окремої релізної логіки.
|
|
27
31
|
|
|
28
32
|
## Гарантії поведінки
|
|
29
33
|
|
|
@@ -88,6 +88,7 @@ export async function fixWorker(violations, ctx, deps = {}) {
|
|
|
88
88
|
|
|
89
89
|
/** @type {string[]} */
|
|
90
90
|
const touchedFiles = []
|
|
91
|
+
const mutationRefreshFiles = []
|
|
91
92
|
/** @type {Array<{provider: string, hook: string, files: string[], error: string}>} */
|
|
92
93
|
const failed = []
|
|
93
94
|
let feedback = null
|
|
@@ -105,6 +106,7 @@ export async function fixWorker(violations, ctx, deps = {}) {
|
|
|
105
106
|
try {
|
|
106
107
|
const res = await provider[hook]({ ...args, cwd: ctx.cwd, ctx: hookCtx(ctx, deadlineAt) })
|
|
107
108
|
touchedFiles.push(...(res?.touchedFiles ?? []))
|
|
109
|
+
mutationRefreshFiles.push(...(res?.mutationRefreshFiles ?? []))
|
|
108
110
|
if (res?.feedback?.previousError) feedback = res.feedback
|
|
109
111
|
deferred.push(...(res?.deferred ?? []))
|
|
110
112
|
for (const failure of res?.failed ?? []) {
|
|
@@ -137,5 +139,5 @@ export async function fixWorker(violations, ctx, deps = {}) {
|
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
|
|
140
|
-
return { touchedFiles, failed, deferred, feedback }
|
|
142
|
+
return { touchedFiles, mutationRefreshFiles: [...new Set(mutationRefreshFiles)], failed, deferred, feedback }
|
|
141
143
|
}
|
|
@@ -113,7 +113,7 @@ export async function lint(ctx) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
if (!(await provider.detect(cwd))) continue
|
|
116
|
-
let rows = await provider.collect(cwd, {})
|
|
116
|
+
let rows = await provider.collect(cwd, { mutationRefreshFiles: ctx.mutationRefreshFiles ?? [] })
|
|
117
117
|
|
|
118
118
|
// LLM-класифікація survived-мутантів (allowed gaps): verdict-и
|
|
119
119
|
// equivalent/defensive/glue/wrapper з confidence ≥ порогу виключаються зі
|
|
@@ -126,10 +126,18 @@ function isStandaloneConcern(patterns) {
|
|
|
126
126
|
* @param {string} cwd Робоча директорія для запуску детектора.
|
|
127
127
|
* @param {import('./progress.mjs').ProgressReporter|null} [progress] Reporter прогресу.
|
|
128
128
|
* @param {boolean} [verbose] Детальний вивід (прокидається у ctx concern-а).
|
|
129
|
+
* @param {string[]} [mutationRefreshFiles] Source-файли з cache-independent mutation verdict-ом.
|
|
129
130
|
* @returns {Promise<LintViolation[]>} Актуальні порушення concern-а після re-detect.
|
|
130
131
|
*/
|
|
131
|
-
async function reDetect(item, cwd, progress = null, verbose = false) {
|
|
132
|
-
const ctx = {
|
|
132
|
+
async function reDetect(item, cwd, progress = null, verbose = false, mutationRefreshFiles = []) {
|
|
133
|
+
const ctx = {
|
|
134
|
+
cwd,
|
|
135
|
+
ruleId: item.entry.ruleId,
|
|
136
|
+
concernId: item.entry.concern.name,
|
|
137
|
+
files: item.files,
|
|
138
|
+
verbose,
|
|
139
|
+
mutationRefreshFiles
|
|
140
|
+
}
|
|
133
141
|
const res = await runConcernDetector(item.entry.concern, ctx)
|
|
134
142
|
progress?.detectSnapshot(progressKey(item), res.violations.length)
|
|
135
143
|
return res.violations
|
|
@@ -416,7 +424,7 @@ async function runRung(rung, worker, violations, feedback, rungDeps) {
|
|
|
416
424
|
// ніколи не виконується.
|
|
417
425
|
let after
|
|
418
426
|
try {
|
|
419
|
-
after = await reDetect(item, cwd, progress, verbose)
|
|
427
|
+
after = await reDetect(item, cwd, progress, verbose, workerResult?.mutationRefreshFiles ?? [])
|
|
420
428
|
} catch (detectError) {
|
|
421
429
|
snapshot.rollback()
|
|
422
430
|
throw detectError
|
|
@@ -3,7 +3,7 @@ type: JS Module
|
|
|
3
3
|
title: orchestrate.mjs
|
|
4
4
|
resource: npm/skills/git-reconcile/js/orchestrate.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 6e9cb156
|
|
7
7
|
model: openai-codex/gpt-5.5
|
|
8
8
|
tier: cloud-avg
|
|
9
9
|
score: 100
|
|
@@ -21,7 +21,7 @@ docgen:
|
|
|
21
21
|
|
|
22
22
|
Для review-кандидатів `buildTriagePrompt` формує обмежене завдання для LLM: модель отримує вже пораховані Git-факти й має повернути лише JSON-рішення. `callRunner` викликає обраний runner, `parseDecisionEnvelope` дістає структуровану відповідь, а `validateTriageOutcome` приймає тільки повний і узгоджений набір рішень для поточного batch. `callWithValidatedFallback` спершу пробує дешевший рівень, а дорожчий використовує лише після конкретного validation failure.
|
|
23
23
|
|
|
24
|
-
Під час матеріалізації рішення source переноситься у керований worktree. `branchSlug` забезпечує передбачувані rescue
|
|
24
|
+
Під час матеріалізації рішення source переноситься у керований worktree. `branchSlug` забезпечує передбачувані rescue-гілки без крайового дефіса після скорочення, а `ensureLocalWorktreeExclude` не дає службовим worktree забруднювати root `git status`. Після `@7n/mt` actual checkout визначається через `git worktree list --porcelain`, тому collision sanitized-каталогу не веде до реконструйованого cwd. Setup failure повертається як `failed` лише для цієї PR-групи з branch, фактичним worktree та `spawnSync`-діагностикою; source і forensic checkout не очищуються. Якщо cherry-pick стає порожнім, `skipEmptyCherryPick` дозволяє skip лише для доведеного semantic no-op, а `finishCherryPick` завершує активний перенос без прийняття неперевіреного Git-стану. `hasChangesFromBase` відсікає PR без реального tree diff.
|
|
25
25
|
|
|
26
26
|
Behavior-gates будуються навколо baseline: `captureBehaviorBaseline` фіксує стан чистої `origin/<baseBranch>` із repository Git policy, а `captureCachedBehaviorBaseline` перевикористовує цей результат у межах одного прогону для однакової бази. `validateBehaviorState` перевіряє Git-консистентність, scoped lint/docs і test outcome; правила запуску тестів і скриптів беруться з `package.json`. `testFailureSignatures` нормалізує failures, а `acceptsTestOutcome` дозволяє red baseline тільки без нових failures. Якщо валідація падає через типовий formatting, CSpell, docs або changelog-дефект, `remediateBehaviorState` запускає canonical fixers перед ескалацією LLM.
|
|
27
27
|
|
|
@@ -31,58 +31,42 @@ Behavior-gates будуються навколо baseline: `captureBehaviorBasel
|
|
|
31
31
|
|
|
32
32
|
## Публічний API
|
|
33
33
|
|
|
34
|
-
- createPhaseProgress — Створює ANSI-free snapshot progress для однієї фази.
|
|
35
|
-
формат у TTY/CI не засмічує captured output cursor-control кодами, а
|
|
36
|
-
heartbeat показує elapsed time довгих LLM-етапів.
|
|
34
|
+
- createPhaseProgress — Створює ANSI-free snapshot progress для однієї фази.
|
|
37
35
|
- parseWorktrees — Парсить `git worktree list --porcelain` у branch→path.
|
|
38
|
-
- dedupeRefs — Дедуплікує local/remote refs одного commit
|
|
39
|
-
worktree-protection локального ref переноситься у запис.
|
|
36
|
+
- dedupeRefs — Дедуплікує local/remote refs одного commit.
|
|
40
37
|
- conflictFiles — Витягає конфліктні файли з `git merge-tree`.
|
|
41
|
-
- inventoryRepository — Збирає детермінований Git inventory.
|
|
42
|
-
|
|
43
|
-
- buildTriagePrompt — Формує bounded semantic-triage prompt. Git-факти вже пораховані JS; модель
|
|
44
|
-
не виконує shell-команди й повертає лише JSON-рішення.
|
|
38
|
+
- inventoryRepository — Збирає детермінований Git inventory.
|
|
39
|
+
- buildTriagePrompt — Формує bounded semantic-triage prompt.
|
|
45
40
|
- parseDecisionEnvelope — Витягає JSON object із чистої або fenced відповіді.
|
|
46
41
|
- callRunner — Викликає вибраний LLM runner для одного bounded-завдання.
|
|
47
|
-
- callWithValidatedFallback — Виконує
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
- changedNonCodeDirectories — Повертає директорії non-code змін для фінального domain lint.
|
|
65
|
-
- remediateBehaviorState — Запускає canonical fixers у worktree до ескалації min→max. Це прибирає
|
|
66
|
-
formatting/CSpell/doc/changelog дефекти без повторного behavioral LLM.
|
|
67
|
-
- captureBehaviorBaseline — Фіксує test baseline на чистій policy base branch до перенесення source.
|
|
68
|
-
- captureCachedBehaviorBaseline — Повторно використовує test baseline однієї policy base branch між PR-групами.
|
|
69
|
-
Залежності все одно встановлюються в кожному окремому worktree.
|
|
70
|
-
- validateBehaviorState — Додає до Git-state validation test script із репозиторію і changelog gate.
|
|
71
|
-
Саме ці докази вирішують, чи приймати min-результат або ескалювати на max.
|
|
72
|
-
- validateFinalProjectGates — Фінальний domain gate охоплює non-code зміни, зокрема workflows, dependency
|
|
73
|
-
manifests і правила. Code directories уже пройшли scoped lint і tests.
|
|
74
|
-
- cleanupSource — Видаляє точний source після Git-доказу неактуальності або успішного
|
|
75
|
-
перенесення. Protected/open-PR refs не потрапляють у цей крок.
|
|
42
|
+
- callWithValidatedFallback — Виконує min, валідує результат і викликає max лише після validation failure.
|
|
43
|
+
- validateTriageOutcome — Структурно перевіряє triage-рішення.
|
|
44
|
+
- branchSlug — Перетворює title/ref на валідний короткий branch slug.
|
|
45
|
+
- ensureLocalWorktreeExclude — Додає `.worktrees/` до локального Git exclude без tracked-змін.
|
|
46
|
+
- skipEmptyCherryPick — Пропускає лише підтверджений empty cherry-pick.
|
|
47
|
+
- finishCherryPick — Завершує активний cherry-pick.
|
|
48
|
+
- hasChangesFromBase — Перевіряє реальний tree diff, а не commits ahead.
|
|
49
|
+
- testFailureSignatures — Витягає стабільні Vitest failure identifiers.
|
|
50
|
+
- acceptsTestOutcome — Дозволяє red baseline лише без нових failures.
|
|
51
|
+
- sourceDirectories — Зводить code paths до найвужчих директорій для scoped gates.
|
|
52
|
+
- changedNonCodeDirectories — Повертає директорії non-code змін для domain lint.
|
|
53
|
+
- remediateBehaviorState — Запускає canonical fixers перед behavioral max fallback.
|
|
54
|
+
- captureBehaviorBaseline — Фіксує test baseline на чистій policy base branch.
|
|
55
|
+
- captureCachedBehaviorBaseline — Кешує test baseline між PR-групами.
|
|
56
|
+
- validateBehaviorState — Додає Git-state validation, tests і changelog gate.
|
|
57
|
+
- validateFinalProjectGates — Перевіряє фінальні non-code domain gates.
|
|
58
|
+
- cleanupSource — Видаляє тільки доказово безпечний точний source.
|
|
76
59
|
- formatReport — Формує deterministic report.
|
|
77
|
-
- runWithConcurrency — Виконує async jobs із bounded concurrency та стабільним
|
|
60
|
+
- runWithConcurrency — Виконує async jobs із bounded concurrency та стабільним output.
|
|
78
61
|
- normalizePrConcurrency — Нормалізує bounded concurrency PR-фази.
|
|
79
|
-
- runGitReconcileOrchestrator —
|
|
62
|
+
- runGitReconcileOrchestrator — Координує inventory, triage, PR і cleanup.
|
|
80
63
|
|
|
81
64
|
## Гарантії поведінки
|
|
82
65
|
|
|
83
66
|
- Progress є append-only та не містить ANSI cursor-control sequences.
|
|
84
67
|
- Не більше чотирьох PR-груп виконуються одночасно; типовий ліміт — три.
|
|
85
68
|
- Canonical fixers мають пріоритет перед behavioral `max` fallback.
|
|
86
|
-
- Cleanup починається лише після завершення всіх PR jobs і не видаляє
|
|
87
|
-
|
|
69
|
+
- Cleanup починається лише після завершення всіх PR jobs і не видаляє protected/open-PR/failed sources.
|
|
70
|
+
- `spawnSync.error`, зокрема `ENOENT`, не губиться в command diagnostics.
|
|
71
|
+
- Setup failure зберігає forensic worktree і не зупиняє незалежні PR-групи.
|
|
88
72
|
- Test baseline кешується за OID policy base branch у межах одного прогону.
|
|
@@ -138,7 +138,7 @@ export function createPhaseProgress(args) {
|
|
|
138
138
|
* @param {string} cwd робочий каталог
|
|
139
139
|
* @param {typeof spawnSync} spawnFn інжект для тестів
|
|
140
140
|
* @param {{ allowFailure?: boolean, input?: string }} [options] режим помилки та stdin
|
|
141
|
-
* @returns {{ status: number, stdout: string, stderr: string }} результат
|
|
141
|
+
* @returns {{ status: number, stdout: string, stderr: string, error: string }} результат
|
|
142
142
|
*/
|
|
143
143
|
function run(command, args, cwd, spawnFn, options = {}) {
|
|
144
144
|
const childEnv = { ...env, GIT_EDITOR: 'true' }
|
|
@@ -153,11 +153,12 @@ function run(command, args, cwd, spawnFn, options = {}) {
|
|
|
153
153
|
const normalized = {
|
|
154
154
|
status: result.status ?? 1,
|
|
155
155
|
stdout: result.stdout ?? '',
|
|
156
|
-
stderr: result.stderr ?? ''
|
|
156
|
+
stderr: result.stderr ?? '',
|
|
157
|
+
error: result.error ? `${result.error.name ?? 'Error'}${result.error.code ? ` ${result.error.code}` : ''}: ${result.error.message}` : ''
|
|
157
158
|
}
|
|
158
159
|
if (!options.allowFailure && normalized.status !== 0) {
|
|
159
160
|
throw new Error(
|
|
160
|
-
`${command} ${args.join(' ')} → exit ${normalized.status}: ${normalized.stderr || normalized.stdout}`
|
|
161
|
+
`${command} ${args.join(' ')} → exit ${normalized.status}: ${normalized.stderr || normalized.stdout || normalized.error}`
|
|
161
162
|
)
|
|
162
163
|
}
|
|
163
164
|
return normalized
|
|
@@ -666,6 +667,7 @@ export function branchSlug(value) {
|
|
|
666
667
|
.replaceAll(/[^a-z0-9]+/g, '-')
|
|
667
668
|
.replaceAll(/^-|-$/g, '')
|
|
668
669
|
.slice(0, 40)
|
|
670
|
+
.replaceAll(/^-|-$/g, '')
|
|
669
671
|
return slug || 'change'
|
|
670
672
|
}
|
|
671
673
|
|
|
@@ -706,12 +708,22 @@ function chooseBranch(title, cwd, spawnFn) {
|
|
|
706
708
|
function createReconcileWorktree(title, source, cwd, spawnFn) {
|
|
707
709
|
const baseRef = policyBaseRef(cwd)
|
|
708
710
|
const branch = chooseBranch(title, cwd, spawnFn)
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
711
|
+
let worktreeCwd
|
|
712
|
+
try {
|
|
713
|
+
run('npx', ['@7n/mt', 'worktree', 'create', branch, `git-reconcile: ${source}`], cwd, spawnFn)
|
|
714
|
+
const worktrees = parseWorktrees(git(['worktree', 'list', '--porcelain'], cwd, spawnFn).stdout)
|
|
715
|
+
worktreeCwd = worktrees.get(`refs/heads/${branch}`)
|
|
716
|
+
if (!worktreeCwd) throw new Error(`@7n/mt не зареєстрував worktree для ${branch}`)
|
|
717
|
+
git(['switch', '--detach', baseRef], worktreeCwd, spawnFn)
|
|
718
|
+
git(['branch', '-f', branch, baseRef], worktreeCwd, spawnFn)
|
|
719
|
+
git(['switch', branch], worktreeCwd, spawnFn)
|
|
720
|
+
return { branch, cwd: worktreeCwd }
|
|
721
|
+
} catch (error) {
|
|
722
|
+
const setupError = error instanceof Error ? error : new Error(String(error))
|
|
723
|
+
setupError.branch = branch
|
|
724
|
+
if (worktreeCwd) setupError.worktree = worktreeCwd
|
|
725
|
+
throw setupError
|
|
726
|
+
}
|
|
715
727
|
}
|
|
716
728
|
|
|
717
729
|
/**
|
|
@@ -1225,11 +1237,12 @@ async function createPullRequest(args) {
|
|
|
1225
1237
|
return { status: 'kept', error: 'LLM не вибрала жодного валідного commit oid' }
|
|
1226
1238
|
}
|
|
1227
1239
|
|
|
1228
|
-
|
|
1229
|
-
const worktree = createReconcileWorktree(group.title, source, rootCwd, spawnFn)
|
|
1240
|
+
let worktree
|
|
1230
1241
|
let createdPr
|
|
1231
|
-
log(`🌿 ${source} → ${worktree.branch}`)
|
|
1232
1242
|
try {
|
|
1243
|
+
onProgress('worktree')
|
|
1244
|
+
worktree = createReconcileWorktree(group.title, source, rootCwd, spawnFn)
|
|
1245
|
+
log(`🌿 ${source} → ${worktree.branch}`)
|
|
1233
1246
|
const sourceMayChangeCode = (candidate.changedFiles ?? []).some(path => SOURCE_CODE_RE.test(path))
|
|
1234
1247
|
let baseline = null
|
|
1235
1248
|
if (sourceMayChangeCode) {
|
|
@@ -1318,11 +1331,12 @@ async function createPullRequest(args) {
|
|
|
1318
1331
|
removeReconcileWorktree(worktree, rootCwd, spawnFn)
|
|
1319
1332
|
return { status: 'pr-created', url: createdPr, branch: worktree.branch }
|
|
1320
1333
|
} catch (error) {
|
|
1334
|
+
const setup = /** @type {{branch?:string,worktree?:string}} */ (error)
|
|
1321
1335
|
return {
|
|
1322
1336
|
status: 'failed',
|
|
1323
1337
|
error: error instanceof Error ? error.message : String(error),
|
|
1324
|
-
branch: worktree.branch,
|
|
1325
|
-
worktree: worktree.
|
|
1338
|
+
branch: worktree?.branch ?? setup.branch,
|
|
1339
|
+
worktree: worktree?.cwd ?? setup.worktree,
|
|
1326
1340
|
...(createdPr && { url: createdPr })
|
|
1327
1341
|
}
|
|
1328
1342
|
}
|