feat: auto-switch active worktree when browser commands target an inactive worktree

Browser webviews only mount when their worktree is active in the Orca UI.
When a CLI browser command targets a worktree with no registered tabs (meaning
the webviews haven't mounted), automatically send ui:activateWorktree to the
renderer so the webviews mount and become operable.

This prevents the confusing "No browser tab open" error when the agent creates
or interacts with tabs in a worktree that isn't currently focused in the UI.
This commit is contained in:
Jinwoo-H 2026-04-19 18:10:31 -04:00
parent 8d8c1f2cbc
commit 5e5a1847d5

View file

@ -1179,12 +1179,35 @@ export class OrcaRuntimeService {
return undefined
}
try {
return (await this.resolveWorktreeSelector(selector)).id
const worktreeId = (await this.resolveWorktreeSelector(selector)).id
// Why: if the worktree has no registered tabs in the bridge, it's likely
// not the active worktree in the UI (webviews only mount for the active
// worktree). Activate it so existing tabs become operable.
const bridge = this.agentBrowserBridge
if (bridge && bridge.getRegisteredTabs(worktreeId).size === 0) {
await this.ensureBrowserWorktreeActive(worktreeId)
}
return worktreeId
} catch {
return undefined
}
}
// Why: browser tabs only mount (and become operable) when their worktree is
// the active worktree in the renderer. If the CLI targets a different worktree,
// we must switch the UI first so the webview mounts and registerGuest fires.
private async ensureBrowserWorktreeActive(worktreeId: string): Promise<void> {
const win = this.getAuthoritativeWindow()
const repoId = worktreeId.split('::')[0]
if (!repoId) {
return
}
win.webContents.send('ui:activateWorktree', { repoId, worktreeId })
// Why: give the renderer time to mount the webview after switching worktrees.
// The webview needs to attach and fire dom-ready before registerGuest runs.
await new Promise((resolve) => setTimeout(resolve, 500))
}
async browserSnapshot(params: { worktree?: string }): Promise<BrowserSnapshotResult> {
const worktreeId = await this.resolveBrowserWorktreeId(params.worktree)
return this.requireAgentBrowserBridge().snapshot(worktreeId)
@ -1758,6 +1781,12 @@ export class OrcaRuntimeService {
? (await this.resolveWorktreeSelector(params.worktree)).id
: undefined
// Why: browser webviews only mount when their worktree is active in the UI.
// Switch to it before creating the tab so the webview attaches immediately.
if (worktreeId) {
await this.ensureBrowserWorktreeActive(worktreeId)
}
// Why: tab creation is a renderer-side Zustand store operation. The main process
// sends a request, the renderer creates the tab and replies with the workspace ID
// (which is the browserPageId used by registerGuest and the bridge).