* fix(terminal): forward Option hotkeys to kitty-keyboard TUIs on compose layouts
On macOS layouts where Option composes characters (ABC and all non-US, the
effective default), pressing Option+P in a TUI that negotiated the kitty
keyboard protocol made xterm's kitty encoder report the composed codepoint
(alt+pi, CSI 960;3u) instead of the physical key (alt+p, CSI 112;3u). No TUI
binds the composed form, so agent hotkeys like OMP's Alt+P / Alt+M neither
fired nor typed anything.
Fix: mirror each pane's application-negotiated kitty flags with a scan-based
tracker fed only from PTY output (immune to Orca's defensive renderer-side
kitty resets on Ctrl+C interrupts and reattach), and have the terminal
shortcut policy encode Option chords as kitty CSI-u from the physical key
when the pane's app opted in. Dead keys stay exempt so Option composition
still works, and panes without kitty negotiation (shells) are unchanged.
Alt+Arrow / Alt+Backspace now defer to xterm's native kitty encoding in
kitty panes instead of the legacy readline translations.
The daemon's headless emulator tracks the same flags and re-arms them via
the snapshot rehydrate preamble (CSI = flags ; 1 u), so the behavior
survives window reloads and reattaches; PTY exit and cold restore reset the
mirror.
Validated byte-for-byte against a real omp 16.3.15 in a pty: the policy's
emitted CSI-u opens the temporary-model selector (Alt+P) and agent hub
(Alt+A), identical to the legacy ESC-prefixed forms it parses.
* fix(terminal): harden kitty Option-chord mirror for soft resets, replay redelivery, and non-QWERTY layouts
Three review findings on the kitty keyboard mirror, each verified against a
live omp 16.3.15 pty session using the real production modules:
- DECSTR: xterm's soft reset (CSI ! p) clears its kitty flags and stacks for
both screens without switching buffers; the tracker now mirrors that, so a
soft-resetting TUI stops receiving kitty-encoded Option chords.
- Replay redelivery: relay reconnects can redeliver the retained replay
window, and each scan of the app's one-time CSI > u push grew the mirrored
stack while the renderer's post-replay reset drained xterm's copy. The
TUI's single exit pop (omp emits a bare CSI < u on quit) then landed on a
stale frame, leaving Option+B/F/D kitty-encoded in a plain shell. Replay
paths now scan with scanReplay(), which applies pushes as idempotent sets
so redelivery cannot grow the stack; the live-output funnel and the
daemon's once-per-byte emulator keep full stack semantics.
- Layout-correct base keys: kitty CSI-u reports must carry the key's
unshifted codepoint in the active layout, but the encoder resolved it from
a US-QWERTY physical-code table — on Dvorak/Colemak/AZERTY-class layouts
(exactly the population whose effective Option-as-Alt default activates
this path) the wrong key's chord fired, e.g. Colemak Option+P sent alt+r.
A new keyboard-layout module caches Chromium's KeyboardLayoutMap (fetched
at terminal setup and on focus-in, like the option-as-alt probe) and the
policy resolves through it before the US fallback. Verified live: the
layout-resolved bytes open omp's model selector; the US-table bytes do not.
* fix(terminal): reset kitty mirror on fresh spawn to cover replaced-PTY late exits
The exit handler resets the per-pane kitty keyboard mirror, but a late exit
from a replaced PTY takes the stale-transport early return and skips it —
so a restart-in-place could leak the old TUI's kitty flags into the fresh
shell, kitty-encoding Option chords the shell cannot parse. A fresh spawn
is by definition a new process with kitty state at zero, so startFreshSpawn
now resets the reused tracker itself, alongside the other per-pane mode
state it already clears. Reattach paths are untouched, so a live TUI's
mirrored flags still survive reconnects.
---------
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>