Skip to content

feat(tui): add adaptive session tabs - #39396

Merged
kitlangton merged 22 commits into
v2from
tui-tabs-voice
Jul 28, 2026
Merged

feat(tui): add adaptive session tabs#39396
kitlangton merged 22 commits into
v2from
tui-tabs-voice

Conversation

@kitlangton

@kitlangton kitlangton commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What

Adds opt-in persistent session tabs to the TUI while preserving pinned sessions as the default navigation mode.

  • Enabling Settings > Session > Tabs replaces pinned quick slots with tab navigation and restores pins unchanged when disabled.
  • The strip remains visible with one real session. The existing new-session action navigates home without creating a synthetic tab; the first prompt creates and selects the real session tab.
  • Roomy tabs share width equally up to 32 cells. Under pressure, inactive tabs contract evenly toward 8 cells while the active tab receives the remaining width. A sticky overflow window takes over when needed.
  • Active, unread, attention, error, running, and idle states use distinct semantic treatments without status glyphs.
  • Running sweeps fade from their current phase on completion while a fast-attack, slow-decay accent background pulse is composited over them. Completion orange remains suppressed until the entire root-session family has no running or pending work.

How

  • context/session-tabs.tsx owns the real root-session working set, unread state, family activity, navigation, deletion reconciliation, and serialized persistence writes. Failed writes do not advance the persisted snapshot, so a later save can retry them.
  • context/session-tabs-model.ts contains the pure open, close, cycle, sticky-window, and adaptive-width rules.
  • component/session-tabs.tsx coordinates adaptive geometry, cached family status, state transitions, terminal-width title fading, and overlaid hover actions for real sessions.
  • ui/animation.ts gives numeric objects and arrays one lazy shared scheduler with spring and tween retargeting, disabled-animation snapping, and per-animation timing. The existing prompt metadata fade uses the same scheduler.
  • component/tab-pulse.tsx uses OpenTUI's shared render frame. Inactive pulse renderables are not live; running, fade-out, and completion channels share one compositing pass.
  • Mutually exclusive keymap layers prevent tab shortcuts from colliding with pinned-session quick slots.

Persistence

Real tabs and unread state are stored in the TUI global state directory as session-tabs.json.

Each TUI reads the global snapshot at startup and then owns process-local state. Running terminals do not live-sync, so concurrent writers are currently last-writer-wins. This PR does not claim project-scoped or synchronized tab workspaces; if cross-terminal sharing is desired, that state should become service-owned rather than adding more client-side file coordination.

Scope

  • Tabs remain disabled by default for compatibility with existing pinned-session behavior.
  • This does not add service, protocol, or database state.
  • This does not preserve transcript scroll position per tab; session routes retain their existing bottom-on-entry behavior.
  • This does not change Warp's interception of Ctrl+Tab; leader-arrow bindings remain available.

Testing

  • bun run test from packages/tui: 562 passed, 5 skipped, 0 failed.
  • bun typecheck from packages/tui: passed.
  • Push hook: all 33 workspace typecheck tasks passed.
  • Live PTY verification against the V2 service at compact and roomy widths.
  • Verified tab/pin mode switching, one-session visibility, sticky overflow, selection transitions, and resize stability.

Demo

Real-session route with one-space rail-less tab spacing:

Active session tabs

Flow

flowchart LR
  Settings{Session tabs enabled?}
  Pins[Pinned session picker]
  Sessions[Persisted real tabs]
  Home[New session screen]
  Created[First prompt creates session]

  Settings -- No --> Pins
  Settings -- Yes --> Sessions
  Sessions -- New session action --> Home
  Home -- Submit first prompt --> Created
  Created -- Add real tab --> Sessions
Loading

@kitlangton
kitlangton merged commit 37a1b80 into v2 Jul 28, 2026
9 checks passed
@kitlangton
kitlangton deleted the tui-tabs-voice branch July 28, 2026 21: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