Repository navigation
fix(agent-launch): a phone's launch leaves the desktop window where it is - #26025
Conversation
… where it is A launch from the phone (or any paired client) revealed the workspace on the host desktop: the early tab's viewer rule said `reveal-owner` for callers whose navigation is their own, and with no early tab the spawn surfaced the owner by default. One predicate, `agentLaunchMovesHostWindow`, now decides both: paired callers get `none` for the shown tab and `surfaceOwner: false` at spawn. The device still selects the tab for itself; the CLI and the desktop are unchanged.
…desktop window where it is An agent.launch that creates its workspace never asked agentLaunchMovesHostWindow: the create payload's activate/runHooks passed straight through, so a paired caller that set either would switch the desktop to the new workspace and reveal the startup terminal there. No shipped client sends them through agent.launch yet, so nothing changes today; it closes the gap before a phone's work-item creates move here. For a caller whose launch does not move the host window, the create now runs unactivated, which provisions setup and default tabs in the background. runHooks keeps its setup half as setupDecision 'run'. CLI and desktop creates are unchanged. Also makes the CLI "still reveals" test assert that a terminal was actually created, so it cannot pass with none.
…host to run setup The caller-selection header said a launch that creates its workspace relies on worktree.create's host activation to run setup. Since the previous commit that holds only for in-process callers: a paired client's create never activates the host window, and its setup and default tabs are provisioned in the background. Comment only.
Review summaryThe problem. Starting an agent from the phone (or any paired device) also moved the desktop app: its sidebar scrolled to that workspace, expanded it and highlighted it, even when you were working in another workspace on the desktop. The decision for this work is that a phone or paired launch leaves the desktop where it is. What changes for you. A launch from a phone or another paired device now moves only that device. The phone still lands on its new agent tab (terminal or chat); the desktop just gets the tab in that workspace, with no sidebar scroll or highlight. Launches from the desktop itself and from the What review fixed (pushed to this branch):
Deferred (small, none user-visible today):
Verified:
Not verified:
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review. 📝 WalkthroughWalkthroughAgent launch handling now uses a shared decision to determine whether a launch moves the host window. That decision affects tab viewer selection, workspace activation and hooks, and terminal surface ownership. Tests cover paired phone and desktop launches, local launches, and CLI launches. Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to The reviewed paired-launch behavior preserves the desktop workspace selection, and no concrete merge-blocking regression was established. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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. Comment |
…aunch-leaves-desktop # Conflicts: # src/main/runtime/rpc/methods/agent-launch.test.ts
ELI5
When you start an agent from your phone, the desktop app reacts too: its sidebar scrolls to that workspace, expands it and highlights it, even if you were working somewhere else on the desktop.
After this change, a launch from your phone (or from another paired device) moves only the phone. The phone still opens the agent's tab; the desktop just gets a new tab in that workspace, with no sidebar scroll and no highlight. Launches from the desktop itself and from the
orcaCLI behave exactly as before.Not covered yet: on the phone, "new workspace from an issue, PR or Linear item, with an agent" still moves the desktop to the new workspace, on this PR as on main. That flow uses
worktree.create, notagent.launch. It gets the same rule when those launches move ontoagent.launch(the next steps of the agent-launch work).What Changed
Before: a paired device's
agent.launchrevealed the workspace on the host desktop in two places:reveal-ownerfor any caller whose navigation isn't the host (a phone, a paired desktop or web client). That rule makes the desktop window reveal the workspace in the sidebar.surfaceOwner: false. The window treats that as "reveal the owner" and does the same reveal.A third path was open but unused: an
agent.launchthat creates a workspace passed the caller'sactivate/runHooksstraight through, so a paired client that sentactivate: truewould have switched the desktop to the new workspace. No shipped client sends that throughagent.launchtoday.After: one predicate,
agentLaunchMovesHostWindow, answers "may this launch move the host window?". It's true for the desktop's own window and for in-process callers (the CLI), and false for any caller whose navigation is its own (clientKindset without being the desktop). All three paths ask it:nonefor those callers: the tab is created in place and nothing moves.surfaceOwner: falsefor those callers, so the no-early-tab path matches.activate: false,runHooks: false, andrunHooks' setup half kept assetupDecision: 'run'). Setup and default tabs are provisioned in the background, the same path today's phones already take.Unchanged:
selectAgentLaunchTabForCallerstill selects the new tab for that device.activate. For a chat it only sets the active tab in the runtime's tab snapshot that the phone mirrors. The desktop never switches workspace from that snapshot (verified in code and in live QA row 7).worktree.createitself (see "Not covered yet" above).Why
The host's navigation model already says a paired device steers only its own view (
resolveRuntimeNavigationTarget: "treating that as navigation lets one device steer every UI"), and the shared viewer-rule type says "a paired device never moves the host window".agent.launchwas the exception: before #25430 its spawn revealed the desktop for every caller, and #25430 kept that reveal for paired callers so as not to change behaviour in the same PR. This PR removes the exception.Alternatives considered:
activatefor paired callers. Not needed: it moves only the phone's mirrored snapshot, which a phone launching into a new workspace relies on to open the chat.Difference from the common pattern (intended): in the common pattern, creating a session never moves the host's view at all; each client navigates its own view after its create call. Here the host still reveals on create, and paired callers opt out. This is intended for now: desktop-window and CLI launches rely on that reveal (a CLI launch with
presentation: 'focused'moves the window by design), and this PR's decision is only about paired devices. Moving the reveal out of the shared launch path would change CLI and desktop behaviour, which is out of scope here.Linked Issue
Follow-up to #25430 (split out of it at review so that PR kept today's reveal for paired callers).
Visual Proof
Live QA on an M4 MacBook Air: two hidden, isolated dev hosts (this PR at
1fd740f6dd4, andorigin/main), a stub agent only, Orca Mobile on the iOS simulator driven withorca emulator. A store watcher on each desktop recorded the active workspace, each workspace's tabs and active tab, the sidebar reveal (pendingRevealWorktree) and keyboard focus around each action.presentation: 'focused'activate, so it can't separate the arms)Phone after the launch (this PR), on its new
claudetab:Desktop after the phone launch, this PR then main. In this small fixture both workspaces already fit in the sidebar, so main's reveal doesn't show in a still frame. The difference is the reveal recorded by the store watcher (table above).
Testing
agent-launch-instant-tab.test.ts:nonefor a phone (focused and default) and for a paired desktop. It's unchanged for the CLI (focus-window/reveal-owner), the desktop (focus-in-workspace) and background (none).surfaceOwner: falsefor a phone that reads no early tab, and for a phone launch with no operation id. A CLI launch with no early tab still spawns and still reveals (nosurfaceOwner).agent-launch.test.ts, "whose window a new workspace moves": a phone and a paired desktop, in chat and terminal mode, sendingactivate: true, runHooks: truecreate withactivate: false, runHooks: false, setupDecision: 'run'; a pairedsetupDecision: 'skip'is kept; a CLI caller'sactivate/runHooksare unchanged.The expected
createTerminalarguments for phone-caller launches inagent-launch.test.tsandagent-launch-floating-workspace.test.tsnow includesurfaceOwner: false.Checked against the old code: with the source changes reverted, the new tests fail; with the change, all pass.
pnpm tc:node, oxlint and oxfmt pass on the changed files; CI is green.I manually tested these changes locally (see Visual Proof)
Automated tests added/updated, or explained why not below
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
mobile/orsrc/sharedtouched. Old and new phones both get "the desktop stays put". Old phones never read the early tab, so for them the spawn-path half is what applies.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)