Skip to content

feat(tui): flow transcript with top-left banner - #55

Merged
quickbeard merged 4 commits into
mainfrom
landing-top-left
Jul 13, 2026
Merged

quickbeard merged 4 commits into
mainfrom
landing-top-left

Conversation

@quickbeard

@quickbeard quickbeard commented Jul 13, 2026 •

Copy link
Copy Markdown
Owner

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_bottom tips 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 its maxHeight is clamped to the content height via a transcriptHeight signal; 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).
  • The clamp is measured in the renderer root's layout-changed handler by reading the freshly computed height off the scrollbox content's yoga node, then re-running calculateLayout so the clamp lands in the same frame. (scroll.scrollHeight is 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_bottom slot 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: both home_bottom contributors honor placement="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:

  • Empty session: logo top-left, tip beneath, input directly below, empty space at the bottom.
  • After a short exchange: banner still visible at the top, input sitting directly under the assistant's reply.
  • Streaming stability: sampled 400 rapid capture-pane frames during a multi-stanza generation — the banner row never moved (12 shifted/blank frames before the same-frame clamp fix).
  • After a long response: input pinned to the bottom, transcript sticky-scrolled to the latest output; paging up reaches the banner at the top of the scrollback.
  • Reopening the session with -c: full transcript renders scrolled to the bottom with the input at the bottom.
  • bun turbo typecheck passes across all 31 packages (pre-push hook).
  • The home route path is untouched (no placement prop → centered, upstream spacing).
  • test/app-lifecycle.test.tsx epilogue test fails identically on clean main (known flake), unrelated to this change.

🤖 Generated with Claude Code

quickbeard and others added 2 commits July 13, 2026 15:20
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>
@quickbeard quickbeard changed the title feat(tui): move landing banner top-left with prompt beneath feat(tui): Codex-style flow transcript with top-left banner Jul 13, 2026
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>
@quickbeard quickbeard changed the title feat(tui): Codex-style flow transcript with top-left banner feat(tui): flow transcript with top-left banner Jul 13, 2026
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@quickbeard
quickbeard merged commit 629d84d into main Jul 13, 2026
4 of 5 checks passed
@quickbeard
quickbeard deleted the landing-top-left branch July 13, 2026 10:01
quickbeard added a commit that referenced this pull request Jul 14, 2026
Human-readable summary of the fork's user-facing fixes and features
(PRs #48, #51, #53, #55, #56, #60, #63, #65), complementing the
per-file conflict-resolution detail in DIVERGENCES.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
quickbeard added a commit that referenced this pull request Jul 14, 2026
Human-readable summary of the fork's user-facing fixes and features
(PRs #48, #51, #53, #55, #56, #60, #63, #65), complementing the
per-file conflict-resolution detail in DIVERGENCES.md.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant