Skip to content

feat(tui): move busy progress indicator above the input - #24

Merged
jkyberneees merged 1 commit into
mainfrom
feat/busy-status-line
Aug 8, 2026
Merged

feat(tui): move busy progress indicator above the input#24
jkyberneees merged 1 commit into
mainfrom
feat/busy-status-line

Conversation

@jkyberneees

Copy link
Copy Markdown
Contributor

Why

The ⠸ 🧠 thinking spinner lived in the header's top-right corner — the farthest spot from where your eyes are after hitting enter. It now renders on its own row between the transcript and the input box, right below the last user message.

What changed

  • statusLine() (new) — the busy indicator (spinner + context-aware label + elapsed timer) on a dedicated row above the input; hidden when idle, while an approval panel owns the input area, or while disconnected (header badge carries those states). Zero height cost when hidden.
  • statusBadge() — header keeps session-level states (disconnected / reconnecting… / ⚠ approval required / ● ready); the segment is empty while busy — no duplicate spinner, no trailing padding.
  • LayoutinputAreaHeight() accounts for the row via a shared statusLineVisible() predicate; every busy transition (sendPrompt, done, error, disconnect, errMsg) calls relayout() so the viewport shrinks/reclaims the row exactly.
  • README — "Context-aware progress" bullet updated to the new position.

Design note

Deliberately not injected into the transcript below the user message: it would scroll away as the reply streams, and an in-transcript thinking placeholder is explicitly off-limits (AGENTS.md, TestEmptyStreamingTurnHidden). The fixed line above the input sits directly below the last message at the moment it matters — the pattern other agent TUIs converged on.

Tests

  • TestStatusBadgeStates rewritten for the header/status-line split, incl. approval arriving mid-turn (badge announces, status line yields)
  • New TestStatusLinePlacement: renders below the last user message, absent from the header, exact +1-row layout math, hidden when idle / approval pending

Checklist

  • make fmt
  • make vet
  • make lint — 0 issues
  • make test — full -race suite green

The `⠸ 🧠 thinking` spinner sat in the header's top-right corner — the
farthest spot from where the eyes are after submitting a prompt. It now
renders on its own row between the transcript and the input box, right
below the last user message.

- statusBadge() keeps session-level header states (disconnected,
  reconnecting, approval required, ready); while busy the header segment
  is empty, so there is no duplicate spinner
- new statusLine() carries the context-aware label (tool progress,
  thinking, composing) with the elapsed timer; hidden while an approval
  panel owns the input area or the socket is down
- inputAreaHeight() accounts for the row via a shared statusLineVisible()
  predicate, and every busy transition (submit, done, error, disconnect,
  errMsg) relayouts so the viewport shrinks/reclaims the row exactly

Deliberately not injected into the transcript: it would scroll away as
the reply streams, and an in-transcript thinking placeholder is explicitly
off-limits (AGENTS.md, TestEmptyStreamingTurnHidden).
@jkyberneees
jkyberneees merged commit 94fc3e7 into main Aug 8, 2026
5 checks passed
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