fix(orchestration): resolve explicit worker worktrees directly (#14275)

* fix(orchestration): resolve explicit worker worktrees directly

* fix(orchestration): share worker workspace resolution

* fix(runtime): reject cross-host path ambiguity

* fix(orchestration): share federated workspace resolution

* refactor(runtime): share worktree host identity

* test(orchestration): align worker lifecycle fixtures

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
This commit is contained in:
Dong dahao
2026-08-13 15:26:58 -07:00
committed by GitHub
co-authored by Jinwoo-H
parent 202ce1ef0e
commit d243137e35
9 changed files with 433 additions and 44 deletions
+51 -14
View File
@@ -261,6 +261,7 @@ import { assertWorktreeUnlockedForRemoval } from '../../shared/worktree-removal'
import {
LOCAL_EXECUTION_HOST_ID,
getRepoExecutionHostId,
getWorktreeExecutionHostId,
parseExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
@@ -2492,6 +2493,11 @@ type TerminalWorkspaceLaunchScope = {
folderWorkspace: FolderWorkspace | null
}
type ResolvedTerminalWorkspaceLaunchTarget = {
scope: TerminalWorkspaceLaunchScope
managedWorktree: ResolvedWorktree | null
}
type WorktreeLineageInput = {
parentWorkspace?: string
envParentWorkspace?: string
@@ -21363,6 +21369,14 @@ export class OrcaRuntimeService {
return await this.resolveWorktreeSelector(worktreeSelector)
}
async showManagedTerminalWorkspace(worktreeSelector: string) {
const target = await this.resolveTerminalWorkspaceLaunchTarget(worktreeSelector)
if (!target.managedWorktree) {
throw new Error('selector_not_found')
}
return target.managedWorktree
}
async scanWorkspacePorts(repoId?: string): Promise<WorkspacePortScanResult> {
return scanWorkspacePortProbes(await this.getWorkspacePortProbes(repoId))
}
@@ -28630,7 +28644,7 @@ export class OrcaRuntimeService {
private async resolveFolderWorkspaceLaunchScope(
selector: string
): Promise<TerminalWorkspaceLaunchScope | null> {
): Promise<(TerminalWorkspaceLaunchScope & { folderWorkspace: FolderWorkspace }) | null> {
const workspace = this.resolveFolderWorkspaceSelector(selector)
if (!workspace) {
return null
@@ -28710,23 +28724,35 @@ export class OrcaRuntimeService {
private async resolveTerminalWorkspaceLaunchScope(
selector: string
): Promise<TerminalWorkspaceLaunchScope> {
return (await this.resolveTerminalWorkspaceLaunchTarget(selector)).scope
}
private async resolveTerminalWorkspaceLaunchTarget(
selector: string
): Promise<ResolvedTerminalWorkspaceLaunchTarget> {
const floatingTerminalSelector =
selector === FLOATING_TERMINAL_WORKTREE_ID ||
selector === `id:${FLOATING_TERMINAL_WORKTREE_ID}`
if (floatingTerminalSelector) {
// Why: the floating sentinel is terminal-only — no backing repo/worktree record for other workspace APIs.
return {
id: FLOATING_TERMINAL_WORKTREE_ID,
path: homedir(),
connectionId: null,
repo: null,
folderWorkspace: null
scope: {
id: FLOATING_TERMINAL_WORKTREE_ID,
path: homedir(),
connectionId: null,
repo: null,
folderWorkspace: null
},
managedWorktree: null
}
}
const folderScope = await this.resolveFolderWorkspaceLaunchScope(selector)
if (folderScope) {
return folderScope
return {
scope: folderScope,
managedWorktree: this.folderWorkspaceToResolvedWorktree(folderScope.folderWorkspace)
}
}
const workspaceSelector = selector.startsWith('id:') ? selector.slice(3) : selector
@@ -28735,11 +28761,14 @@ export class OrcaRuntimeService {
const worktree = await this.resolveWorktreeSelector(worktreeSelector)
const repo = this.store?.getRepo(worktree.repoId) ?? null
return {
id: worktree.id,
path: worktree.path,
connectionId: repo?.connectionId ?? null,
repo,
folderWorkspace: null
scope: {
id: worktree.id,
path: worktree.path,
connectionId: repo?.connectionId ?? null,
repo,
folderWorkspace: null
},
managedWorktree: worktree
}
}
@@ -28814,8 +28843,16 @@ export class OrcaRuntimeService {
runtimePathsEqual(worktree.path, selector.slice(5))
)
if (candidates.length > 1) {
// Why: the same physical path can appear under multiple repo IDs; a path selector is exact, so take the first row over a dup-registration ambiguity.
candidates = [candidates[0]]
const hostIds = new Set(
candidates.map((worktree) => {
const repo = this.store?.getRepo(worktree.repoId)
return getWorktreeExecutionHostId(worktree, repo)
})
)
// Why: duplicate registrations on one host describe one path; identical paths on different hosts do not.
if (hostIds.size === 1) {
candidates = [candidates[0]]
}
}
} else if (selector.startsWith('branch:')) {
const branchSelector = selector.slice(7)
@@ -0,0 +1,305 @@
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const electronMocks = vi.hoisted(() => {
const ipcMain = {
on: vi.fn(() => ipcMain),
removeListener: vi.fn(() => ipcMain),
emit: vi.fn(() => true)
}
return {
BrowserWindow: { fromId: vi.fn((): unknown => null) },
webContents: { fromId: vi.fn((): unknown => null) },
ipcMain,
app: { getPath: vi.fn(() => '/tmp'), isPackaged: false }
}
})
vi.mock('electron', () => electronMocks)
const scanLocalRepoWorktreesForResolution = vi.hoisted(() => vi.fn())
vi.mock('./repo-worktree-resolution-scan', () => ({ scanLocalRepoWorktreesForResolution }))
const getSshGitProvider = vi.hoisted(() => vi.fn())
vi.mock('../providers/ssh-git-dispatch', () => ({
getSshGitProvider,
getSshGitProviderGeneration: vi.fn(() => 0),
requireSshGitProvider: (connectionId: string) => getSshGitProvider(connectionId)
}))
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../shared/constants'
import type { FolderWorkspace, ProjectGroup, Repo, WorktreeMeta } from '../../shared/types'
import {
registerSshFilesystemProvider,
unregisterSshFilesystemProvider
} from '../providers/ssh-filesystem-dispatch'
import { OrcaRuntimeService } from './orca-runtime'
const REPO_ID = 'repo-1'
const REPO_PATH = '/repo'
const WORKTREE_PATH = '/repo/feature'
const WORKTREE_ID = `${REPO_ID}::${WORKTREE_PATH}`
function makeMeta(displayName: string, hostId?: WorktreeMeta['hostId']): WorktreeMeta {
return {
displayName,
comment: '',
linkedIssue: null,
linkedPR: null,
linkedLinearIssue: null,
linkedGitLabMR: null,
linkedGitLabIssue: null,
isArchived: false,
isUnread: false,
isPinned: false,
sortOrder: 0,
lastActivityAt: 0,
...(hostId ? { hostId } : {})
}
}
function makeStore(
options: {
repos?: Repo[]
meta?: Record<string, WorktreeMeta>
folderWorkspaces?: FolderWorkspace[]
projectGroups?: ProjectGroup[]
} = {}
) {
const repos = options.repos ?? [
{
id: REPO_ID,
path: REPO_PATH,
displayName: 'App',
badgeColor: 'blue',
addedAt: 1
}
]
const meta = options.meta ?? { [WORKTREE_ID]: makeMeta('Feature') }
const store = {
getRepo: (id: string) => repos.find((repo) => repo.id === id),
getRepos: () => repos,
getAllWorktreeMeta: () => meta,
getWorktreeMeta: (id: string) => meta[id],
setWorktreeMeta: (id: string, patch: Partial<WorktreeMeta>) => {
meta[id] = { ...(meta[id] ?? makeMeta('')), ...patch }
return meta[id]
},
getAllWorktreeLineage: () => ({}),
getAllWorkspaceLineage: () => ({}),
removeWorktreeLineage: vi.fn(),
removeWorkspaceLineage: vi.fn(),
getGitHubCache: () => undefined,
getSettings: () => ({
workspaceDir: '/tmp/workspaces',
nestWorkspaces: false,
refreshLocalBaseRefOnWorktreeCreate: false,
branchPrefix: 'none',
branchPrefixCustom: ''
}),
getProjects: () => [],
getFolderWorkspaces: () => options.folderWorkspaces ?? [],
getProjectGroups: () => options.projectGroups ?? []
}
return store
}
describe('orchestration worker workspace resolution', () => {
const tempPaths: string[] = []
beforeEach(() => {
scanLocalRepoWorktreesForResolution.mockReset().mockResolvedValue({
ok: true,
worktrees: [
{
path: WORKTREE_PATH,
head: 'abc',
branch: 'feature',
isBare: false,
isMainWorktree: false
}
]
})
getSshGitProvider.mockReset()
})
afterEach(async () => {
await Promise.all(tempPaths.splice(0).map((path) => rm(path, { recursive: true, force: true })))
})
it.each([
['full id', `id:${WORKTREE_ID}`],
['path', `path:${WORKTREE_PATH}`],
['name', 'name:Feature']
])('resolves a local worktree by %s with one catalog scan', async (_label, selector) => {
const runtime = new OrcaRuntimeService(makeStore() as never)
await expect(runtime.showManagedTerminalWorkspace(selector)).resolves.toMatchObject({
id: WORKTREE_ID,
path: WORKTREE_PATH
})
expect(scanLocalRepoWorktreesForResolution).toHaveBeenCalledOnce()
})
it('preserves a disconnected SSH worktree with unknown legacy ownership', async () => {
const remoteRepo = {
id: REPO_ID,
path: REPO_PATH,
displayName: 'Remote app',
badgeColor: 'blue',
addedAt: 1,
connectionId: 'ssh-1'
} satisfies Repo
const runtime = new OrcaRuntimeService(
makeStore({
repos: [remoteRepo],
meta: { [WORKTREE_ID]: makeMeta('Remote feature') }
}) as never
)
await expect(runtime.showManagedTerminalWorkspace(`id:${WORKTREE_ID}`)).resolves.toMatchObject({
id: WORKTREE_ID,
hostId: 'ssh:ssh-1'
})
})
it('does not fall back from the floating terminal sentinel to another workspace', async () => {
const runtime = new OrcaRuntimeService(makeStore() as never)
await expect(
runtime.showManagedTerminalWorkspace(`id:${FLOATING_TERMINAL_WORKTREE_ID}`)
).rejects.toThrow('selector_not_found')
expect(scanLocalRepoWorktreesForResolution).not.toHaveBeenCalled()
})
it('rejects an ambiguous worktree name', async () => {
const secondPath = '/repo/other'
scanLocalRepoWorktreesForResolution.mockResolvedValue({
ok: true,
worktrees: [
{ path: WORKTREE_PATH, head: 'a', branch: 'one', isBare: false, isMainWorktree: false },
{ path: secondPath, head: 'b', branch: 'two', isBare: false, isMainWorktree: false }
]
})
const runtime = new OrcaRuntimeService(
makeStore({
meta: {
[WORKTREE_ID]: makeMeta('Duplicate'),
[`${REPO_ID}::${secondPath}`]: makeMeta('Duplicate')
}
}) as never
)
await expect(runtime.showManagedTerminalWorkspace('name:Duplicate')).rejects.toThrow(
'selector_ambiguous'
)
})
it('rejects the same worktree path on different execution hosts', async () => {
const remoteRepo = {
id: 'repo-remote',
path: '/remote-repo',
displayName: 'Remote app',
badgeColor: 'blue',
addedAt: 1,
connectionId: 'ssh-1'
} satisfies Repo
getSshGitProvider.mockReturnValue({
listWorktrees: vi.fn().mockResolvedValue([
{
path: WORKTREE_PATH,
head: 'remote',
branch: 'remote-feature',
isBare: false,
isMainWorktree: false
}
])
})
const runtime = new OrcaRuntimeService(
makeStore({
repos: [makeStore().getRepos()[0], remoteRepo],
meta: {
[WORKTREE_ID]: makeMeta('Local feature'),
[`${remoteRepo.id}::${WORKTREE_PATH}`]: makeMeta('Remote feature')
}
}) as never
)
await expect(runtime.showManagedTerminalWorkspace(`path:${WORKTREE_PATH}`)).rejects.toThrow(
'selector_ambiguous'
)
})
it('resolves local and SSH folder workspaces without a Git catalog scan', async () => {
const localPath = await mkdtemp(join(tmpdir(), 'orca-worker-local-folder-'))
tempPaths.push(localPath)
const group = { id: 'group-1', name: 'Group', parentPath: localPath } as ProjectGroup
const localFolder = {
id: 'local-folder',
projectGroupId: group.id,
name: 'Local folder',
folderPath: localPath
} as FolderWorkspace
const remoteFolder = {
...localFolder,
id: 'remote-folder',
name: 'Remote folder',
folderPath: '/srv/app',
connectionId: 'ssh-folder'
}
registerSshFilesystemProvider('ssh-folder', {
stat: vi.fn().mockResolvedValue({ type: 'directory', size: 0, mtime: 1 })
} as never)
try {
const runtime = new OrcaRuntimeService(
makeStore({
folderWorkspaces: [localFolder, remoteFolder],
projectGroups: [group]
}) as never
)
await expect(
runtime.showManagedTerminalWorkspace('folder:local-folder')
).resolves.toMatchObject({
id: 'folder:local-folder',
path: localPath,
hostId: 'local'
})
await expect(
runtime.showManagedTerminalWorkspace('id:folder:remote-folder')
).resolves.toMatchObject({ id: 'folder:remote-folder', hostId: 'ssh:ssh-folder' })
} finally {
unregisterSshFilesystemProvider('ssh-folder')
}
expect(scanLocalRepoWorktreesForResolution).not.toHaveBeenCalled()
})
it('rejects a folder workspace whose execution host is ambiguous', async () => {
const folderPath = '/workspace'
const group = { id: 'group-1', name: 'Group', parentPath: folderPath } as ProjectGroup
const folder = {
id: 'folder-1',
projectGroupId: group.id,
name: 'Ambiguous folder',
folderPath
} as FolderWorkspace
const repos = [
{ id: 'local', path: '/workspace/local', projectGroupId: group.id },
{ id: 'remote', path: '/workspace/remote', projectGroupId: group.id, connectionId: 'ssh-1' }
].map((repo) => ({
displayName: repo.id,
badgeColor: 'blue',
addedAt: 1,
...repo
})) as Repo[]
const runtime = new OrcaRuntimeService(
makeStore({ repos, folderWorkspaces: [folder], projectGroups: [group] }) as never
)
await expect(runtime.showManagedTerminalWorkspace('folder:folder-1')).rejects.toThrow(
'folder_workspace_connection_ambiguous'
)
expect(scanLocalRepoWorktreesForResolution).not.toHaveBeenCalled()
})
})
@@ -15,17 +15,17 @@ describe('federated worker agent launch', () => {
vi.restoreAllMocks()
})
it('creates the remote worker terminal from the agent id, never as a command', async () => {
it('creates an exact folder worker terminal from the agent id, never as a command', async () => {
db = new OrchestrationDb(':memory:')
const runtime = new OrcaRuntimeService()
runtime.setOrchestrationDb(db)
vi.spyOn(runtime, 'validateOrchestrationAgentLauncher').mockImplementation(() => {})
vi.spyOn(runtime, 'showManagedWorktree').mockResolvedValue({
id: 'repo::remote-worktree'
vi.spyOn(runtime, 'showManagedTerminalWorkspace').mockResolvedValue({
id: 'folder:remote-workspace'
} as never)
const createTerminal = vi.spyOn(runtime, 'createTerminal').mockResolvedValue({
handle: 'term_remote_worker',
worktreeId: 'repo::remote-worktree',
worktreeId: 'folder:remote-workspace',
title: 'worker'
})
vi.spyOn(runtime, 'waitForTerminal').mockResolvedValue({
@@ -60,7 +60,7 @@ describe('federated worker agent launch', () => {
taskId: 'task_remote',
taskSpec: 'remote cursor worker',
protocolVersion: 3,
worktree: 'id:repo::remote-worktree',
worktree: 'folder:remote-workspace',
agent: 'cursor',
model: 'gpt-5.3-codex',
effort: 'high'
@@ -91,14 +91,14 @@ describe('federated worker agent launch', () => {
}
})
expect(createTerminal).toHaveBeenCalledWith(
'id:repo::remote-worktree',
'id:folder:remote-workspace',
expect.objectContaining({
startupAgent: 'cursor',
launchPreferences: { model: 'gpt-5.3-codex', effort: 'high' }
})
)
expect(createTerminal).toHaveBeenCalledWith(
'id:repo::remote-worktree',
'id:folder:remote-workspace',
expect.not.objectContaining({ command: expect.anything() })
)
})
@@ -129,7 +129,7 @@ export const ORCHESTRATION_FEDERATION_ATTACH_METHODS: RpcMethod[] = [
)
appendFederationSetupEffect(effects, setup)
} else {
worktree = await runtime.showManagedWorktree(params.worktree).catch(() => {
worktree = await runtime.showManagedTerminalWorkspace(params.worktree).catch(() => {
throw new OrchestrationError(
'worktree_not_found_on_server',
`Worktree ${params.worktree} was not found on the selected worker server.`
@@ -48,7 +48,7 @@ describe('orchestration worker release recovery', () => {
vi.spyOn(runtime, 'showTerminal').mockImplementation(
async (handle) => ({ handle, worktreeId: 'repo::worktree', status: 'running' }) as never
)
vi.spyOn(runtime, 'showManagedWorktree').mockResolvedValue({
vi.spyOn(runtime, 'showManagedTerminalWorkspace').mockResolvedValue({
id: 'repo::worktree'
} as never)
vi.spyOn(runtime, 'createTerminal').mockResolvedValue({
@@ -61,7 +61,7 @@ describe('orchestration worker release', () => {
vi.spyOn(runtime, 'showTerminal').mockImplementation(
async (handle) => ({ handle, worktreeId: 'repo::worktree', status: 'running' }) as never
)
vi.spyOn(runtime, 'showManagedWorktree').mockResolvedValue({
vi.spyOn(runtime, 'showManagedTerminalWorkspace').mockResolvedValue({
id: 'repo::worktree'
} as never)
vi.spyOn(runtime, 'createTerminal').mockResolvedValue({
@@ -60,21 +60,21 @@ export const ORCHESTRATION_WORKER_START_METHODS: RpcMethod[] = [
const { agent, launch } = prepareLocalWorkerStart({ params, createsWorktree, runtime })
const coordinatorTerminal = await runtime.showTerminal(params.from)
const coordinatorWorktree = await runtime.showManagedWorktree(
`id:${coordinatorTerminal.worktreeId}`
)
if (createsWorktree) {
const creationWorktree = createsWorktree
? await runtime.showManagedWorktree(`id:${coordinatorTerminal.worktreeId}`)
: undefined
if (creationWorktree) {
await assertOrchestrationWorktreeCreationSupported({
runtime,
repoSelector: params.repo ?? coordinatorWorktree.repoId,
repoSelector: params.repo ?? creationWorktree.repoId,
existingPlacement: 'current or an exact existing folder workspace'
})
}
let resolvedWorktree = createsWorktree
let resolvedWorktree = creationWorktree
? undefined
: requestedWorktree === 'current'
? coordinatorWorktree
: await runtime.showManagedWorktree(requestedWorktree)
? await runtime.showManagedTerminalWorkspace(`id:${coordinatorTerminal.worktreeId}`)
: await runtime.showManagedTerminalWorkspace(requestedWorktree)
let explicitTerminal
if (params.terminal) {
explicitTerminal = await runtime.showTerminal(params.terminal)
@@ -96,7 +96,7 @@ export const ORCHESTRATION_WORKER_START_METHODS: RpcMethod[] = [
worktree: requestedWorktree,
resolvedWorktreeId: resolvedWorktree?.id ?? null,
name: params.name ?? null,
repo: params.repo ?? (createsWorktree ? coordinatorWorktree.repoId : null),
repo: params.repo ?? creationWorktree?.repoId ?? null,
baseBranch: params.baseBranch ?? null,
terminal: params.terminal ?? null,
agent: agent ?? null,
@@ -135,14 +135,14 @@ export const ORCHESTRATION_WORKER_START_METHODS: RpcMethod[] = [
state: 'not_applicable'
}
try {
if (createsWorktree) {
if (creationWorktree) {
failedStage = 'worktree_create'
const created = await createWorkerWorktree({
runtime,
db,
dispatchId: started.dispatch.id,
requestedWorktree,
coordinatorWorktree,
coordinatorWorktree: creationWorktree,
params,
agent: agent as TuiAgent,
launchPreferences: launch.preferences,
@@ -9,6 +9,7 @@ import { OrcaRuntimeService } from '../../orca-runtime'
import type { RuntimeTerminalSummary } from '../../../../shared/runtime-types'
import { ORCHESTRATION_ASK_MAX_TIMEOUT_MS } from '../../../../shared/orchestration-ask-timeout'
import { ORCHESTRATION_CONTRACT_VERSION } from '../../../../shared/protocol-version'
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../../shared/constants'
function lifecycleGroupRecipientError(type: 'worker_done' | 'heartbeat'): string {
return `${type} messages belong to one exact Dispatch and cannot target a group address.`
@@ -2180,6 +2181,9 @@ describe('orchestration RPC methods', () => {
vi.spyOn(runtime, 'showManagedWorktree').mockResolvedValue({
id: 'repo::worktree'
} as never)
vi.spyOn(runtime, 'showManagedTerminalWorkspace').mockResolvedValue({
id: 'repo::worktree'
} as never)
vi.spyOn(runtime, 'createTerminal').mockResolvedValue({
handle: 'term_worker',
worktreeId: 'repo::worktree',
@@ -2381,17 +2385,25 @@ describe('orchestration RPC methods', () => {
expect(runtime.sendTerminalAgentPrompt).toHaveBeenCalled()
})
it('starts a fresh agent in an exact existing worktree without replaying setup', async () => {
it('starts in an exact existing worktree from a floating coordinator', async () => {
setup()
mockCurrentWorkerStart()
const createWorktree = vi.spyOn(runtime, 'createManagedWorktree')
vi.mocked(runtime.showManagedWorktree).mockImplementation(
async (selector) =>
({
id: selector === 'id:repo::other' ? 'repo::other' : 'repo::worktree',
repoId: 'repo'
}) as never
)
vi.mocked(runtime.showTerminal).mockResolvedValue({
handle: 'term_coord',
worktreeId: FLOATING_TERMINAL_WORKTREE_ID,
status: 'running'
} as never)
vi.mocked(runtime.showManagedWorktree).mockImplementation(async (selector) => {
if (selector === `id:${FLOATING_TERMINAL_WORKTREE_ID}`) {
throw new Error('selector_not_found')
}
return { id: 'repo::other', repoId: 'repo' } as never
})
vi.mocked(runtime.showManagedTerminalWorkspace).mockResolvedValue({
id: 'repo::other',
repoId: 'repo'
} as never)
const task = db.createTask({ spec: 'existing worktree worker' })
const result = (await call('orchestration.workerStart', {
@@ -2415,6 +2427,41 @@ describe('orchestration RPC methods', () => {
expect.objectContaining({ startupAgent: 'codex', surfaceOwner: false })
)
expect(createWorktree).not.toHaveBeenCalled()
expect(runtime.showTerminal).toHaveBeenCalledWith('term_coord')
expect(runtime.showManagedWorktree).not.toHaveBeenCalledWith(
`id:${FLOATING_TERMINAL_WORKTREE_ID}`
)
expect(runtime.showManagedTerminalWorkspace).toHaveBeenCalledOnce()
expect(runtime.showManagedTerminalWorkspace).toHaveBeenCalledWith('id:repo::other')
})
it('starts in an exact existing folder workspace from a floating coordinator', async () => {
setup()
mockCurrentWorkerStart()
vi.mocked(runtime.showTerminal).mockResolvedValue({
handle: 'term_coord',
worktreeId: FLOATING_TERMINAL_WORKTREE_ID,
status: 'running'
} as never)
vi.mocked(runtime.showManagedWorktree).mockRejectedValue(new Error('selector_not_found'))
vi.mocked(runtime.showManagedTerminalWorkspace).mockResolvedValue({
id: 'folder:workspace-1',
repoId: 'folder-workspace:group-1'
} as never)
const task = db.createTask({ spec: 'folder workspace worker' })
await expect(
call('orchestration.workerStart', {
task: task.id,
from: 'term_coord',
worktree: 'folder:workspace-1',
agent: 'codex'
})
).resolves.toMatchObject({ state: 'ready' })
expect(runtime.createTerminal).toHaveBeenCalledWith(
'id:folder:workspace-1',
expect.objectContaining({ startupAgent: 'codex', surfaceOwner: false })
)
})
it('reuses only an explicitly selected existing agent terminal', async () => {
@@ -269,7 +269,7 @@ async function releaseCompletedWorker(terminalState: 'running' | 'exited'): Prom
: null
)
vi.spyOn(runtime, 'validateOrchestrationAgentLauncher').mockImplementation(() => {})
vi.spyOn(runtime, 'showManagedWorktree').mockResolvedValue({ id: WORKTREE_ID } as never)
vi.spyOn(runtime, 'showManagedTerminalWorkspace').mockResolvedValue({ id: WORKTREE_ID } as never)
vi.spyOn(runtime, 'createTerminal').mockResolvedValue({
handle: TERMINAL_HANDLE,
worktreeId: WORKTREE_ID,