Skip to content

Redesign graveyard screen with shared card components - #149

Merged
TraderSamwise merged 2 commits into
masterfrom
chore/tui-next-5
Jun 16, 2026
Merged

Redesign graveyard screen with shared card components#149
TraderSamwise merged 2 commits into
masterfrom
chore/tui-next-5

Conversation

@TraderSamwise

@TraderSamwise TraderSamwise commented Jun 15, 2026

Copy link
Copy Markdown
Owner

What

Brings the graveyard screen into the dashboard's design language and removes footer/help-styling duplication across the TUI.

Graveyard redesign (Direction B)

  • Graveyarded worktrees and standalone-agent groups now render as the dashboard's rounded card() primitive in the muted tone (everything in the graveyard is dead), replacing the old flat indented text lines.
  • A new buildGraveyardCards() folds the flat view-model row stream into card blocks: each worktree → a card with its dead agents/services as body rows; each standalone-agent group → its own card.
  • [N] resurrect numbers render as real keycaps on selectable rows, recency shows as a chip in the card summary, dead agents/services keep the muted / status dots.
  • Focus/scroll mapping preserved; empty state unchanged.

DRY: consolidate footer/help-hint styling

There were three near-identical help/footer stylers. Consolidated into shared theme.ts helpers — keycapHint, keycapHints, keycapHintLines:

  • subscreens' styleFooterkeycapHints
  • dashboard's styleHelpGroup + buildHelpLineskeycapHintLines
  • overlays' hints() and styleHelpLine() now build on keycapHint

Preview (ANSI stripped, 120 cols)

  Worktrees

╭ ▸  1  test6 · test6 ──────────────────────────── 1 agent ╮
│   ○ claude:claude-ifc0xo (c64917c2…)                     │
╰──────────────────────────────────────────────────────────╯

  Agents by Worktree

╭ chat-parser ─────────────────────────────────────────────╮
│    4  ○ codex:codex-mrh12h                                │
╰──────────────────────────────────────────────────────────╯

Tests

  • typecheck ✓, lint ✓, build ✓
  • 1312 tests pass; added 4 graveyard-render + 3 keycap-hint-helper tests

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Improved keyboard keycap hint rendering, including muted labels and width-aware wrapping for help/footer text.
    • Added a two-pane layout width helper to keep the shared layout consistent.
  • Refactor
    • Updated dashboard help-key formatting to use the new keycap hint wrapping.
    • Refreshed the graveyard screen to use a card-based grouping layout for worktrees and agents.
    • Updated overlay/footer key-hint rendering to use the new hint formatting.
  • Tests
    • Added coverage for keycap hint tokens, grouping, and wrapping behavior.
    • Added a test suite covering graveyard screen rendering for key actions and statuses.

Render graveyarded worktrees and standalone agents as the dashboard's
rounded card() primitive in the muted tone (everything in the graveyard
is dead), with keycap resurrect numbers and recency chips — replacing the
old flat indented text lines so the screen matches the dashboard.

Consolidate the three near-identical footer/help-hint stylers (subscreens'
styleFooter, the dashboard's styleHelpGroup/buildHelpLines, overlays' hint
rendering) into shared keycapHint/keycapHints/keycapHintLines helpers in
theme.ts to prevent future style drift.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 16, 2026 12:01am

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 94bf68d3-285a-459f-a039-29f212dae94d

📥 Commits

Reviewing files that changed from the base of the PR and between 60a92cc and d4fe867.

📒 Files selected for processing (3)
  • src/tui/render/text.ts
  • src/tui/screens/subscreen-renderers.test.ts
  • src/tui/screens/subscreen-renderers.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/tui/screens/subscreen-renderers.test.ts
  • src/tui/screens/subscreen-renderers.ts

📝 Walkthrough

Walkthrough

Three new theme exports (keycapHint, keycapHints, keycapHintLines) are added to theme.ts for building styled keyboard hint segments with ANSI-aware width wrapping. All TUI screen footers, overlay hints, and the dashboard help-line builder are migrated to these helpers, removing the old styleFooter helper. The graveyard screen renderer is refactored from a flat row loop to a card-block grouping approach with new internal types and comprehensive tests. A new twoPaneLeftWidth layout helper centralizes left-pane width calculation.

Changes

keycapHint helpers, footer migration, and graveyard card renderer

Layer / File(s) Summary
keycapHint / keycapHints / keycapHintLines theme helpers
src/tui/render/theme.ts, src/tui/render/theme.test.ts
Exports three new helpers: keycapHint combines a keycap with an optional muted label; keycapHints parses a bracketed/plain key-hint string into styled segments; keycapHintLines wraps those segments into width-constrained lines using visibleWidth. Tests cover single hints, grouped footer strings, and multi-line wrapping.
Adopt keycapHint in dashboard and overlay renderers
src/tui/screens/dashboard-renderers.ts, src/tui/screens/overlay-renderers.ts
dashboard-renderers.ts removes its local bracketed-group parsing and calls keycapHintLines directly. overlay-renderers.ts replaces keycap() + muted style() composition with keycapHint() in both hints() and styleHelpLine().
Remove styleFooter and migrate subscreen footers
src/tui/screens/subscreen-renderers.ts
Removes the styleFooter helper and updates footers for workflow, activity, threads, notifications, and plans screens plus graveyard delete overlay button labels to use keycapHints/keycapHint directly.
Graveyard card-block rendering refactor
src/tui/screens/subscreen-renderers.ts
Introduces GraveyardCardRow, GraveyardCardBlock, GraveyardBlock types and buildGraveyardCards to group flat GraveyardViewRow[] into header/card blocks rendered via card(). renderGraveyardScreen rebuilds lineByItemIndex from block start lines and per-row actionIndex values.
Graveyard screen rendering tests
src/tui/screens/subscreen-renderers.test.ts
Adds Vitest suite with helpers that build deterministic graveyard view models and render via mocked TUI context. Tests assert card frame glyphs, keycap numbering, offline status dot, recency chip formatting, and orphan agent rendering as loose rows without card glyphs.
Extract twoPaneLeftWidth layout helper
src/tui/render/text.ts
Introduces exported helper twoPaneLeftWidth(cols) that centralizes the left-pane width calculation for the shared two-pane layout. Updates composeTwoPane to call this helper instead of duplicating the width formula inline.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • TraderSamwise/aimux#136: Modifies overlay-renderers.ts keycap/hint rendering toward the same theme-based design language that this PR extends with keycapHint.
  • TraderSamwise/aimux#135: Introduces src/tui/render/theme.ts primitives used by the dashboard; this PR adds keycapHint* helpers to that same file.
  • TraderSamwise/aimux#115: Exercises the TUI keycap-hint rendering changes by adding the Ctrl+A o overseer help binding line in the dashboard help overlay.

Poem

🐇 Hop hop, the keycaps align,
Each hint now styled in one clean line.
The graveyard cards stack neat in rows,
No more flat loops — the rabbit knows!
[Enter] yes, [Esc] goodnight,
The footer renders just right. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: redesigning the graveyard screen to use shared card components, which is the primary objective reflected across multiple files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/tui-next-5

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/tui/screens/subscreen-renderers.test.ts (1)

8-8: ⚡ Quick win

Stabilize recency assertions by freezing test time.

Line 8 uses Date.now() and Line 66 asserts an exact relative-time label ("1w ago"). This can become brittle as recency formatting thresholds evolve. Freeze the clock (or inject a fixed now) so this test stays deterministic.

Suggested change
-import { describe, expect, it } from "vitest";
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
@@
 function renderGraveyard(graveyardIndex = 0): string {
@@
 describe("renderGraveyardScreen", () => {
+  beforeEach(() => {
+    vi.useFakeTimers();
+    vi.setSystemTime(new Date("2026-01-10T00:00:00.000Z"));
+  });
+
+  afterEach(() => {
+    vi.useRealTimers();
+  });
+
   it("renders graveyarded worktrees as design-language cards", () => {

Also applies to: 64-67

🤖 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 `@src/tui/screens/subscreen-renderers.test.ts` at line 8, The `ago` function on
line 8 uses `Date.now()` directly, making the test brittle because relative-time
label assertions at lines 64-67 depend on the actual current time and will fail
as thresholds in the codebase evolve. Freeze the test clock by either mocking
Date.now() at the test setup level or refactoring the `ago` function to accept
an optional `now` parameter (defaulting to Date.now() for production but
allowing injection of a fixed timestamp in tests). This ensures the
relative-time assertions like "1w ago" remain deterministic and stable
regardless of when the test is run.
🤖 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 `@src/tui/screens/subscreen-renderers.ts`:
- Around line 464-465: The cardWidth calculation for two-pane mode at Line 464
uses 58% of cols, but the split-pane layout elsewhere (Line 503) is based on a
56% left-pane assumption, causing the graveyard card to be wider than the list
pane and clip content. Change the Math.max calculation for twoPane cardWidth to
use 56% instead of 58% to align with the split-pane sizing contract used
throughout this renderer.

---

Nitpick comments:
In `@src/tui/screens/subscreen-renderers.test.ts`:
- Line 8: The `ago` function on line 8 uses `Date.now()` directly, making the
test brittle because relative-time label assertions at lines 64-67 depend on the
actual current time and will fail as thresholds in the codebase evolve. Freeze
the test clock by either mocking Date.now() at the test setup level or
refactoring the `ago` function to accept an optional `now` parameter (defaulting
to Date.now() for production but allowing injection of a fixed timestamp in
tests). This ensures the relative-time assertions like "1w ago" remain
deterministic and stable regardless of when the test is run.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 527b30de-ade0-4562-9e18-311a6e3eaf4e

📥 Commits

Reviewing files that changed from the base of the PR and between 2b65110 and 60a92cc.

📒 Files selected for processing (6)
  • src/tui/render/theme.test.ts
  • src/tui/render/theme.ts
  • src/tui/screens/dashboard-renderers.ts
  • src/tui/screens/overlay-renderers.ts
  • src/tui/screens/subscreen-renderers.test.ts
  • src/tui/screens/subscreen-renderers.ts

Comment thread src/tui/screens/subscreen-renderers.ts Outdated
- Render orphan agents/teammates (no worktree group) as loose selectable
  rows beneath their section header instead of wrapping them in a
  blank-titled card.
- Derive the graveyard two-pane card width from a shared twoPaneLeftWidth()
  helper (also used by composeTwoPane) so card width matches the list pane
  by construction rather than a duplicated 0.58 literal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@TraderSamwise

Copy link
Copy Markdown
Owner Author

Concurrent sub-agent review (findings not overlapping the CodeRabbit thread):

  • [Fixed in d4fe867] Orphan agents/teammates (which have no worktree group) were being wrapped in a blank-titled ╭ ───╮ card via the implicit ensureCard() path — visual regression vs the old flat rows. Now rendered as loose selectable rows beneath their section header; cards are reserved for worktree/agent-worktree groupings. Regression test added.
  • [By design] Selecting a standalone agent inside an "Agents by Worktree" card maps focus to the agent's body row (not the card's top rule), so a tall card's header can scroll just above the viewport. This is intentional — you want the selected agent centered, and composeSplitScreen keeps it within a 1-line margin. Worktree rows (where the worktree itself is the selectable unit) still focus the card title.

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