mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-24 03:54:43 -07:00
fix(cli): improve focus navigation for interactive and background shells (#18343)
This commit is contained in:
@@ -405,55 +405,4 @@ describe('<BackgroundShellDisplay />', () => {
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('unfocuses the shell when Shift+Tab is pressed', async () => {
|
||||
render(
|
||||
<ScrollProvider>
|
||||
<BackgroundShellDisplay
|
||||
shells={mockShells}
|
||||
activePid={shell1.pid}
|
||||
width={80}
|
||||
height={24}
|
||||
isFocused={true}
|
||||
isListOpenProp={false}
|
||||
/>
|
||||
</ScrollProvider>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
simulateKey({ name: 'tab', shift: true });
|
||||
});
|
||||
|
||||
expect(mockSetEmbeddedShellFocused).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('shows a warning when Tab is pressed', async () => {
|
||||
render(
|
||||
<ScrollProvider>
|
||||
<BackgroundShellDisplay
|
||||
shells={mockShells}
|
||||
activePid={shell1.pid}
|
||||
width={80}
|
||||
height={24}
|
||||
isFocused={true}
|
||||
isListOpenProp={false}
|
||||
/>
|
||||
</ScrollProvider>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(0);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
simulateKey({ name: 'tab' });
|
||||
});
|
||||
|
||||
expect(mockHandleWarning).toHaveBeenCalledWith(
|
||||
'Press Shift+Tab to focus out.',
|
||||
);
|
||||
expect(mockSetEmbeddedShellFocused).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ import { cpLen, cpSlice, getCachedStringWidth } from '../utils/textUtils.js';
|
||||
import { type BackgroundShell } from '../hooks/shellCommandProcessor.js';
|
||||
import { Command, keyMatchers } from '../keyMatchers.js';
|
||||
import { useKeypress } from '../hooks/useKeypress.js';
|
||||
import { commandDescriptions } from '../../config/keyBindings.js';
|
||||
import { formatCommand } from '../utils/keybindingUtils.js';
|
||||
import {
|
||||
ScrollableList,
|
||||
type ScrollableListRef,
|
||||
@@ -64,8 +64,6 @@ export const BackgroundShellDisplay = ({
|
||||
dismissBackgroundShell,
|
||||
setActiveBackgroundShellPid,
|
||||
setIsBackgroundShellListOpen,
|
||||
handleWarning,
|
||||
setEmbeddedShellFocused,
|
||||
} = useUIActions();
|
||||
const activeShell = shells.get(activePid);
|
||||
const [output, setOutput] = useState<string | AnsiOutput>(
|
||||
@@ -138,27 +136,6 @@ export const BackgroundShellDisplay = ({
|
||||
(key) => {
|
||||
if (!activeShell) return;
|
||||
|
||||
// Handle Shift+Tab or Tab (in list) to focus out
|
||||
if (
|
||||
keyMatchers[Command.UNFOCUS_BACKGROUND_SHELL](key) ||
|
||||
(isListOpenProp &&
|
||||
keyMatchers[Command.UNFOCUS_BACKGROUND_SHELL_LIST](key))
|
||||
) {
|
||||
setEmbeddedShellFocused(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle Tab to warn but propagate
|
||||
if (
|
||||
!isListOpenProp &&
|
||||
keyMatchers[Command.SHOW_BACKGROUND_SHELL_UNFOCUS_WARNING](key)
|
||||
) {
|
||||
handleWarning(
|
||||
`Press ${commandDescriptions[Command.UNFOCUS_BACKGROUND_SHELL]} to focus out.`,
|
||||
);
|
||||
// Fall through to allow Tab to be sent to the shell
|
||||
}
|
||||
|
||||
if (isListOpenProp) {
|
||||
// Navigation (Up/Down/Enter) is handled by RadioButtonSelect
|
||||
// We only handle special keys not consumed by RadioButtonSelect or overriding them if needed
|
||||
@@ -188,7 +165,7 @@ export const BackgroundShellDisplay = ({
|
||||
}
|
||||
|
||||
if (keyMatchers[Command.TOGGLE_BACKGROUND_SHELL](key)) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyMatchers[Command.KILL_BACKGROUND_SHELL](key)) {
|
||||
@@ -216,7 +193,27 @@ export const BackgroundShellDisplay = ({
|
||||
{ isActive: isFocused && !!activeShell },
|
||||
);
|
||||
|
||||
const helpText = `${commandDescriptions[Command.TOGGLE_BACKGROUND_SHELL]} Hide | ${commandDescriptions[Command.KILL_BACKGROUND_SHELL]} Kill | ${commandDescriptions[Command.TOGGLE_BACKGROUND_SHELL_LIST]} List`;
|
||||
const helpTextParts = [
|
||||
{ label: 'Close', command: Command.TOGGLE_BACKGROUND_SHELL },
|
||||
{ label: 'Kill', command: Command.KILL_BACKGROUND_SHELL },
|
||||
{ label: 'List', command: Command.TOGGLE_BACKGROUND_SHELL_LIST },
|
||||
];
|
||||
|
||||
const helpTextStr = helpTextParts
|
||||
.map((p) => `${p.label} (${formatCommand(p.command)})`)
|
||||
.join(' | ');
|
||||
|
||||
const renderHelpText = () => (
|
||||
<Text>
|
||||
{helpTextParts.map((p, i) => (
|
||||
<Text key={p.label}>
|
||||
{i > 0 ? ' | ' : ''}
|
||||
{p.label} (
|
||||
<Text color={theme.text.accent}>{formatCommand(p.command)}</Text>)
|
||||
</Text>
|
||||
))}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const renderTabs = () => {
|
||||
const shellList = Array.from(shells.values()).filter(
|
||||
@@ -230,7 +227,7 @@ export const BackgroundShellDisplay = ({
|
||||
const availableWidth =
|
||||
width -
|
||||
TAB_DISPLAY_HORIZONTAL_PADDING -
|
||||
getCachedStringWidth(helpText) -
|
||||
getCachedStringWidth(helpTextStr) -
|
||||
pidInfoWidth;
|
||||
|
||||
let currentWidth = 0;
|
||||
@@ -272,7 +269,7 @@ export const BackgroundShellDisplay = ({
|
||||
}
|
||||
|
||||
if (shellList.length > tabs.length && !isListOpenProp) {
|
||||
const overflowLabel = ` ... (${commandDescriptions[Command.TOGGLE_BACKGROUND_SHELL_LIST]}) `;
|
||||
const overflowLabel = ` ... (${formatCommand(Command.TOGGLE_BACKGROUND_SHELL_LIST)}) `;
|
||||
const overflowWidth = getCachedStringWidth(overflowLabel);
|
||||
|
||||
// If we only have one tab, ensure we don't show the overflow if it's too cramped
|
||||
@@ -324,7 +321,7 @@ export const BackgroundShellDisplay = ({
|
||||
<Box flexDirection="column" height="100%" width="100%">
|
||||
<Box flexShrink={0} marginBottom={1} paddingTop={1}>
|
||||
<Text bold>
|
||||
{`Select Process (${commandDescriptions[Command.BACKGROUND_SHELL_SELECT]} to select, ${commandDescriptions[Command.BACKGROUND_SHELL_ESCAPE]} to cancel):`}
|
||||
{`Select Process (${formatCommand(Command.BACKGROUND_SHELL_SELECT)} to select, ${formatCommand(Command.KILL_BACKGROUND_SHELL)} to kill, ${formatCommand(Command.BACKGROUND_SHELL_ESCAPE)} to cancel):`}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box flexGrow={1} width="100%">
|
||||
@@ -450,7 +447,7 @@ export const BackgroundShellDisplay = ({
|
||||
(PID: {activeShell?.pid}) {isFocused ? '(Focused)' : ''}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text color={theme.text.accent}>{helpText}</Text>
|
||||
{renderHelpText()}
|
||||
</Box>
|
||||
<Box flexGrow={1} overflow="hidden" paddingX={CONTENT_PADDING_X}>
|
||||
{isListOpenProp ? renderProcessList() : renderOutput()}
|
||||
|
||||
@@ -982,15 +982,19 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyMatchers[Command.TOGGLE_BACKGROUND_SHELL](key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyMatchers[Command.FOCUS_SHELL_INPUT](key)) {
|
||||
// If we got here, Autocomplete didn't handle the key (e.g. no suggestions).
|
||||
if (
|
||||
activePtyId ||
|
||||
(backgroundShells.size > 0 && backgroundShellHeight > 0)
|
||||
) {
|
||||
setEmbeddedShellFocused(true);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fall back to the text buffer's default input handling for all other keys
|
||||
|
||||
@@ -8,6 +8,12 @@ import { render } from '../../test-utils/render.js';
|
||||
import { ShellInputPrompt } from './ShellInputPrompt.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { ShellExecutionService } from '@google/gemini-cli-core';
|
||||
import { useUIActions, type UIActions } from '../contexts/UIActionsContext.js';
|
||||
|
||||
// Mock useUIActions
|
||||
vi.mock('../contexts/UIActionsContext.js', () => ({
|
||||
useUIActions: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock useKeypress
|
||||
const mockUseKeypress = vi.fn();
|
||||
@@ -31,9 +37,13 @@ vi.mock('@google/gemini-cli-core', async () => {
|
||||
describe('ShellInputPrompt', () => {
|
||||
const mockWriteToPty = vi.mocked(ShellExecutionService.writeToPty);
|
||||
const mockScrollPty = vi.mocked(ShellExecutionService.scrollPty);
|
||||
const mockHandleWarning = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(useUIActions).mockReturnValue({
|
||||
handleWarning: mockHandleWarning,
|
||||
} as Partial<UIActions> as UIActions);
|
||||
});
|
||||
|
||||
it('renders nothing', () => {
|
||||
@@ -43,6 +53,23 @@ describe('ShellInputPrompt', () => {
|
||||
expect(lastFrame()).toBe('');
|
||||
});
|
||||
|
||||
it('sends tab to pty', () => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={true} />);
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
handler({
|
||||
name: 'tab',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: '\t',
|
||||
});
|
||||
|
||||
expect(mockWriteToPty).toHaveBeenCalledWith(1, '\t');
|
||||
});
|
||||
|
||||
it.each([
|
||||
['a', 'a'],
|
||||
['b', 'b'],
|
||||
|
||||
@@ -40,6 +40,11 @@ export const ShellInputPrompt: React.FC<ShellInputPromptProps> = ({
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow unfocus to bubble up
|
||||
if (keyMatchers[Command.UNFOCUS_SHELL_INPUT](key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key.ctrl && key.shift && key.name === 'up') {
|
||||
ShellExecutionService.scrollPty(activeShellPtyId, -1);
|
||||
return true;
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
exports[`<BackgroundShellDisplay /> > highlights the focused state 1`] = `
|
||||
"┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1: npm star... (PID: 1001) (Focused) Ctrl+B Hide | Ctrl+K Kill | Ctrl+L List │
|
||||
│ 1: npm sta... (PID: 1001) (Focused) Close (Ctrl+B) | Kill (Ctrl+K) | List (Ctrl+L) │
|
||||
│ Starting server... │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────┘"
|
||||
`;
|
||||
|
||||
exports[`<BackgroundShellDisplay /> > keeps exit code status color even when selected 1`] = `
|
||||
"┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1: npm star... (PID: 1003) (Focused) Ctrl+B Hide | Ctrl+K Kill | Ctrl+L List │
|
||||
│ 1: npm sta... (PID: 1003) (Focused) Close (Ctrl+B) | Kill (Ctrl+K) | List (Ctrl+L) │
|
||||
│ │
|
||||
│ Select Process (Enter to select, Esc to cancel): │
|
||||
│ Select Process (Enter to select, Ctrl+K to kill, Esc to cancel): │
|
||||
│ │
|
||||
│ 1. npm start (PID: 1001) │
|
||||
│ 2. tail -f log.txt (PID: 1002) │
|
||||
@@ -21,23 +21,23 @@ exports[`<BackgroundShellDisplay /> > keeps exit code status color even when sel
|
||||
|
||||
exports[`<BackgroundShellDisplay /> > renders tabs for multiple shells 1`] = `
|
||||
"┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1: npm start 2: tail -f log.txt (PID: 1001) Ctrl+B Hide | Ctrl+K Kill | Ctrl+L List │
|
||||
│ 1: npm start 2: tail -f lo... (PID: 1001) Close (Ctrl+B) | Kill (Ctrl+K) | List (Ctrl+L) │
|
||||
│ Starting server... │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────┘"
|
||||
`;
|
||||
|
||||
exports[`<BackgroundShellDisplay /> > renders the output of the active shell 1`] = `
|
||||
"┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1: npm ... 2: tail... (PID: 1001) Ctrl+B Hide | Ctrl+K Kill | Ctrl+L List │
|
||||
│ 1: ... 2: ... (PID: 1001) Close (Ctrl+B) | Kill (Ctrl+K) | List (Ctrl+L) │
|
||||
│ Starting server... │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────┘"
|
||||
`;
|
||||
|
||||
exports[`<BackgroundShellDisplay /> > renders the process list when isListOpenProp is true 1`] = `
|
||||
"┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1: npm star... (PID: 1001) (Focused) Ctrl+B Hide | Ctrl+K Kill | Ctrl+L List │
|
||||
│ 1: npm sta... (PID: 1001) (Focused) Close (Ctrl+B) | Kill (Ctrl+K) | List (Ctrl+L) │
|
||||
│ │
|
||||
│ Select Process (Enter to select, Esc to cancel): │
|
||||
│ Select Process (Enter to select, Ctrl+K to kill, Esc to cancel): │
|
||||
│ │
|
||||
│ ● 1. npm start (PID: 1001) │
|
||||
│ 2. tail -f log.txt (PID: 1002) │
|
||||
@@ -46,9 +46,9 @@ exports[`<BackgroundShellDisplay /> > renders the process list when isListOpenPr
|
||||
|
||||
exports[`<BackgroundShellDisplay /> > scrolls to active shell when list opens 1`] = `
|
||||
"┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1: npm star... (PID: 1002) (Focused) Ctrl+B Hide | Ctrl+K Kill | Ctrl+L List │
|
||||
│ 1: npm sta... (PID: 1002) (Focused) Close (Ctrl+B) | Kill (Ctrl+K) | List (Ctrl+L) │
|
||||
│ │
|
||||
│ Select Process (Enter to select, Esc to cancel): │
|
||||
│ Select Process (Enter to select, Ctrl+K to kill, Esc to cancel): │
|
||||
│ │
|
||||
│ 1. npm start (PID: 1001) │
|
||||
│ ● 2. tail -f log.txt (PID: 1002) │
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import React, { act } from 'react';
|
||||
import React from 'react';
|
||||
import {
|
||||
ShellToolMessage,
|
||||
type ShellToolMessageProps,
|
||||
@@ -77,16 +77,6 @@ describe('<ShellToolMessage />', () => {
|
||||
setEmbeddedShellFocused: mockSetEmbeddedShellFocused,
|
||||
};
|
||||
|
||||
// Helper to render with context
|
||||
const renderWithContext = (
|
||||
ui: React.ReactElement,
|
||||
streamingState: StreamingState,
|
||||
) =>
|
||||
renderWithProviders(ui, {
|
||||
uiActions,
|
||||
uiState: { streamingState },
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
@@ -140,40 +130,5 @@ describe('<ShellToolMessage />', () => {
|
||||
expect(mockSetEmbeddedShellFocused).toHaveBeenCalledWith(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('resets focus when shell finishes', async () => {
|
||||
let updateStatus: (s: ToolCallStatus) => void = () => {};
|
||||
|
||||
const Wrapper = () => {
|
||||
const [status, setStatus] = React.useState(ToolCallStatus.Executing);
|
||||
updateStatus = setStatus;
|
||||
return (
|
||||
<ShellToolMessage
|
||||
{...shellProps}
|
||||
status={status}
|
||||
embeddedShellFocused={true}
|
||||
activeShellPtyId={1}
|
||||
ptyId={1}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const { lastFrame } = renderWithContext(<Wrapper />, StreamingState.Idle);
|
||||
|
||||
// Verify it is initially focused
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toContain('(Focused)');
|
||||
});
|
||||
|
||||
// Now update status to Success
|
||||
await act(async () => {
|
||||
updateStatus(ToolCallStatus.Success);
|
||||
});
|
||||
|
||||
// Should call setEmbeddedShellFocused(false) because isThisShellFocused became false
|
||||
await waitFor(() => {
|
||||
expect(mockSetEmbeddedShellFocused).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -89,20 +89,6 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
|
||||
|
||||
useMouseClick(contentRef, handleFocus, { isActive: !!isThisShellFocusable });
|
||||
|
||||
const wasFocusedRef = React.useRef(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isThisShellFocused) {
|
||||
wasFocusedRef.current = true;
|
||||
} else if (wasFocusedRef.current) {
|
||||
if (embeddedShellFocused) {
|
||||
setEmbeddedShellFocused(false);
|
||||
}
|
||||
|
||||
wasFocusedRef.current = false;
|
||||
}
|
||||
}, [isThisShellFocused, embeddedShellFocused, setEmbeddedShellFocused]);
|
||||
|
||||
const { shouldShowFocusHint } = useFocusHint(
|
||||
isThisShellFocusable,
|
||||
isThisShellFocused,
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('Focus Hint', () => {
|
||||
|
||||
// Now it SHOULD contain the focus hint
|
||||
expect(lastFrame()).toMatchSnapshot('after-delay-no-output');
|
||||
expect(lastFrame()).toContain('(tab to focus)');
|
||||
expect(lastFrame()).toContain('(Tab to focus)');
|
||||
});
|
||||
|
||||
it('shows focus hint after delay with output', async () => {
|
||||
@@ -95,7 +95,7 @@ describe('Focus Hint', () => {
|
||||
});
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot('after-delay-with-output');
|
||||
expect(lastFrame()).toContain('(tab to focus)');
|
||||
expect(lastFrame()).toContain('(Tab to focus)');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('Focus Hint', () => {
|
||||
|
||||
// The focus hint should be visible
|
||||
expect(lastFrame()).toMatchSnapshot('long-description');
|
||||
expect(lastFrame()).toContain('(tab to focus)');
|
||||
expect(lastFrame()).toContain('(Tab to focus)');
|
||||
// The name should still be visible
|
||||
expect(lastFrame()).toContain(SHELL_COMMAND_NAME);
|
||||
});
|
||||
|
||||
@@ -22,6 +22,8 @@ import {
|
||||
type ToolResultDisplay,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { useInactivityTimer } from '../../hooks/useInactivityTimer.js';
|
||||
import { formatCommand } from '../../utils/keybindingUtils.js';
|
||||
import { Command } from '../../../config/keyBindings.js';
|
||||
|
||||
export const STATUS_INDICATOR_WIDTH = 3;
|
||||
|
||||
@@ -117,7 +119,9 @@ export const FocusHint: React.FC<{
|
||||
return (
|
||||
<Box marginLeft={1} flexShrink={0}>
|
||||
<Text color={theme.text.accent}>
|
||||
{isThisShellFocused ? '(Focused)' : '(tab to focus)'}
|
||||
{isThisShellFocused
|
||||
? `(${formatCommand(Command.UNFOCUS_SHELL_INPUT)} to unfocus)`
|
||||
: `(${formatCommand(Command.FOCUS_SHELL_INPUT)} to focus)`}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`Focus Hint > 'ShellToolMessage' > shows focus hint after delay even with NO output > after-delay-no-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing (tab to focus) │
|
||||
│ Shell Command A tool for testing (Tab to focus) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
@@ -14,7 +14,7 @@ exports[`Focus Hint > 'ShellToolMessage' > shows focus hint after delay even wit
|
||||
|
||||
exports[`Focus Hint > 'ShellToolMessage' > shows focus hint after delay with output > after-delay-with-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing (tab to focus) │
|
||||
│ Shell Command A tool for testing (Tab to focus) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
@@ -26,7 +26,7 @@ exports[`Focus Hint > 'ShellToolMessage' > shows focus hint after delay with out
|
||||
|
||||
exports[`Focus Hint > 'ToolMessage' > shows focus hint after delay even with NO output > after-delay-no-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing (tab to focus) │
|
||||
│ Shell Command A tool for testing (Tab to focus) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
@@ -38,7 +38,7 @@ exports[`Focus Hint > 'ToolMessage' > shows focus hint after delay even with NO
|
||||
|
||||
exports[`Focus Hint > 'ToolMessage' > shows focus hint after delay with output > after-delay-with-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing (tab to focus) │
|
||||
│ Shell Command A tool for testing (Tab to focus) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
@@ -50,6 +50,6 @@ exports[`Focus Hint > 'ToolMessage' > shows focus hint after delay with output >
|
||||
|
||||
exports[`Focus Hint > handles long descriptions by shrinking them to show the focus hint > long-description 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA… (tab to focus) │
|
||||
│ Shell Command AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA… (Tab to focus) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user