feat(vscode): show loading spinner when closing a worktree in agent manager (#487)

* feat(vscode): show loading spinner when closing a worktree in agent manager

Replace the close button with a small spinner while the worktree is being
removed from disk, so the UI feels responsive during the async operation.

* Update README with Kilo Code content and demo gif

* Update README.md

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>

* fix: add .vscode-test/ to kilo-vscode gitignore

The @vscode/test-cli downloads VS Code Electron binaries into
.vscode-test/ when running extension tests. This directory was not
gitignored, causing 1000+ test artifacts to appear in diffs.

---------

Co-authored-by: Mark IJbema <mark@kilocode.ai>
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
This commit is contained in:
Marius
2026-02-19 19:25:27 +00:00
committed by GitHub
co-authored by Mark IJbema kiloconnect[bot]
parent 0e990a147d
commit 3f8cfea6c8
2 changed files with 24 additions and 8 deletions
@@ -59,6 +59,7 @@ const AgentManagerContent: Component = () => {
const [managedSessions, setManagedSessions] = createSignal<ManagedSessionState[]>([])
const [selection, setSelection] = createSignal<SidebarSelection>(LOCAL)
const [repoBranch, setRepoBranch] = createSignal<string | undefined>()
const [deletingWorktrees, setDeletingWorktrees] = createSignal<Set<string>>(new Set())
// Recover persisted local session IDs from webview state
const persisted = vscode.getState<{ localSessionIDs?: string[] }>()
@@ -342,6 +343,12 @@ const AgentManagerContent: Component = () => {
const ms = state.sessions.find((s) => s.id === current)
if (ms?.worktreeId) setSelection(ms.worktreeId)
}
// Clear deleting state for worktrees that have been removed
const ids = new Set(state.worktrees.map((wt) => wt.id))
setDeletingWorktrees((prev) => {
const next = new Set([...prev].filter((id) => ids.has(id)))
return next.size === prev.size ? prev : next
})
}
})
@@ -371,6 +378,7 @@ const AgentManagerContent: Component = () => {
const wt = worktrees().find((w) => w.id === worktreeId)
if (!wt) return
const doDelete = () => {
setDeletingWorktrees((prev) => new Set([...prev, wt.id]))
vscode.postMessage({ type: "agentManager.deleteWorktree", worktreeId: wt.id })
if (selection() === wt.id) {
const next = nextSelectionAfterDelete(
@@ -548,14 +556,16 @@ const AgentManagerContent: Component = () => {
<span class="am-worktree-branch" title={wt.branch}>
{worktreeLabel(wt)}
</span>
<IconButton
icon="close-small"
size="small"
variant="ghost"
label="Close worktree"
class="am-worktree-close"
onClick={(e: MouseEvent) => handleDeleteWorktree(wt.id, e)}
/>
<Show when={!deletingWorktrees().has(wt.id)} fallback={<Spinner class="am-worktree-spinner" />}>
<IconButton
icon="close-small"
size="small"
variant="ghost"
label="Close worktree"
class="am-worktree-close"
onClick={(e: MouseEvent) => handleDeleteWorktree(wt.id, e)}
/>
</Show>
</div>
)}
</For>
@@ -167,6 +167,12 @@
opacity: 1;
}
.am-worktree-spinner {
width: 16px;
height: 16px;
flex-shrink: 0;
}
/* Session list */
.am-list {