diff --git a/packages/cli/src/ui/components/StickyHeader.tsx b/packages/cli/src/ui/components/StickyHeader.tsx index 62d5dcd22d..9c44c76855 100644 --- a/packages/cli/src/ui/components/StickyHeader.tsx +++ b/packages/cli/src/ui/components/StickyHeader.tsx @@ -67,7 +67,6 @@ export const StickyHeader: React.FC = ({ borderLeft={true} borderRight={true} paddingX={1} - paddingBottom={1} paddingTop={isFirst ? 0 : 1} > {children} diff --git a/packages/cli/src/ui/components/ToolConfirmationQueue.tsx b/packages/cli/src/ui/components/ToolConfirmationQueue.tsx index e5294e9614..1fa34a6641 100644 --- a/packages/cli/src/ui/components/ToolConfirmationQueue.tsx +++ b/packages/cli/src/ui/components/ToolConfirmationQueue.tsx @@ -66,9 +66,9 @@ export const ToolConfirmationQueue: React.FC = ({ // ToolConfirmationMessage needs to know the height available for its OWN content. // We subtract the lines used by the Queue wrapper: - // - 2 lines for the rounded border + // - 2 lines for the rounded border (top/bottom) // - 2 lines for the Header (text + margin) - // - 2 lines for Tool Identity (text + margin) + // - 2 lines for Tool Identity (text + margin) if shown const availableContentHeight = constrainHeight ? Math.max(maxHeight - (hideToolIdentity ? 4 : 6), 4) : undefined; @@ -83,10 +83,7 @@ export const ToolConfirmationQueue: React.FC = ({ > {/* Header */} - + {getConfirmationHeader(tool.confirmationDetails)} @@ -98,7 +95,7 @@ export const ToolConfirmationQueue: React.FC = ({ {!hideToolIdentity && ( - + MainContent Tool Output Height Logic > 'Normal mode - Con ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command Running a long command... │ │ │ -│ ... first 10 lines hidden (Ctrl+O to show) ... │ -│ Line 11 │ +│ ... first 11 lines hidden (Ctrl+O to show) ... │ │ Line 12 │ │ Line 13 │ │ Line 14 │ diff --git a/packages/cli/src/ui/components/messages/ShellToolMessage.tsx b/packages/cli/src/ui/components/messages/ShellToolMessage.tsx index f3694f3490..533850f6d5 100644 --- a/packages/cli/src/ui/components/messages/ShellToolMessage.tsx +++ b/packages/cli/src/ui/components/messages/ShellToolMessage.tsx @@ -190,6 +190,7 @@ export const ShellToolMessage: React.FC = ({ borderLeft={true} borderRight={true} paddingX={1} + paddingTop={1} flexDirection="column" > ', () => { ]; const item = createItem(toolCalls); const { lastFrame, unmount } = await renderWithProviders( - + , { diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 7aadaf8e26..65ef9d41d0 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -222,38 +222,41 @@ export const ToolGroupMessage: React.FC = ({ !Array.isArray(prevGroup) && isCompactTool(prevGroup, isCompactModeEnabled); - if (Array.isArray(group)) { + const isAgentGroup = Array.isArray(group); + const isCompact = + !isAgentGroup && isCompactTool(group, isCompactModeEnabled); + + if (isFirst) { + height += (borderTopOverride ?? false) ? 1 : 0; + } else if (isCompact && prevIsCompact) { + height += 0; + } else if (isCompact || prevIsCompact) { + height += 1; + } else { + // Gap is provided by StickyHeader's paddingTop=1 + height += 0; + } + + const isFirstProp = !!(isFirst + ? (borderTopOverride ?? true) + : prevIsCompact); + + if (isAgentGroup) { // Agent group height += 1; // Header height += group.length; // 1 line per agent - const isFirstProp = isFirst - ? (borderTopOverride ?? true) - : prevIsCompact; if (isFirstProp) height += 1; // Top border - - // Spacing logic - if (isFirst) { - height += (borderTopOverride ?? true) ? 1 : 0; - } else { - height += 1; // marginTop - } } else { - const isCompact = isCompactTool(group, isCompactModeEnabled); if (isCompact) { height += 1; // Base height for compact tool - // Spacing logic (matching marginTop) - if (isFirst) { - height += (borderTopOverride ?? true) ? 1 : 0; - } else if (!prevIsCompact) { - height += 1; - } } else { - height += 3; // Static overhead for standard tool - if (isFirst) { - height += (borderTopOverride ?? true) ? 1 : 0; - } else { - height += 1; // marginTop is always 1 for non-compact tools (not first) - } + // Static overhead for standard tool header: + // 1 line for header text + // 1 line for dark separator + // 1 line for tool body internal paddingTop=1 + // 1 line for top border (if isFirstProp) OR StickyHeader paddingTop=1 (if !isFirstProp) + height += 3; + height += isFirstProp ? 1 : 1; // Either top border or paddingTop } } } @@ -351,12 +354,14 @@ export const ToolGroupMessage: React.FC = ({ let marginTop = 0; if (isFirst) { - // marginTop = (borderTopOverride ?? true) ? 1 : 0; marginTop = (borderTopOverride ?? false) ? 1 : 0; } else if (isCompact && prevIsCompact) { marginTop = 0; - } else { + } else if (isCompact || prevIsCompact) { marginTop = 1; + } else { + // Subsequent standard tools: StickyHeader's paddingTop=1 provides the gap. + marginTop = 0; } const isFirstProp = !!(isFirst diff --git a/packages/cli/src/ui/components/messages/ToolMessage.tsx b/packages/cli/src/ui/components/messages/ToolMessage.tsx index 5747f7677f..3f3f01778f 100644 --- a/packages/cli/src/ui/components/messages/ToolMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolMessage.tsx @@ -119,6 +119,7 @@ export const ToolMessage: React.FC = ({ borderLeft={true} borderRight={true} paddingX={1} + paddingTop={1} flexDirection="column" > {status === CoreToolCallStatus.Executing && progress !== undefined && ( diff --git a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx index 3a2ca1b2ed..2b05eb453b 100644 --- a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx +++ b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx @@ -179,10 +179,16 @@ export const ToolResultDisplay: React.FC = ({ // Final render based on session mode if (isAlternateBuffer) { + // If availableTerminalHeight is undefined, we don't have a fixed budget, + // so if maxLines is also undefined, we shouldn't cap the height at all. + const effectiveMaxHeight = + maxLines ?? + (availableTerminalHeight !== undefined ? availableHeight : undefined); + return ( > Height Constraints > defaults to ACTIVE_SHELL_MA "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command │ │ │ -│ Line 90 │ │ Line 91 │ │ Line 92 │ │ Line 93 │ @@ -129,7 +128,6 @@ exports[` > Height Constraints > respects availableTerminalH "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command │ │ │ -│ Line 94 │ │ Line 95 │ │ Line 96 │ │ Line 97 │ @@ -143,7 +141,6 @@ exports[` > Height Constraints > stays constrained in altern "╭──────────────────────────────────────────────────────────────────────────────╮ │ ✓ Shell Command A shell command │ │ │ -│ Line 90 │ │ Line 91 │ │ Line 92 │ │ Line 93 │ @@ -161,7 +158,6 @@ exports[` > Height Constraints > uses ACTIVE_SHELL_MAX_LINES "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command │ │ │ -│ Line 90 │ │ Line 91 │ │ Line 92 │ │ Line 93 │ @@ -179,11 +175,10 @@ exports[` > Height Constraints > uses full availableTerminal "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command (Shift+Tab to unfocus) │ │ │ -│ Line 4 │ │ Line 5 │ │ Line 6 │ -│ Line 7 █ │ -│ Line 8 █ │ +│ Line 7 │ +│ Line 8 │ │ Line 9 █ │ │ Line 10 █ │ │ Line 11 █ │ diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap index 6980837725..6fe4e28b70 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolGroupMessage.test.tsx.snap @@ -32,7 +32,6 @@ exports[` > Border Color Logic > uses gray border when all t │ ✓ test-tool A tool for testing │ │ │ │ Test result │ - │ │ │ ✓ another-tool A tool for testing │ │ │ @@ -62,10 +61,12 @@ exports[` > Golden Snapshots > renders canceled tool calls > exports[` > Golden Snapshots > renders empty tool calls array 1`] = `""`; exports[` > Golden Snapshots > renders header when scrolled 1`] = ` -"│ ✓ tool-1 Description 1. This is a long description that will need to b… │ -│──────────────────────────────────────────────────────────────────────────│ - -│ │ ▄ +"╭──────────────────────────────────────────────────────────────────────────╮ +│ ✓ tool-1 Description 1. This is a long description that will need to b… │ +│──────────────────────────────────────────────────────────────────────────│ ▄ +│ line4 │ █ +│ line5 │ █ +│ │ █ │ ✓ tool-2 Description 2 │ █ │ │ █ │ line1 │ █ @@ -80,12 +81,10 @@ exports[` > Golden Snapshots > renders mixed tool calls incl │ ✓ read_file Read a file │ │ │ │ Test result │ - │ │ │ ⊶ run_shell_command Run command │ │ │ │ Test result │ - │ │ │ o write_file Write to file │ │ │ @@ -99,12 +98,10 @@ exports[` > Golden Snapshots > renders multiple tool calls w │ ✓ successful-tool This tool succeeded │ │ │ │ Test result │ - │ │ │ o pending-tool This tool is pending │ │ │ │ Test result │ - │ │ │ x error-tool This tool failed │ │ │ @@ -147,7 +144,6 @@ exports[` > Golden Snapshots > renders with limited terminal │ ✓ tool-with-result Tool with output │ │ │ │ This is a long result that might need height constraints │ - │ │ │ ✓ another-tool Another tool │ │ │ @@ -170,12 +166,10 @@ exports[` > Height Calculation > calculates available height │ ✓ test-tool A tool for testing │ │ │ │ Result 1 │ - │ │ │ ✓ test-tool A tool for testing │ │ │ │ Result 2 │ - │ │ │ ✓ test-tool A tool for testing │ │ │ diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap index e34e66cc48..f4b3a35884 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap @@ -37,8 +37,7 @@ exports[`ToolResultDisplay > renders string result as plain text when renderOutp `; exports[`ToolResultDisplay > truncates very long string results 1`] = ` -"... 249 hidden (Ctrl+O) ... -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"... 250 hidden (Ctrl+O) ... aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolStickyHeaderRegression.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolStickyHeaderRegression.test.tsx.snap index 16627ec220..66ca527b4b 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ToolStickyHeaderRegression.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolStickyHeaderRegression.test.tsx.snap @@ -40,7 +40,7 @@ exports[`ToolMessage Sticky Header Regression > verifies that multiple ToolMessa "│ │ │ ✓ tool-2 Description for tool-2 │ │────────────────────────────────────────────────────────────────────────│ -│ c2-09 │ ▄ -│ c2-10 │ ▀ +│ c2-10 │ +╰────────────────────────────────────────────────────────────────────────╯ █ " `; diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index 1f140b9bc9..e45be2c840 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -17,7 +17,7 @@ import { CoreToolCallStatus } from '@google/gemini-cli-core'; */ export const TOOL_RESULT_STATIC_HEIGHT = 1; export const TOOL_RESULT_ASB_RESERVED_LINE_COUNT = 6; -export const TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT = 3; +export const TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT = 4; export const TOOL_RESULT_MIN_LINES_SHOWN = 2; /**