merge: 合并失败补救完成后自动收口原任务 [tsk_BagzbKZNAHXV]

手工解决 src/api/server.ts 冲突(keep-both):main 的 cleanupTaskRunArtifacts(合并后回收 run 目录)与分支的 findMergeOriginTask/remediateOrigin(补救任务合并成功后自动把原任务标 done)互补,均保留;ensureMergeRemediationTask 调用补 conflictFiles。其余文件(store.ts/types.ts/merge.ts/web/test)自动合并。typecheck + 183 测试全绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 20:10:00 +08:00
7 changed files with 149 additions and 8 deletions
+7 -4
View File
@@ -6,6 +6,7 @@ export interface MergeResult {
ok: boolean;
mergeCommit?: string; // 成功时为合并后 defaultBranch 的 HEAD(重复合并时为当前 HEAD,不新建提交)
error?: string;
conflictFiles?: string[]; // 失败为冲突时的冲突文件列表(结构化,供事件/时间线展示)
}
/** 临时合并 worktree 目录(确定性):<dataDir>/worktrees/_merge/<taskId>/ */
@@ -57,8 +58,9 @@ async function mergeInPrimaryCheckout(
let conflicted = '';
try { conflicted = (await git(repoPath, ['diff', '--name-only', '--diff-filter=U'])).trim(); } catch { /* ignore */ }
await git(repoPath, ['merge', '--abort']).catch(() => undefined);
const files = conflicted ? `;冲突文件:${conflicted.split('\n').join('、')}` : '';
return { ok: false, error: `${(e as Error).message}${files}` };
const conflictFiles = conflicted ? conflicted.split('\n') : [];
const files = conflictFiles.length ? `;冲突文件:${conflictFiles.join('、')}` : '';
return { ok: false, error: `${(e as Error).message}${files}`, conflictFiles };
}
}
@@ -116,8 +118,9 @@ export async function mergeBranch(
conflicted = (await git(dir, ['diff', '--name-only', '--diff-filter=U'])).trim();
} catch { /* 收集失败不影响报错 */ }
await git(dir, ['merge', '--abort']).catch(() => undefined);
const files = conflicted ? `;冲突文件:${conflicted.split('\n').join('、')}` : '';
return { ok: false, error: `${(e as Error).message}${files}` };
const conflictFiles = conflicted ? conflicted.split('\n') : [];
const files = conflictFiles.length ? `;冲突文件:${conflictFiles.join('、')}` : '';
return { ok: false, error: `${(e as Error).message}${files}`, conflictFiles };
} finally {
// 4) 无论成败都清理临时 worktree
await git(repoPath, ['worktree', 'remove', '--force', dir]).catch(() => undefined);