Skip to content

Fix approval overlay pushing the prompt box off screen on short terminals - #597

Merged
TheGreatAxios merged 2 commits into
mainfrom
cl-5750-the-approval-surface-pushes-the-prompt-box-off-screen-and-renders
Aug 24, 2026
Merged

Fix approval overlay pushing the prompt box off screen on short terminals#597
TheGreatAxios merged 2 commits into
mainfrom
cl-5750-the-approval-surface-pushes-the-prompt-box-off-screen-and-renders

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Closes CL-5750.

Observed before the fix (permission overlay, 80-col terminal, src/tui/shell.ts in-flow layout with a live transcript):

  • 40 rows: no problem — overlay + all context text + choices fit comfortably above the prompt box.
  • 24 rows: overlay renders but only 1 choice row survives the fixed 8-line context budget; the resolver's "nothing left to collapse" fallback silently sizes the overlay below its own render minimum.
  • 15 rows: same shrinkage, worse — fewer choices fit.
  • 12 rows: zero choice rows painted. The overlay's fixed context text alone consumed the entire box the resolver could afford; the prompt box stayed on screen, but the operator had nothing to click.
  • 10 rows: same as 12 — no choices painted, overlay renders but is entirely context text with no options visible or reachable via what's on screen.

Root cause: composeDecisionBody's context section used a fixed 8-line budget (DECISION_CONTEXT_ROWS) regardless of terminal height. On a short terminal, the resulting overlay chrome (border + title + header + 8 lines of context) could exceed what the geometry resolver could ever grant (bounded by both the prompt's floor and OVERLAY_MAX_FRACTION). When the resolver's collapse loop ran out of zones to shrink, its fallback path (resolve.ts, "nothing left — accept best effort") silently accepted an overlay height below the overlay's own stated render minimum, instead of shrinking the overlay's own content. That produced a box whose fixed body text alone ate the whole frame, leaving no room for a single choice.

Fix:

  • src/tui/shell.ts: decisionContextBudget now computes the context-line budget from the terminal height, the prompt's floor (PROMPT_BASE_ROWS), the overlay's fraction cap (OVERLAY_MAX_FRACTION), and one guaranteed choice row — shrinking down to 0 context lines on the shortest terminals. Recomputed on resize (overlayRawBodyText is now cached so a live resize re-shapes the body instead of leaving it stuck at whatever it opened with).
  • src/tui/overlay-body.ts: composeDecisionBody now accepts a budget of 0, meaning the context section (and its surrounding blank rows) is skipped entirely rather than forced to cost at least one row it cannot afford.

What wins when the terminal is too short for both: the approval choices win. The header (which tool / which question) is never dropped, but everything below it — the command detail, scope descriptions, "N more lines" hints — shrinks first, down to nothing, so at least one choice row and the prompt box (at its 3-row floor) are always painted together. An approval the operator cannot answer deadlocks the whole session, so it outranks readability of the context.

Tests added (src/tui/approval-prompt-visibility.test.ts): for terminal heights 10, 12, 15, 24, and 40 rows —

  • the prompt box's own border is painted in the captured frame (not just present in layout state) and never clipped past the frame's last row;
  • at least one approval choice is both tracked in the list-viewport state and actually painted in the frame;
  • a pathologically tall body (20 context lines) at 12 rows still leaves the prompt box and at least one choice visible;
  • at 24 rows, no dead-space zones sit between the overlay and the prompt box.

One existing CL-5694 overflow test asserted that a collapsed-command hint always appears in the rendered overlay body even at the shortest supported height; that assertion is now relaxed to check the hint against the raw (unrendered) body string instead, since the new priority is choices-over-context-detail at extreme heights — the hint's own source text is unaffected, only what gets painted when the terminal is too short for both.

bun run check is green (lint 0 errors, tsc --noEmit clean, build succeeds, 5377 tests pass).

@linear-code

linear-code Bot commented Aug 24, 2026

Copy link
Copy Markdown

CL-5750

@TheGreatAxios
TheGreatAxios force-pushed the cl-5750-the-approval-surface-pushes-the-prompt-box-off-screen-and-renders branch from 62e475d to 1a063d4 Compare August 24, 2026 05:12
@TheGreatAxios
TheGreatAxios enabled auto-merge (squash) August 24, 2026 05:21
…ompt box visible on short terminals

The decision overlay's context body used a fixed 8-line budget regardless of
terminal height. On a short terminal the resulting chrome could exceed the
overlay's own render minimum (border + title + header + at least one choice),
so the geometry resolver's "nothing left to collapse" fallback accepted an
overlay smaller than that minimum — the box rendered past its assigned rows
or lost every choice, while the prompt box stayed on screen but unanswerable.

The context budget is now computed from the terminal height, the prompt
floor, and the overlay's fraction cap, shrinking (down to 0 lines) so the
header and at least one choice row always fit. Recomputed on resize too.
…body text

applyOverlayBodyText cached every opened overlay's raw body text for a
resize to re-shape against, but a palette stacked over an open permission or
operator overlay called it too, with its own (empty) body — overwriting the
approval's cache. Popping the palette restores overlayBodyLines from the
snapshot but not this cache, so a resize right after re-shaped the approval
from the palette's stale empty string, blanking its body entirely (header
included). The cache write is now scoped to decision overlays, since a
palette never reads it back.

Also tightens decisionContextBudget's docblock and a test comment that
overclaimed the guarantee held below 10 rows; the resolver's own collapse
fallback (unrelated to this budget) still has a gap below that floor.
@TheGreatAxios
TheGreatAxios force-pushed the cl-5750-the-approval-surface-pushes-the-prompt-box-off-screen-and-renders branch from d928db5 to d7839db Compare August 24, 2026 05:23
@TheGreatAxios
TheGreatAxios merged commit 8af97ac into main Aug 24, 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