feat(coder): guard session delete against worktree work loss
Deleting a BooChat session CASCADE-wipes its session_worktrees row, which would silently orphan uncommitted/unpushed/unmerged work in the worktree. Add a pre-DELETE gate: the server reads session_worktrees from the shared DB first (no row = chat-only session = delete immediately, zero round-trip), and for worktree-backed sessions calls a new BooCoder endpoint that runs git on the host (only the host systemd service can see /tmp/booworktrees). checkWorktreeWorkAtRisk reports dirty/unpushed/unmerged via the audited hostExec+shellEscape path; default branch is detected from refs/remotes/origin/HEAD (not the worktree's own branch), never hardcoded. Any at-risk worktree returns 409 with per-worktree RiskReport[]; force=true bypasses the check entirely. Fail-closed: coder unreachable/errored also blocks (force still escapes). The sidebar renders a block dialog distinguishing work-at-risk (Commit/Stash/Force) from couldn't-verify (Cancel/Force only); stash uses -u and re-blocks on remaining commits with an explanatory message. Commit never auto-commits — it routes the user to the session. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -151,8 +151,17 @@ export const api = {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(body),
|
||||
}),
|
||||
remove: (id: string) =>
|
||||
request<void>(`/api/sessions/${id}`, { method: 'DELETE' }),
|
||||
// force=true bypasses the server-side worktree work-loss guard. A blocked
|
||||
// delete throws ApiError(409) whose body carries { error, reports }.
|
||||
remove: (id: string, force = false) =>
|
||||
request<void>(`/api/sessions/${id}${force ? '?force=true' : ''}`, { method: 'DELETE' }),
|
||||
// Stash the session's worktree (uncommitted changes) on the host, via the
|
||||
// BooCoder proxy. Recoverable escape from the work-at-risk dialog.
|
||||
worktreeStash: (id: string) =>
|
||||
request<{ results: { worktreePath: string; stashed: boolean; error?: string }[] }>(
|
||||
`/api/coder/sessions/${id}/worktree-stash`,
|
||||
{ method: 'POST' },
|
||||
),
|
||||
archive: (id: string) =>
|
||||
request<void>(`/api/sessions/${id}/archive`, { method: 'POST' }),
|
||||
unarchive: (id: string) =>
|
||||
|
||||
Reference in New Issue
Block a user