Skip to content

fix: auto-restart stale daemon and improve connection error messages#1028

Merged
jackwener merged 5 commits intomainfrom
fix/daemon-reconnect-ux
Apr 15, 2026
Merged

fix: auto-restart stale daemon and improve connection error messages#1028
jackwener merged 5 commits intomainfrom
fix/daemon-reconnect-ux

Conversation

@jackwener
Copy link
Copy Markdown
Owner

Summary

Fixes the issue where a stale daemon (started before extension was installed) causes persistent "Browser not connected" errors that users can't resolve without discovering opencli daemon stop on their own.

  • Auto-restart: bridge.ts now auto-restarts the daemon when extension doesn't connect within the timeout, instead of just giving up. This gives the extension a fresh WebSocket endpoint to connect to.
  • Better error messages: All three error surfaces (cli.ts, bridge.ts, doctor.ts) now suggest opencli daemon stop && opencli doctor as the quick fix, instead of only saying "install the extension" or "run opencli doctor".

Root cause

The daemon is passive — it waits for the extension to connect via WebSocket at /ext. If the daemon starts before the extension is installed, and the extension's reconnection attempts fail (e.g., due to MV3 service worker suspension timing), the connection is never established. The old behavior was to wait 10s then tell the user to install the extension (which they already had).

Test plan

  • All 203 test files pass (1546 tests)
  • Manual: start daemon → install extension → verify auto-restart connects
  • Manual: verify improved error message shows "daemon stop && doctor" hint

When daemon is running but extension never connected (stale daemon started
before extension was installed), the CLI now auto-restarts the daemon to
give the extension a fresh WebSocket endpoint, instead of just waiting
and then telling the user to install the extension.

Also improves error messages across cli.ts, bridge.ts, and doctor.ts to
suggest "opencli daemon stop && opencli doctor" as the quick fix, since
that's what actually resolves the issue.
- Daemon /status now includes `daemonVersion` field
- bridge.ts: when daemon is running but extension not connected, checks
  daemonVersion vs CLI version. Only auto-restarts if version mismatch
  (stale daemon from older CLI). Same-version daemon shows improved error
  message with "opencli daemon stop && opencli doctor" hint.
- doctor.ts: explicitly identifies stale daemon (version mismatch) in
  diagnostics report, shows daemon version in status line
- cli.ts: error message changed to suggest "opencli daemon stop && opencli doctor"
…pawn

- Missing daemonVersion (pre-version daemon) is now treated as stale,
  covering the most common user scenario (old daemon without version field)
- After requestDaemonShutdown(), poll until daemon actually stops (port
  released) before spawning new one, with 3s timeout
- If shutdown request fails, log warning instead of silently proceeding
- doctor.ts also treats missing daemonVersion as stale with clear message
- If shutdown request fails or port isn't released within 3s, throw
  'Stale daemon could not be replaced' instead of blindly spawning on
  an occupied port
- Add tests for all three stale-daemon branches: same-version (no
  restart), missing daemonVersion (stale), mismatched version (stale)
… matching

browserAction() now checks `instanceof BrowserConnectError` first and
renders both message and hint, instead of string-matching on message
content. This ensures stale daemon errors ("Stale daemon could not be
replaced") surface the actionable hint to the user.
@jackwener jackwener merged commit 0040081 into main Apr 15, 2026
13 checks passed
@jackwener jackwener deleted the fix/daemon-reconnect-ux branch April 15, 2026 03:33
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.

1 participant