fix(cli): prevent crash in AnsiOutputText when handling non-array data (#24498)

This commit is contained in:
Sehoon Shon
2026-04-02 07:48:17 -04:00
committed by GitHub
parent 242afd49a1
commit 44c8b43328
3 changed files with 44 additions and 7 deletions

View File

@@ -156,4 +156,30 @@ describe('<AnsiOutputText />', () => {
expect(lastFrame()).toBeDefined();
unmount();
});
describe('robustness', () => {
it('does NOT crash when data is undefined', async () => {
const { lastFrame, unmount } = await render(
<AnsiOutputText
data={undefined as unknown as AnsiOutput}
width={80}
disableTruncation={true}
/>,
);
expect(lastFrame({ allowEmpty: true }).trim()).toBe('');
unmount();
});
it('does NOT crash when data is an object but not an array', async () => {
const { lastFrame, unmount } = await render(
<AnsiOutputText
data={{ summary: 'test' } as unknown as AnsiOutput}
width={80}
disableTruncation={true}
/>,
);
expect(lastFrame({ allowEmpty: true }).trim()).toBe('');
unmount();
});
});
});

View File

@@ -35,14 +35,16 @@ export const AnsiOutputText: React.FC<AnsiOutputProps> = ({
? Math.min(availableHeightLimit, maxLines)
: (availableHeightLimit ?? maxLines ?? DEFAULT_HEIGHT);
const lastLines = disableTruncation
? data
: numLinesRetained === 0
? []
: data.slice(-numLinesRetained);
const lastLines = Array.isArray(data)
? disableTruncation
? data
: numLinesRetained === 0
? []
: data.slice(-numLinesRetained)
: [];
return (
<Box flexDirection="column" width={width} flexShrink={0} overflow="hidden">
{lastLines.map((line: AnsiLine, lineIndex: number) => (
{(lastLines as AnsiLine[]).map((line: AnsiLine, lineIndex: number) => (
<Box key={lineIndex} height={1} overflow="hidden">
<AnsiLineText line={line} />
</Box>

View File

@@ -158,7 +158,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
terminalWidth={childWidth}
/>
);
} else {
} else if (Array.isArray(contentData)) {
const shouldDisableTruncation =
isAlternateBuffer ||
(availableTerminalHeight === undefined && maxLines === undefined);
@@ -175,6 +175,15 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
disableTruncation={shouldDisableTruncation}
/>
);
} else if (typeof contentData === 'object' && contentData !== null) {
// Render as JSON for other non-null objects
content = (
<Text wrap="wrap" color={theme.text.primary}>
{JSON.stringify(contentData, null, 2)}
</Text>
);
} else {
content = null;
}
// Final render based on session mode