From ab8c24f5eab534697f26cf7da7a4f182c7665f3e Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Fri, 31 Oct 2025 07:43:12 -0700 Subject: [PATCH] Fixes for Ink 6.4.0 (#12352) --- packages/cli/src/test-utils/render.tsx | 25 ++++++- .../ui/components/LoadingIndicator.test.tsx | 1 + .../src/ui/components/LoadingIndicator.tsx | 5 +- .../LoopDetectionConfirmation.test.tsx | 2 + .../components/LoopDetectionConfirmation.tsx | 62 ++++++++--------- .../src/ui/components/PrepareLabel.test.tsx | 4 +- .../ShellConfirmationDialog.test.tsx | 2 + .../ui/components/ShellConfirmationDialog.tsx | 66 ++++++++++--------- .../src/ui/components/SuggestionsDisplay.tsx | 2 +- .../__snapshots__/InputPrompt.test.tsx.snap | 16 ++--- .../LoadingIndicator.test.tsx.snap | 4 +- .../__snapshots__/PrepareLabel.test.tsx.snap | 2 +- 12 files changed, 114 insertions(+), 77 deletions(-) diff --git a/packages/cli/src/test-utils/render.tsx b/packages/cli/src/test-utils/render.tsx index 0413c4a46d..8fc0f5308f 100644 --- a/packages/cli/src/test-utils/render.tsx +++ b/packages/cli/src/test-utils/render.tsx @@ -5,6 +5,7 @@ */ import { render as inkRender } from 'ink-testing-library'; +import { Box } from 'ink'; import type React from 'react'; import { act } from 'react'; import { LoadedSettings, type Settings } from '../config/settings.js'; @@ -22,6 +23,7 @@ import { type Config } from '@google/gemini-cli-core'; // Wrapper around ink-testing-library's render that ensures act() is called export const render = ( tree: React.ReactElement, + terminalWidth?: number, ): ReturnType => { let renderResult: ReturnType = undefined as unknown as ReturnType; @@ -29,6 +31,19 @@ export const render = ( renderResult = inkRender(tree); }); + if (terminalWidth !== undefined && renderResult?.stdout) { + // Override the columns getter on the stdout instance provided by ink-testing-library + Object.defineProperty(renderResult.stdout, 'columns', { + get: () => terminalWidth, + configurable: true, + }); + + // Trigger a rerender so Ink can pick up the new terminal width + act(() => { + renderResult.rerender(tree); + }); + } + const originalUnmount = renderResult.unmount; const originalRerender = renderResult.rerender; @@ -148,13 +163,21 @@ export const renderWithProviders = ( - {component} + + {component} + , + terminalWidth, ); }; diff --git a/packages/cli/src/ui/components/LoadingIndicator.test.tsx b/packages/cli/src/ui/components/LoadingIndicator.test.tsx index db7a410e23..f56fe80039 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.test.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.test.tsx @@ -47,6 +47,7 @@ const renderWithContext = ( {ui} , + width, ); }; diff --git a/packages/cli/src/ui/components/LoadingIndicator.tsx b/packages/cli/src/ui/components/LoadingIndicator.tsx index ed089fe0fd..bd0b7e81f9 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.tsx @@ -67,7 +67,10 @@ export const LoadingIndicator: React.FC = ({ )} {!isNarrow && cancelAndTimerContent && ( - {cancelAndTimerContent} + <> + + {cancelAndTimerContent} + )} {!isNarrow && {/* Spacer */}} diff --git a/packages/cli/src/ui/components/LoopDetectionConfirmation.test.tsx b/packages/cli/src/ui/components/LoopDetectionConfirmation.test.tsx index 87b57033ee..1e7d579a02 100644 --- a/packages/cli/src/ui/components/LoopDetectionConfirmation.test.tsx +++ b/packages/cli/src/ui/components/LoopDetectionConfirmation.test.tsx @@ -14,6 +14,7 @@ describe('LoopDetectionConfirmation', () => { it('renders correctly', () => { const { lastFrame } = renderWithProviders( , + { width: 101 }, ); expect(lastFrame()).toMatchSnapshot(); }); @@ -21,6 +22,7 @@ describe('LoopDetectionConfirmation', () => { it('contains the expected options', () => { const { lastFrame } = renderWithProviders( , + { width: 100 }, ); const output = lastFrame()!.toString(); diff --git a/packages/cli/src/ui/components/LoopDetectionConfirmation.tsx b/packages/cli/src/ui/components/LoopDetectionConfirmation.tsx index 2439367d84..d1393e7bee 100644 --- a/packages/cli/src/ui/components/LoopDetectionConfirmation.tsx +++ b/packages/cli/src/ui/components/LoopDetectionConfirmation.tsx @@ -50,37 +50,39 @@ export function LoopDetectionConfirmation({ ]; return ( - - - - - - ? - + + + + + + + ? + + + + + + A potential loop was detected + {' '} + + - - - - A potential loop was detected - {' '} - - - - - - - This can happen due to repetitive tool calls or other model - behavior. Do you want to keep loop detection enabled or disable it - for this session? - - - + + + + This can happen due to repetitive tool calls or other model + behavior. Do you want to keep loop detection enabled or disable + it for this session? + + + + diff --git a/packages/cli/src/ui/components/PrepareLabel.test.tsx b/packages/cli/src/ui/components/PrepareLabel.test.tsx index c34090661c..5c06817836 100644 --- a/packages/cli/src/ui/components/PrepareLabel.test.tsx +++ b/packages/cli/src/ui/components/PrepareLabel.test.tsx @@ -73,13 +73,14 @@ describe('PrepareLabel', () => { textColor={color} isExpanded={true} />, + 100, ); expect(lastFrame()).toMatchSnapshot(); unmount(); }); it('creates centered window around match when collapsed', () => { - const prefix = 'cd /very/long/path/that/keeps/going/'.repeat(3); + const prefix = 'cd_/very/long/path/that/keeps/going/'.repeat(3); const core = 'search-here'; const suffix = '/and/then/some/more/components/'.repeat(3); const label = prefix + core + suffix; @@ -92,6 +93,7 @@ describe('PrepareLabel', () => { textColor={color} isExpanded={false} />, + 100, ); const out = lastFrame(); const f = flat(out); diff --git a/packages/cli/src/ui/components/ShellConfirmationDialog.test.tsx b/packages/cli/src/ui/components/ShellConfirmationDialog.test.tsx index bacf055fa5..fb656b613f 100644 --- a/packages/cli/src/ui/components/ShellConfirmationDialog.test.tsx +++ b/packages/cli/src/ui/components/ShellConfirmationDialog.test.tsx @@ -19,6 +19,7 @@ describe('ShellConfirmationDialog', () => { it('renders correctly', () => { const { lastFrame } = renderWithProviders( , + { width: 101 }, ); expect(lastFrame()).toMatchSnapshot(); }); @@ -45,6 +46,7 @@ describe('ShellConfirmationDialog', () => { it('calls onConfirm with Cancel when "No (esc)" is selected', () => { const { lastFrame } = renderWithProviders( , + { width: 100 }, ); const select = lastFrame()!.toString(); // Simulate selecting the third option diff --git a/packages/cli/src/ui/components/ShellConfirmationDialog.tsx b/packages/cli/src/ui/components/ShellConfirmationDialog.tsx index a9e9cd47e7..18613d888f 100644 --- a/packages/cli/src/ui/components/ShellConfirmationDialog.tsx +++ b/packages/cli/src/ui/components/ShellConfirmationDialog.tsx @@ -68,41 +68,43 @@ export const ShellConfirmationDialog: React.FC< ]; return ( - - - - Shell Command Execution - - - A custom command wants to run the following shell commands: - - - {commands.map((cmd) => ( - - - - ))} + + + + + Shell Command Execution + + + A custom command wants to run the following shell commands: + + + {commands.map((cmd) => ( + + + + ))} + - - - Do you want to proceed? - + + Do you want to proceed? + - + + ); }; diff --git a/packages/cli/src/ui/components/SuggestionsDisplay.tsx b/packages/cli/src/ui/components/SuggestionsDisplay.tsx index 7d7c405471..1a8c7cab81 100644 --- a/packages/cli/src/ui/components/SuggestionsDisplay.tsx +++ b/packages/cli/src/ui/components/SuggestionsDisplay.tsx @@ -112,7 +112,7 @@ export function SuggestionsDisplay({ )} {isActive && isLong && ( - + {isExpanded ? ' ← ' : ' → '} )} diff --git a/packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap index cd2cbb17d2..3fe5d2a2a7 100644 --- a/packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/InputPrompt.test.tsx.snap @@ -2,7 +2,7 @@ exports[`InputPrompt > command search (Ctrl+R when not in shell) > expands and collapses long suggestion via Right/Left arrows > command-search-render-collapsed-match 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ (r:) Type your message or @path/to/file │ +│ (r:) Type your message or @path/to/file │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll → lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll @@ -11,7 +11,7 @@ exports[`InputPrompt > command search (Ctrl+R when not in shell) > expands and c exports[`InputPrompt > command search (Ctrl+R when not in shell) > expands and collapses long suggestion via Right/Left arrows > command-search-render-expanded-match 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ (r:) Type your message or @path/to/file │ +│ (r:) Type your message or @path/to/file │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll ← lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll @@ -20,38 +20,38 @@ exports[`InputPrompt > command search (Ctrl+R when not in shell) > expands and c exports[`InputPrompt > command search (Ctrl+R when not in shell) > renders match window and expanded view (snapshots) > command-search-render-collapsed-match 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ (r:) commit │ +│ (r:) commit │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ git commit -m "feat: add search" in src/app" `; exports[`InputPrompt > command search (Ctrl+R when not in shell) > renders match window and expanded view (snapshots) > command-search-render-expanded-match 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ (r:) commit │ +│ (r:) commit │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ git commit -m "feat: add search" in src/app" `; exports[`InputPrompt > snapshots > should not show inverted cursor when shell is focused 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ > Type your message or @path/to/file │ +│ > Type your message or @path/to/file │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯" `; exports[`InputPrompt > snapshots > should render correctly in shell mode 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ! Type your message or @path/to/file │ +│ ! Type your message or @path/to/file │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯" `; exports[`InputPrompt > snapshots > should render correctly in yolo mode 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ * Type your message or @path/to/file │ +│ * Type your message or @path/to/file │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯" `; exports[`InputPrompt > snapshots > should render correctly when accepting edits 1`] = ` "╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ > Type your message or @path/to/file │ +│ > Type your message or @path/to/file │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯" `; diff --git a/packages/cli/src/ui/components/__snapshots__/LoadingIndicator.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/LoadingIndicator.test.tsx.snap index 3d472f97e2..e2aa300572 100644 --- a/packages/cli/src/ui/components/__snapshots__/LoadingIndicator.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/LoadingIndicator.test.tsx.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[` > should truncate long primary text instead of wrapping 1`] = ` -"MockResponding This is an extremely long loading phrase that should be truncated in t (esc to -Spinner cancel, 5s)" +"MockRespondin This is an extremely long loading phrase that shoul… (esc to +gSpinner cancel, 5s)" `; diff --git a/packages/cli/src/ui/components/__snapshots__/PrepareLabel.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/PrepareLabel.test.tsx.snap index a5e7a067c0..86c2da9f20 100644 --- a/packages/cli/src/ui/components/__snapshots__/PrepareLabel.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/PrepareLabel.test.tsx.snap @@ -1,7 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`PrepareLabel > creates centered window around match when collapsed 1`] = ` -"...ry/long/path/that/keeps/going/cd /very/long/path/that/keeps/going/search-here/and/then/some/more/ +"...ry/long/path/that/keeps/going/cd_/very/long/path/that/keeps/going/search-here/and/then/some/more/ components//and/then/some/more/components//and/..." `;