Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
This commit is contained in:
Jacob Richman
2026-01-22 16:02:14 -08:00
committed by GitHub
parent beacc4f6fd
commit a1f5d39029
6 changed files with 342 additions and 130 deletions
@@ -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>