Skip to content

fix(web-desktop): mirror a web-started Auto Run into the desktop app - #1520

Merged
pedramamini merged 1 commit into
rcfrom
fix/1519-mirror-web-autorun-to-desktop
Sep 7, 2026
Merged

fix(web-desktop): mirror a web-started Auto Run into the desktop app#1520
pedramamini merged 1 commit into
rcfrom
fix/1519-mirror-web-autorun-to-desktop

Conversation

@pedramamini

@pedramamini pedramamini commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

closes #1519

The report

Start an Auto Run from the web-desktop browser client and the desktop app never shows the agent as Auto Run-active, though it is running. Close the browser and the next queued task may never start. Starting from the desktop shows correctly in the browser.

Two symptoms, two different bugs

The reporter's instinct that these "likely share one root cause" is right about the root cause and wrong about the fix boundary, so this PR deliberately only takes the first.

Symptom (a), the desktop showing nothing, is a real gap and is fixed here.

Symptom (b), the run dying when the web client closes, is #1470 and is not fixed here. The run loop is a live async closure with let cursors inside it; when the client holding it goes away, the loop goes with it. Re-claiming an orphaned run needs a renderer liveness/ownership primitive that does not exist yet, which is exactly what #1470 is open on. Shipping a guess there can have two clients spawning tasks into the same working tree.

Root cause of (a)

Auto Run is renderer-owned state, so a run lives entirely in whichever client pressed Go. #1508 taught a web-desktop tab to RENDER a run owned by the desktop, but only in that direction:

  • The owner pushes state to main every tick via web:broadcastAutoRunState.
  • Main fans it out as an autorun_state WebSocket packet.
  • The Electron desktop app is not a WebSocket client.

So a run started in a browser tab had no path back to the desktop at all. useAutoRunStateMirror even encoded the assumption, gating both its effects on isWebDesktop(), and the preload comment said "In the Electron desktop app nothing sends it". True of the channel, wrong about the need.

The change

  • main/ipc/handlers/web.ts - forwardAutoRunStateToDesktopWindows() sends a bridge-originated broadcast straight to the desktop windows on remote:autoRunStateMirror, the channel the mirror hook already consumes. One consumer, two producers.
  • useAutoRunStateMirror drops its isWebDesktop() gate so the desktop has a consumer.
  • Preload and hook docs corrected; they asserted the one-way behaviour as intentional.

The echo, which is the part worth reviewing

The forward is narrowed to frames that arrived over the WebSocket bridge, identified by the synthetic FAKE_EVENT (type: 'bridge') that handleBridgeInvoke calls ipcMain handlers with.

A desktop-owned run must never be echoed back to its owner. The owning window would receive its own state and applyAutoRunMirrorFrame could stamp its own live run mirrored: true - and every Auto Run mutator refuses a mirrored entry, so Stop, Skip, Resume and Abort would go dead on the window actually driving the run. The renderer has its own ownership guard (existing?.isRunning === true && !isMirror), but the cheapest way to be certain is not to send the echo at all. Both layers are now in place.

It also deliberately bypasses safeSend, which fans every push out to the bridge as well - that would deliver this frame to web clients a second time, on a second channel, when they already receive it as autorun_state.

Deliberately unchanged

Targeting rc, not main

src/web-desktop/ and useAutoRunStateMirror.ts do not exist on main - the whole feature is rc-only.

Validation

  • npm run lint clean (all three tsconfigs).
  • npx eslint clean on every changed file.
  • npm run test - 42,091 passed, 0 failures.
  • 6 new tests covering the forward: fan-out to all windows, the owner echo being suppressed, null teardown reaching the desktop, destroyed-window skip, one window throwing not costing the others, and the forward surviving Live Mode having no server attached.

Local runs are single-OS; both CI matrix legs still need to be green.

Summary by CodeRabbit

  • New Features

    • Auto-run state is now mirrored between browser and desktop clients, keeping run status visible across connected views.
    • State updates, including cleared states, are forwarded to available desktop windows.
  • Bug Fixes

    • Improved auto-run synchronization when multiple desktop windows are open.
    • Updates continue reaching available windows when another window is closed or unavailable.

Auto Run is renderer-owned state, so a run lives entirely in the client
that started it. #1508 taught a web-desktop browser tab to RENDER a run
owned by the desktop, but only in that direction: `autorun_state` is a
WebSocket packet and the Electron app is not a WebSocket client, so a run
started IN the browser had no path back. The desktop drew the agent as
idle for the whole run.

Main now forwards a bridge-originated `web:broadcastAutoRunState` straight
to the desktop windows on `remote:autoRunStateMirror`, the channel the
mirror hook already consumes, and the hook drops its web-desktop-only
gate so the desktop has a consumer for it.

Forwarding is narrowed to frames that arrived over the WebSocket bridge.
A desktop-owned run must never be echoed back to its owner: the owning
window would receive its own state and could stamp its live run
`mirrored: true`, disabling Stop, Skip, Resume and Abort on the window
actually driving it. It also deliberately bypasses `safeSend`, whose
bridge fanout would deliver the same frame to web clients a second time
on a second channel.

This fixes visibility only. A run still dies with the client that owns
it (#1470), which needs the renderer ownership primitive that issue is
blocked on.
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: a4519f80-792f-4c32-93cc-6947289fe4b8

📥 Commits

Reviewing files that changed from the base of the PR and between d62b57b and 1deab18.

📒 Files selected for processing (4)
  • src/__tests__/main/ipc/handlers/web.test.ts
  • src/main/ipc/handlers/web.ts
  • src/main/preload/process/autoRunControlRemote.ts
  • src/renderer/hooks/batch/useAutoRunStateMirror.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

Auto Run state from web-desktop bridge invokes is now forwarded to Electron desktop windows. The renderer mirror hook consumes forwarded state in all builds while preserving local-run ownership behavior. Tests cover forwarding, filtering, clearing, destroyed windows, send failures, and absent web servers.

Changes

Auto Run state mirroring

Layer / File(s) Summary
Bridge forwarding and validation
src/main/ipc/handlers/web.ts, src/__tests__/main/ipc/handlers/web.test.ts
The main handler identifies bridge-originated invokes and sends remote:autoRunStateMirror to available desktop windows. Tests cover filtering, clearing, window failures, and multiple windows.
Desktop mirror subscription
src/renderer/hooks/batch/useAutoRunStateMirror.ts, src/main/preload/process/autoRunControlRemote.ts
The renderer subscribes to mirrored Auto Run state in all builds. The preload documentation describes both mirror producers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 1deab

Browser-originated Auto Run state is now reflected in Desktop windows without echoing Desktop-owned runs. The change is ready to merge with no identified merge-blocking risk.

Sequence Diagram(s)

sequenceDiagram
  participant WebDesktop as Web-desktop bridge
  participant MainProcess as Main process
  participant DesktopWindow as Electron desktop window
  participant MirrorHook as useAutoRunStateMirror
  WebDesktop->>MainProcess: Invoke web:broadcastAutoRunState
  MainProcess->>DesktopWindow: Send remote:autoRunStateMirror
  DesktopWindow->>MirrorHook: Deliver session ID and state
  MirrorHook-->>DesktopWindow: Update or reap mirrored state
Loading

Suggested reviewers: reachrazamair, chr1syy, jsydorowicz21

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements the visibility synchronization objective from issue #1519 by forwarding bridge-originated Auto Run state to desktop windows. It does not implement the issue's separate requirement to… Implement or explicitly split and track the disconnect-continuation requirement, including shared backend ownership and queue advancement after the web client closes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: mirroring Auto Run started in Web-Desktop into the desktop app.
Out of Scope Changes check ✅ Passed The code, tests, and documentation changes remain within the scope of mirroring Web-Desktop Auto Run state into the desktop app. No unrelated changes are evident.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 4 files.
Full details: Linked Issues check

Explanation

The PR implements the visibility synchronization objective from issue #1519 by forwarding bridge-originated Auto Run state to desktop windows. It does not implement the issue's separate requirement to continue queued runs after the Web-Desktop disconnects.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1519-mirror-web-autorun-to-desktop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes web-desktop-owned Auto Runs visible in Electron by forwarding bridge-originated state frames directly to desktop renderers and enabling the existing mirror consumer in both builds.

  • Restricts desktop forwarding to WebSocket bridge invocations to avoid echoing desktop-owned runs.
  • Reuses the existing remote:autoRunStateMirror channel without duplicating WebSocket fan-out.
  • Preserves read-only mirror semantics and stale-mirror cleanup.
  • Adds coverage for fan-out, teardown, destroyed and failing windows, owner-echo suppression, and operation without an attached web server.

Confidence Score: 5/5

The PR appears safe to merge, with the new reverse mirror path preserving owner controls and existing read-only behavior.

No actionable failures remain: bridge-originated frames reach desktop consumers, desktop-originated frames are excluded, per-window failures are isolated, and mirror consumption does not create a broadcast feedback loop.

Important Files Changed

Filename Overview
src/main/ipc/handlers/web.ts Adds bridge-origin detection and safely forwards web-owned Auto Run state to all live desktop windows without re-fanning it to the bridge.
src/renderer/hooks/batch/useAutoRunStateMirror.ts Enables the existing mirror subscription and stale-mirror reaper in Electron while retaining local-run ownership guards.
src/main/preload/process/autoRunControlRemote.ts Updates channel documentation to describe both WebSocket and Electron-main producers.
src/tests/main/ipc/handlers/web.test.ts Adds focused tests for desktop forwarding, teardown, echo suppression, window failures, and operation without a web server.

Sequence Diagram

sequenceDiagram
    participant Web as Web-desktop owner
    participant Bridge as WebSocket bridge
    participant Main as Electron main
    participant Desktop as Desktop renderer
    participant Peers as Web-desktop peers

    Web->>Bridge: bridge.invoke(web:broadcastAutoRunState)
    Bridge->>Main: handler(FAKE_EVENT, sessionId, state)
    Main->>Main: update Auto Run tracker
    Main->>Desktop: remote:autoRunStateMirror
    Main->>Peers: autorun_state
    Desktop->>Desktop: apply read-only mirrored state
Loading

Reviews (1): Last reviewed commit: "fix(web-desktop): mirror a web-started A..." | Re-trigger Greptile

@pedramamini
pedramamini merged commit 926df90 into rc Sep 7, 2026
7 checks passed
@pedramamini
pedramamini deleted the fix/1519-mirror-web-autorun-to-desktop branch September 7, 2026 04:42
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