fix(worktree): subagent sessions kept when deleting worktree group from sidebar (#1806)

* fix(worktree): include sessions when deleting worktree group from sidebar

allGroupSessions was guarded by group.isArchivedBucket, returning [] for
active worktree groups. This caused the 'delete worktree' button in the
sidebar to send an empty session list — SessionDialogs only removed the
git worktree directory and skipped archiving any sessions, leaving them
orphaned.

Remove the guard so all sessions (including recursive children /
subagent sessions) are collected regardless of archived state.

* fix(sessions): delete all descendants on hard-delete instead of relying on server cascade

The previous code sent only the root session ID and assumed the server
would cascade-delete all children. If the cascade failed, children were
left orphaned. Delete root + descendants individually; 404 responses
from already-cascade-deleted children are treated as success.

* fix(sessions): clear worktree metadata when deleting a session

Deleted sessions kept their worktree attachment in both
session-worktree-store and session-ui-store. Clean it up on successful
deletion and on 404 (already deleted).

* fix(worktree): search subagent sessions across all directories before delete

WorktreeSectionContent and BranchPickerDialog used useSessions(), which
is scoped to the current sync directory. Subagent sessions created in
other worktrees/project roots were missed and left orphaned. Search
across active + archived global sessions when collecting descendants.

---------

Co-authored-by: Leonid Skorobogatyy <bash@opencode.itc.local>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
bashrusakh
2026-06-29 00:42:13 +03:00
committed by GitHub
co-authored by Leonid Skorobogatyy Bohdan Triapitsyn
parent ca64f1a886
commit c184ddf185
4 changed files with 33 additions and 16 deletions
+8
View File
@@ -466,6 +466,10 @@ function restoreSessionListSnapshots(snapshots: SessionListSnapshot[]): void {
}
}
function cleanupSessionWorktreeMetadata(sessionId: string): void {
useSessionUIStore.getState().setWorktreeMetadata(sessionId, null)
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function deleteSession(sessionId: string, _options?: Record<string, unknown>): Promise<boolean> {
const sessionDirectory = getSessionDirectory(sessionId)
@@ -484,6 +488,7 @@ export async function deleteSession(sessionId: string, _options?: Record<string,
throw new Error("session.delete failed: server did not confirm deletion")
}
useGlobalSessionsStore.getState().removeSessions([sessionId])
cleanupSessionWorktreeMetadata(sessionId)
return true
} catch (error) {
console.error("[session-actions] deleteSession failed", error)
@@ -491,6 +496,7 @@ export async function deleteSession(sessionId: string, _options?: Record<string,
// Subsequent delete attempts for those children return 404; treat as
// success since the session was already deleted by the cascade.
if ((error as { status?: number })?.status === 404) {
cleanupSessionWorktreeMetadata(sessionId)
return true
}
restoreSessionListSnapshots(snapshots)
@@ -514,10 +520,12 @@ export async function deleteSessionInDirectory(sessionId: string, directory: str
throw new Error("session.delete failed: server did not confirm deletion")
}
useGlobalSessionsStore.getState().removeSessions([sessionId])
cleanupSessionWorktreeMetadata(sessionId)
return true
} catch (error) {
console.error("[session-actions] deleteSessionInDirectory failed", error)
if ((error as { status?: number })?.status === 404) {
cleanupSessionWorktreeMetadata(sessionId)
return true
}
restoreSessionListSnapshots(snapshots)