Files
claude-chill/crates
adam 7e0accc032 fix: tmux passthrough + renderer state drift + exit cleanup
Investigating "weird redraw issues" surfaced by the wezterm-term swap
turned up four separate bugs in the proxy↔terminal byte path:

1. TerminfoRenderer caches CellAttributes across render_to calls.
   The trailing raw `\x1b[0m` and out-of-band CLEAR_SCREEN writes
   left its `current_attr` desynced from the real terminal — next
   frame's SGR transitions were computed against the wrong baseline,
   manifesting as bg-color smears and sticky links. Route the reset
   through `Change::AllAttributes(default)` so the renderer's pen
   stays in sync, and recreate the renderer whenever `force_full`
   fires (startup, lookback exit, alt exit, resize) so the cached
   state can't outlive an out-of-band write.

2. Proxy startup didn't clear the terminal, so the first VT diff
   landed on top of whatever the user's shell had on screen. Wipe
   on spawn alongside enabling bracketed paste.

3. `Drop` only disabled bracketed paste and restored termios, so an
   exit mid-render leaked active styles into the shell prompt and
   left Claude's last UI frame on screen. Add OSC-8 close → SGR 0 →
   CLEAR_SCREEN → CURSOR_HOME before the existing teardown.

4. Under tmux, steady-state diff renders produced a palimpsest of
   stacked frames because termwiz's `Surface::diff_lines` only walks
   the new frame's *visible* cells — cells that became blank don't
   generate clearing Changes. tmux is also tracking the grid and is
   sensitive to the partial repaint stream. Detect `$TMUX` at spawn
   and switch to passthrough: feed wezterm-term for state but
   forward raw child bytes to stdout. Lookback's one-shot full
   repaint still uses the renderer (screen is cleared first, so
   the diff_lines blank-cell behavior is fine).

Test infrastructure:
- New shared `test_support::pty_mock_binary()` honors CARGO_TARGET_DIR,
  tries debug/release, and panics with an actionable message instead
  of returning Option<String>. All 8 `let Some(...) else { return; }`
  silent-skip patterns replaced with direct destructure.
- Mirror is now advanced after `render_to` succeeds, not before.

New regression tests:
- `sgr_reemitted_on_second_frame_after_wire_reset`
- `hyperlink_reemitted_on_second_frame_after_wire_close`
- `forced_full_render_reemits_sgr_after_renderer_recreate`
- `test_lookback_exit_emits_clear_screen` asserts CLEAR/HOME precede
  the SYNC-wrapped repaint payload.

122 passing / 0 failing / 4 ignored (the two pre-existing
underline-style cases plus the claude-CLI-required integration).
2026-05-03 06:08:27 +00:00
..