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

@@ -6,7 +6,59 @@ loosely follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Fixed
- Long claude session resume (and codex steady-state rendering) is
noticeably faster. Two costs that scaled per-PTY-chunk are now
deferred or short-circuited: (1) `drawSidebar()` used to run
synchronously for every chunk that scrolled — on a session
resume where every chunk scrolls, this rebuilt the full sidebar
string hundreds of times for a frame that was almost always
cache-equal. The sidebar now signals dirty and the chrome ticker
(60 Hz) handles the repaint. (2) `pumpChild` polled the
emulator's OSC title after every PTY chunk via CGO, even for
chunks (the common case under codex/ratatui) that carry no OSC
bytes at all. The poll is now gated on a containsOSC scan over
the chunk.
- Click-and-drag text selection from alt-screen TUIs (codex in
particular) now works. Patterm used to keep host SGR mouse
reporting armed continuously, which forced the host terminal to
forward every click as an escape sequence and prevented native
selection. The host's mouse mode now follows the focused child's
screen side: primary-screen children keep mouse armed (so wheel
scrollback works), alt-screen children get host mouse disabled by
default. Alt-screen TUIs that need mouse events (vim, less, etc.)
re-enable mouse-mode themselves; the viewport renderer forwards
those toggles to the host while the child is on alt. Leaving alt
re-arms host mouse reporting so wheel scrollback resumes.
### Added
- MCP `initialize.instructions`, the `spawn_agent` tool description
(visible to LLMs via `tools/list`), and the `help('spawning')`
topic now spell out — in the three places vendor TUIs actually
consult — that the connected `patterm` MCP server is the only
correct way to drive the host. Anti-patterns called out by name:
(a) trying to launch `patterm` / `patterm mcp-stdio` themselves,
(b) piping JSON-RPC into the per-PID Unix socket via `perl` /
`nc` / `socat` / `curl`, and (c) shelling out to `claude` /
`codex` / `opencode` to start a peer. Each of those bypasses
caller identity, so a sub-agent spawned that way reads back as
a stray top-level tab instead of a child under the spawning
agent. Codex was hitting (b) and (c) in practice — this is the
fix.
- `--debug[=DIR]` flag captures detailed run artefacts for offline
analysis: a verbose `patterm.log` (the existing `PATTERM_DEBUG_LOG`
stream), an `events.jsonl` lifecycle log (spawn / exit / idle-state
changes with timestamps), and per-child `<id>.raw` files containing
the raw PTY byte stream. With no argument, the dated subdir
`$XDG_STATE_HOME/patterm/debug/YYYYMMDD-HHMMSS` is used; pass an
explicit path to override. All output goes to files — stdout/stderr
are untouched.
- `--profile[=DIR]` flag captures pprof data for performance work:
`cpu.pprof` (running for the lifetime of the session), plus
`heap.pprof` and `goroutine.pprof` snapshots written on shutdown.
Defaults to `$XDG_STATE_HOME/patterm/profile/YYYYMMDD-HHMMSS`.
All diagnostics (startup, errors) are written to `profile.log`
inside the dir, never to stdout/stderr.
- "New Terminal" entry in the command palette spawns a bare interactive
`$SHELL` pane (kind `terminal`). Unlike "Run process: …" presets,
which are session-persistent and reachable via `restart_process`,