fix(cli): say a headless terminal create found no workspace, not that the window is missing (#33264)

* fix(cli): say a headless terminal create found no workspace, not that the window is missing (#33044)

On a windowless `orca serve` host, `orca terminal create` from a folder
outside any workspace failed with "No renderer window available". The
create falls through to the window-only path because no workspace was
resolved, so name that and point at --worktree instead. Behavior is
unchanged; only the error message for this already-failing create.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(runtime): pass the no-workspace message to the window lookup instead of relabeling every error

A catch-all would rename any other window-lookup failure as a missing workspace.

---------

Co-authored-by: tnfhrnsss <tnfhrns@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Neil
2026-10-24 14:46:49 -07:00
committed by GitHub
co-authored by Claude Opus 5.5 tnfhrnsss
parent e2b0e9a19e
commit 81a6cea193
5 changed files with 19 additions and 5 deletions
@@ -36,7 +36,7 @@ export abstract class OrcaRuntimeWithCreateAgentSession extends OrcaRuntimeWithG
agentTeamsEnv?: Record<string, string>
): Record<string, string>
abstract getAuthoritativeWindow(): BrowserWindow
abstract getAuthoritativeWindow(missingWindowMessage?: string): BrowserWindow
abstract waitForTerminalHandle(tabId: string, timeoutMs?: number): Promise<string>
@@ -0,0 +1,10 @@
import { expect, it } from 'vitest'
import { wireHeadlessServeRuntime } from './orca-runtime-test-scenario-builders.spec'
it('tells a workspace-less create on a windowless host to pass --worktree', async () => {
const runtime = wireHeadlessServeRuntime()
await expect(runtime.createTerminal(undefined, { title: 'probe' })).rejects.toThrow(
/No workspace was given or found.*Pass --worktree.*No terminal was created\./
)
})
@@ -3,6 +3,10 @@ import * as dependencies from './orca-runtime-create-terminal-dependencies'
import type { OrcaRuntimeWithCreateTerminal } from './terminal/launch/terminal-create'
import type { RuntimeTerminalPresentation } from '../../shared/runtime-types'
// Without a window, the missing piece the caller can supply is the workspace, so name that.
const NO_WORKSPACE_OR_WINDOW_MESSAGE =
'No workspace was given or found for this terminal, and this Orca host has no open app window to create one in. Pass --worktree to choose a workspace. No terminal was created.'
// A create with no workspace lands in whatever the window is showing, so only the window can make it.
export async function createDesktopTerminal(
runtime: OrcaRuntimeWithCreateTerminal,
@@ -17,7 +21,7 @@ export async function createDesktopTerminal(
}
opts = applyRemoteViewerLaunchEnv(opts, opts.terminalImageViewerSupported)
runtime.assertGraphReady()
const win = runtime.getAuthoritativeWindow()
const win = runtime.getAuthoritativeWindow(NO_WORKSPACE_OR_WINDOW_MESSAGE)
const requestId = dependencies.randomUUID()
const reply = await new Promise<{ tabId: string; title: string }>((resolve, reject) => {
const timer = setTimeout(() => {
@@ -25,10 +25,10 @@ export abstract class OrcaRuntimeWithResolveWaiter extends OrcaRuntimeWithResolv
return `${tabId}::${leafId}`
}
getAuthoritativeWindow(): BrowserWindow {
getAuthoritativeWindow(missingWindowMessage = 'No renderer window available'): BrowserWindow {
const win = this.getAvailableAuthoritativeWindow()
if (!win || win.isDestroyed()) {
throw new Error('No renderer window available')
throw new Error(missingWindowMessage)
}
return win
}
@@ -51,7 +51,7 @@ export abstract class OrcaRuntimeWithTerminalDrivers extends OrcaRuntimeWithFitO
repoId?: string
hostId?: ExecutionHostId
}): BrowserNetworkExecutionHost | Promise<BrowserNetworkExecutionHost>
abstract getAuthoritativeWindow(): BrowserWindow
abstract getAuthoritativeWindow(missingWindowMessage?: string): BrowserWindow
protected abstract getAvailableAuthoritativeWindow(): BrowserWindow | null
protected abstract markHeadlessBrowserSessionTabActive(
worktreeId: string | undefined,