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:
@@ -397,12 +397,15 @@ func (s *Session) pumpChild(c *Child, runID uint64) {
|
||||
}
|
||||
// OSC 0/2 title updates ride on the same byte stream as
|
||||
// the rest of the output. Polling the emulator after each
|
||||
// Write is cheap (one cgo call returning a borrowed
|
||||
// string) and lets the classifier treat title changes as
|
||||
// an activity signal — even when the title isn't visible
|
||||
// in the rendered grid.
|
||||
if t, terr := em.Title(); terr == nil {
|
||||
c.recordTitle(t)
|
||||
// chunk is cheap on its own (one CGO call) but codex/
|
||||
// ratatui sends so many small chunks that the per-chunk
|
||||
// CGO cost becomes measurable. Skip the Title poll when
|
||||
// the chunk doesn't carry an OSC start byte at all; the
|
||||
// title can only change on chunks that include one.
|
||||
if containsOSC(chunk) {
|
||||
if t, terr := em.Title(); terr == nil {
|
||||
c.recordTitle(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
c.recordWrite(chunk)
|
||||
@@ -679,6 +682,24 @@ func (s *Session) Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
// containsOSC reports whether chunk holds a sequence that could begin
|
||||
// an OSC. OSC starts as ESC ] (0x1b 0x5d) or the bare C1 ] (0x9d),
|
||||
// so a chunk without either cannot have changed the emulator's OSC
|
||||
// title state. Used to short-circuit the per-chunk Title() poll from
|
||||
// pumpChild, which otherwise pays a CGO call for every chunk even
|
||||
// when codex/ratatui is just emitting SGR-styled output.
|
||||
func containsOSC(chunk []byte) bool {
|
||||
for i, b := range chunk {
|
||||
if b == 0x9d {
|
||||
return true
|
||||
}
|
||||
if b == 0x1b && i+1 < len(chunk) && chunk[i+1] == ']' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func logf(format string, args ...any) {
|
||||
if os.Getenv("PATTERM_DEBUG_LOG") == "" {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user