From da9292fbccad9f4c20f439e240790da3ab3a92d3 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Thu, 14 May 2026 14:09:12 +0200 Subject: [PATCH 1/2] fix(agent-manager): support diff sidebar with terminals --- .changeset/terminals-split-diff-sidebar.md | 5 + .../agent-manager/AgentManagerApp.tsx | 128 +++++++++--------- .../webview-ui/agent-manager/DiffPanel.tsx | 11 +- .../agent-manager/FullScreenDiffView.tsx | 11 +- .../agent-manager/agent-manager.css | 32 ++++- .../agent-manager/review-annotations.ts | 8 +- .../agent-manager/terminal/TerminalTab.tsx | 10 ++ .../src/types/messages/extension-messages.ts | 8 ++ 8 files changed, 141 insertions(+), 72 deletions(-) create mode 100644 .changeset/terminals-split-diff-sidebar.md diff --git a/.changeset/terminals-split-diff-sidebar.md b/.changeset/terminals-split-diff-sidebar.md new file mode 100644 index 00000000000..8474c11fc35 --- /dev/null +++ b/.changeset/terminals-split-diff-sidebar.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Support viewing Agent Manager terminal tabs alongside the right diff sidebar, and send review comments to the active terminal. diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx index 1e7c0daf916..8cc186ff2ea 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx @@ -1528,6 +1528,7 @@ const AgentManagerContent: Component = () => { const openReviewTab = () => { const sel = selection() if (sel === null) return + terms.setActiveId(undefined) setSidePanel(null) setReviewOpenForContext(sel, true) setReviewActive(true) @@ -3007,76 +3008,73 @@ const AgentManagerContent: Component = () => { /> - {/* Stacking container: the terminal layer is an absolutely- - positioned overlay on top of the chat. This sub-container - is position:relative so the overlay does not cover the - tab bar above (which lives outside this stack). */} + {/* Terminal overlay is scoped to the main pane so it does not cover the tab bar or side panel. */}
- {/* Terminal tabs are kept mounted regardless of visibility so - output keeps streaming across worktree switches without - detaching xterm from the paint tree. */} - {renderTerminalLayer({ state: terms })} - {/* Chat + side diff panel (hidden when review tab or terminal tab is active) */} + {/* Chat/terminal + side diff panel. Keep it mounted under the + review tab so live xterm canvases never leave the paint tree. */}
-
- { - if (localSessionIDs().includes(id)) { - session.selectSession(id) - if (selection() === null) setSelection(LOCAL) - return - } - // Navigate to owning worktree instead of forcing into local mode - if (worktreeSessionIds().has(id)) { - const ms = managedSessions().find((s) => s.id === id) - if (ms?.worktreeId) { - selectWorktree(ms.worktreeId) +
+ {/* Keep terminal tabs mounted so output streams across worktree switches. */} + {renderTerminalLayer({ state: terms })} +
+ { + if (localSessionIDs().includes(id)) { session.selectSession(id) - setReviewActive(false) + if (selection() === null) setSelection(LOCAL) return } - } - openLocally(id) - }} - onShowHistory={() => setHistory(true)} - onForkMessage={readOnly() ? undefined : handleForkSession} - readonly={readOnly()} - continueInWorktree={selection() === LOCAL} - promptBoxId={`agent-manager:${selection() ?? "unassigned"}`} - pendingSessionID={selection() === LOCAL ? activePendingId() : undefined} - /> - -
- - {t("agentManager.session.readonly")} - - -
-
+ // Navigate to owning worktree instead of forcing into local mode + if (worktreeSessionIds().has(id)) { + const ms = managedSessions().find((s) => s.id === id) + if (ms?.worktreeId) { + selectWorktree(ms.worktreeId) + session.selectSession(id) + setReviewActive(false) + return + } + } + openLocally(id) + }} + onShowHistory={() => setHistory(true)} + onForkMessage={readOnly() ? undefined : handleForkSession} + readonly={readOnly()} + continueInWorktree={selection() === LOCAL} + promptBoxId={`agent-manager:${selection() ?? "unassigned"}`} + pendingSessionID={selection() === LOCAL ? activePendingId() : undefined} + /> + +
+ + {t("agentManager.session.readonly")} + + +
+
+
@@ -3121,6 +3119,7 @@ const AgentManagerContent: Component = () => { }} onRevertFile={revertCtl.revert} revertingFiles={revertCtl.reverting()} + activeTerminalId={terms.activeId()} />
@@ -3151,6 +3150,7 @@ const AgentManagerContent: Component = () => { }} onRevertFile={revertCtl.revert} revertingFiles={revertCtl.reverting()} + activeTerminalId={terms.activeId()} onClose={closeReviewTab} />
diff --git a/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx b/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx index 21e95375cfe..72de493aabd 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx @@ -54,6 +54,7 @@ interface DiffPanelProps { onOpenFile?: (relativePath: string, line?: number) => void onRevertFile?: (file: string) => void revertingFiles?: Set + activeTerminalId?: string } export const DiffPanel: Component = (props) => { @@ -305,6 +306,7 @@ export const DiffPanel: Component = (props) => { deleteComment, cancelDraft, labels: labels(), + activeTerminalId: props.activeTerminalId, }) } @@ -328,7 +330,14 @@ export const DiffPanel: Component = (props) => { const all = comments() if (all.length === 0) return window.dispatchEvent( - new MessageEvent("message", { data: { type: "appendReviewComments", comments: all, autoSend: true } }), + new MessageEvent("message", { + data: { + type: props.activeTerminalId ? "appendReviewCommentsToTerminal" : "appendReviewComments", + comments: all, + autoSend: true, + targetTerminalId: props.activeTerminalId, + }, + }), ) preserveScroll(() => setComments([])) props.onSendAll?.() diff --git a/packages/kilo-vscode/webview-ui/agent-manager/FullScreenDiffView.tsx b/packages/kilo-vscode/webview-ui/agent-manager/FullScreenDiffView.tsx index 596fa54f465..6f8b8828f77 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/FullScreenDiffView.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/FullScreenDiffView.tsx @@ -59,6 +59,7 @@ interface FullScreenDiffViewProps { onOpenFile?: (relativePath: string, line?: number) => void onRevertFile?: (file: string) => void revertingFiles?: Set + activeTerminalId?: string /** Defaults to true. Hides the per-file Revert action when false. */ canRevert?: boolean /** Defaults to true. Disables comment creation and "Send all" when false. */ @@ -320,6 +321,7 @@ export const FullScreenDiffView: Component = (props) => deleteComment, cancelDraft, labels: labels(), + activeTerminalId: props.activeTerminalId, }) } @@ -336,7 +338,14 @@ export const FullScreenDiffView: Component = (props) => const all = comments() if (all.length === 0) return window.dispatchEvent( - new MessageEvent("message", { data: { type: "appendReviewComments", comments: all, autoSend: true } }), + new MessageEvent("message", { + data: { + type: props.activeTerminalId ? "appendReviewCommentsToTerminal" : "appendReviewComments", + comments: all, + autoSend: true, + targetTerminalId: props.activeTerminalId, + }, + }), ) preserveScroll(() => setComments([])) props.onSendAll?.() diff --git a/packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css b/packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css index 6edf23a786b..305359b3dc7 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css +++ b/packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css @@ -1650,16 +1650,38 @@ body.am-wt-dragging-active * { flex-direction: column; flex: 1; min-height: 0; + min-width: 0; isolation: isolate; } +.am-detail-content-hidden { + position: absolute; + inset: 0; + opacity: 0; + pointer-events: none; + z-index: 0; +} + .am-detail-split { flex-direction: row; } -.am-detail-split .am-chat-wrapper { +.am-main-pane { + display: flex; + flex-direction: column; flex: 1; + min-height: 0; min-width: 0; + position: relative; + isolation: isolate; +} + +.am-main-pane-terminal-active .am-chat-wrapper { + opacity: 0; + pointer-events: none; +} + +.am-detail-split .am-main-pane { border-right: 1px solid var(--border-weak-base); } @@ -4331,9 +4353,9 @@ body.vscode-high-contrast-light { * subtree and stop xterm's internal rAF render loop, causing the * "press Enter to see content" bug on worktree switches. * - * Stack: position:relative container hosting the chat, review, and - * terminal layer. Sits below the tab bar inside `.am-detail`. - * Layer: absolute-positioned overlay covering the stack. + * Stack: position:relative container hosting the main pane, review, + * and side panel. Sits below the tab bar inside `.am-detail`. + * Layer: absolute-positioned overlay covering the main pane. * `pointer-events: none` when no terminal is active, letting * clicks fall through to the chat behind it. * Slots: absolute-positioned and stacked inside the layer; only the @@ -4355,7 +4377,7 @@ body.vscode-high-contrast-light { opacity: 0; pointer-events: none; background: var(--vscode-terminal-background, #1e1e1e); - z-index: 1; + z-index: 30; /* Force a dedicated compositor layer so opacity flips do not re-lay-out the xterm canvases underneath. */ will-change: opacity; diff --git a/packages/kilo-vscode/webview-ui/agent-manager/review-annotations.ts b/packages/kilo-vscode/webview-ui/agent-manager/review-annotations.ts index 3271f3ad854..3c46aac071c 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/review-annotations.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/review-annotations.ts @@ -35,6 +35,7 @@ interface AnnotationHandlers { deleteComment: (id: string) => void cancelDraft: () => void labels: AnnotationLabels + activeTerminalId?: string } function focusWhenConnected(el: HTMLTextAreaElement): void { @@ -269,7 +270,12 @@ export function buildReviewAnnotation( makeActionButton(handlers.labels.sendToChat, makeIcon("M1 1l14 7-14 7V9l10-1L1 7z"), () => { window.dispatchEvent( new MessageEvent("message", { - data: { type: "appendReviewComments", comments: [comment], autoSend: true }, + data: { + type: handlers.activeTerminalId ? "appendReviewCommentsToTerminal" : "appendReviewComments", + comments: [comment], + autoSend: true, + targetTerminalId: handlers.activeTerminalId, + }, }), ) handlers.deleteComment(comment.id) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx b/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx index 551e8c482f3..57827df8bb3 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx @@ -19,6 +19,8 @@ import { UnicodeGraphemesAddon } from "@xterm/addon-unicode-graphemes" import "@xterm/xterm/css/xterm.css" import { useVSCode } from "../../src/context/vscode" import { useLanguage } from "../../src/context/language" +import { formatReviewCommentsMarkdown } from "../../src/utils/review-comment-markdown" +import type { ReviewComment } from "../../src/types/messages" interface Props { terminalId: string @@ -279,6 +281,14 @@ export const TerminalTab: Component = (props) => { pendingFrame = requestAnimationFrame(runRepaint) } const fontSub = vscode.onMessage((message) => { + if (message.type === "appendReviewCommentsToTerminal") { + if (message.targetTerminalId !== props.terminalId) return + const comments = (message as { comments?: ReviewComment[] }).comments + if (!Array.isArray(comments) || comments.length === 0) return + term.paste(`${formatReviewCommentsMarkdown(comments)}\n`) + return + } + const size = message.type === "fontSizeChanged" ? message.fontSize : message.type === "ready" ? message.fontSize : undefined if (size === undefined) return diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts index 6fd8493b298..a7718ae35e4 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts @@ -243,6 +243,13 @@ export interface AppendReviewCommentsMessage { autoSend?: boolean } +export interface AppendReviewCommentsToTerminalMessage { + type: "appendReviewCommentsToTerminal" + comments: ReviewComment[] + autoSend?: boolean + targetTerminalId: string +} + export interface TriggerTaskMessage { type: "triggerTask" text: string @@ -958,6 +965,7 @@ export type ExtensionMessage = | SetChatBoxMessage | AppendChatBoxMessage | AppendReviewCommentsMessage + | AppendReviewCommentsToTerminalMessage | TriggerTaskMessage | VariantsLoadedMessage | CloudSessionDataLoadedMessage From 1daaa0a8deba344b0aa8865ac4eabe84c598b346 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Thu, 14 May 2026 14:21:21 +0200 Subject: [PATCH 2/2] fix(agent-manager): remove redundant terminal comments cast --- .../webview-ui/agent-manager/terminal/TerminalTab.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx b/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx index 57827df8bb3..14cb63a4de8 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx @@ -20,7 +20,6 @@ import "@xterm/xterm/css/xterm.css" import { useVSCode } from "../../src/context/vscode" import { useLanguage } from "../../src/context/language" import { formatReviewCommentsMarkdown } from "../../src/utils/review-comment-markdown" -import type { ReviewComment } from "../../src/types/messages" interface Props { terminalId: string @@ -283,7 +282,7 @@ export const TerminalTab: Component = (props) => { const fontSub = vscode.onMessage((message) => { if (message.type === "appendReviewCommentsToTerminal") { if (message.targetTerminalId !== props.terminalId) return - const comments = (message as { comments?: ReviewComment[] }).comments + const comments = message.comments if (!Array.isArray(comments) || comments.length === 0) return term.paste(`${formatReviewCommentsMarkdown(comments)}\n`) return