feat(cli): improve visibility of shell commands in chat history

- Render the high-level intent description in the tool header.
- Display the full colorized bash command inside the tool's content box.
- Pass tool arguments to the UI to enable detailed rendering of completed tools.
This commit is contained in:
Taylor Mullen
2026-03-17 16:20:33 -07:00
parent e1eefffcf1
commit 1b4301d498
8 changed files with 78 additions and 5 deletions
@@ -132,6 +132,15 @@ describe('<ShellToolMessage />', () => {
{ status: CoreToolCallStatus.Success },
undefined,
],
[
'renders with colorized command in body',
{
status: CoreToolCallStatus.Success,
args: { command: 'for i in {1..3}; do echo $i; done' },
description: 'Loop through numbers',
},
undefined,
],
[
'renders in Error state',
{ status: CoreToolCallStatus.Error, resultDisplay: 'Error output' },
@@ -5,7 +5,7 @@
*/
import React from 'react';
import { Box, type DOMElement } from 'ink';
import { Box, Text, type DOMElement } from 'ink';
import { ShellInputPrompt } from '../ShellInputPrompt.js';
import { StickyHeader } from '../StickyHeader.js';
import { useUIActions } from '../../contexts/UIActionsContext.js';
@@ -24,6 +24,9 @@ import type { ToolMessageProps } from './ToolMessage.js';
import { ACTIVE_SHELL_MAX_LINES } from '../../constants.js';
import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js';
import { useUIState } from '../../contexts/UIStateContext.js';
import { colorizeCode } from '../../utils/CodeColorizer.js';
import { useSettings } from '../../contexts/SettingsContext.js';
import { theme } from '../../semantic-colors.js';
import {
type Config,
ShellExecutionService,
@@ -45,6 +48,8 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
description,
args,
resultDisplay,
status,
@@ -77,6 +82,7 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
constrainHeight,
} = useUIState();
const isAlternateBuffer = useAlternateBuffer();
const settings = useSettings();
const isThisShellFocused = checkIsShellFocused(
name,
@@ -165,6 +171,8 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
resultDisplay,
);
const shellCommand = args?.['command'];
return (
<>
<StickyHeader
@@ -209,6 +217,18 @@ export const ShellToolMessage: React.FC<ShellToolMessageProps> = ({
paddingX={1}
flexDirection="column"
>
{typeof shellCommand === 'string' && (
<Box flexDirection="row" marginBottom={1}>
<Text color={theme.text.secondary}>$ </Text>
{colorizeCode({
code: shellCommand,
language: 'bash',
maxWidth: terminalWidth - 4, // account for padding and borders
settings,
hideLineNumbers: true,
})}
</Box>
)}
<ToolResultDisplay
resultDisplay={resultDisplay}
availableTerminalHeight={availableTerminalHeight}
@@ -44,6 +44,7 @@ export interface ToolMessageProps extends IndividualToolCallDisplay {
export const ToolMessage: React.FC<ToolMessageProps> = ({
name,
description,
args: _args,
resultDisplay,
status,
kind,
@@ -331,3 +331,13 @@ exports[`<ShellToolMessage /> > Snapshots > renders in Success state (history mo
│ Test result │
"
`;
exports[`<ShellToolMessage /> > Snapshots > renders with colorized command in body 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────╮
│ ✓ Shell Command Loop through numbers │
│ │
│ $ for i in {1..3}; do echo $i; done │
│ │
│ Test result │
"
`;
+1
View File
@@ -51,6 +51,7 @@ export function mapToDisplay(
parentCallId: call.request.parentCallId,
name: displayName,
description,
args: call.request.args,
renderOutputAsMarkdown,
};
+1
View File
@@ -102,6 +102,7 @@ export interface IndividualToolCallDisplay {
parentCallId?: string;
name: string;
description: string;
args?: Record<string, unknown>;
resultDisplay: ToolResultDisplay | undefined;
status: CoreToolCallStatus;
// True when the tool was initiated directly by the user (slash/@/shell flows).