Skip to content

Fix terminals staying black after mobile PWA resumes from background - #53

Merged
powerfooI merged 1 commit into
mainfrom
fix-terminal-resume-recovery
Aug 26, 2026
Merged

Fix terminals staying black after mobile PWA resumes from background#53
powerfooI merged 1 commit into
mainfrom
fix-terminal-resume-recovery

Conversation

@powerfooI

Copy link
Copy Markdown
Owner

Summary

Fixes terminals staying black after the mobile PWA returns from the lock screen or switches back from another app, requiring a manual page refresh to recover.

Root cause: while the OS freezes the page, it can kill the bridge WebSocket without delivering a close event. On resume, the overdue heartbeat fires on the zombie socket, the delayed close event tears the connection down (advancing the client generation, which status listeners capture), and the rejected heartbeat ping then triggers a second teardown that advances the generation again without a status transition. Scoped clients keep the stale generation forever: reconnect and global RPCs succeed, but terminal attach, metadata refresh, and terminal input are silently discarded as stale.

Changes:

  • Make handleDisconnect idempotent once the socket is fully torn down, and only let the heartbeat probe force-reconnect a live connection, so the client generation cannot advance twice without a status transition.
  • Probe the bridge socket as soon as the page foregrounds instead of waiting out the heartbeat interval.
  • On foreground resume, repaint xterm and re-arm terminals that lost their attach; surface an explicit error instead of a silent black terminal when the attach watchdog exhausts retries.
  • Fall back to a single rate-limited page reload when repeated attaches right after a genuine suspension still produce no frames.

Verification

  • bun run format:check && bun run lint && bun run test — 716 tests pass, including new regressions covering the frozen-resume generation desync.
  • cd web && bun run typecheck && bun run build; cd server && bun run typecheck.
  • Manually verified on a phone PWA over LAN: terminal content restores about two seconds after unlocking instead of staying black until a manual refresh.

Copilot AI lite review requested due to automatic review settings August 26, 2026 09:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes directly address the described root cause, include targeted regression tests for the generation/teardown edge case, and keep recovery behavior rate-limited and explicit.

Pull request overview

Fixes a mobile PWA resume failure mode where the bridge WebSocket can die silently while the page is frozen, leading to generation desync and terminals staying black until a manual refresh. The PR hardens the bridge connection lifecycle and adds a terminal-specific recovery path (including a rate-limited reload as a last resort) so terminals recover automatically after foregrounding.

Changes:

  • Harden bridge reconnection logic: make disconnect handling idempotent and add an explicit foreground probe to detect silently-dead sockets immediately.
  • Add terminal recovery utilities + tests to decide when a post-resume reload is allowed and rate-limited.
  • Add TerminalView resume handling: repaint xterm, re-arm stuck attaches on foreground, and surface an explicit attach error before falling back to a rate-limited reload.
File summaries
File Description
web/src/terminalRecovery.ts Adds reusable helpers/constants for arming post-resume recovery and rate-limiting reloads via storage.
web/src/terminalRecovery.test.ts Unit tests for the new terminal recovery decision logic and storage handling.
web/src/store.ts Probes the bridge immediately on foreground to kick off reconnect/reattach without waiting for the next heartbeat tick.
web/src/components/TerminalView.tsx Adds foreground/visibility recovery: repaint xterm, re-arm attach when stuck, and perform rate-limited reload on repeated no-frame attaches.
web/src/api.ts Makes heartbeat probe behavior safer and adds probeConnectionNow; makes handleDisconnect idempotent after full teardown.
web/src/api.test.ts Regression tests for probe/heartbeat/teardown generation behavior and silent-close detection.
CHANGELOG.md Documents the mobile PWA terminal resume fix under Unreleased.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@powerfooI
powerfooI merged commit b3f37ae into main Aug 26, 2026
2 checks passed
@powerfooI
powerfooI deleted the fix-terminal-resume-recovery branch August 26, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants