From 904d3e9b396e234aa578b888cd08023b64e098ad Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Fri, 21 Aug 2026 12:42:33 +0200 Subject: [PATCH] fix(agent-manager): address review feedback --- .../kilo-vscode/src/agent-manager/pr-status-bridge.ts | 6 ++++-- .../src/agent-manager/worktree-diff-controller.ts | 9 ++++++--- .../webview-ui/agent-manager/AgentManagerApp.tsx | 6 +++--- .../webview-ui/agent-manager/project/switch.ts | 3 ++- .../webview-ui/agent-manager/selection-actions.ts | 9 ++++++++- .../webview-ui/agent-manager/sidebar-collapse.ts | 3 ++- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/kilo-vscode/src/agent-manager/pr-status-bridge.ts b/packages/kilo-vscode/src/agent-manager/pr-status-bridge.ts index d9e97f0826..df5dbbec50 100644 --- a/packages/kilo-vscode/src/agent-manager/pr-status-bridge.ts +++ b/packages/kilo-vscode/src/agent-manager/pr-status-bridge.ts @@ -104,6 +104,7 @@ export class PRStatusBridge { } private handleComment(m: Record): boolean { + if (typeof m.projectId === "string" && m.projectId !== this.host.projectId?.()) return true const id = m.worktreeId as string const threadId = m.threadId as string const projectId = typeof m.projectId === "string" ? m.projectId : this.host.projectId?.() @@ -111,13 +112,14 @@ export class PRStatusBridge { const cwd = wt?.path ?? this.host.getWorkspaceRoot() const resolve = m.type === "agentManager.resolveComment" const resultType = resolve ? "agentManager.resolveCommentResult" : "agentManager.unresolveCommentResult" - const result = (success: boolean) => + const result = (success: boolean, error?: string) => this.host.postToWebview({ type: resultType, ...(projectId ? { projectId } : {}), worktreeId: id, threadId, success, + ...(error ? { error } : {}), }) if (!cwd) { this.host.log("resolveComment: no cwd for worktree", id) @@ -132,7 +134,7 @@ export class PRStatusBridge { }, (err: unknown) => { this.host.log(`${resultType} failed: ${err instanceof Error ? err.message : String(err)}`) - result(false) + result(false, ghErrorReason(err instanceof Error ? err.message : String(err))) }, ) return true diff --git a/packages/kilo-vscode/src/agent-manager/worktree-diff-controller.ts b/packages/kilo-vscode/src/agent-manager/worktree-diff-controller.ts index 8a24d3b436..c974638913 100644 --- a/packages/kilo-vscode/src/agent-manager/worktree-diff-controller.ts +++ b/packages/kilo-vscode/src/agent-manager/worktree-diff-controller.ts @@ -174,7 +174,7 @@ export class WorktreeDiffController { } public async request(id: string): Promise { - if (this.controller.currentId !== id) { + if (this.controller.currentId !== id || this.owner !== this.ctx.projectId?.()) { await this.activate(id, false, true) return } @@ -242,7 +242,7 @@ export class WorktreeDiffController { } public start(id: string): void { - if (this.controller.isPolling && this.controller.currentId === id) return + if (this.controller.isPolling && this.controller.currentId === id && this.owner === this.ctx.projectId?.()) return this.ctx.log(`Starting diff polling for ${id}`) void this.activate(id, true, true) } @@ -286,10 +286,13 @@ export class WorktreeDiffController { private async activate(id: string, poll: boolean, fetch: boolean): Promise { this.target = undefined this.poll = poll - this.owner = this.ctx.projectId?.() + const owner = this.ctx.projectId?.() + this.owner = owner await this.ready("stateReady rejected, continuing diff activate:") + if (this.owner !== owner || this.ctx.projectId?.() !== owner) return const { ctx } = parseDiffId(id) const resolved = await this.resolve(ctx) + if (this.owner !== owner || this.ctx.projectId?.() !== owner) return this.target = resolved ? { sessionId: id, ...resolved } : undefined // Clear any stale source notice up front; sources only push a notice when // one is active, so a swap away from a noticing source must reset it. diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx index 64dd8ecbf8..b5b1ab4917 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx @@ -302,7 +302,7 @@ const AgentManagerContent: Component = () => { setSessionsCollapsed(collapsed) vscode.postMessage({ type: "agentManager.setSessionsCollapsed", collapsed }) } - const sidebar = createSidebarCollapse(vscode) + const sidebar = createSidebarCollapse(vscode, { initial: persisted?.sidebarCollapsed }) const sidebarCollapsed = sidebar.collapsed const expandSidebar = sidebar.expand const toggleSidebar = sidebar.toggle @@ -700,6 +700,7 @@ const AgentManagerContent: Component = () => { owns: (sel) => worktrees().some((wt) => wt.id === sel), pending: isPending, locals: localSessionIDs, + localTab: (id) => id === REVIEW_TAB_ID || isTerminalTabId(id), set: (sel, tab) => registry.active().tabMemory.set(sel, tab), }) createEffect(() => { @@ -1145,8 +1146,7 @@ const AgentManagerContent: Component = () => { }) requestChatFocus() } - // Recover sidebar collapsed state and mark hydrated so transitions enable - sidebar.hydrate() + sidebar.hydrate(state.sidebarCollapsed) } const applyProjectSwitch = (state: AgentManagerStateMessage): "first" | "switched" | "same" => { diff --git a/packages/kilo-vscode/webview-ui/agent-manager/project/switch.ts b/packages/kilo-vscode/webview-ui/agent-manager/project/switch.ts index 423041c888..d40568660b 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/project/switch.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/project/switch.ts @@ -10,8 +10,8 @@ export function switchProject(opts: { }): "first" | "switched" | "same" { const previous = opts.current() if (opts.id === previous) return "same" - opts.set(opts.id) if (previous === undefined) { + opts.set(opts.id) opts.first() return "first" } @@ -19,5 +19,6 @@ export function switchProject(opts: { opts.hide() opts.history() opts.reset() + opts.set(opts.id) return "switched" } diff --git a/packages/kilo-vscode/webview-ui/agent-manager/selection-actions.ts b/packages/kilo-vscode/webview-ui/agent-manager/selection-actions.ts index 52de92a539..0fdf31a0d2 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/selection-actions.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/selection-actions.ts @@ -35,6 +35,7 @@ export function createTabMemory(opts: { owns: (selection: string) => boolean pending: (id: string) => boolean locals: () => string[] + localTab?: (id: string) => boolean set: (selection: string, tab: string) => void }) { return () => { @@ -42,7 +43,11 @@ export function createTabMemory(opts: { const tab = opts.tab() if (sel === null || !tab) return if (opts.multi() && opts.applied() !== opts.active()) return - if (opts.multi() && !(sel === LOCAL ? opts.pending(tab) || opts.locals().includes(tab) : opts.owns(sel))) return + if ( + opts.multi() && + !(sel === LOCAL ? (opts.localTab?.(tab) ?? (opts.pending(tab) || opts.locals().includes(tab))) : opts.owns(sel)) + ) + return rememberSelectionTab(opts.set, sel, tab) } } @@ -133,8 +138,10 @@ export function selectLocalAction( deps.terms.setActiveId(undefined) const real = locals.filter((item) => !deps.isPending(item.id)) const target = remembered ? real.find((s) => s.id === remembered) : undefined + const draft = remembered && deps.isPending(remembered) ? remembered : undefined const fallback = target?.id ?? + draft ?? (remembered && ids.includes(remembered) ? remembered : undefined) ?? real[0]?.id ?? ids[0] ?? diff --git a/packages/kilo-vscode/webview-ui/agent-manager/sidebar-collapse.ts b/packages/kilo-vscode/webview-ui/agent-manager/sidebar-collapse.ts index 5045aa4841..5d4723d9a0 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/sidebar-collapse.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/sidebar-collapse.ts @@ -30,7 +30,8 @@ export function createSidebarCollapse(vscode: VsCodePoster, opts: Options = {}) collapsed, hydrated, /** Apply state from extension push without re-broadcasting. */ - hydrate: () => { + hydrate: (value?: boolean) => { + if (value !== undefined) setCollapsed(value) if (!hydrated()) requestAnimationFrame(() => setHydrated(true)) }, /** Ensure the sidebar is visible; no-op + no message when already open. */