hermes-agent/ui-tui/src
Brooklyn Nicholson f823535db2 perf(tui): instrument stdout drain — rule out terminal parse bottleneck
Adds four fields to FrameEvent.phases and the matching profile
summary:

  optimizedPatches  post-optimize patch count (what's actually
                    written to stdout; the .patches field is
                    pre-optimize)
  writeBytes        UTF-8 byte count of the write this frame
  backpressure      true when Node's stdout.write returned false
                    (Writable buffer full — outer terminal can't
                    keep up)
  prevFrameDrainMs  end-to-end drain time of the PREVIOUS frame's
                    write, captured from stdout.write's 2-arg
                    callback.  Reported on the next frame so the
                    measurement reflects "time until OS flushed
                    the bytes to the terminal fd", not "time until
                    queued in Node".

writeDiffToTerminal() now returns { bytes, backpressure } and
accepts an optional onDrain callback.  Only attached on TTY with
diff; piped/non-TTY stdout bypasses flow control so the callback
would fire synchronously anyway.

Initial measurements under hold-wheel_up against 1106-msg session
(30Hz for 6s):

  patches total    28,888
  optimized total  16,700   (ratio 0.58 — optimizer cuts ~42%)
  writeBytes       42 KB / 10s = 4.2 KB/s throughput
  drainMs p50      0.14 ms   terminal accepts bytes instantly
  drainMs p99      0.85 ms
  backpressure     0% of frames

This rules out the terminal-parse hypothesis — Cursor's xterm.js
drains our output in sub-millisecond time at only 4 KB/s.  The
remaining lag has to be in the render pipeline, not the wire.
Profile output now includes the bytes+drain+backpressure lines to
keep this visible on every subsequent iteration.
2026-04-26 17:06:22 -05:00
..
__tests__ feat(tui): anchor todo panel above streaming output 2026-04-26 16:26:50 -05:00
app perf(tui): scroll one row at a time per wheel event, half-viewport per pageUp 2026-04-26 17:01:22 -05:00
components revert(tui): drop DeferredMd, profiling showed it was neutral 2026-04-26 17:03:38 -05:00
config perf(tui): scroll one row at a time per wheel event, half-viewport per pageUp 2026-04-26 17:01:22 -05:00
content fix(tui): address Copilot review on editor handoff 2026-04-25 20:34:24 -05:00
domain fix(tui): apply details mode live 2026-04-26 13:34:33 -05:00
hooks feat(tui): archive todos at turn end with incomplete hint 2026-04-26 16:14:58 -05:00
lib perf(tui): instrument stdout drain — rule out terminal parse bottleneck 2026-04-26 17:06:22 -05:00
protocol refactor(tui): /clean pass across ui-tui — 49 files, −217 LOC 2026-04-16 22:32:53 -05:00
types perf(tui): instrument stdout drain — rule out terminal parse bottleneck 2026-04-26 17:06:22 -05:00
app.tsx fix(tui): apply ui-tui fix pass and restore type-check 2026-04-25 14:08:54 -05:00
banner.ts refactor(tui): /clean pass across ui-tui — 49 files, −217 LOC 2026-04-16 22:32:53 -05:00
entry.tsx perf(tui): full-pipeline instrumentation + profiling harness 2026-04-26 16:36:25 -05:00
gatewayClient.ts fix(tui): address PR #13231 review comments 2026-04-20 19:09:09 -05:00
gatewayTypes.ts fix(tui): stabilize live progress rendering 2026-04-26 15:23:43 -05:00
theme.ts feat(tui): subagent spawn observability overlay 2026-04-22 10:38:17 -05:00
types.ts feat(tui): collapse completed todo panel on turn end 2026-04-26 16:24:15 -05:00