Guards four unbounded growth paths reachable at idle — the shape matches
reports of the TUI hitting V8's 2GB heap limit after ~1m of idle with 0
tokens used (Mark-Compact freed ~6MB of 2045MB → pure retention).
- `GatewayClient.logs` + `gateway.stderr` events: 200-line cap is bytes-
uncapped; a chatty Python child emitting multi-MB lines (traceback,
dumped config, unsplit JSON) retains everything. Truncate at 4KB/line.
- `GatewayClient.bufferedEvents`: unbounded until `drain()` fires. Cap
at 2000 so a pre-mount event storm can't pin memory indefinitely.
- `useMainApp` gateway `exit` handler: didn't reset `turnController`, so
a mid-stream crash left `bufRef`/`reasoningText` alive forever.
- `pasteSnips` count-capped (32) but byte-uncapped. Add a 4MB total cap
and clear snips in `clearIn` so submitted pastes don't linger.
- `StylePool.transitionCache`: uncapped `Map<number,string>`. Full-clear
at 32k entries (mirrors `charCache` pattern).
- drop inline `import()` type annotation in useSessionLifecycle (import
`PanelSection` at the top like everything else)
- include `panel` and `session.resumeById` in the useMainApp useMemo
deps now that the event handler depends on them
- wrap the derived `selected` range in a useMemo so it has stable
identity and stops invalidating the TextInput `rendered` memo every
render
- prettier re-sorting of a couple of export/import lines
- hermes-ink: export `withInkSuspended()` + `useExternalProcess()` that
pause/resume Ink around an arbitrary external process (built on the
existing enterAlternateScreen/exitAlternateScreen plumbing)
- tui: `launchHermesCommand(args)` spawns the `hermes` binary with
inherited stdio, with `HERMES_BIN` override for non-standard launches
- tui: `/model` and `/setup` slash commands invoke the CLI wizards
in-place, then re-preflight `setup.status` and auto-start a session on
success — no more exit-and-relaunch to finish first-run setup
- setup panel now advertises those slashes instead of only pointing
users back at the shell
- tui_gateway: route approvals through gateway callback (HERMES_GATEWAY_SESSION/
HERMES_EXEC_ASK) so dangerous commands emit approval.request instead of
silently falling through the CLI input() path and auto-denying
- approval UX: dedicated PromptZone between transcript and composer, safer
defaults (sel=0, numeric quick-picks, no Esc=deny), activity trail line,
outcome footer under the cost row
- text input: Ctrl+A select-all, real forward Delete, Ctrl+W always consumed
(fixes Ctrl+Backspace at cursor 0 inserting literal w)
- hermes-ink selection: swap synchronous onRender() for throttled
scheduleRender() on drag, and only notify React subscribers on presence
change — no more per-cell paint/subscribe spam
- useConfigSync: silence config.get polling failures instead of surfacing
'error: timeout: config.get' in the transcript