hermes-agent/web/src
Austin Pickett b8ceba97ed fix(web): make PTY resume sanitizer work against real PTY output
Review follow-up on the salvaged #47772 work. Three defects made the
filter a no-op or actively harmful in production, plus both Copilot
review items.

1. The blank-line burst filter never fired. pty_bridge.py spawns via
   ptyprocess.PtyProcess.spawn() and never calls setraw(), so the PTY
   line discipline runs with ONLCR: every LF the child writes reaches
   xterm as CRLF. The /\n{50,}/ pattern requires consecutive LF, so a
   real 1000-row burst matched nothing (verified against a live PTY:
   b"A"+b"\n"*5+b"B" is read back as b"A\r\n\r\n\r\n\r\n\r\nB").
   Now matches /(?:\r?\n){50,}/.

2. Bursts split across WebSocket frames were not collapsed. bridge.read()
   does os.read(fd, 65536) per drain tick and each read is forwarded as
   its own frame, so a burst spans frames and each fragment fell under
   the 50 threshold (3000 rows survived in a 40-byte-read simulation).
   The sanitizer now holds back a trailing newline run — including a lone
   trailing CR, since a frame can split a CRLF pair — and resolves it on
   the next frame or on flush.

3. Erase-code stripping was permanent, not resume-scoped. resumeParam is
   the durable session identity and is never cleared after connect, so
   every spinner/progress/status redraw in a resumed session lost its
   ESC[K and left stale glyphs. Suppression is now bounded to
   PTY_RESUME_SANITIZE_WINDOW_MS (30s) after connect; burst collapsing
   still applies for the life of the socket.

Copilot review items:
- flush() no longer writes a buffered partial CSI into xterm. #pending
  only ever holds an incomplete sequence, and emitting one leaves the
  parser in an in-escape state that swallows output after reconnect. A
  buffered newline run is still emitted (collapsed).
- Test expectations updated accordingly.

Tests: 29 cases (was 18), now using CRLF fixtures that match real PTY
output, plus cross-frame burst reassembly, CRLF-pair frame splits, and
post-window erase preservation. Full web suite 135 passing.
2026-07-29 12:21:48 -04:00
..
components fix(models): match bare Kimi Coding k3 when searching kimi 2026-07-26 21:22:40 -07:00
contexts fix(web): remove marketing backdrop stack for lighter dashboard shell 2026-06-29 12:30:24 -07:00
hooks Merge remote-tracking branch 'origin/main' into refactor/use-ds-primitives 2026-05-28 14:20:49 -04:00
i18n salvage(#51128): translate new session-filter strings across 17 locales; expose public get_session_rich_row for search hydration 2026-07-28 22:41:56 -07:00
lib fix(web): make PTY resume sanitizer work against real PTY output 2026-07-29 12:21:48 -04:00
pages fix(web): make PTY resume sanitizer work against real PTY output 2026-07-29 12:21:48 -04:00
plugins fix(web): theme terminal foreground and restore backdrop plugin slot 2026-06-29 12:30:24 -07:00
themes fix(web): theme terminal foreground and restore backdrop plugin slot 2026-06-29 12:30:24 -07:00
App.tsx perf(web): lazy-load dashboard routes and split heavy vendors 2026-07-26 16:30:28 -07:00
index.css feat(web): add Arabic (ar) locale with RTL support 2026-07-24 12:10:00 -05:00
main.tsx fix(dashboard): remove country flags from language picker (#29997) 2026-05-21 13:10:52 -07:00