feat(tui): premium splash + working-view redesign#83
Conversation
Centralized truecolor theme and a visual-first session UI. Splash: - Two-tone ANSI Shadow ZERO wordmark (bright blocks / dim shadow) - Replace Enter/Tab/Ctrl+C keycaps with a permission-mode status line - Rounded boxes for header and prompt Working view (3 zones): - Header bar: cwd, git branch, provider/model, run state - Role-gutter rows (you / zero), tool rows with ok/err status and arg hints - Colorized diff cards for patch/edit output - Pinned status line: mode (left) + model, tokens, cost (right) Internals: - Centralized palette in theme.go (role/status/diff/mode styles) - Enrich transcriptRow with tool/status/detail for structured rendering - gitBranch resolves .git/HEAD including worktrees
Zero automated PR reviewVerdict: No blockers found Blockers
Validation
ScopeHead: This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality. |
|
Ready to act? Review this PR in Change Stack to turn feedback into patch suggestions you can inspect and refine. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds a premium startup splash and refactors TUI rendering: centralized theme, startupView layout, width-aware row rendering (including tool-call/result metadata and diff cards), model UI state/window tracking, and command handling that toggles the splash; tests validate splash behavior and bordered block widths. ChangesPremium Startup Splash & Enhanced Transcript Rendering
Sequence Diagram(s)sequenceDiagram
participant TUI_View as TUI View
participant RenderRow as renderRow
participant ToolCall as renderToolCallRow
participant ToolResult as renderToolResultRow
participant DiffCard as diffCard
TUI_View->>RenderRow: renderRow(transcriptRow, width)
alt transcriptRow.kind == "tool-call"
RenderRow->>ToolCall: format tool name + detail
ToolCall->>TUI_View: formatted tool-call line
else transcriptRow.kind == "tool-result"
RenderRow->>ToolResult: check status, pass detail
alt looksLikeDiff(detail)
ToolResult->>DiffCard: build diffCard(detail, width)
DiffCard->>TUI_View: diff card block
else
ToolResult->>TUI_View: truncated muted one-line summary
end
else
RenderRow->>TUI_View: apply zeroTheme styling for conversation rows
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/tui/model_test.go`:
- Around line 145-167: The test calls next.View() before setting the model's
terminal dimensions, causing layout-dependent output to be incorrect; update the
model returned by m.Update (the variable named next of type model) to set
next.width and next.height to the same dimensions used in
TestInitialRenderShowsPremiumStartupSplash (e.g., assign appropriate integer
values to next.width and next.height) before calling next.View(), so the
splash/working view renders deterministically.
- Around line 169-177: The test TestStartupSplashStaysVisibleOnEmptySubmit must
set the model's terminal dimensions before calling View and assert that
working-view UI pieces are not present: initialize m.width and m.height (or call
the same size helper used in other tests) after newModel(...) and before calling
m.Update/View, then keep the positive assertion for "terminal coding agent" and
add negative assertions using assertNotContains for the role gutter markers and
status line strings (e.g. "▍ you", "◇ zero", "● ready") to match the pattern
used in TestInitialRenderShowsPremiumStartupSplash.
In `@internal/tui/startup.go`:
- Around line 213-218: The function fitStyledLine currently returns the input
unchanged and causes borderedBlock layout overflow; fix it by implementing
rune-safe truncation of styled/ANSI text: detect visible width with
lipgloss.Width, strip ANSI sequences (or use lipgloss utilities), truncate the
visible runes to the target width without breaking multi-rune graphemes, and
reapply/retain styling or use lipgloss.NewStyle().Width(width).Render(line) to
produce a width-limited rendered string; update fitStyledLine to return that
truncated/styled result so borderedBlock's padding math is correct.
- Around line 151-167: borderedBlock misaligns when lines are longer than
available width because fitStyledLine currently returns the full line; update
fitStyledLine to truncate strings to the provided width using lipgloss-aware
measurement (use lipgloss.Width to measure and lipgloss.Truncate or equivalent
to cut to the available width while preserving styling), ensure it accepts the
available width argument name matching usage in borderedBlock, and adjust the
call-sites (borderedBlock) to pass the numeric available width; add unit tests
that render oversized unstyled and styled lines through borderedBlock to assert
the right border stays aligned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 45593fdb-cd33-47da-82b5-af58c3b4bbe7
📒 Files selected for processing (7)
internal/tui/model.gointernal/tui/model_test.gointernal/tui/rendering.gointernal/tui/startup.gointernal/tui/theme.gointernal/tui/transcript.gointernal/tui/view.go
gnanam1990
left a comment
There was a problem hiding this comment.
Findings:
-
[blocking]
internal/tui/model.go:177-179strips the enrichedtranscriptRowfields before rendering.runAgentnow builds tool rows withtool,status, anddetail, but the response handler appends them withappendRow(m.transcript, row.kind, row.text), which keeps onlykindandtext. As a result, tool result rows lose their status/output/diff detail beforerenderToolResultRowruns, so error results can render as a green success icon and diff cards never appear in the live TUI path. Preserve the full row object when appendingmsg.rows(and add a regression around an error or diff tool result). -
[blocking]
internal/tui/session.go:108-110andinternal/tui/session.go:192-195have the same issue for resumed sessions.transcriptRowsFromSessionEventsdoes not populatetool,status, ordetailfor tool rows, thenhandleResumeCommandcopies rows throughappendRow, dropping any future metadata anyway. With the new renderer, resumedEventToolResultrows fall back to treating the whole old text as the tool name and default to a success icon with no output summary. Reconstruct and preserve full tool result rows from session events so resume shows the same status/detail semantics as live runs.
Validation run locally on the latest head fca36cb:
git merge --no-commit --no-ff origin/mainmerged cleanlygo test -count=1 ./internal/tuipassed before and after the merge checkgit diff --checkpassed
The earlier CodeRabbit sizing/truncation comments look fixed on the latest head, and CodeRabbit now approves; this remaining issue is in the newly introduced tool-row data flow.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
internal/tui/model_test.go (1)
186-188: 💤 Low valueConsider using string literals instead of Unicode escapes for readability.
The Unicode escape sequences work correctly but are harder to read than their literal forms. For test assertions, readability helps future maintainers.
♻️ Proposed refactor for readability
- assertNotContains(t, view, "\u258d you") - assertNotContains(t, view, "\u25c7 zero") - assertNotContains(t, view, "\u25cf ready") + assertNotContains(t, view, "▍ you") + assertNotContains(t, view, "◇ zero") + assertNotContains(t, view, "● ready")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/tui/model_test.go` around lines 186 - 188, The assertions use Unicode escape sequences which hurt readability; update the three asserts in model_test.go (the calls to assertNotContains with variable view) to use the actual Unicode characters instead of escapes — replace "\u258d you" with "▍ you", "\u25c7 zero" with "◇ zero", and "\u25cf ready" with "● ready" so the test strings are human-readable while keeping behavior the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@internal/tui/model_test.go`:
- Around line 186-188: The assertions use Unicode escape sequences which hurt
readability; update the three asserts in model_test.go (the calls to
assertNotContains with variable view) to use the actual Unicode characters
instead of escapes — replace "\u258d you" with "▍ you", "\u25c7 zero" with "◇
zero", and "\u25cf ready" with "● ready" so the test strings are human-readable
while keeping behavior the same.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: f5062c64-8718-4d88-a5c7-7bfe770c3f05
📒 Files selected for processing (5)
internal/tui/model.gointernal/tui/model_test.gointernal/tui/session.gointernal/tui/session_test.gointernal/tui/transcript.go
🚧 Files skipped from review as they are similar to previous changes (2)
- internal/tui/transcript.go
- internal/tui/model.go
Review: PR #83 — feat(tui): premium splash + working-view redesign (Vasanthdev2004 / Vasanth)URL: #83 Ownership FitExcellent match for Vasanth's lane (Product UX and TUI owner):
Directly addresses "TUI command flows need polish beyond basic rendering" and "startup screen stays minimal until the user asks for panels" from the baseline in WORK_SPLIT_PRD. What the PR Delivers (User-Visible)
Code & Architecture Observations (Runtime Contract Lens)Positive (from runtime owner's view):
Potential concerns / questions for discussion (why "Changes requested" was placed):
Tests & DoD
Fits the "For every code PR: Add or update tests..." rule. Alignment with PRD / WORK_SPLIT
Overall RecommendationStrong direction — this is the visual identity Zero needs. Conditional approve / Changes requested (consistent with existing gnanam1990 flag):
Once the runtime consumption and permission UX coordination points are addressed or explicitly deferred with owners' agreement, this should land cleanly. Vasanth: excellent work on the polish. This moves the "daily CLI feel" needle significantly. |
gnanam1990
left a comment
There was a problem hiding this comment.
The changes requested in my earlier review have been addressed:
- c536772: Preserves enriched transcriptRow metadata (tool/status/detail) for tool results in live updates, resume path, and added regression test. This was the main blocking point.
- fca36cb: Stabilizes splash/ startup rendering with proper width/height handling and test updates.
Relevant TUI tests pass. Good follow-through.
Approving.
Summary
Gives the terminal UI a visual-first identity: a centralized truecolor theme, a polished startup splash, and a three-zone working/session view.
Splash
ZEROwordmark — solid block strokes in bright cyan, drop-shadow strokes in dim cyan (depth with no per-glyph hacks;lipgloss.Widthignores ANSI so centering stays correct).Enter / Tab / Ctrl+Ckeycap hints with a professional⏵⏵permission-mode status line (shift+tab to cycle).╭──╮) for the header and prompt instead of ASCII+--+.Working / session view (3 zones)
zero · <cwd> · <git branch> · <provider/model> … ● ready— branch resolves from.git/HEAD(handles worktrees).▍ you/◇ zero, tool rows▸ read_file <arg hint>with✓/✗status, and colorized diff cards (╭─ edit · <tool> ─╮, green+/ red−) for patch/edit output.model · Nk↑ Nk↓ · $cost(from the usage tracker) on the right.Internals
theme.go(bright/dim cyan pair + role/status/diff/mode styles), shared by both views — replaces the raw ANSI"14"/"10"/"8".transcriptRowwithtool/status/detailso tool results can render structured cards.Deferred (follow-up)
bubbles/viewport+ alt-screen. The 3-zone structure is in place; the body renders inline for now (terminal-native scroll, no regression). Wiring the viewport needs height plumbing and is cleaner as its own change.Testing
go build ./...✓go test ./...(whole module) ✓go vet ./internal/tui/✓TestStartupSplashCollapsesAfterFirstPromptwas updated to assert the new working-view rendering (role gutters + status line) instead of the olduser:/assistant:prefixes; all other tests unchanged.Summary by CodeRabbit
New Features
Tests
Runtime / TUI contract note
TestAgentEventRenderingMappingCoversRuntimeContract: text, tool calls/results, plan updates, usage footer, errors, and control-only events are mapped explicitly.tui-sandbox-permissionsfollow-up once runtime permission events land, so this splash work does not redefine that contract.