Skip to content

feat(tui): make session tab status explicit - #45347

Merged
kitlangton merged 9 commits into
v2from
tab-status-icons
Aug 27, 2026
Merged

feat(tui): make session tab status explicit#45347
kitlangton merged 9 commits into
v2from
tab-status-icons

Conversation

@kitlangton

@kitlangton kitlangton commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Why
Session tabs distinguish running work and pending input mostly through subtle colors and the wave animation. It is easy to miss that a background session is waiting for an answer or permission rather than still working.

What Changes
Keep the wave, but give each state a recognizable indicator beside the title in both the top strip and sidebar:

Settings > Tabs > Indicators switches between status icons (default) and always show numbers. The latter keeps the numbered-tab presentation without holding Control, while retaining status colors and background animations. The preference is saved as tabs.indicators (status or numbers) in cli.json and applies immediately in both layouts.

State Default Indicator
Working Standard Braille spinner
Question pending ?
Permission pending !
Finished with unread activity Small bullet, original unread/accent color
Unread failure Same bullet, error red
Idle/read Blank
New-session placeholder +

The unread bullet appears in its final color immediately. Reading it gives a subtle brighten-and-fade into the current tab background over 180 ms, then leaves the slot blank. It never transitions through the running color. The existing background wave and clear pulse remain.

Selecting a pending ? or ! keeps its glow active, easing to 70% strength over 200 ms. Leaving restores full strength without replaying ignition; the clear pulse runs only when the request resolves. Requests include child sessions, and permission takes precedence when both kinds are pending. The public plugin API still exposes attention as a Boolean.

In status-icon mode, hold Control for 300 ms to reveal numbers with their existing colors and pulse. Release or terminal blur hides them immediately. Brief chords do not flash numbers, and jump bindings are not delayed. Kitty modifier-only reports update held state before command matching, preserving transcript selections and leader sequences; associated-text reporting preserves casing.

Semantic text.status.running, question, permission, and unread theme tokens distinguish running, attention, and unread colors. Built-in light/dark and standalone themes inherit defaults from their own hues and feedback tokens. The Tabs story retains alternate spinner/marker controls, reduced motion, both layouts, and idle/showcase resets for exploration.

Demo
Before 2602dcd0a7, after d521be850a. The same deterministic fixture drives real isolated sessions and the production TUI with a fictional simulated model. This 12-second, real-time sidebar crop shows the unchanged default status-icon mode: working, pending question/permission selection, unread clearing, and Control reveal/release. Setup and gaps are trimmed; no story controls or acceleration. The subsequently added number-mode setting is shown below.

final-tab-status.mp4

Number-mode setting at de2ecc2c4c, exercised through the real settings dialog in an isolated Drive session:

Tabs indicator setting

Scope
This changes tab presentation and modifier tracking, not the execution-outcome model. Alternate spinner and unread-marker styles are story controls only; production defaults are the Braille spinner and small bullet.

Verification

cd packages/tui
bun run test ./test/config-v2.test.tsx ./test/component/session-tabs-status.test.tsx ./test/keymap-kitty.test.tsx ./test/component/session-tabs-mouse.test.tsx ./test/component/tab-pulse.test.tsx
bun run test ./test/keymap-kitty.test.tsx ./test/keymap.test.tsx ./test/component/session-tabs-status.test.tsx ./test/component/session-tabs-mouse.test.tsx ./test/component/tab-pulse.test.tsx ./test/context/session-tabs.test.tsx ./test/theme/v2 ./test/util/selection.test.ts
bun run test ./test/keymap-kitty.test.tsx ./test/keymap.test.tsx ./test/component/session-tabs-status.test.tsx ./test/component/session-tabs-mouse.test.tsx ./test/component/tab-pulse.test.tsx ./test/context/session-tabs.test.tsx ./test/theme/v2 ./test/app-lifecycle.test.tsx ./test/util/selection.test.ts
bun run test ./test/app-lifecycle.test.tsx -t 'shows jump to latest after scrolling one line above the final message'
bun run test ./test/component/session-tabs-status.test.tsx
bun typecheck
cd ../theme
bun run test
bun typecheck
cd ../cli
bun typecheck
cd ../www
bun typecheck
bun run check:generated
bun run build

The latest mode-setting regression batch passed 37 tests (404 assertions). After the preceding test cleanup, the focused TUI suite passed all 103 tests (689 assertions); the four consolidated theme tests passed with 36 assertions. TUI, CLI, and website typechecks passed, as did all 32 normal pre-push typecheck tasks. The website build, formatting, and git diff --check passed.

The website's generated-file check initially found pre-existing stale message-update API snapshots. The build regenerated them and the check passed; those unrelated generated diffs are excluded from this PR.

Before the test cleanup, the broader TUI batch passed 112 tests and hit the previously observed timeout in shows jump to latest after scrolling one line above the final message; the isolated rerun passed. No scrolling code changed. An earlier full TUI run had the same intermittent failure (813 passed, 5 skipped).

Coverage includes first-frame unread/error colors, marker fade and interruption, animated attention dimming without clear/reignition, delayed and cancelled Control reveal, left/right Control and focus loss, selection copying, shifted leader sequences, Caps Lock text, child-request precedence, inline layout, mouse behavior, and light/dark/custom/standalone theme fallback. The real story was also exercised at narrow and wide terminal sizes.

A separate real Drive run passed the settings workflow: switch to numbers, verify the saved preference, resize from the sidebar to the narrow top strip, and switch back to status icons. Component tests verify that number mode survives Control release and blur and can be toggled without remounting.

Both Drive captures reached every checkpoint, but its bundled Ghostty replay crashed during export. The published clip replays the unchanged PTY bytes and timestamps through Drive's alternate-parser interface with xterm-headless, using the same rendering and encoding path. All eight comparison phases and the dot's fade were visually inspected. Capture commands are not counted as passing end-to-end tests.

@kitlangton
kitlangton marked this pull request as ready for review August 26, 2026 18:09
@kitlangton
kitlangton merged commit 4ac19d7 into v2 Aug 27, 2026
10 checks passed
@kitlangton
kitlangton deleted the tab-status-icons branch August 27, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant