mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-16 17:11:04 -07:00
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
This commit is contained in:
@@ -5,17 +5,9 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, Text, type DOMElement } from 'ink';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { Box, type DOMElement } from 'ink';
|
||||
import { ShellInputPrompt } from '../ShellInputPrompt.js';
|
||||
import { StickyHeader } from '../StickyHeader.js';
|
||||
import {
|
||||
SHELL_COMMAND_NAME,
|
||||
SHELL_NAME,
|
||||
SHELL_FOCUS_HINT_DELAY_MS,
|
||||
} from '../../constants.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { SHELL_TOOL_NAME } from '@google/gemini-cli-core';
|
||||
import { useUIActions } from '../../contexts/UIActionsContext.js';
|
||||
import { useMouseClick } from '../../hooks/useMouseClick.js';
|
||||
import { ToolResultDisplay } from './ToolResultDisplay.js';
|
||||
@@ -24,6 +16,10 @@ import {
|
||||
ToolInfo,
|
||||
TrailingIndicator,
|
||||
STATUS_INDICATOR_WIDTH,
|
||||
isThisShellFocusable as checkIsShellFocusable,
|
||||
isThisShellFocused as checkIsShellFocused,
|
||||
useFocusHint,
|
||||
FocusHint,
|
||||
} from './ToolShared.js';
|
||||
import type { ToolMessageProps } from './ToolMessage.js';
|
||||
import type { Config } from '@google/gemini-cli-core';
|
||||
@@ -65,13 +61,13 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
|
||||
|
||||
borderDimColor,
|
||||
}) => {
|
||||
const isThisShellFocused =
|
||||
(name === SHELL_COMMAND_NAME ||
|
||||
name === SHELL_NAME ||
|
||||
name === SHELL_TOOL_NAME) &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
ptyId === activeShellPtyId &&
|
||||
embeddedShellFocused;
|
||||
const isThisShellFocused = checkIsShellFocused(
|
||||
name,
|
||||
status,
|
||||
ptyId,
|
||||
activeShellPtyId,
|
||||
embeddedShellFocused,
|
||||
);
|
||||
|
||||
const { setEmbeddedShellFocused } = useUIActions();
|
||||
|
||||
@@ -81,12 +77,7 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
|
||||
|
||||
// The shell is focusable if it's the shell command, it's executing, and the interactive shell is enabled.
|
||||
|
||||
const isThisShellFocusable =
|
||||
(name === SHELL_COMMAND_NAME ||
|
||||
name === SHELL_NAME ||
|
||||
name === SHELL_TOOL_NAME) &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
config?.getEnableInteractiveShell();
|
||||
const isThisShellFocusable = checkIsShellFocusable(name, status, config);
|
||||
|
||||
const handleFocus = () => {
|
||||
if (isThisShellFocusable) {
|
||||
@@ -112,38 +103,11 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
|
||||
}
|
||||
}, [isThisShellFocused, embeddedShellFocused, setEmbeddedShellFocused]);
|
||||
|
||||
const [lastUpdateTime, setLastUpdateTime] = React.useState<Date | null>(null);
|
||||
|
||||
const [userHasFocused, setUserHasFocused] = React.useState(false);
|
||||
|
||||
const [showFocusHint, setShowFocusHint] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (resultDisplay) {
|
||||
setLastUpdateTime(new Date());
|
||||
}
|
||||
}, [resultDisplay]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!lastUpdateTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
setShowFocusHint(true);
|
||||
}, SHELL_FOCUS_HINT_DELAY_MS);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [lastUpdateTime]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isThisShellFocused) {
|
||||
setUserHasFocused(true);
|
||||
}
|
||||
}, [isThisShellFocused]);
|
||||
|
||||
const shouldShowFocusHint =
|
||||
isThisShellFocusable && (showFocusHint || userHasFocused);
|
||||
const { shouldShowFocusHint } = useFocusHint(
|
||||
isThisShellFocusable,
|
||||
isThisShellFocused,
|
||||
resultDisplay,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -163,13 +127,10 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
|
||||
emphasis={emphasis}
|
||||
/>
|
||||
|
||||
{shouldShowFocusHint && (
|
||||
<Box marginLeft={1} flexShrink={0}>
|
||||
<Text color={theme.text.accent}>
|
||||
{isThisShellFocused ? '(Focused)' : '(tab to focus)'}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
<FocusHint
|
||||
shouldShowFocusHint={shouldShowFocusHint}
|
||||
isThisShellFocused={isThisShellFocused}
|
||||
/>
|
||||
|
||||
{emphasis === 'high' && <TrailingIndicator />}
|
||||
</StickyHeader>
|
||||
|
||||
@@ -13,9 +13,8 @@ import { ToolMessage } from './ToolMessage.js';
|
||||
import { ShellToolMessage } from './ShellToolMessage.js';
|
||||
import { ToolConfirmationMessage } from './ToolConfirmationMessage.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { SHELL_COMMAND_NAME, SHELL_NAME } from '../../constants.js';
|
||||
import { SHELL_TOOL_NAME } from '@google/gemini-cli-core';
|
||||
import { useConfig } from '../../contexts/ConfigContext.js';
|
||||
import { isShellTool, isThisShellFocused } from './ToolShared.js';
|
||||
|
||||
interface ToolGroupMessageProps {
|
||||
groupId: number;
|
||||
@@ -37,21 +36,22 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
activeShellPtyId,
|
||||
embeddedShellFocused,
|
||||
}) => {
|
||||
const isEmbeddedShellFocused =
|
||||
embeddedShellFocused &&
|
||||
toolCalls.some(
|
||||
(t) =>
|
||||
t.ptyId === activeShellPtyId && t.status === ToolCallStatus.Executing,
|
||||
);
|
||||
const isEmbeddedShellFocused = toolCalls.some((t) =>
|
||||
isThisShellFocused(
|
||||
t.name,
|
||||
t.status,
|
||||
t.ptyId,
|
||||
activeShellPtyId,
|
||||
embeddedShellFocused,
|
||||
),
|
||||
);
|
||||
|
||||
const hasPending = !toolCalls.every(
|
||||
(t) => t.status === ToolCallStatus.Success,
|
||||
);
|
||||
|
||||
const config = useConfig();
|
||||
const isShellCommand = toolCalls.some(
|
||||
(t) => t.name === SHELL_COMMAND_NAME || t.name === SHELL_NAME,
|
||||
);
|
||||
const isShellCommand = toolCalls.some((t) => isShellTool(t.name));
|
||||
const borderColor =
|
||||
(isShellCommand && hasPending) || isEmbeddedShellFocused
|
||||
? theme.ui.symbol
|
||||
@@ -105,10 +105,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
{toolCalls.map((tool, index) => {
|
||||
const isConfirming = toolAwaitingApproval?.callId === tool.callId;
|
||||
const isFirst = index === 0;
|
||||
const isShellTool =
|
||||
tool.name === SHELL_COMMAND_NAME ||
|
||||
tool.name === SHELL_NAME ||
|
||||
tool.name === SHELL_TOOL_NAME;
|
||||
const isShellToolCall = isShellTool(tool.name);
|
||||
|
||||
const commonProps = {
|
||||
...tool,
|
||||
@@ -131,7 +128,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
||||
minHeight={1}
|
||||
width={terminalWidth}
|
||||
>
|
||||
{isShellTool ? (
|
||||
{isShellToolCall ? (
|
||||
<ShellToolMessage
|
||||
{...commonProps}
|
||||
activeShellPtyId={activeShellPtyId}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { Box } from 'ink';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
import { StickyHeader } from '../StickyHeader.js';
|
||||
import { ToolResultDisplay } from './ToolResultDisplay.js';
|
||||
@@ -16,15 +15,12 @@ import {
|
||||
TrailingIndicator,
|
||||
type TextEmphasis,
|
||||
STATUS_INDICATOR_WIDTH,
|
||||
isThisShellFocusable as checkIsShellFocusable,
|
||||
isThisShellFocused as checkIsShellFocused,
|
||||
useFocusHint,
|
||||
FocusHint,
|
||||
} from './ToolShared.js';
|
||||
import {
|
||||
SHELL_COMMAND_NAME,
|
||||
SHELL_FOCUS_HINT_DELAY_MS,
|
||||
} from '../../constants.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import type { Config } from '@google/gemini-cli-core';
|
||||
import { useInactivityTimer } from '../../hooks/useInactivityTimer.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { type Config } from '@google/gemini-cli-core';
|
||||
import { ShellInputPrompt } from '../ShellInputPrompt.js';
|
||||
|
||||
export type { TextEmphasis };
|
||||
@@ -60,39 +56,21 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
|
||||
ptyId,
|
||||
config,
|
||||
}) => {
|
||||
const isThisShellFocused =
|
||||
(name === SHELL_COMMAND_NAME || name === 'Shell') &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
ptyId === activeShellPtyId &&
|
||||
embeddedShellFocused;
|
||||
|
||||
const [lastUpdateTime, setLastUpdateTime] = useState<Date | null>(null);
|
||||
const [userHasFocused, setUserHasFocused] = useState(false);
|
||||
const showFocusHint = useInactivityTimer(
|
||||
!!lastUpdateTime,
|
||||
lastUpdateTime ? lastUpdateTime.getTime() : 0,
|
||||
SHELL_FOCUS_HINT_DELAY_MS,
|
||||
const isThisShellFocused = checkIsShellFocused(
|
||||
name,
|
||||
status,
|
||||
ptyId,
|
||||
activeShellPtyId,
|
||||
embeddedShellFocused,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (resultDisplay) {
|
||||
setLastUpdateTime(new Date());
|
||||
}
|
||||
}, [resultDisplay]);
|
||||
const isThisShellFocusable = checkIsShellFocusable(name, status, config);
|
||||
|
||||
useEffect(() => {
|
||||
if (isThisShellFocused) {
|
||||
setUserHasFocused(true);
|
||||
}
|
||||
}, [isThisShellFocused]);
|
||||
|
||||
const isThisShellFocusable =
|
||||
(name === SHELL_COMMAND_NAME || name === 'Shell') &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
config?.getEnableInteractiveShell();
|
||||
|
||||
const shouldShowFocusHint =
|
||||
isThisShellFocusable && (showFocusHint || userHasFocused);
|
||||
const { shouldShowFocusHint } = useFocusHint(
|
||||
isThisShellFocusable,
|
||||
isThisShellFocused,
|
||||
resultDisplay,
|
||||
);
|
||||
|
||||
return (
|
||||
// It is crucial we don't replace this <> with a Box because otherwise the
|
||||
@@ -112,13 +90,10 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
|
||||
description={description}
|
||||
emphasis={emphasis}
|
||||
/>
|
||||
{shouldShowFocusHint && (
|
||||
<Box marginLeft={1} flexShrink={0}>
|
||||
<Text color={theme.text.accent}>
|
||||
{isThisShellFocused ? '(Focused)' : '(tab to focus)'}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
<FocusHint
|
||||
shouldShowFocusHint={shouldShowFocusHint}
|
||||
isThisShellFocused={isThisShellFocused}
|
||||
/>
|
||||
{emphasis === 'high' && <TrailingIndicator />}
|
||||
</StickyHeader>
|
||||
<Box
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { act } from 'react';
|
||||
import { ToolMessage } from './ToolMessage.js';
|
||||
import { ShellToolMessage } from './ShellToolMessage.js';
|
||||
import { ToolCallStatus, StreamingState } from '../../types.js';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import {
|
||||
SHELL_COMMAND_NAME,
|
||||
SHELL_FOCUS_HINT_DELAY_MS,
|
||||
} from '../../constants.js';
|
||||
import type { Config, ToolResultDisplay } from '@google/gemini-cli-core';
|
||||
|
||||
vi.mock('../GeminiRespondingSpinner.js', () => ({
|
||||
GeminiRespondingSpinner: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('./ToolResultDisplay.js', () => ({
|
||||
ToolResultDisplay: () => null,
|
||||
}));
|
||||
|
||||
describe('Focus Hint', () => {
|
||||
const mockConfig = {
|
||||
getEnableInteractiveShell: () => true,
|
||||
} as Config;
|
||||
|
||||
const baseProps = {
|
||||
callId: 'tool-123',
|
||||
name: SHELL_COMMAND_NAME,
|
||||
description: 'A tool for testing',
|
||||
resultDisplay: undefined as ToolResultDisplay | undefined,
|
||||
status: ToolCallStatus.Executing,
|
||||
terminalWidth: 80,
|
||||
confirmationDetails: undefined,
|
||||
emphasis: 'medium' as const,
|
||||
isFirst: true,
|
||||
borderColor: 'green',
|
||||
borderDimColor: false,
|
||||
config: mockConfig,
|
||||
ptyId: 1,
|
||||
activeShellPtyId: 1,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
const testCases = [
|
||||
{ Component: ToolMessage, componentName: 'ToolMessage' },
|
||||
{ Component: ShellToolMessage, componentName: 'ShellToolMessage' },
|
||||
];
|
||||
|
||||
describe.each(testCases)('$componentName', ({ Component }) => {
|
||||
it('shows focus hint after delay even with NO output', async () => {
|
||||
const { lastFrame } = renderWithProviders(
|
||||
<Component {...baseProps} resultDisplay={undefined} />,
|
||||
{ uiState: { streamingState: StreamingState.Idle } },
|
||||
);
|
||||
|
||||
// Initially, no focus hint
|
||||
expect(lastFrame()).toMatchSnapshot('initial-no-output');
|
||||
|
||||
// Advance timers by the delay
|
||||
act(() => {
|
||||
vi.advanceTimersByTime(SHELL_FOCUS_HINT_DELAY_MS + 100);
|
||||
});
|
||||
|
||||
// Now it SHOULD contain the focus hint
|
||||
expect(lastFrame()).toMatchSnapshot('after-delay-no-output');
|
||||
expect(lastFrame()).toContain('(tab to focus)');
|
||||
});
|
||||
|
||||
it('shows focus hint after delay with output', async () => {
|
||||
const { lastFrame } = renderWithProviders(
|
||||
<Component {...baseProps} resultDisplay="Some output" />,
|
||||
{ uiState: { streamingState: StreamingState.Idle } },
|
||||
);
|
||||
|
||||
// Initially, no focus hint
|
||||
expect(lastFrame()).toMatchSnapshot('initial-with-output');
|
||||
|
||||
// Advance timers
|
||||
act(() => {
|
||||
vi.advanceTimersByTime(SHELL_FOCUS_HINT_DELAY_MS + 100);
|
||||
});
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot('after-delay-with-output');
|
||||
expect(lastFrame()).toContain('(tab to focus)');
|
||||
});
|
||||
});
|
||||
|
||||
it('handles long descriptions by shrinking them to show the focus hint', async () => {
|
||||
const longDescription = 'A'.repeat(100);
|
||||
const { lastFrame } = renderWithProviders(
|
||||
<ToolMessage
|
||||
{...baseProps}
|
||||
description={longDescription}
|
||||
resultDisplay="output"
|
||||
/>,
|
||||
{ uiState: { streamingState: StreamingState.Idle } },
|
||||
);
|
||||
|
||||
act(() => {
|
||||
vi.advanceTimersByTime(SHELL_FOCUS_HINT_DELAY_MS + 100);
|
||||
});
|
||||
|
||||
// The focus hint should be visible
|
||||
expect(lastFrame()).toMatchSnapshot('long-description');
|
||||
expect(lastFrame()).toContain('(tab to focus)');
|
||||
// The name should still be visible
|
||||
expect(lastFrame()).toContain(SHELL_COMMAND_NAME);
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { GeminiRespondingSpinner } from '../GeminiRespondingSpinner.js';
|
||||
@@ -12,12 +12,116 @@ import {
|
||||
SHELL_COMMAND_NAME,
|
||||
SHELL_NAME,
|
||||
TOOL_STATUS,
|
||||
SHELL_FOCUS_HINT_DELAY_MS,
|
||||
} from '../../constants.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { SHELL_TOOL_NAME } from '@google/gemini-cli-core';
|
||||
import {
|
||||
type Config,
|
||||
SHELL_TOOL_NAME,
|
||||
type ToolResultDisplay,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { useInactivityTimer } from '../../hooks/useInactivityTimer.js';
|
||||
|
||||
export const STATUS_INDICATOR_WIDTH = 3;
|
||||
|
||||
/**
|
||||
* Returns true if the tool name corresponds to a shell tool.
|
||||
*/
|
||||
export function isShellTool(name: string): boolean {
|
||||
return (
|
||||
name === SHELL_COMMAND_NAME ||
|
||||
name === SHELL_NAME ||
|
||||
name === SHELL_TOOL_NAME
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the shell tool call is currently focusable.
|
||||
*/
|
||||
export function isThisShellFocusable(
|
||||
name: string,
|
||||
status: ToolCallStatus,
|
||||
config?: Config,
|
||||
): boolean {
|
||||
return !!(
|
||||
isShellTool(name) &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
config?.getEnableInteractiveShell()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this specific shell tool call is currently focused.
|
||||
*/
|
||||
export function isThisShellFocused(
|
||||
name: string,
|
||||
status: ToolCallStatus,
|
||||
ptyId?: number,
|
||||
activeShellPtyId?: number | null,
|
||||
embeddedShellFocused?: boolean,
|
||||
): boolean {
|
||||
return !!(
|
||||
isShellTool(name) &&
|
||||
status === ToolCallStatus.Executing &&
|
||||
ptyId === activeShellPtyId &&
|
||||
embeddedShellFocused
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to manage focus hint state.
|
||||
*/
|
||||
export function useFocusHint(
|
||||
isThisShellFocusable: boolean,
|
||||
isThisShellFocused: boolean,
|
||||
resultDisplay: ToolResultDisplay | undefined,
|
||||
) {
|
||||
const [lastUpdateTime, setLastUpdateTime] = useState<Date | null>(null);
|
||||
const [userHasFocused, setUserHasFocused] = useState(false);
|
||||
const showFocusHint = useInactivityTimer(
|
||||
isThisShellFocusable,
|
||||
lastUpdateTime ? lastUpdateTime.getTime() : 0,
|
||||
SHELL_FOCUS_HINT_DELAY_MS,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (resultDisplay) {
|
||||
setLastUpdateTime(new Date());
|
||||
}
|
||||
}, [resultDisplay]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isThisShellFocused) {
|
||||
setUserHasFocused(true);
|
||||
}
|
||||
}, [isThisShellFocused]);
|
||||
|
||||
const shouldShowFocusHint =
|
||||
isThisShellFocusable && (showFocusHint || userHasFocused);
|
||||
|
||||
return { shouldShowFocusHint };
|
||||
}
|
||||
|
||||
/**
|
||||
* Component to render the focus hint.
|
||||
*/
|
||||
export const FocusHint: React.FC<{
|
||||
shouldShowFocusHint: boolean;
|
||||
isThisShellFocused: boolean;
|
||||
}> = ({ shouldShowFocusHint, isThisShellFocused }) => {
|
||||
if (!shouldShowFocusHint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box marginLeft={1} flexShrink={0}>
|
||||
<Text color={theme.text.accent}>
|
||||
{isThisShellFocused ? '(Focused)' : '(tab to focus)'}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export type TextEmphasis = 'high' | 'medium' | 'low';
|
||||
|
||||
type ToolStatusIndicatorProps = {
|
||||
@@ -29,10 +133,7 @@ export const ToolStatusIndicator: React.FC<ToolStatusIndicatorProps> = ({
|
||||
status,
|
||||
name,
|
||||
}) => {
|
||||
const isShell =
|
||||
name === SHELL_COMMAND_NAME ||
|
||||
name === SHELL_NAME ||
|
||||
name === SHELL_TOOL_NAME;
|
||||
const isShell = isShellTool(name);
|
||||
const statusColor = isShell ? theme.ui.symbol : theme.status.warning;
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
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) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
exports[`Focus Hint > 'ShellToolMessage' > shows focus hint after delay even with NO output > initial-no-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
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) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
exports[`Focus Hint > 'ShellToolMessage' > shows focus hint after delay with output > initial-with-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
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) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
exports[`Focus Hint > 'ToolMessage' > shows focus hint after delay even with NO output > initial-no-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
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) │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
exports[`Focus Hint > 'ToolMessage' > shows focus hint after delay with output > initial-with-output 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command A tool for testing │
|
||||
│ │"
|
||||
`;
|
||||
|
||||
exports[`Focus Hint > handles long descriptions by shrinking them to show the focus hint > long-description 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Shell Command AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA… (tab to focus) │
|
||||
│ │"
|
||||
`;
|
||||
Reference in New Issue
Block a user