@@ -84,7 +84,7 @@ authorization (`/mcp` is the surface that names them), painted in
8484not spent on these standing marks. The brand
8585lockup sits at the left of the bottom rule with the working directory and git
8686branch at its right (` AppShell.promptTopRule ` / ` promptBottomRule ` ,
87- ` src/tui/shell.ts ` ). Context occupancy rides that bottom rule as a percent:
87+ ` src/tui/shell/internals .ts ` ). Context occupancy rides that bottom rule as a percent:
88880–60 ` UI.textDim ` , 61–80 ` UI.warning ` , 81–100 ` UI.error ` ; an optional cost
8989suffix stays dim. Both rules cost zero transcript rows because they
9090ride the prompt box's own border.
@@ -265,7 +265,7 @@ for `/status` or an operator question mid-run.
265265A blocking surface (permissions, an operator question, the model/provider
266266picker, help) occupies the shell's ** single overlay host**
267267(` src/tui/geometry/resolve.ts ` ,
268- ` src/tui/shell.ts:openListOverlay ` ). A second command surface replaces a
268+ ` src/tui/shell/overlay-host .ts:openListOverlay ` ). A second command surface replaces a
269269non-gate list on that host, or waits with a system line while a live
270270gate holds it. Palette may stack over a primary; Escape always walks
271271back along a single path to the prompt.
@@ -316,17 +316,23 @@ transcript, because that text would otherwise be unreachable before
316316approval. That dump carries no gutter label.
317317
318318The decision surfaces (permission approval, operator question) are the one
319- framed content in the shell, and they are shaped rather than merely listed
320- (` src/tui/overlay-body.ts ` ): a dithered header (` ░▒▓ ` ) carries the
321- subject in the action color — the only Breakthrough Orange on the card.
322- The overlay host border and title use calm dim chrome (` UI.textDim ` );
323- consequence impact in the description zone paints ` UI.warning ` (sand), not
324- orange. A blank row separates the subject from context. Choices wrap on word
325- boundaries — never middle-ellipsized — to a shared row count at the current
326- width (minimum two rows so short labels still breathe; a taller wrap raises
327- every choice to the same height so list paging stays a simple multiple). The
328- active choice is marked by a solid block (` █ ` ) rather than a background fill
329- (cream text, not orange).
319+ framed content in the shell, and their body is shaped rather than merely
320+ listed (` src/tui/overlay-body.ts ` ): a dithered header (` ░▒▓ ` ) carries the
321+ subject in the action color — the only Breakthrough Orange on the card. The
322+ overlay host border and title use calm dim chrome (` UI.textDim ` ); consequence
323+ impact in the description zone paints ` UI.warning ` (sand), not orange. A
324+ blank row separates the subject from context. Choices are deliberately small:
325+ each one is a bare, single-line action name (` Reject ` , ` Accept once ` , the
326+ scope's label) with no consequence text folded into the row. A scope's hint
327+ paints instead as a body message above the choice list
328+ (` permissionBodyFromRequest ` in ` src/tui/gate-wire.ts ` ), and the expand key,
329+ which binds only when the subject carries collapsed payloads, reveals the
330+ full body — collapsed payloads and hints alike — in the overlay
331+ and, whole, in the transcript. Every choice reserves the same fixed two rows
332+ (label plus a row of air) so list paging stays a simple multiple. The active
333+ choice is marked by text color alone — cream (` UI.text ` ) against the dim rows
334+ — with no leading marker, block, or background fill (` createOverlayList ` in
335+ ` src/tui/shell/overlay-list.ts ` ).
330336
331337## How selectors should work
332338
@@ -344,7 +350,7 @@ explicit pick and can go stale (`ProductHostConfig.activeModelId`'s doc
344350comment and ` annotateCurrent ` in ` src/tui/product-host.ts ` ).
345351
346352The ` / ` command list specifically (` src/tui/command-catalog.ts ` ,
347- ` shell.ts:openPalette ` /` repaintPalette ` ): width matches the prompt box — both
353+ ` src/tui/ shell/palette .ts:openPalette` /` repaintPalette ` ): width matches the prompt box — both
348354are painted at the geometry resolver's shared ` contentWidth `
349355(` geometry/resolve.ts:assignRects ` , ` overlay-view.ts:overlayRowWidth ` ). There is no
350356leading marker column and no per-row kind column; the selected row is marked
@@ -378,14 +384,14 @@ queued gate); Enter then dismisses and leaves the prompt as typed (`/z`).
378384Every entry is backed by the live command registry
379385(` src/tui/command-catalog.ts:commandItemsFromRegistry ` ) — there is no
380386separate palette overlay and no shell-owned action outside the registry. The
381- overlay this reuses is still internally called ` "palette" ` (` shell.ts ` 's
387+ overlay this reuses is still internally called ` "palette" ` (` src/tui/ shell/internals .ts` 's
382388` PrimaryOverlayKind ` ), a naming leftover from when a Ctrl+O command palette
383389also opened it; that chord is gone (see keybindings.ts), and the identifier
384390stayed because renaming an internal overlay tag has no user-facing effect.
385391
386392` ? ` no longer binds anything — it is a literal character everywhere, prompt
387393or transcript. The shortcut list it used to open is still reachable, as
388- ` /help ` (` src/tui/commands/built-in.ts ` , routed to ` shell.ts:openHelpOverlay `
394+ ` /help ` (` src/tui/commands/built-in.ts ` , routed to ` src/tui/ shell/palette .ts:openHelpOverlay`
389395via ` openCommandSurface ` 's ` "help" ` case, ` command-surfaces.ts ` ); the ` / ` row
390396in ` SHELL_SHORTCUTS ` documents that in place of a dedicated ` ? ` row.
391397
@@ -408,7 +414,7 @@ permissions. An 80-column terminal still seats the compact mark next to
408414them; when the terminal is too narrow, the hints win and the mark drops.
409415
410416The running build version is chrome, not part of the landing composition:
411- ` shell.ts ` 's ` versionRow ` /` versionBadge ` , a dedicated row pinned to the
417+ ` src/tui/ shell/index .ts` 's ` versionRow ` /` versionBadge ` , a dedicated row pinned to the
412418terminal's last line and right-aligned, distinct from ` landing.ts ` 's hero and
413419below sections. It only reserves that row while the landing screen is
414420showing (` relayout ` 's ` versionReserved ` /` terminalForGeometry ` ) — once there
@@ -427,7 +433,7 @@ runs — sees one row fewer than the real terminal. The badge does not sit in
427433way the task or agents panel is. An operator composing a long prompt on the
428434landing screen at, say, 23 rows gets an 8-row cap instead of 9. This is a
429435known, accepted cost of the badge rather than an oversight — see
430- ` terminalForGeometry ` 's doc comment in ` shell.ts ` for the exact mechanism.
436+ ` terminalForGeometry ` 's doc comment in ` src/tui/ shell/layout .ts` for the exact mechanism.
431437
432438While the landing is mounted, a mount-scoped 125ms timer advances snow
433439across a frozen mountain. It is cancelled on the first real transcript
@@ -586,13 +592,13 @@ Up/Down are caret motion first inside a multi-line buffer. History recall
586592only fires when the caret is already at the first or last wrapped row of the
587593buffer — i.e., has nowhere further to go
588594(` promptCaretAtFirstRow ` /` promptCaretAtLastRow ` in ` prompt-input.ts ` ,
589- consumed in ` shell.ts ` 's key handler). This is deliberate, not incidental:
595+ consumed in ` src/tui/ shell/keys .ts` 's key handler). This is deliberate, not incidental:
590596with DEC mouse reporting on, a terminal translates a wheel tick into the same
591597arrow-key byte sequence as a real keypress, so scroll and history navigation
592598cannot both be arrow-driven at the same time without one shadowing the
593599other. That is also why the main shell routes the mouse wheel to the
594600transcript rather than the prompt even when the wheel event hits the prompt's
595- own hit-tested region (` routePromptWheelToTranscript ` , ` shell.ts ` ) — arrow
601+ own hit-tested region (` routePromptWheelToTranscript ` , ` src/tui/ shell/keys .ts` ) — arrow
596602keys stay history/caret, wheel stays transcript scroll, and the two never
597603collide.
598604
@@ -602,17 +608,17 @@ paste replayed as raw keystrokes on a terminal that never sends a real
602608` paste ` event, so pasted multi-line text does not get split into multiple
603609sent messages. Once a real ` paste ` event has fired even once, the fallback
604610heuristic is permanently skipped for the rest of the session
605- (` shell.ts ` , the ` sawBracketedPaste ` guard).
611+ (` src/tui/ shell/keys .ts` , the ` sawBracketedPaste ` guard).
606612
607613Ctrl+V and Ctrl+P attach a PNG from the macOS clipboard
608- (` attachClipboardImage ` in ` shell.ts ` → ` readClipboardImage ` in
614+ (` attachClipboardImage ` in ` src/tui/ shell/prompt .ts` → ` readClipboardImage ` in
609615` image-attachments.ts ` ).
610616Cmd+V stays text (bracketed paste above). Clipboard image attach is
611617macOS-only; Linux/Windows bitmap clipboard paste is not supported.
612618` /paste-image ` is the same attach path.
613619
614620@-mention path completion opens a popup keyed off the ` @token ` under the
615- cursor (` openAtMentionSuggestions ` , ` src/tui/shell.ts ` ); every keystroke re-queries,
621+ cursor (` openAtMentionSuggestions ` , ` src/tui/shell/internals .ts ` ); every keystroke re-queries,
616622and a generation counter discards a slower, stale query's results if a newer
617623one already landed. Accept is refused unless that generation is still current
618624and a live ` @ ` token is under the cursor (the same ` @ ` the lookup started on).
@@ -631,7 +637,7 @@ Consecutive kills in the same direction accumulate into one ring entry the
631637way readline does, so a ` Ctrl+K Ctrl+K … Ctrl+Y ` sequence restores the whole
632638killed run in original order.
633639
634- The prompt repaints on every keystroke (` onFrame ` in ` shell.ts ` calls
640+ The prompt repaints on every keystroke (` onFrame ` in ` src/tui/ shell/index .ts` calls
635641` syncPromptRows ` /` syncTranscriptSpacer ` /` syncNoticeAfterLayout ` every frame,
636642not on a debounce) — anything added to the prompt's paint path must stay
637643cheap, because it runs at typing speed.
@@ -642,7 +648,7 @@ attachments. Clearing prompt text arms a 2-second quit window
642648Ctrl+C while the window is open quits — this
643649replaced an Ink-era yes/no exit-confirm modal with the same intent (an
644650explicit second confirmation) without adding a modal (` handleCtrlC ` ,
645- ` shell.ts ` ). See "Soft steer vs. follow-up" above for the two
651+ ` src/tui/ shell/prompt .ts` ). See "Soft steer vs. follow-up" above for the two
646652mid-run gestures and what interrupting does to fleet-agent lanes. The interrupt
647653keeps whatever is sitting in the queue rather than discarding it — the
648654operator typed those messages meaning them delivered, not meaning "cancel
@@ -671,7 +677,7 @@ running its own selection. Two chords cover remaining copy needs:
671677 ` ttlMs: RUNTIME_FLASH_MS ` so they clear themselves; omit TTL only for
672678 live conditions that stay true until replaced (stall notice, landing hold).
673679- ** Alt+M** toggles DEC mouse reporting off and back on
674- (` toggleMouseCapture ` , ` shell.ts ` ). Off, the terminal's own drag-select
680+ (` toggleMouseCapture ` , ` src/tui/ shell/copy .ts` ). Off, the terminal's own drag-select
675681 and copy work exactly as in any other terminal program; the status flash
676682 names the trade both ways ("Mouse released · drag to select and copy as
677683 usual · Alt+M to click rows" / "Mouse captured · drag text to copy ·
0 commit comments