From af01995c3bbca788dea00b75f2c83a1d20ab3025 Mon Sep 17 00:00:00 2001 From: wienans <40465543+wienans@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:46:25 +0100 Subject: [PATCH] feat(vscode): Delete Agent Group (#109) --- .../agent-manager/AgentManagerSidebar.tsx | 73 ++++++++++++++++++- packages/ui/src/stores/useAgentGroupsStore.ts | 44 +++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/views/agent-manager/AgentManagerSidebar.tsx b/packages/ui/src/components/views/agent-manager/AgentManagerSidebar.tsx index cf11bd38..9b8e3ed3 100644 --- a/packages/ui/src/components/views/agent-manager/AgentManagerSidebar.tsx +++ b/packages/ui/src/components/views/agent-manager/AgentManagerSidebar.tsx @@ -6,6 +6,7 @@ import { RiSearchLine, RiGitBranchLine, } from '@remixicon/react'; +import { toast } from 'sonner'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay'; @@ -15,6 +16,14 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; import { cn } from '@/lib/utils'; import { useAgentGroupsStore, type AgentGroup } from '@/stores/useAgentGroupsStore'; import { useDirectoryStore } from '@/stores/useDirectoryStore'; @@ -41,6 +50,34 @@ interface AgentGroupItemProps { const AgentGroupItem: React.FC = ({ group, isSelected, onSelect }) => { const [menuOpen, setMenuOpen] = React.useState(false); + const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false); + const [isDeleting, setIsDeleting] = React.useState(false); + const deleteGroup = useAgentGroupsStore((state) => state.deleteGroup); + + const handleDelete = async () => { + setIsDeleting(true); + try { + const { success, deletedCount, failedCount } = await deleteGroup(group.name); + + if (success) { + toast.success(`Deleted agent group "${group.name}"`, { + description: `${deletedCount} session${deletedCount !== 1 ? 's' : ''} removed with worktrees archived.`, + }); + } else if (deletedCount > 0) { + toast.warning(`Partially deleted agent group "${group.name}"`, { + description: `${deletedCount} deleted, ${failedCount} failed.`, + }); + } else { + toast.error(`Failed to delete agent group "${group.name}"`); + } + } catch (error) { + toast.error(`Failed to delete agent group "${group.name}"`); + console.error('Delete group error:', error); + } finally { + setIsDeleting(false); + setShowDeleteConfirm(false); + } + }; return (
= ({ group, isSelected, onSe - + { + e.stopPropagation(); + setMenuOpen(false); + setShowDeleteConfirm(true); + }} + > Delete
+ + + + + Delete Agent Group + + Are you sure you want to delete "{group.name}"? This will remove {group.sessionCount} session{group.sessionCount !== 1 ? 's' : ''} and archive their worktrees. This action cannot be undone. + + + + + + + + ); }; diff --git a/packages/ui/src/stores/useAgentGroupsStore.ts b/packages/ui/src/stores/useAgentGroupsStore.ts index af3770d2..0b26d426 100644 --- a/packages/ui/src/stores/useAgentGroupsStore.ts +++ b/packages/ui/src/stores/useAgentGroupsStore.ts @@ -2,6 +2,7 @@ import { create } from 'zustand'; import { devtools } from 'zustand/middleware'; import { opencodeClient } from '@/lib/opencode/client'; import { useDirectoryStore } from './useDirectoryStore'; +import { useSessionStore } from './useSessionStore'; import type { WorktreeMetadata } from '@/types/worktree'; import { listWorktrees, mapWorktreeToMetadata } from '@/lib/git/worktreeService'; import type { Session } from '@opencode-ai/sdk/v2'; @@ -72,6 +73,8 @@ interface AgentGroupsActions { getSelectedGroup: () => AgentGroup | null; /** Get the currently selected session */ getSelectedSession: () => AgentGroupSession | null; + /** Delete a group and all its sessions, archiving worktrees */ + deleteGroup: (groupName: string) => Promise<{ success: boolean; deletedCount: number; failedCount: number }>; /** Clear error */ clearError: () => void; } @@ -318,6 +321,47 @@ export const useAgentGroupsStore = create()( clearError: () => { set({ error: null }); }, + + deleteGroup: async (groupName: string) => { + const { groups, selectedGroupName } = get(); + const group = groups.find((g) => g.name === groupName); + + if (!group) { + return { success: false, deletedCount: 0, failedCount: 0 }; + } + + // Get all session IDs from the group + const sessionIds = group.sessions.map((s) => s.id); + + if (sessionIds.length === 0) { + return { success: true, deletedCount: 0, failedCount: 0 }; + } + + // Delete sessions using sessionStore.deleteSessions + // archiveWorktree: true - removes the git worktree + // deleteRemoteBranch: false - does not delete remote branch + const { deletedIds, failedIds } = await useSessionStore.getState().deleteSessions( + sessionIds, + { + archiveWorktree: true, + deleteRemoteBranch: false, + } + ); + + // If the deleted group was selected, clear selection + if (selectedGroupName === groupName) { + set({ selectedGroupName: null, selectedSessionId: null }); + } + + // Reload groups to reflect changes + await get().loadGroups(); + + return { + success: failedIds.length === 0, + deletedCount: deletedIds.length, + failedCount: failedIds.length, + }; + }, }), { name: 'agent-groups-store' } )