Files
orca/src/shared/workspace-launch-kind.ts
Brennan Benson b66ef2e8a8 fix(agent-launch): resolve a launch scope, not a git worktree record (#21193)
* fix(agent-launch): resolve a launch scope, not a git worktree record

`agent.launch` asked the runtime for a managed worktree record and then read
exactly one field off it, `.id`. That record does not exist for every workspace
a launch can run in, so the request refused launches the method could otherwise
run: the floating workspace resolves to a scope with an id and a path but no
worktree row, and `showManagedTerminalWorkspace` throws `selector_not_found`
rather than hand back the id it had already resolved.

A folder workspace survived that only because the resolver fabricates a worktree
row for it. The scope is the answer that is real for all three kinds, so the
launch asks for that instead. `showManagedTerminalWorkspace` is unchanged -
callers that genuinely need the git record still get it, and still get the
refusal.

With floating now reaching the mode decision, the host must know which kind of
workspace it resolved. The kind is derived from the id it resolved itself,
never accepted from a caller, and the route module's existing `floating`
blocker does the rest: a workspace with nowhere to keep a session runs a
terminal agent.

Behaviour change, deliberate: a floating-workspace `agent.launch` used to fail
with `selector_not_found` and now succeeds as a terminal agent. That is what
lets the floating titlebar agent button move onto the shared launch command
instead of driving tab startup itself.

No wire change: `AgentLaunchTarget` is untouched.

* test(agent-launch): cover floating RPC workspace resolution
2026-09-17 13:03:24 -07:00

24 lines
1.1 KiB
TypeScript

/**
* Which kind of workspace a launch lands in, read from the workspace's own id.
*
* The three kinds are not interchangeable to a launch: only a git worktree and a folder workspace
* have somewhere a structured session can live, and the floating terminal — a sentinel with no
* backing repo, worktree or folder row — can host a PTY and nothing else.
*
* It lives in `shared` because both sides of the launch ask the same question: the renderer when a
* user opens an agent tab, and the host when it resolves an `agent.launch` target. A host must
* never take the answer from a caller, so it derives it here from the id it resolved itself.
*/
import { FLOATING_TERMINAL_WORKTREE_ID } from './constants'
import { parseWorkspaceKey } from './workspace-scope'
export type WorkspaceLaunchKind = 'git-worktree' | 'folder' | 'floating'
export function workspaceKindForWorktreeId(worktreeId: string): WorkspaceLaunchKind {
if (worktreeId === FLOATING_TERMINAL_WORKTREE_ID) {
return 'floating'
}
return parseWorkspaceKey(worktreeId)?.type === 'folder' ? 'folder' : 'git-worktree'
}