Clear TODO backlog: --debug/--profile, codex selection, MCP orientation, perf

- Add --debug[=DIR] / --profile[=DIR] flags that write run artefacts
  (patterm.log, events.jsonl, per-child raw PTY captures, CPU + heap
  + goroutine pprof) to a dir without polluting stdout/stderr.
- Strengthen vendor-TUI orientation in three places (MCP
  initialize.instructions, the spawn_agent tool description, and
  help('spawning')) to head off codex's habits of poking the Unix
  socket via perl and shelling out to launch peers — both bypass
  caller identity and produce orphaned top-level tabs.
- Fix click-and-drag text selection from alt-screen TUIs. Host SGR
  mouse reporting now follows the focused child's screen side
  instead of being permanently armed; alt-screen TUIs that need
  mouse re-enable it themselves and the toggle is forwarded.
- Move drawSidebar() off the per-PTY-chunk hot path. Long claude
  session resume was paying a full sidebar rebuild for every
  scrolled chunk; the chrome ticker now drains a dirty flag at 60 Hz.
- Gate the per-chunk Title() CGO poll on a containsOSC scan so
  codex/ratatui's many SGR-only chunks no longer pay a CGO call each.
This commit is contained in:
2026-05-15 12:41:47 +01:00
parent 01fc108086
commit c120342709
11 changed files with 536 additions and 36 deletions

View File

@@ -33,6 +33,14 @@ type viewportRenderer struct {
// cache so the next drawSidebar repaints over the clobber.
scrolled bool
// childOnAlt tracks whether the focused child has entered its
// alternate screen (via ?47 / ?1047 / ?1049). Used to gate mouse-
// tracking-mode forwarding to the host: filter on primary so
// patterm's wheel-scrollback stays armed, forward on alt so codex
// (which disables mouse) lets the user select text and vim (which
// enables it) still gets mouse events.
childOnAlt bool
// skipUTF8 is set when the current multi-byte UTF-8 character started
// past the viewport's right edge. The starter byte was dropped, so
// the remaining continuation bytes must be dropped too instead of
@@ -65,6 +73,16 @@ func newViewportRenderer(l terminalLayout) *viewportRenderer {
return vr
}
// SetChildOnAlt seeds the renderer's view of the focused child's screen
// side. Used when a new renderer is constructed for an already-running
// child whose alt-screen transition we missed, so subsequent mouse-mode
// toggles are filtered/forwarded according to the right side.
func (vr *viewportRenderer) SetChildOnAlt(onAlt bool) {
vr.mu.Lock()
defer vr.mu.Unlock()
vr.childOnAlt = onAlt
}
func (vr *viewportRenderer) SetLayout(l terminalLayout) {
vr.mu.Lock()
defer vr.mu.Unlock()
@@ -236,15 +254,36 @@ func (vr *viewportRenderer) emitCSI() {
return
}
if isAltScreenMode(params) {
// Track the child's screen side so we know whether to filter
// or forward subsequent mouse-mode toggles. Entering alt
// disables host mouse reporting by default so codex (and
// any other alt-screen TUI that doesn't request mouse)
// allows the user to click-drag to select text. Alt-screen
// TUIs that want mouse (vim, less with -X) re-enable it
// via ?1000h after switching to alt — the forwarder below
// passes that through. Leaving alt re-arms host mouse for
// primary-screen wheel-scrollback.
wasAlt := vr.childOnAlt
vr.childOnAlt = final == 'h'
if !wasAlt && vr.childOnAlt {
vr.pending.WriteString("\x1b[?1000l\x1b[?1006l")
}
if wasAlt && !vr.childOnAlt {
vr.pending.WriteString("\x1b[?1000h\x1b[?1006h")
}
return
}
if isMouseTrackingMode(params) {
// Patterm owns mouse reporting on the host so wheel events keep
// flowing for scroll-viewport. The child's own emulator still
// observes the mode set/reset (it processes the same bytes we
// hand to ghostty_terminal_vt_write), so we know whether the
// child wants mouse input — we just don't let it disarm our
// host listener.
// On the child's primary screen patterm owns mouse reporting so
// wheel events keep flowing for in-pane scrollback — drop the
// child's toggle. On the alt screen the child should be free
// to enable mouse (vim, less) or disable it (codex); we forward
// the toggle to the host so click-and-drag selection works for
// alt-screen TUIs that don't want mouse, and mouse-aware ones
// still see the events they need.
if vr.childOnAlt {
vr.pending.Write(vr.buf)
}
return
}
}