fix(terminal): hold synchronized resize repaints#303
Conversation
Issue: Grid/full resize in v0.64.0 made long terminal histories visibly repaint from the top because child TUIs received SIGWINCH and Architect presented their resize output before it settled. Solution: Keep the real PTY resize so agents learn the new dimensions, but suppress rendering while visible sessions are in DEC synchronized output mode. Track when mode 2026 starts and clear it after one second so a broken app cannot freeze the view.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8fc3c349f8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR addresses a terminal UX issue during grid/full transitions by detecting DEC synchronized output mode and temporarily holding render/present so users don’t see an in-progress top-to-bottom repaint during resize-triggered repaints.
Changes:
- Track per-session synchronized output state and start timestamp, with a 1s timeout to force-clear stuck mode.
- Skip render/present while any visible session is in synchronized output mode; continue processing PTY output and expire stuck mode in the frame loop.
- Document the resize/render invariant in the architecture notes.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/session/state.zig | Adds synchronized-output tracking/timeout logic plus unit tests around forced expiry. |
| src/app/runtime.zig | Detects synchronized output across visible sessions and suppresses rendering/idle classification while holding. |
| docs/ARCHITECTURE.md | Documents the new synchronized-output resize/render behavior and timeout. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Issue: Address PR #303 review comments about hidden sessions blocking full-view rendering and synchronized-output holds spinning the event loop. Solution: Scope full-view holds to the focused session while keeping previous-session checks for transitions that render both sessions. Pace synchronized-output holds with an explicit frame sleep so the loop keeps processing output and timeouts without relying on vsync presentation.
Handle DECRQM in Architect's VT stream handler so apps can query synchronized output state. Unknown ANSI and private modes now get the standard ;0 reply.
Solution
Grid/full transitions should still resize the PTY so running agents receive SIGWINCH and can adapt to the new terminal dimensions. The problem was that Architect presented the child process's resize repaint while it was still in progress, which made long sessions appear to scroll down from the top.
This change tracks DEC synchronized output mode on each session and skips render/present while any visible session is synchronizing. The previous frame stays on screen until the app finishes repainting, with a one-second timeout so a stuck synchronized-output mode cannot freeze the view indefinitely.
The architecture notes now document the resize/render invariant: PTY resize remains real, but synchronized resize repaints are held until they settle.
Test plan