Skip to content

fix(desktop): recover workspace after Electron main-process restart #172

Description

@akoita

What happened?

When the Electron main process rebuilds or restarts while a review is open, the renderer can continue displaying the previous review but approval, export, and review refresh operations fail.

The host stores the active workspace only in the process-local active variable in apps/desktop/src/electron/host.ts. A main-process restart clears that variable. The renderer can retain its existing DesktopReviewState, so the UI appears usable even though the replacement host has no open workspace.

A subsequent review.load fails with Open a workspace first. Approval and export similarly fail because review.dispatch and export.write resolve the stale workspace ID through workspaceFor.

Expected behavior: after a main-process restart, DraftLoop should either restore the previously opened local workspace safely or discard the stale review and present an actionable Open workspace recovery screen. It must not leave an apparently actionable review connected to a host with no workspace context.

Reproduction steps

  1. Start the desktop app in development mode:

    DRAFT_LOOP_ANTHROPIC_AUTH_MODE=api-key \\
    DRAFT_LOOP_OPENAI_AUTH_MODE=user-session \\
    pnpm --filter @draft-loop/desktop start
    
  2. Open a workspace and run a review.

  3. While the review remains rendered, trigger an Electron main-process rebuild/restart, for example by changing a main-process dependency during Forge/Vite development.

  4. Observe that the renderer may continue showing the review.

  5. Attempt to refresh, approve, or export.

Actual result: the operation fails and the terminal reports:

desktop host error (review.load): NativeHostError: Open a workspace first.

Immediate workaround: reload or restart the renderer, choose Open workspace, and select the existing workspace directory again.

Environment

  • OS: Ubuntu 24.04 Linux
  • Node: 24.5.0
  • pnpm: 10.18.3
  • Desktop package: 0.7.0-alpha.1
  • Revision: 3ca5bfb
  • Launch mode: Electron Forge with Vite development bundles

Relevant logs

[plugin-vite] target built src/electron/preload.ts
[plugin-vite] target built src/electron/main.ts

desktop host error (review.load): NativeHostError: Open a workspace first.

The Vite native-config/CommonJS warnings printed nearby appear unrelated.

Root cause

  • createNativeHost keeps the selected workspace only in a closure-local active variable.
  • workspace.open and workspace.create populate it, but a replacement main process starts with it unset.
  • Renderer startup and polling call review.load without a workspace identifier.
  • Polling failures preserve the last successful review state and set only the inline operation error, creating a stale split-brain UI.
  • Existing restart tests explicitly reopen the workspace before loading, so they do not cover host loss while renderer state survives.

Proposed fix

  1. Persist the most recently opened workspace root locally in the Electron main process, outside renderer-controlled IPC data.
  2. Restore and validate that root before the renderer performs its first review.load after a main-process restart.
  3. If restoration is unavailable or invalid, treat a not-found refresh/dispatch result as loss of workspace context: clear stale review state and show the workspace-opening recovery UI.
  4. Keep arbitrary filesystem paths out of renderer command input and preserve the native directory-selection boundary.

Acceptance criteria

  • A main-process restart while a review is visible does not leave approval or export controls attached to stale host state.
  • A valid previously opened workspace is restored safely, or the UI provides an actionable Open workspace recovery path.
  • Approval and Markdown export work after recovery.
  • Invalid, moved, or deleted remembered workspace paths fail safely and require explicit workspace selection.
  • A regression test covers: open workspace → load review → recreate host/main lifecycle → recover → approve → export.
  • Existing desktop host, bridge, and renderer tests continue to pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions