diff --git a/.changeset/sync-inspector-width.md b/.changeset/sync-inspector-width.md index 02eeb4e7239..9372f7ace4b 100644 --- a/.changeset/sync-inspector-width.md +++ b/.changeset/sync-inspector-width.md @@ -2,4 +2,4 @@ "kilo-code": patch --- -Persist the Agent Manager inspector width and share it between the terminal and diff viewer. +Persist the Agent Manager inspector width, share it between the terminal and diff viewer, and keep resizing responsive. diff --git a/packages/kilo-vscode/tests/unit/agent-manager-terminal-layout.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-terminal-layout.test.ts index a38ffbb7b99..185e7770c80 100644 --- a/packages/kilo-vscode/tests/unit/agent-manager-terminal-layout.test.ts +++ b/packages/kilo-vscode/tests/unit/agent-manager-terminal-layout.test.ts @@ -5,6 +5,10 @@ import { clampPanelWidth, maxPanelWidth, minPanelWidth } from "../../webview-ui/ const css = readFileSync(resolve(import.meta.dir, "../../webview-ui/agent-manager/agent-manager.css"), "utf8") const app = readFileSync(resolve(import.meta.dir, "../../webview-ui/agent-manager/AgentManagerApp.tsx"), "utf8") +const terminal = readFileSync( + resolve(import.meta.dir, "../../webview-ui/agent-manager/terminal/TerminalTab.tsx"), + "utf8", +) test("xterm owns the padding used by FitAddon", () => { const host = css.match(/\.am-terminal-host\s*\{([^}]*)\}/)?.[1] @@ -23,6 +27,18 @@ test("uses one persisted width for the diff and terminal inspector", () => { expect(app).not.toContain("terminalWidth") }) +test("limits inspector layout updates during resize", () => { + expect(app).toContain("SIDE_RESIZE_INTERVAL_MS = 32") + expect(app).toContain("time - sideResizeTime < SIDE_RESIZE_INTERVAL_MS") +}) + +test("does not refit hidden terminal buffers during resize", () => { + const callback = terminal.match(/const ro = new ResizeObserver\(\(\) => \{([\s\S]*?)\n \}\)/)?.[1] + expect(callback).toBeDefined() + expect(callback).toContain("if (!props.active) return") + expect(callback!.indexOf("if (!props.active) return")).toBeLessThan(callback!.indexOf("fit.fit()")) +}) + test("clamps the restored inspector width to the shared layout bounds", () => { expect(clampPanelWidth(undefined, 1200)).toBe(600) expect(clampPanelWidth(500, 1200)).toBe(500) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx index a68c1099f47..b69f95f8bf8 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx @@ -200,6 +200,7 @@ type SidePanel = "diff" | "pr" | "terminal" | null const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.userAgent) // Fallback keybindings before extension sends resolved ones const MAX_JUMP_INDEX = 9 +const SIDE_RESIZE_INTERVAL_MS = 32 const defaultBindings: Record = { previousSession: isMac ? "⌘⌥↑" : "Ctrl+Alt+↑", @@ -308,6 +309,7 @@ const AgentManagerContent: Component = () => { let pendingSidebarWidth: number | undefined let sideRaf: number | undefined let pendingSideWidth: number | undefined + let sideResizeTime = 0 const [history, setHistory] = createSignal(false) const [sidePanel, setSidePanel] = createSignal(null) @@ -323,10 +325,16 @@ const AgentManagerContent: Component = () => { const resizeSide = (width: number) => { pendingSideWidth = clampPanelWidth(width, window.innerWidth) if (sideRaf !== undefined) return - sideRaf = requestAnimationFrame(() => { + const flush = (time: number) => { + if (time - sideResizeTime < SIDE_RESIZE_INTERVAL_MS) { + sideRaf = requestAnimationFrame(flush) + return + } sideRaf = undefined + sideResizeTime = time setPanelWidth(pendingSideWidth!) - }) + } + sideRaf = requestAnimationFrame(flush) } const showSideTerminal = () => { setHistory(false) 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 8b6e2956b78..f6fcd115403 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx @@ -377,9 +377,9 @@ export const TerminalTab: Component = (props) => { open(url) } - // Resize: fit on any host size change and forward new cols/rows to - // the backend PTY. Debounced because a user drag can fire dozens of - // resize events per second. + // Resize the visible terminal and forward new cols/rows to the backend + // PTY. Hidden terminals refit when activated, avoiding scrollback reflow + // for every mounted terminal during an inspector drag. let resizeTimer: ReturnType | undefined let lastCols = term.cols let lastRows = term.rows @@ -395,6 +395,7 @@ export const TerminalTab: Component = (props) => { }) } const ro = new ResizeObserver(() => { + if (!props.active) return try { fit.fit() } catch (err) {