From ca25b396a28c4d6b2e23bc5bd7297a5e5b9f6c5b Mon Sep 17 00:00:00 2001 From: Christopher Tso Date: Sun, 28 Jun 2026 23:15:44 +0200 Subject: [PATCH 1/2] fix(results): ignore missing WIP branch cleanup --- packages/core/src/evaluation/results-repo.ts | 14 +++++++++++++- packages/core/test/evaluation/results-repo.test.ts | 6 ++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/core/src/evaluation/results-repo.ts b/packages/core/src/evaluation/results-repo.ts index e57c9cb6b..f9cae5266 100644 --- a/packages/core/src/evaluation/results-repo.ts +++ b/packages/core/src/evaluation/results-repo.ts @@ -4124,7 +4124,19 @@ export async function deleteWipBranch(params: { }): Promise { const normalized = normalizeResultsConfig(params.config); const cloneDir = await ensureResultsRepoClone(normalized); - await runGit(['push', normalized.remote, '--delete', params.wipBranch], { cwd: cloneDir }); + const result = await runGit(['push', normalized.remote, '--delete', params.wipBranch], { + cwd: cloneDir, + check: false, + }); + if (result.exitCode === 0 || isMissingRemoteRefDelete(result)) { + return; + } + throw new Error(result.stderr.trim() || result.stdout.trim() || 'Failed to delete WIP branch'); +} + +function isMissingRemoteRefDelete(result: { stdout: string; stderr: string }): boolean { + const text = `${result.stderr}\n${result.stdout}`.toLowerCase(); + return text.includes('remote ref does not exist') || text.includes('unable to delete'); } // git exits non-zero with one of these messages when the requested ref/object diff --git a/packages/core/test/evaluation/results-repo.test.ts b/packages/core/test/evaluation/results-repo.test.ts index 408546090..883901a00 100644 --- a/packages/core/test/evaluation/results-repo.test.ts +++ b/packages/core/test/evaluation/results-repo.test.ts @@ -2808,4 +2808,10 @@ describe('WIP branch helpers', () => { const branchesAfter = git('git branch -r', cloneDir); expect(branchesAfter).not.toContain(`origin/${wipBranch}`); }, 30000); + + it('deleteWipBranch ignores a missing remote WIP branch', async () => { + await expect( + deleteWipBranch({ config, wipBranch: 'agentv/wip/test-host/missing-run' }), + ).resolves.toBeUndefined(); + }, 30000); }); From 40c704aecce4c5b7ad0b4f1d23b1a3b546699614 Mon Sep 17 00:00:00 2001 From: Christopher Tso Date: Mon, 29 Jun 2026 03:36:57 +0200 Subject: [PATCH 2/2] fix(results): tighten WIP branch delete guard --- packages/core/src/evaluation/results-repo.ts | 2 +- .../core/test/evaluation/results-repo.test.ts | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/core/src/evaluation/results-repo.ts b/packages/core/src/evaluation/results-repo.ts index f9cae5266..e86ba98db 100644 --- a/packages/core/src/evaluation/results-repo.ts +++ b/packages/core/src/evaluation/results-repo.ts @@ -4136,7 +4136,7 @@ export async function deleteWipBranch(params: { function isMissingRemoteRefDelete(result: { stdout: string; stderr: string }): boolean { const text = `${result.stderr}\n${result.stdout}`.toLowerCase(); - return text.includes('remote ref does not exist') || text.includes('unable to delete'); + return text.includes('remote ref does not exist'); } // git exits non-zero with one of these messages when the requested ref/object diff --git a/packages/core/test/evaluation/results-repo.test.ts b/packages/core/test/evaluation/results-repo.test.ts index 883901a00..651df142d 100644 --- a/packages/core/test/evaluation/results-repo.test.ts +++ b/packages/core/test/evaluation/results-repo.test.ts @@ -2814,4 +2814,40 @@ describe('WIP branch helpers', () => { deleteWipBranch({ config, wipBranch: 'agentv/wip/test-host/missing-run' }), ).resolves.toBeUndefined(); }, 30000); + + it('deleteWipBranch surfaces non-missing remote delete failures', async () => { + const wipBranch = 'agentv/wip/test-host/rejected-delete'; + const handle = await setupWipWorktree({ config, wipBranch }); + const runDir = path.join(rootDir, 'run-rejected-delete-test'); + writeRunArtifacts(runDir, 'default', '2026-01-15T13-00-00'); + + try { + await pushWipCheckpoint({ + handle, + sourceDir: runDir, + destinationPath: 'default/2026-01-15T13-00-00', + }); + } finally { + await handle.cleanup(); + } + + const hookPath = path.join(remoteDir, 'hooks', 'update'); + writeFileSync( + hookPath, + [ + '#!/usr/bin/env sh', + 'if [ "$3" = "0000000000000000000000000000000000000000" ]; then', + ' echo "unable to delete protected WIP branch" >&2', + ' exit 1', + 'fi', + 'exit 0', + '', + ].join('\n'), + ); + chmodSync(hookPath, 0o755); + + await expect(deleteWipBranch({ config, wipBranch })).rejects.toThrow( + /unable to delete protected WIP branch|hook declined/, + ); + }, 30000); });