diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx index 7afd9a780ba..53299f60f86 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx @@ -329,12 +329,12 @@ const AgentManagerContent: Component = () => { const [diffLoading, setDiffLoading] = createSignal(false) const [diffWidth, setDiffWidth] = createSignal(Math.round(window.innerWidth * 0.5)) - // Full-screen review state (in-memory, per worktree) - const [reviewOpenByWorktree, setReviewOpenByWorktree] = createSignal>({}) - const [reviewCommentsByWorktree, setReviewCommentsByWorktree] = createSignal>({}) + // Full-screen review state (in-memory, per sidebar context: local/worktree) + const [reviewOpenByContext, setReviewOpenByContext] = createSignal>({}) + const [reviewCommentsByContext, setReviewCommentsByContext] = createSignal>({}) const [reviewActive, setReviewActive] = createSignal(false) const [reviewDiffStyle, setReviewDiffStyle] = createSignal<"unified" | "split">("unified") - // reviewOpen (memo below) controls tab presence for selected worktree. + // reviewOpen (memo below) controls tab presence for selected context. // Per-worktree git stats (diff additions/deletions, commits missing from origin) const [worktreeStats, setWorktreeStats] = createSignal>({}) @@ -358,33 +358,33 @@ const AgentManagerContent: Component = () => { const reviewOpen = createMemo(() => { const sel = selection() - if (!sel || sel === LOCAL) return false - return reviewOpenByWorktree()[sel] === true + if (sel === null) return false + return reviewOpenByContext()[sel] === true }) - const setReviewOpenForWorktree = (worktreeId: string, open: boolean) => { - setReviewOpenByWorktree((prev) => { - if (prev[worktreeId] === open) return prev - return { ...prev, [worktreeId]: open } + const setReviewOpenForContext = (context: string, open: boolean) => { + setReviewOpenByContext((prev) => { + if (prev[context] === open) return prev + return { ...prev, [context]: open } }) } const setReviewOpenForSelection = (open: boolean) => { const sel = selection() - if (!sel || sel === LOCAL) return - setReviewOpenForWorktree(sel, open) + if (sel === null) return + setReviewOpenForContext(sel, open) } const reviewComments = createMemo(() => { const sel = selection() - if (!sel || sel === LOCAL) return [] as ReviewComment[] - return reviewCommentsByWorktree()[sel] ?? [] + if (sel === null) return [] as ReviewComment[] + return reviewCommentsByContext()[sel] ?? [] }) const setReviewCommentsForSelection = (comments: ReviewComment[]) => { const sel = selection() - if (!sel || sel === LOCAL) return - setReviewCommentsByWorktree((prev) => ({ ...prev, [sel]: comments })) + if (sel === null) return + setReviewCommentsByContext((prev) => ({ ...prev, [sel]: comments })) } const applyStateForSelection = createMemo(() => { @@ -633,14 +633,14 @@ const AgentManagerContent: Component = () => { createEffect(() => { const ids = new Set(worktrees().map((wt) => wt.id)) - setReviewOpenByWorktree((prev) => { - const next = Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))) + setReviewOpenByContext((prev) => { + const next = Object.fromEntries(Object.entries(prev).filter(([id]) => id === LOCAL || ids.has(id))) if (Object.keys(next).length === Object.keys(prev).length) return prev return next }) - setReviewCommentsByWorktree((prev) => { - const next = Object.fromEntries(Object.entries(prev).filter(([id]) => ids.has(id))) + setReviewCommentsByContext((prev) => { + const next = Object.fromEntries(Object.entries(prev).filter(([id]) => id === LOCAL || ids.has(id))) if (Object.keys(next).length === Object.keys(prev).length) return prev return next }) @@ -722,7 +722,7 @@ const AgentManagerContent: Component = () => { createEffect(() => { const sel = selection() - if (!sel || sel === LOCAL) { + if (sel === null) { if (reviewActive()) setReviewActive(false) return } @@ -903,6 +903,7 @@ const AgentManagerContent: Component = () => { session.clearCurrentSession() vscode.postMessage({ type: "agentManager.showExistingLocalTerminal" }) } + setReviewActive(remembered === REVIEW_TAB_ID && reviewOpenByContext()[LOCAL] === true) } const selectWorktree = (worktreeId: string) => { @@ -919,7 +920,7 @@ const AgentManagerContent: Component = () => { } else { session.setCurrentSessionID(undefined) } - setReviewActive(remembered === REVIEW_TAB_ID && reviewOpenByWorktree()[worktreeId] === true) + setReviewActive(remembered === REVIEW_TAB_ID && reviewOpenByContext()[worktreeId] === true) } onMount(() => { @@ -1288,9 +1289,13 @@ const AgentManagerContent: Component = () => { return } if (review) { - // Review tab is open but no specific session — try using any session in the worktree - const sel = selection() - if (sel && sel !== LOCAL) { + // Review tab is open but no specific session — use local sentinel for local, + // or any session in the selected worktree. + if (sel === LOCAL) { + vscode.postMessage({ type: "agentManager.startDiffWatch", sessionId: LOCAL }) + return + } + if (sel) { const managed = managedSessions().find((ms) => ms.worktreeId === sel) if (managed) { vscode.postMessage({ type: "agentManager.startDiffWatch", sessionId: managed.id }) @@ -1311,9 +1316,9 @@ const AgentManagerContent: Component = () => { const openReviewTab = () => { const sel = selection() - if (!sel || sel === LOCAL) return + if (sel === null) return setDiffOpen(false) - setReviewOpenForWorktree(sel, true) + setReviewOpenForContext(sel, true) setReviewActive(true) } @@ -1333,16 +1338,18 @@ const AgentManagerContent: Component = () => { setReviewOpenForSelection(false) } - // Data for the review tab: use current session's diff data, or first available for the worktree + // Data for the review tab: use local diff data for local context, + // current session for selected worktree context, or first available in that worktree. const reviewDiffs = createMemo(() => { const data = diffDatas() const sel = selection() const id = session.currentSessionID() + if (sel === LOCAL) return data[LOCAL] ?? [] if (id && data[id]) { const current = managedSessions().find((s) => s.id === id) - if (sel && sel !== LOCAL && current?.worktreeId === sel) return data[id]! + if (sel && current?.worktreeId === sel) return data[id]! } - if (!sel || sel === LOCAL) return [] + if (!sel) return [] const ids = managedSessions() .filter((s) => s.worktreeId === sel) .map((s) => s.id) @@ -1569,8 +1576,9 @@ const AgentManagerContent: Component = () => { const tabIds = createMemo(() => { const ids = activeTabs().map((s) => s.id) const sel = selection() - if (!sel || sel === LOCAL) return ids + if (sel === null) return ids const current = reviewOpen() ? [...ids, REVIEW_TAB_ID] : ids + if (sel === LOCAL) return current return applyTabOrder( current.map((id) => ({ id })), worktreeTabOrder()[sel], @@ -1588,7 +1596,12 @@ const AgentManagerContent: Component = () => { if (typeof from !== "string" || typeof to !== "string") return const sel = selection() if (sel === LOCAL) { - setLocalSessionIDs((prev) => reorderTabs(prev, from, to) ?? prev) + setLocalSessionIDs((prev) => { + const ids = reviewOpen() ? [...prev, REVIEW_TAB_ID] : prev + const reordered = reorderTabs(ids, from, to) + if (!reordered) return prev + return reordered.filter((id) => id !== REVIEW_TAB_ID) + }) return } if (sel) { @@ -2423,7 +2436,7 @@ const AgentManagerContent: Component = () => { ) })()} - + { comments={reviewComments()} onCommentsChange={setReviewCommentsForSelection} onClose={() => setDiffOpen(false)} - onExpand={selection() !== LOCAL ? openReviewTab : undefined} + onExpand={selection() !== null ? openReviewTab : undefined} onOpenFile={(file) => { const id = session.currentSessionID() if (id) vscode.postMessage({ type: "agentManager.openFile", sessionId: id, filePath: file })