On Windows (PowerShell inside Windows Terminal), `otto` painted the
welcome banner three times in scrollback instead of updating one
frame in place.
Root cause (pi-tui's differential render path):
- `tui.ts` uses RELATIVE cursor movement (`\x1b[N A/B`) for
diff-rendering. That requires `hardwareCursorRow` to match
the actual terminal cursor row.
- The welcome screen's yellow rule is exactly `termWidth` chars
(`welcome-screen.ts:192`) — the canonical auto-wrap edge case.
- Windows ConPTY's cursor state after writing exactly-width
characters differs from xterm's "pending wrap" semantic.
Each render drifts the tracked cursor by ~1 row.
- workflow's `session_start` handler has 5+ `await` boundaries,
each potentially scheduling a render. Drift compounds.
- After ~3 renders, differential updates write to wrong rows;
previous frame stays visible → stacked frames in scrollback.
Two pi-tui changes:
1. Re-enable DEC 2026 synchronized output on Windows. Modern
Windows Terminal supports `\x1b[?2026h/l`; the prior
`platform !== "win32"` guard predates that.
2. Force `fullRender(true)` (absolute-positioned clear + repaint)
for all non-first renders on Windows. Bypasses the
cursor-relative differential path entirely.
Trade-off: tiny extra write traffic per render, masked by sync
output. Opt-outs via PI_DISABLE_SYNC_OUTPUT=1 and
PI_DISABLE_WIN32_FULL_REDRAW=1.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>