From 7242361a6937c7caa34ffbeb55a12276800568da Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sun, 26 Apr 2026 16:55:56 -0500 Subject: [PATCH] fix(tui): wrap streaming markdown split in column Box MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit StreamingMd returned <> — a bare Fragment with two children. Each returns a , but its parent in messageLine.tsx (line 169) is `` with no flexDirection, which Ink defaults to 'row'. So during streaming the two column boxes rendered side-by-side, producing the visible "tokens jumble into two columns until it fixes itself" bug — the "fix" was message.complete flipping isStreaming→false, which swaps the StreamingMd subtree for a single DeferredMd/Md child (no siblings → row direction is harmless). Wrap the two siblings in a flexDirection="column" Box so they stack. Localized fix so the non-streaming path (single-child, works fine in a row parent) is untouched. Reported by user: > "tokens streaming... going into 2 columns randomly and jumbling > together until it fixes itself" No test changes — findStableBoundary tests still pass (the layout change is parent-structural, not in the boundary logic). Build clean, tsc clean, 352 tests pass. --- ui-tui/src/components/streamingMarkdown.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ui-tui/src/components/streamingMarkdown.tsx b/ui-tui/src/components/streamingMarkdown.tsx index e6dcbbfbcd..111ed61e09 100644 --- a/ui-tui/src/components/streamingMarkdown.tsx +++ b/ui-tui/src/components/streamingMarkdown.tsx @@ -19,11 +19,16 @@ // flips off → message moves to history and renders via directly), so // the ref resets naturally. // -// See src/app/useMainApp.ts for the reasoning on why we don't memoize the -// whole Md text during streaming: that cache never hits because `text` is -// growing. Mirror claude-code's `StreamingMarkdown` approach adapted to -// our line-based tokenizer. +// Layout: the two subtrees MUST render stacked (column). The parent +// container in messageLine.tsx is a default `flexDirection: 'row'` Box +// (Ink's default), so returning a bare Fragment of two siblings +// laid them out side-by-side — producing the "two jumbled columns while +// streaming" rendering bug. Wrapping in a flexDirection="column" Box +// here localizes the fix to the streaming path; the non-streaming +// already returns its own column Box, so its single-child case was never +// affected. +import { Box } from '@hermes/ink' import { memo, useRef } from 'react' import type { Theme } from '../theme.js' @@ -113,10 +118,10 @@ export const StreamingMd = memo(function StreamingMd({ compact, t, text }: Strea } return ( - <> + - + ) })