Repository navigation
feat(tui): flow transcript with top-left banner - #55
Merged
Merged
Conversation
The empty-session landing screen previously centered the logo and tip vertically while the prompt stayed anchored at the bottom, leaving a large void between them. Now the logo sits top-left with the tip flush beneath it and the prompt directly below (Codex-style); a trailing flex spacer keeps the group at the top only while the session is empty, so the prompt returns to the bottom once the first message arrives. The tip renders through the shared home_bottom slot (also used by the still-reachable home route), so left alignment is opt-in via a new optional placement slot prop honored by the tips and which-key contributors; no prop keeps the centered layout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Instead of snapping back to the bottom once the first message arrives, the prompt now rides directly below the last message and only reaches the bottom when the conversation fills the screen, like Codex. The banner moves inside the scrollbox as the transcript's first entry for root sessions, so it scrolls away with history and stays visible above short conversations. The scrollbox holds its flex-derived height regardless of content, so its maxHeight is clamped to the content height via a signal sampled from scroll.scrollHeight on the renderer root's layout-changed event; an unconditional trailing spacer absorbs the leftover space. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
While streaming into a transcript shorter than the screen, each content growth painted one frame with the previous clamp: the viewport was a row short, sticky-scroll shifted the transcript up, and the next frame shifted it back — visible flicker that stopped once the prompt reached the bottom (where the clamp no longer binds). layout-changed fires after yoga computes the layout but before it is applied and painted, and scroll.scrollHeight still holds last frame's value at that point. Read the fresh height off the content's yoga node instead and re-run calculateLayout so the frame paints with the updated clamp. Verified by sampling 400 rapid tmux captures during generation: the banner row never moves (12 shifted/blank frames before the fix). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks the session screen into a scrollback-style flow layout: the codev logo + tip sit at the top-left as the transcript's first entry, the prompt rides directly below the last message (or below the banner when the session is empty), and it only reaches the bottom of the screen once the conversation fills it — instead of a centered banner with a bottom-anchored input and a void between them.
packages/tui/src/routes/session/index.tsx: the banner (Logo+home_bottomtips slot) moves inside the transcript scrollbox as its first entry for root sessions (subagent sessions keep a plain 1-row pad), so it stays above short conversations and scrolls away with history. The scrollbox holds its flex-derived height regardless of content, so itsmaxHeightis clamped to the content height via atranscriptHeightsignal; an unconditional trailing flexGrow spacer absorbs the leftover space below the prompt. Once content overflows, the clamp exceeds the available space and the existing sticky-scroll behavior takes over (prompt effectively bottom-anchored, transcript pinned to the latest output).layout-changedhandler by reading the freshly computed height off the scrollbox content's yoga node, then re-runningcalculateLayoutso the clamp lands in the same frame. (scroll.scrollHeightis a frame stale at that point; painting with a stale clamp shifted the transcript up and back down each streamed line — visible flicker whenever the transcript was shorter than the screen.)packages/plugin/src/tui.ts:home_bottomslot props widened from{}to{ placement?: "center" | "start" }. The slot is shared with the still-reachable home route, so alignment is opt-in; no prop keeps the centered layout.feature-plugins/home/tips.tsx/feature-plugins/system/which-key.tsx: bothhome_bottomcontributors honorplacement="start"(left-align; tips drop their paddingTop 3).DIVERGENCES.md: updated the session route row and added rows for the three newly-diverged files.Verification
Drove the real TUI under tmux (120×35/45 and 100×28) through the full lifecycle:
capture-paneframes during a multi-stanza generation — the banner row never moved (12 shifted/blank frames before the same-frame clamp fix).-c: full transcript renders scrolled to the bottom with the input at the bottom.bun turbo typecheckpasses across all 31 packages (pre-push hook).placementprop → centered, upstream spacing).test/app-lifecycle.test.tsxepilogue test fails identically on cleanmain(known flake), unrelated to this change.🤖 Generated with Claude Code