From 76f7b1bffd578e7c6ceca569d52b0fba9da81580 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 7 Apr 2026 21:16:38 +0000 Subject: [PATCH] fix(cli): bound memory growth in high-volume components --- packages/cli/src/ui/components/AnsiOutput.tsx | 5 ++-- .../messages/SubagentProgressDisplay.tsx | 8 +++---- .../src/ui/components/shared/text-buffer.ts | 24 ++++++++++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/ui/components/AnsiOutput.tsx b/packages/cli/src/ui/components/AnsiOutput.tsx index 617740d4ad..77af60e519 100644 --- a/packages/cli/src/ui/components/AnsiOutput.tsx +++ b/packages/cli/src/ui/components/AnsiOutput.tsx @@ -35,16 +35,17 @@ export const AnsiOutputText: React.FC = ({ ? Math.min(availableHeightLimit, maxLines) : (availableHeightLimit ?? maxLines ?? DEFAULT_HEIGHT); + const MAXIMUM_ANSI_LINES_RENDERED = 1000; const lastLines = Array.isArray(data) ? disableTruncation - ? data + ? data.slice(-MAXIMUM_ANSI_LINES_RENDERED) : numLinesRetained === 0 ? [] : data.slice(-numLinesRetained) : []; return ( - {(lastLines as AnsiLine[]).map((line: AnsiLine, lineIndex: number) => ( + {lastLines.map((line: AnsiLine, lineIndex: number) => ( diff --git a/packages/cli/src/ui/components/messages/SubagentProgressDisplay.tsx b/packages/cli/src/ui/components/messages/SubagentProgressDisplay.tsx index 995c404d9d..8289e9ec71 100644 --- a/packages/cli/src/ui/components/messages/SubagentProgressDisplay.tsx +++ b/packages/cli/src/ui/components/messages/SubagentProgressDisplay.tsx @@ -86,8 +86,9 @@ export const SubagentProgressDisplay: React.FC< )} - {(historyOverrides ?? progress.recentActivity).map( - (item: SubagentActivityItem) => { + {(historyOverrides ?? progress.recentActivity) + .slice(-100) + .map((item: SubagentActivityItem) => { if (item.type === 'thought') { const isCancellation = item.content === 'Request cancelled.'; const icon = isCancellation ? 'ℹ ' : '💭'; @@ -155,8 +156,7 @@ export const SubagentProgressDisplay: React.FC< ); } return null; - }, - )} + })} {progress.result && ( diff --git a/packages/cli/src/ui/components/shared/text-buffer.ts b/packages/cli/src/ui/components/shared/text-buffer.ts index d6b95d6016..56ab575c96 100644 --- a/packages/cli/src/ui/components/shared/text-buffer.ts +++ b/packages/cli/src/ui/components/shared/text-buffer.ts @@ -2779,7 +2779,29 @@ export function textBufferReducer( action: TextBufferAction, options: TextBufferOptions = {}, ): TextBufferState { - const newState = textBufferReducerLogic(state, action, options); + let newState = textBufferReducerLogic(state, action, options); + + const MAX_TEXT_BUFFER_LINES = 10000; + if (newState.lines.length > MAX_TEXT_BUFFER_LINES) { + const excess = newState.lines.length - MAX_TEXT_BUFFER_LINES; + const newLines = newState.lines.slice(excess); + const newCursorRow = Math.max(0, newState.cursorRow - excess); + let newExpandedPaste = newState.expandedPaste; + if (newExpandedPaste) { + const newStartLine = newExpandedPaste.startLine - excess; + if (newStartLine < 0) { + newExpandedPaste = null; + } else { + newExpandedPaste = { ...newExpandedPaste, startLine: newStartLine }; + } + } + newState = { + ...newState, + lines: newLines, + cursorRow: newCursorRow, + expandedPaste: newExpandedPaste, + }; + } const newTransformedLines = newState.lines !== state.lines