diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx index 357df25780d6..2cfc352fd6d5 100644 --- a/packages/tui/src/routes/session/index.tsx +++ b/packages/tui/src/routes/session/index.tsx @@ -121,7 +121,14 @@ const TRANSCRIPT_BACKFILL_CHUNK = 60 type PendingAction = "steer" | "queue" | "cancel" const context = createContext<{ + /** Content width: terminal width minus vertical tabs, sidebar, and padding. */ width: number + /** + * Shared reactive terminal size. Transcript-row components must read this + * instead of calling useTerminalDimensions(), which registers one renderer + * resize listener per mounted component and grows with transcript length. + */ + terminal: { width: number; height: number } sessionID: string thinkingMode: () => ThinkingMode showThinking: () => boolean @@ -1124,12 +1131,25 @@ export function Session(props: { verticalTabsWidth: number }) { ), ) + // Memoized per axis so width readers do not re-run on height-only resizes + // (dimensions() is one object signal with identity equality) and vice versa. + const terminalWidth = createMemo(() => dimensions().width) + const terminalHeight = createMemo(() => dimensions().height) + return ( @@ -1829,10 +1848,10 @@ function AssistantFooter(props: { message: SessionMessageAssistant }) { {Locale.titlecase(props.message.agent)} - = 28}> + = 28}> · {model()} - = 36)}> + = 36)}> · {Locale.duration(duration())} @@ -2521,9 +2540,8 @@ function ToolImages(props: { parts: readonly SessionMessageAssistantTool[] }) { function SessionImages(props: { images: readonly { uri: string }[]; paddingLeft?: number }) { const ctx = use() const dialog = useDialog() - const dimensions = useTerminalDimensions() const images = createMemo(() => (ctx.config.session?.image_preview ? props.images : [])) - const height = createMemo(() => Math.max(4, Math.min(8, Math.floor(dimensions().height / 4)))) + const height = createMemo(() => Math.max(4, Math.min(8, Math.floor(ctx.terminal.height / 4)))) const visible = createMemo(() => images().slice(0, 3)) return (