feat(ui): Re-apply Dense Tool Output features

This commit is contained in:
Jarrod Whelan
2026-02-09 20:46:37 -08:00
parent eb94284256
commit 142ccf2140
27 changed files with 1165 additions and 621 deletions

View File

@@ -171,6 +171,18 @@ describe('<HistoryItemDisplay />', () => {
expect(lastFrame()).toContain('Agent powering down. Goodbye!');
});
it('renders InfoMessage for "debug" type with gear icon', () => {
const item: HistoryItem = {
...baseItem,
type: MessageType.DEBUG,
text: 'Debug info',
};
const { lastFrame } = renderWithProviders(
<HistoryItemDisplay {...baseItem} item={item} />,
);
expect(lastFrame()).toContain('⚙ Debug info');
});
it('should escape ANSI codes in text content', () => {
const historyItem: HistoryItem = {
id: 1,

View File

@@ -18,6 +18,7 @@ import { GeminiMessageContent } from './messages/GeminiMessageContent.js';
import { CompressionMessage } from './messages/CompressionMessage.js';
import { WarningMessage } from './messages/WarningMessage.js';
import { Box } from 'ink';
import { theme } from '../semantic-colors.js';
import { AboutBox } from './AboutBox.js';
import { StatsDisplay } from './StatsDisplay.js';
import { ModelStatsDisplay } from './ModelStatsDisplay.js';
@@ -96,6 +97,27 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
color={itemForDisplay.color}
/>
)}
{itemForDisplay.type === 'verbose' && (
<InfoMessage
text={itemForDisplay.text}
icon={itemForDisplay.icon || ' '}
color={theme.text.secondary}
/>
)}
{itemForDisplay.type === 'debug' && (
<InfoMessage
text={itemForDisplay.text}
icon={'⚙ '}
color={theme.text.accent}
/>
)}
{itemForDisplay.type === 'trace' && (
<InfoMessage
text={itemForDisplay.text}
icon={'🔍 '}
color={theme.text.accent}
/>
)}
{itemForDisplay.type === 'warning' && (
<WarningMessage text={itemForDisplay.text} />
)}

View File

@@ -7,13 +7,14 @@
import { renderWithProviders } from '../../test-utils/render.js';
import { waitFor } from '../../test-utils/async.js';
import { MainContent } from './MainContent.js';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { Box, Text } from 'ink';
import type React from 'react';
import { useAlternateBuffer } from '../hooks/useAlternateBuffer.js';
import { ToolCallStatus } from '../types.js';
import { SHELL_COMMAND_NAME } from '../constants.js';
import type { UIState } from '../contexts/UIStateContext.js';
import type { HistoryItem } from '../types.js';
// Mock dependencies
vi.mock('../contexts/AppContext.js', async () => {
@@ -26,6 +27,23 @@ vi.mock('../contexts/AppContext.js', async () => {
};
});
const mockSettings = {
merged: {
output: {
verbosity: 'info',
},
},
};
vi.mock('../contexts/SettingsContext.js', async (importOriginal) => {
const actual =
await importOriginal<typeof import('../contexts/SettingsContext.js')>();
return {
...actual,
useSettings: () => mockSettings,
};
});
vi.mock('../hooks/useAlternateBuffer.js', () => ({
useAlternateBuffer: vi.fn(),
}));
@@ -78,6 +96,11 @@ describe('MainContent', () => {
beforeEach(() => {
vi.mocked(useAlternateBuffer).mockReturnValue(false);
mockSettings.merged.output.verbosity = 'info';
});
afterEach(() => {
vi.clearAllMocks();
});
it('renders in normal buffer mode', async () => {
@@ -221,4 +244,38 @@ describe('MainContent', () => {
},
);
});
it('filters out verbose items when verbosity is info', async () => {
const history: HistoryItem[] = [
{ id: 1, type: 'user', text: 'Visible User Message' },
{ id: 2, type: 'verbose', text: 'Hidden Verbose Log' },
];
mockSettings.merged.output.verbosity = 'info';
const { lastFrame } = renderWithProviders(<MainContent />, {
uiState: { ...defaultMockUiState, history } as Partial<UIState>,
});
await waitFor(() => expect(lastFrame()).toContain('AppHeader'));
const output = lastFrame();
expect(output).toContain('Visible User Message');
expect(output).not.toContain('Hidden Verbose Log');
});
it('shows verbose items when verbosity is verbose', async () => {
const history: HistoryItem[] = [
{ id: 1, type: 'user', text: 'Visible User Message' },
{ id: 2, type: 'verbose', text: 'Visible Verbose Log' },
];
mockSettings.merged.output.verbosity = 'verbose';
const { lastFrame } = renderWithProviders(<MainContent />, {
uiState: { ...defaultMockUiState, history } as Partial<UIState>,
});
await waitFor(() => expect(lastFrame()).toContain('AppHeader'));
const output = lastFrame();
expect(output).toContain('Visible User Message');
expect(output).toContain('Visible Verbose Log');
});
});

View File

@@ -20,6 +20,8 @@ import { MAX_GEMINI_MESSAGE_LINES } from '../constants.js';
import { useConfirmingTool } from '../hooks/useConfirmingTool.js';
import { ToolConfirmationQueue } from './ToolConfirmationQueue.js';
import { useConfig } from '../contexts/ConfigContext.js';
import { VERBOSITY_MAPPING, Verbosity } from '../types.js';
import { useSettings } from '../contexts/SettingsContext.js';
const MemoizedHistoryItemDisplay = memo(HistoryItemDisplay);
const MemoizedAppHeader = memo(AppHeader);
@@ -32,6 +34,7 @@ export const MainContent = () => {
const { version } = useAppContext();
const uiState = useUIState();
const config = useConfig();
const settings = useSettings();
const isAlternateBuffer = useAlternateBuffer();
const confirmingTool = useConfirmingTool();
@@ -53,9 +56,24 @@ export const MainContent = () => {
availableTerminalHeight,
} = uiState;
const currentVerbosity =
VERBOSITY_MAPPING[settings.merged.output?.verbosity ?? 'info'] ??
Verbosity.INFO;
const filteredHistory = useMemo(
() =>
uiState.history.filter((item) => {
const itemType = item.type;
const itemVerbosity =
item.verbosity ?? VERBOSITY_MAPPING[itemType] ?? Verbosity.INFO;
return itemVerbosity <= currentVerbosity;
}),
[uiState.history, currentVerbosity],
);
const historyItems = useMemo(
() =>
uiState.history.map((h) => (
filteredHistory.map((h) => (
<MemoizedHistoryItemDisplay
terminalWidth={mainAreaWidth}
availableTerminalHeight={staticAreaMaxItemHeight}
@@ -67,7 +85,7 @@ export const MainContent = () => {
/>
)),
[
uiState.history,
filteredHistory,
mainAreaWidth,
staticAreaMaxItemHeight,
uiState.slashCommands,
@@ -116,10 +134,10 @@ export const MainContent = () => {
const virtualizedData = useMemo(
() => [
{ type: 'header' as const },
...uiState.history.map((item) => ({ type: 'history' as const, item })),
...filteredHistory.map((item) => ({ type: 'history' as const, item })),
{ type: 'pending' as const },
],
[uiState.history],
[filteredHistory],
);
const renderItem = useCallback(

View File

@@ -1,28 +1,5 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`AlternateBufferQuittingDisplay > renders with a tool awaiting confirmation > with_confirming_tool 1`] = `
"
███ █████████
░░░███ ███░░░░░███
░░░███ ███ ░░░
░░░███░███
███░ ░███ █████
███░ ░░███ ░░███
███░ ░░█████████
░░░ ░░░░░░░░░
Tips for getting started:
1. Ask questions, edit files, or run commands.
2. Be specific for the best results.
3. Create GEMINI.md files to customize your interactions with Gemini.
4. /help for more information.
Action Required (was prompted):
? confirming_tool Confirming tool description
"
`;
exports[`AlternateBufferQuittingDisplay > renders with active and pending tool messages > with_history_and_pending 1`] = `
"
███ █████████
@@ -39,14 +16,21 @@ Tips for getting started:
2. Be specific for the best results.
3. Create GEMINI.md files to customize your interactions with Gemini.
4. /help for more information.
╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ tool1 Description for tool 1 │
│ │
╰──────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ tool2 Description for tool 2 │
╰──────────────────────────────────────────────────────────────────────────╯"
╭─────────────────────────────────────────────────────────────────────────────
│ ✓ tool1 Description for tool 1
╰─────────────────────────────────────────────────────────────────────────────
╭─────────────────────────────────────────────────────────────────────────────╮
tool2 Description for tool 2
│ │
╰─────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────────────────────────────────────────────────────╮
│ o tool3 Description for tool 3 │
│ │
╰─────────────────────────────────────────────────────────────────────────────╯
"
`;
exports[`AlternateBufferQuittingDisplay > renders with empty history and no pending items > empty 1`] = `
@@ -83,14 +67,16 @@ Tips for getting started:
2. Be specific for the best results.
3. Create GEMINI.md files to customize your interactions with Gemini.
4. /help for more information.
╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ tool1 Description for tool 1 │
│ │
╰──────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ tool2 Description for tool 2 │
╰──────────────────────────────────────────────────────────────────────────╯"
╭─────────────────────────────────────────────────────────────────────────────
│ ✓ tool1 Description for tool 1
╰─────────────────────────────────────────────────────────────────────────────
╭─────────────────────────────────────────────────────────────────────────────╮
tool2 Description for tool 2
│ │
╰─────────────────────────────────────────────────────────────────────────────╯
"
`;
exports[`AlternateBufferQuittingDisplay > renders with pending items but no history > with_pending_no_history 1`] = `
@@ -108,7 +94,12 @@ Tips for getting started:
1. Ask questions, edit files, or run commands.
2. Be specific for the best results.
3. Create GEMINI.md files to customize your interactions with Gemini.
4. /help for more information."
4. /help for more information.
╭─────────────────────────────────────────────────────────────────────────────╮
│ o tool3 Description for tool 3 │
│ │
╰─────────────────────────────────────────────────────────────────────────────╯
"
`;
exports[`AlternateBufferQuittingDisplay > renders with user and gemini messages > with_user_gemini_messages 1`] = `
@@ -127,9 +118,8 @@ Tips for getting started:
2. Be specific for the best results.
3. Create GEMINI.md files to customize your interactions with Gemini.
4. /help for more information.
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
> Hello Gemini
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
✦ Hello User!
"
> Hello Gemini
✦ Hello User!"
`;

View File

@@ -28,7 +28,8 @@ AppHeader
│ Line 20 │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
ShowMoreLines"
ShowMoreLines
"
`;
exports[`MainContent > MainContent Tool Output Height Logic > 'ASB mode - Unfocused shell' 1`] = `
@@ -53,7 +54,8 @@ AppHeader
│ Line 19 █ │
│ Line 20 █ │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
ShowMoreLines"
ShowMoreLines
"
`;
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Constrained height' 1`] = `
@@ -77,7 +79,8 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Con
│ Line 19 │
│ Line 20 │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
ShowMoreLines"
ShowMoreLines
"
`;
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unconstrained height' 1`] = `
@@ -101,7 +104,8 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unc
│ Line 19 │
│ Line 20 │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
ShowMoreLines"
ShowMoreLines
"
`;
exports[`MainContent > does not constrain height in alternate buffer mode 1`] = `

View File

@@ -10,236 +10,9 @@ exports[`SettingsDialog > Initial Rendering > should render settings list with v
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode false │
│ Enable Vim keybindings
│ ● Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models).
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Auto Theme Switching true │
│ Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'accessibility settings enabled' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode true* │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Auto Theme Switching true │
│ Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'all boolean settings disabled' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode false* │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true* │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false* │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false* │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Auto Theme Switching true │
│ Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'default state' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode false │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Auto Theme Switching true │
│ Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'file filtering settings configured' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode false │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Auto Theme Switching true │
│ Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'focused on scope selector' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ Vim Mode false │
│ Enable Vim keybindings │
│ │
@@ -258,57 +31,8 @@ exports[`SettingsDialog > Snapshot Tests > should render 'focused on scope selec
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
Auto Theme Switching true │
Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
│ │
│ ▼ │
│ │
│ > Apply To │
│ ● 1. User Settings │
│ 2. Workspace Settings │
│ 3. System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'mixed boolean and number settings' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode false* │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update false* │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Auto Theme Switching true │
│ Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
Verbose Output History true │
Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
@@ -317,12 +41,12 @@ exports[`SettingsDialog > Snapshot Tests > should render 'mixed boolean and numb
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ (Use Enter to select, Tab to change focus, Esc to close)
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'tools and security settings' correctly 1`] = `
exports[`SettingsDialog > Snapshot Tests > should render 'accessibility settings enabled' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
@@ -332,7 +56,10 @@ exports[`SettingsDialog > Snapshot Tests > should render 'tools and security set
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode false │
│ ● Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode true* │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
@@ -350,11 +77,8 @@ exports[`SettingsDialog > Snapshot Tests > should render 'tools and security set
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
Auto Theme Switching true │
Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
Verbose Output History true │
Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
@@ -363,7 +87,283 @@ exports[`SettingsDialog > Snapshot Tests > should render 'tools and security set
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ (Use Enter to select, Tab to change focus, Esc to close)
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'all boolean settings disabled' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode false* │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true* │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false* │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false* │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Verbose Output History true │
│ Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'default state' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode false │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Verbose Output History true │
│ Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'file filtering settings configured' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode false │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Verbose Output History true │
│ Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'focused on scope selector' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode false │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Verbose Output History true │
│ Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
│ > Apply To │
│ ● 1. User Settings │
│ 2. Workspace Settings │
│ 3. System Settings │
│ │
│ (Use Enter to select, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'mixed boolean and number settings' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode false* │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update false* │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Verbose Output History true │
│ Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
exports[`SettingsDialog > Snapshot Tests > should render 'tools and security settings' correctly 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ > Settings │
│ │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Search to filter │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Preview Features (e.g., models) false │
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode false │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update true │
│ Enable automatic updates. │
│ │
│ Enable Prompt Completion false │
│ Enable AI-powered prompt completion suggestions while typing. │
│ │
│ Debug Keystroke Logging false │
│ Enable debug logging of keystrokes to the console. │
│ │
│ Enable Session Cleanup false │
│ Enable automatic session cleanup │
│ │
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
│ Verbose Output History true │
│ Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
│ Apply To │
│ ● User Settings │
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Tab to change focus, Esc to close) │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;
@@ -378,7 +378,10 @@ exports[`SettingsDialog > Snapshot Tests > should render 'various boolean settin
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ ▲ │
│ ● Vim Mode true*
│ ● Preview Features (e.g., models) false
│ Enable preview features (e.g., preview models). │
│ │
│ Vim Mode true* │
│ Enable Vim keybindings │
│ │
│ Enable Auto Update false* │
@@ -396,11 +399,8 @@ exports[`SettingsDialog > Snapshot Tests > should render 'various boolean settin
│ Output Format Text │
│ The format of the CLI output. Can be \`text\` or \`json\`. │
│ │
Auto Theme Switching true │
Automatically switch between default light and dark themes based on terminal backgro… │
│ │
│ Terminal Background Polling Interval 60 │
│ Interval in seconds to poll the terminal background color. │
Verbose Output History true │
Show verbose output history. When enabled, output history will include autonomous to… │
│ │
│ ▼ │
│ │
@@ -409,7 +409,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'various boolean settin
│ Workspace Settings │
│ System Settings │
│ │
│ (Use Enter to select, Ctrl+L to reset, Tab to change focus, Esc to close) │
│ (Use Enter to select, Tab to change focus, Esc to close)
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
`;

View File

@@ -0,0 +1,125 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect } from 'vitest';
import { renderWithProviders } from '../../../test-utils/render.js';
import { DenseToolMessage } from './DenseToolMessage.js';
import type { ToolResultDisplay } from '../../types.js';
import { ToolCallStatus } from '../../types.js';
describe('DenseToolMessage', () => {
const defaultProps = {
callId: 'call-1',
name: 'test-tool',
description: 'Test description',
status: ToolCallStatus.Success,
resultDisplay: 'Success result',
confirmationDetails: undefined,
isFirst: true,
};
it('renders correctly for a successful string result', () => {
const { lastFrame } = renderWithProviders(
<DenseToolMessage {...defaultProps} />,
);
const output = lastFrame();
expect(output).toContain('test-tool');
expect(output).toContain('Test description');
expect(output).toContain('→ Success result');
});
it('truncates long string results', () => {
const longResult = 'A'.repeat(200);
const { lastFrame } = renderWithProviders(
<DenseToolMessage {...defaultProps} resultDisplay={longResult} />,
);
// Remove all whitespace to check the continuous string content truncation
const output = lastFrame()?.replace(/\s/g, '');
expect(output).toContain('A'.repeat(117) + '...');
});
it('flattens newlines in string results', () => {
const multilineResult = 'Line 1\nLine 2';
const { lastFrame } = renderWithProviders(
<DenseToolMessage {...defaultProps} resultDisplay={multilineResult} />,
);
const output = lastFrame();
expect(output).toContain('→ Line 1 Line 2');
});
it('renders correctly for file diff results', () => {
const diffResult = {
fileDiff: 'diff content',
fileName: 'test.ts',
filePath: '/path/to/test.ts',
originalContent: 'old content',
newContent: 'new content',
};
const { lastFrame } = renderWithProviders(
<DenseToolMessage {...defaultProps} resultDisplay={diffResult} />,
);
const output = lastFrame();
expect(output).toContain('→ Diff applied to test.ts');
});
it('renders correctly for todo updates', () => {
const todoResult = {
todos: [],
};
const { lastFrame } = renderWithProviders(
<DenseToolMessage {...defaultProps} resultDisplay={todoResult} />,
);
const output = lastFrame();
expect(output).toContain('→ Todos updated');
});
it('renders generic output message for unknown object results', () => {
const genericResult = {
some: 'data',
} as unknown as ToolResultDisplay;
const { lastFrame } = renderWithProviders(
<DenseToolMessage {...defaultProps} resultDisplay={genericResult} />,
);
const output = lastFrame();
expect(output).toContain('→ Output received');
});
it('renders correctly for error status with string message', () => {
const { lastFrame } = renderWithProviders(
<DenseToolMessage
{...defaultProps}
status={ToolCallStatus.Error}
resultDisplay="Error occurred"
/>,
);
const output = lastFrame();
expect(output).toContain('→ Error occurred');
});
it('renders generic failure message for error status without string message', () => {
const { lastFrame } = renderWithProviders(
<DenseToolMessage
{...defaultProps}
status={ToolCallStatus.Error}
resultDisplay={undefined}
/>,
);
const output = lastFrame();
expect(output).toContain('→ Failed');
});
it('does not render result arrow if resultDisplay is missing', () => {
const { lastFrame } = renderWithProviders(
<DenseToolMessage
{...defaultProps}
status={ToolCallStatus.Pending}
resultDisplay={undefined}
/>,
);
const output = lastFrame();
expect(output).not.toContain('→');
});
});

View File

@@ -0,0 +1,78 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { Box, Text } from 'ink';
import { ToolCallStatus } from '../../types.js';
import type { IndividualToolCallDisplay } from '../../types.js';
import { ToolStatusIndicator } from './ToolShared.js';
import { theme } from '../../semantic-colors.js';
interface DenseToolMessageProps extends IndividualToolCallDisplay {
isFirst: boolean;
}
interface FileDiffResult {
fileDiff: string;
fileName: string;
}
export const DenseToolMessage: React.FC<DenseToolMessageProps> = ({
name,
description,
status,
resultDisplay,
}) => {
let denseResult: string | undefined;
if (status === ToolCallStatus.Success && resultDisplay) {
if (typeof resultDisplay === 'string') {
const flattened = resultDisplay.replace(/\n/g, ' ').trim();
denseResult =
flattened.length > 120 ? flattened.slice(0, 117) + '...' : flattened;
} else if (typeof resultDisplay === 'object') {
if ('fileDiff' in resultDisplay) {
denseResult = `Diff applied to ${(resultDisplay as FileDiffResult).fileName}`;
} else if ('todos' in resultDisplay) {
denseResult = 'Todos updated';
} else {
// Fallback for AnsiOutput or other objects
denseResult = 'Output received';
}
}
} else if (status === ToolCallStatus.Error) {
if (typeof resultDisplay === 'string') {
const flattened = resultDisplay.replace(/\n/g, ' ').trim();
denseResult =
flattened.length > 120 ? flattened.slice(0, 117) + '...' : flattened;
} else {
denseResult = 'Failed';
}
}
return (
<Box marginLeft={3} flexDirection="row" flexWrap="wrap">
<ToolStatusIndicator status={status} name={name} />
<Box maxWidth={25} flexShrink={1} flexGrow={0}>
<Text color={theme.text.primary} bold wrap="truncate-end">
{name}
</Text>
</Box>
<Box marginLeft={1} flexShrink={1} flexGrow={0}>
<Text color={theme.text.secondary} wrap="truncate-end">
{description}
</Text>
</Box>
{denseResult && (
<Box marginLeft={1} flexGrow={1}>
<Text color={theme.text.accent} wrap="wrap">
{denseResult}
</Text>
</Box>
)}
</Box>
);
};

View File

@@ -18,6 +18,8 @@ import { isShellTool, isThisShellFocused } from './ToolShared.js';
import { ASK_USER_DISPLAY_NAME } from '@google/gemini-cli-core';
import { ShowMoreLines } from '../ShowMoreLines.js';
import { useUIState } from '../../contexts/UIStateContext.js';
import { useSettings } from '../../contexts/SettingsContext.js';
import { DenseToolMessage } from './DenseToolMessage.js';
interface ToolGroupMessageProps {
groupId: number;
@@ -63,6 +65,8 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
const config = useConfig();
const { constrainHeight } = useUIState();
const { merged: settings } = useSettings();
const isVerboseMode = settings.output?.verbosity === 'verbose';
const isEventDriven = config.isEventDrivenSchedulerEnabled();
@@ -161,12 +165,25 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
*/
width={terminalWidth}
paddingRight={TOOL_MESSAGE_HORIZONTAL_MARGIN}
marginBottom={1}
>
{visibleToolCalls.map((tool, index) => {
const isConfirming = toolAwaitingApproval?.callId === tool.callId;
const isFirst = index === 0;
const isShellToolCall = isShellTool(tool.name);
// Use dense view if not verbose, not a shell tool (for interactivity), and not confirming (needs prompt)
const useDenseView =
!isVerboseMode &&
!isShellToolCall &&
tool.status !== ToolCallStatus.Confirming;
if (useDenseView) {
return (
<DenseToolMessage key={tool.callId} {...tool} isFirst={isFirst} />
);
}
const commonProps = {
...tool,
availableTerminalHeight: availableTerminalHeightPerToolMessage,
@@ -242,22 +259,59 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
})}
{
/*
We have to keep the bottom border separate so it doesn't get
drawn over by the sticky header directly inside it.
*/
(visibleToolCalls.length > 0 || borderBottomOverride !== undefined) && (
<Box
height={0}
width={contentWidth}
borderLeft={true}
borderRight={true}
borderTop={false}
borderBottom={borderBottomOverride ?? true}
borderColor={borderColor}
borderDimColor={borderDimColor}
borderStyle="round"
/>
)
We have to keep the bottom border separate so it doesn't get
drawn over by the sticky header directly inside it.
Only render if the last tool was displayed in full/verbose mode,
or if explicitly overridden.
*/
(() => {
if (visibleToolCalls.length === 0) {
if (borderBottomOverride !== undefined) {
return (
<Box
height={0}
width={contentWidth}
borderLeft={true}
borderRight={true}
borderTop={false}
borderBottom={borderBottomOverride}
borderColor={borderColor}
borderDimColor={borderDimColor}
borderStyle="round"
/>
);
}
return null;
}
const lastTool = visibleToolCalls[visibleToolCalls.length - 1];
const isShell = isShellTool(lastTool.name);
const isConfirming = lastTool.status === ToolCallStatus.Confirming;
// Logic: If dense view (not verbose, not shell, not confirming), hide border by default
const isDense = !isVerboseMode && !isShell && !isConfirming;
let showBottomBorder = !isDense;
if (borderBottomOverride !== undefined) {
showBottomBorder = borderBottomOverride;
}
if (!showBottomBorder) return null;
return (
<Box
height={0}
width={contentWidth}
borderLeft={true}
borderRight={true}
borderTop={false}
borderBottom={true}
borderColor={borderColor}
borderDimColor={borderDimColor}
borderStyle="round"
/>
);
})()
}
{(borderBottomOverride ?? true) && visibleToolCalls.length > 0 && (
<Box paddingX={1}>

View File

@@ -110,7 +110,7 @@ describe('ToolMessage Sticky Header Regression', () => {
// Scroll down so that tool-1's header should be stuck
await act(async () => {
listRef?.scrollBy(5);
listRef?.scrollBy(6);
});
// tool-1 header should still be visible because it is sticky
@@ -120,10 +120,10 @@ describe('ToolMessage Sticky Header Regression', () => {
expect(lastFrame()).toContain('Description for tool-1');
// Content lines 1-4 should be scrolled off
expect(lastFrame()).not.toContain('c1-01');
expect(lastFrame()).not.toContain('c1-04');
// Line 6 and 7 should be visible (terminalHeight=5 means only 2 lines of content show below 3-line header)
expect(lastFrame()).toContain('c1-06');
expect(lastFrame()).not.toContain('c1-05');
// Line 7 and 8 should be visible (terminalHeight=5 means only 2 lines of content show below 3-line header)
expect(lastFrame()).toContain('c1-07');
expect(lastFrame()).toContain('c1-08');
expect(lastFrame()).toMatchSnapshot();
// Scroll further so tool-1 is completely gone and tool-2's header should be stuck

View File

@@ -1,260 +1,238 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`<ToolGroupMessage /> > Ask User Filtering > does NOT filter out ask_user when status is Error 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ x Ask User │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
`;
exports[`<ToolGroupMessage /> > Ask User Filtering > does NOT filter out ask_user when status is Success 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ Ask User │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
`;
exports[`<ToolGroupMessage /> > Ask User Filtering > filters out ask_user when status is Confirming 1`] = `""`;
exports[`<ToolGroupMessage /> > Ask User Filtering > filters out ask_user when status is Executing 1`] = `""`;
exports[`<ToolGroupMessage /> > Ask User Filtering > filters out ask_user when status is Pending 1`] = `""`;
exports[`<ToolGroupMessage /> > Ask User Filtering > shows other tools when ask_user is filtered out 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ other-tool A tool for testing │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
`;
exports[`<ToolGroupMessage /> > Border Color Logic > uses gray border when all tools are successful and no shell commands 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ test-tool A tool for testing │
│ │
│ Test result │
│ │
│ ✓ another-tool A tool for testing │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ test-tool A tool for testing
│ Test result
│ ✓ another-tool A tool for testing
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Border Color Logic > uses yellow border for shell commands even when successful 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ run_shell_command A tool for testing │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ run_shell_command A tool for testing
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Border Color Logic > uses yellow border when tools are pending 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ o test-tool A tool for testing │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ o test-tool A tool for testing
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Confirmation Handling > renders confirmation with permanent approval disabled 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ? confirm-tool A tool for testing ← │
│ │
│ Test result │
│ Do you want to proceed? │
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. No, suggest changes (esc)
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ? confirm-tool A tool for testing ← │
│ Test result
│ Do you want to proceed?
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. No, suggest changes (esc)
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
"
`;
exports[`<ToolGroupMessage /> > Confirmation Handling > renders confirmation with permanent approval enabled 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ? confirm-tool A tool for testing ← │
│ │
│ Test result │
│ Do you want to proceed? │
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. Allow for all future sessions
4. No, suggest changes (esc)
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ? confirm-tool A tool for testing ← │
│ Test result
│ Do you want to proceed?
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. Allow for all future sessions
4. No, suggest changes (esc)
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
"
`;
exports[`<ToolGroupMessage /> > Confirmation Handling > shows confirmation dialog for first confirming tool only 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ? first-confirm A tool for testing ← │
│ │
│ Test result │
│ Confirm first tool │
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. No, suggest changes (esc)
│ │
? second-confirm A tool for testing
Test result
╰──────────────────────────────────────────────────────────────────────────╯"
`;
exports[`<ToolGroupMessage /> > Event-Driven Scheduler > hides confirming tools when event-driven scheduler is enabled 1`] = `""`;
exports[`<ToolGroupMessage /> > Event-Driven Scheduler > renders nothing when only tool is in-progress AskUser with borderBottom=false 1`] = `""`;
exports[`<ToolGroupMessage /> > Event-Driven Scheduler > shows only successful tools when mixed with confirming tools 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ success-tool A tool for testing │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ? first-confirm A tool for testing ← │
│ Test result
│ Confirm first tool
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. No, suggest changes (esc)
? second-confirm A tool for testing
│ Test result │
╰──────────────────────────────────────────────────────────────────────────────╯
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders empty tool calls array 1`] = `""`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders header when scrolled 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ tool-1 Description 1. This is a long description that will need to b… │
│──────────────────────────────────────────────────────────────────────────│
line5
tool-2 Description 2
│ line1
│ line2 │
╰──────────────────────────────────────────────────────────────────────────╯ █"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ tool-1 Description 1. This is a long description that will need to be tr… │
│──────────────────────────────────────────────────────────────────────────────
tool-2 Description 2 │ █
│ █
line1 │ █
│ line2 │ █
╰──────────────────────────────────────────────────────────────────────────────╯
█"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders mixed tool calls including shell command 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ read_file Read a file │
│ │
│ Test result │
│ │
│ ⊷ run_shell_command Run command │
│ │
│ Test result │
│ │
│ o write_file Write to file │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ read_file Read a file
│ Test result
│ ⊷ run_shell_command Run command
│ Test result
│ o write_file Write to file
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders multiple tool calls with different statuses 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ successful-tool This tool succeeded │
│ │
│ Test result │
│ │
│ o pending-tool This tool is pending │
│ │
│ Test result │
│ │
│ x error-tool This tool failed │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ successful-tool This tool succeeded
│ Test result
│ o pending-tool This tool is pending
│ Test result
│ x error-tool This tool failed
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders shell command with yellow border 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ run_shell_command Execute shell command │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ run_shell_command Execute shell command
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders single successful tool call 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ test-tool A tool for testing │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ test-tool A tool for testing
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders tool call awaiting confirmation 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ? confirmation-tool This tool needs confirmation ← │
│ │
│ Test result │
│ Are you sure you want to proceed? │
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. No, suggest changes (esc)
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ? confirmation-tool This tool needs confirmation ← │
│ Test result
│ Are you sure you want to proceed?
Do you want to proceed?
● 1. Allow once
2. Allow for this session
3. No, suggest changes (esc)
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders tool call with outputFile 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ tool-with-file Tool that saved output to file │
│ │
│ Test result │
│ Output too long and was saved to: /path/to/output.txt │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ tool-with-file Tool that saved output to file
│ Test result
│ Output too long and was saved to: /path/to/output.txt
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders two tool groups where only the last line of the previous group is visible 1`] = `
"──────────────────────────────────────────────────────────────────────────
╭──────────────────────────────────────────────────────────────────────────╮
tool-2 Description 2
│ line1 │
╰──────────────────────────────────────────────────────────────────────────╯ █"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ tool-2 Description 2 │
line1 │ ▄
╰──────────────────────────────────────────────────────────────────────────────╯
█"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders when not focused 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ test-tool A tool for testing │
│ │
│ Test result │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ test-tool A tool for testing
│ Test result
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders with limited terminal height 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ tool-with-result Tool with output │
│ │
│ This is a long result that might need height constraints │
│ │
│ ✓ another-tool Another tool │
│ │
│ More output here │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ tool-with-result Tool with output
│ This is a long result that might need height constraints
│ ✓ another-tool Another tool
│ More output here
╰──────────────────────────────────────────────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Golden Snapshots > renders with narrow terminal width 1`] = `
"╭──────────────────────────────────╮
│ ✓ very-long-tool-name-that-mig… │
│ │
│ Test result │
╰──────────────────────────────────╯"
"╭──────────────────────────────────────
│ ✓ very-long-tool-name-that-might-w… │
│ Test result
╰──────────────────────────────────────
"
`;
exports[`<ToolGroupMessage /> > Height Calculation > calculates available height correctly with multiple tools with results 1`] = `
"╭──────────────────────────────────────────────────────────────────────────╮
│ ✓ test-tool A tool for testing │
│ │
│ Result 1 │
│ │
│ ✓ test-tool A tool for testing │
│ │
│ Result 2 │
│ │
│ ✓ test-tool A tool for testing │
│ │
╰──────────────────────────────────────────────────────────────────────────╯"
"╭──────────────────────────────────────────────────────────────────────────────
│ ✓ test-tool A tool for testing
│ Result 1
│ ✓ test-tool A tool for testing
│ Result 2
│ ✓ test-tool A tool for testing
╰──────────────────────────────────────────────────────────────────────────────
"
`;

View File

@@ -2,7 +2,7 @@
exports[`ToolMessage Sticky Header Regression > verifies that ShellToolMessage in a ToolGroupMessage in a ScrollableList has sticky headers 1`] = `
"╭────────────────────────────────────────────────────────────────────────╮ █
│ ✓ Shell Command Description for Shell Command │
│ ✓ Shell Command Description for Shell Command │
│ │
│ shell-01 │
│ shell-02 │"
@@ -10,7 +10,7 @@ exports[`ToolMessage Sticky Header Regression > verifies that ShellToolMessage i
exports[`ToolMessage Sticky Header Regression > verifies that ShellToolMessage in a ToolGroupMessage in a ScrollableList has sticky headers 2`] = `
"╭────────────────────────────────────────────────────────────────────────╮
│ ✓ Shell Command Description for Shell Command │
│ ✓ Shell Command Description for Shell Command │
│────────────────────────────────────────────────────────────────────────│ █
│ shell-06 │ ▀
│ shell-07 │"
@@ -28,14 +28,14 @@ exports[`ToolMessage Sticky Header Regression > verifies that multiple ToolMessa
"╭────────────────────────────────────────────────────────────────────────╮
│ ✓ tool-1 Description for tool-1 │ █
│────────────────────────────────────────────────────────────────────────│
│ c1-06
│ c1-07 │"
│ c1-07
│ c1-08 │"
`;
exports[`ToolMessage Sticky Header Regression > verifies that multiple ToolMessages in a ToolGroupMessage in a ScrollableList have sticky headers 3`] = `
"│ │
│ ✓ tool-2 Description for tool-2 │
│────────────────────────────────────────────────────────────────────────│
│ c2-10 │
╰────────────────────────────────────────────────────────────────────────╯ █"
╰────────────────────────────────────────────────────────────────────────╯
█"
`;