From da7f0679d848f7c5d43887e7b0cb5b025fe8114f Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Sat, 3 Jan 2026 01:20:56 +0200 Subject: [PATCH] fix(session): handle worktree deletion without sessions --- .../src/components/session/SessionDialogs.tsx | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/packages/ui/src/components/session/SessionDialogs.tsx b/packages/ui/src/components/session/SessionDialogs.tsx index b3163ea7..23f23675 100644 --- a/packages/ui/src/components/session/SessionDialogs.tsx +++ b/packages/ui/src/components/session/SessionDialogs.tsx @@ -28,6 +28,7 @@ import { cn, formatPathForDisplay } from '@/lib/utils'; import type { Session } from '@opencode-ai/sdk'; import type { WorktreeMetadata } from '@/types/worktree'; import { + archiveWorktree, createWorktree, getWorktreeStatus, listWorktrees as listGitWorktrees, @@ -591,13 +592,30 @@ export const SessionDialogs: React.FC = () => { setIsProcessingDelete(true); try { - const archiveWorktree = shouldArchiveWorktree; - const removeRemoteBranch = archiveWorktree && deleteDialogShouldRemoveRemote; + const shouldArchive = shouldArchiveWorktree; + const removeRemoteBranch = shouldArchive && deleteDialogShouldRemoveRemote; + + if (deleteDialog.sessions.length === 0 && isWorktreeDelete && deleteDialog.worktree) { + const shouldRemoveRemote = deleteDialogShouldRemoveRemote && canRemoveRemoteBranches; + await archiveWorktree({ + projectDirectory: projectDirectory, + path: deleteDialog.worktree.path, + branch: deleteDialog.worktree.branch, + force: true, + deleteRemote: shouldRemoveRemote, + }); + const archiveNote = shouldRemoveRemote ? 'Worktree and remote branch removed.' : 'Worktree removed.'; + toast.success('Worktree removed', { + description: renderToastDescription(archiveNote), + }); + closeDeleteDialog(); + return; + } if (deleteDialog.sessions.length === 1) { const target = deleteDialog.sessions[0]; const success = await deleteSession(target.id, { - archiveWorktree, + archiveWorktree: shouldArchive, deleteRemoteBranch: removeRemoteBranch, }); if (!success) { @@ -605,7 +623,7 @@ export const SessionDialogs: React.FC = () => { setIsProcessingDelete(false); return; } - const archiveNote = archiveWorktree + const archiveNote = shouldArchive ? removeRemoteBranch ? 'Worktree and remote branch removed.' : 'Attached worktree archived.' @@ -616,12 +634,12 @@ export const SessionDialogs: React.FC = () => { } else { const ids = deleteDialog.sessions.map((session) => session.id); const { deletedIds, failedIds } = await deleteSessions(ids, { - archiveWorktree, + archiveWorktree: shouldArchive, deleteRemoteBranch: removeRemoteBranch, }); if (deletedIds.length > 0) { - const archiveNote = archiveWorktree + const archiveNote = shouldArchive ? removeRemoteBranch ? 'Archived worktrees and removed remote branches.' : 'Attached worktrees archived.' @@ -653,7 +671,7 @@ export const SessionDialogs: React.FC = () => { } finally { setIsProcessingDelete(false); } - }, [deleteDialog, deleteDialogShouldRemoveRemote, deleteSession, deleteSessions, closeDeleteDialog, shouldArchiveWorktree]); + }, [deleteDialog, deleteDialogShouldRemoveRemote, deleteSession, deleteSessions, closeDeleteDialog, shouldArchiveWorktree, isWorktreeDelete, canRemoveRemoteBranches, projectDirectory]); const worktreeManagerBody = (
@@ -929,27 +947,31 @@ export const SessionDialogs: React.FC = () => { const targetWorktree = deleteDialog?.worktree ?? deleteDialogSummaries[0]?.metadata ?? null; const deleteDialogDescription = deleteDialog ? deleteDialog.mode === 'worktree' - ? `This removes the selected worktree and ${deleteDialog.sessions.length === 1 ? '1 linked session' : `${deleteDialog.sessions.length} linked sessions`}.` + ? deleteDialog.sessions.length === 0 + ? 'This removes the selected worktree.' + : `This removes the selected worktree and ${deleteDialog.sessions.length === 1 ? '1 linked session' : `${deleteDialog.sessions.length} linked sessions`}.` : `This action permanently removes ${deleteDialog.sessions.length === 1 ? '1 session' : `${deleteDialog.sessions.length} sessions`}${deleteDialog.dateLabel ? ` from ${deleteDialog.dateLabel}` : '' }.` : ''; const deleteDialogBody = deleteDialog ? (
-
-
    - {deleteDialog.sessions.slice(0, 3).map((session) => ( -
  • - {session.title || 'Untitled Session'} -
  • - ))} - {deleteDialog.sessions.length > 3 && ( -
  • - +{deleteDialog.sessions.length - 3} more -
  • - )} -
-
+ {deleteDialog.sessions.length > 0 && ( +
+
    + {deleteDialog.sessions.slice(0, 3).map((session) => ( +
  • + {session.title || 'Untitled Session'} +
  • + ))} + {deleteDialog.sessions.length > 3 && ( +
  • + +{deleteDialog.sessions.length - 3} more +
  • + )} +
+
+ )} {isWorktreeDelete ? (