refactor(runtime): check terminal creation and splitting (#27708)

This commit is contained in:
Neil
2026-10-14 19:29:25 -07:00
committed by GitHub
parent 1bdbc23648
commit f5c50642de
39 changed files with 825 additions and 236 deletions
@@ -18,9 +18,9 @@ const LAYOUT_AUTHORITIES = [
'src/main/persistence/restoring-sessions/session-owner-fields.ts',
'src/main/persistence/loading-store/pty-binding-persistence.ts',
'src/main/remote-layout-snapshot/index.ts',
'src/main/runtime/orca-runtime-split-pty-backed-terminal.ts',
'src/main/runtime/terminal/launch/terminal-split-surface.ts',
'src/main/runtime/session-tabs/headless-tab-group-moves.ts',
'src/main/runtime/orca-runtime-create-terminal.ts',
'src/main/runtime/terminal/launch/terminal-create.ts',
'src/renderer/src/runtime/mobile-session-tab-close.ts',
'src/renderer/src/runtime/runtime-layout-client.ts',
'src/renderer/src/store/slices/tabs.ts',
@@ -36,7 +36,7 @@ const STACK_WRITERS = [
'src/renderer/src/components/terminal-pane/TerminalPane.tsx',
'src/renderer/src/runtime/sync-runtime-graph.ts',
'src/renderer/src/runtime/web-session-tabs-sync/store-patch.ts',
'src/main/runtime/orca-runtime-split-terminal.ts',
'src/main/runtime/terminal/launch/terminal-split.ts',
'src/main/runtime/session-graph/session-window-graph.ts',
'src/main/runtime/session-tabs/mobile-session-hydration.ts',
'src/main/runtime/session-tabs/mobile-session-reconciliation.ts',
@@ -65,6 +65,12 @@ const LAYOUT_ORACLE_PREFIXES = [
'config/scripts/pr-layout-oracle-route.mjs'
]
const LAUNCH_LAYOUT_WRITERS = [
'src/main/runtime/terminal/launch/terminal-create.ts',
'src/main/runtime/terminal/launch/terminal-split.ts',
'src/main/runtime/terminal/launch/terminal-split-surface.ts'
]
// Runtime matches only the modules that create, move, close, persist or publish layout.
const LAYOUT_ORACLE_RUNTIME_MODULE =
/^src\/(?:main|renderer\/src)\/runtime\/(?:[^/]+\/)*[^/]*(?:pane-admission|workspace-layout|session-tab|headless-[^/]*tab|layout-client|layout-command-router|layout-projection|create-terminal|split-terminal|split-pty-backed-terminal|terminal-split-layout|spawn-placement|sync-window-graph|runtime-graph|leaf-move)[^/]*\.ts$/
@@ -81,6 +87,7 @@ export function isLayoutOracleSource(file) {
return false
}
return (
LAUNCH_LAYOUT_WRITERS.includes(file) ||
LAYOUT_ORACLE_PREFIXES.some((prefix) => file.startsWith(prefix)) ||
LAYOUT_ORACLE_RUNTIME_MODULE.test(file)
)
-11
View File
@@ -9,11 +9,6 @@ src/main/runtime/orca-runtime-build-headless-mobile-session-browser-tabs.ts
src/main/runtime/orca-runtime-build-pty-terminal-summary.ts
src/main/runtime/orca-runtime-close-mobile-session-tab.ts
src/main/runtime/orca-runtime-controller-knows-pty-is-live.ts
src/main/runtime/orca-runtime-create-agent-session.ts
src/main/runtime/orca-runtime-create-mobile-session-terminal.ts
src/main/runtime/orca-runtime-create-runtime-owned-mobile-session-terminal.ts
src/main/runtime/orca-runtime-create-terminal-desktop.ts
src/main/runtime/orca-runtime-create-terminal.ts
src/main/runtime/orca-runtime-deliver-pending-messages.ts
src/main/runtime/orca-runtime-automation-operations.ts
src/main/runtime/orca-runtime-file-commands.ts
@@ -33,7 +28,6 @@ src/main/runtime/orca-runtime-notify-ssh-state-changed.ts
src/main/runtime/orca-runtime-on-pty-exit.ts
src/main/runtime/orca-runtime-perform-mobile-session-pty-records-refresh.ts
src/main/runtime/orca-runtime-persist-headless-terminal-title.ts
src/main/runtime/orca-runtime-prepare-pty-execution-context.ts
src/main/runtime/orca-runtime-preserved-branch-cleanup.ts
src/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.ts
src/main/runtime/orca-runtime-pty-foreground-process-reads.ts
@@ -43,22 +37,17 @@ src/main/runtime/orca-runtime-refresh-pty-worktree-records-from-controller.ts
src/main/runtime/orca-runtime-refresh-pty-worktree-records-with-controller-inventory.ts
src/main/runtime/orca-runtime-refuse-unattributed-mobile-session-tab-close.ts
src/main/runtime/orca-runtime-register-pty.ts
src/main/runtime/orca-runtime-resolve-browser-network-execution-host-for-worktree.ts
src/main/runtime/orca-runtime-resolve-known-workspace-file-target.ts
src/main/runtime/orca-runtime-resolve-terminal-pane.ts
src/main/runtime/orca-runtime-resolve-terminal-split-source-authority.ts
src/main/runtime/orca-runtime-run-create-mobile-session-terminal.ts
src/main/runtime/orca-runtime-runtime-id.ts
src/main/runtime/orca-runtime-schedule-mobile-session-tabs-changed.ts
src/main/runtime/orca-runtime-serialize-agent-prompt-submission.ts
src/main/runtime/orca-runtime-sleep-resolved-worktree-terminals.ts
src/main/runtime/orca-runtime-split-pty-backed-terminal.ts
src/main/runtime/orca-runtime-split-terminal.ts
src/main/runtime/orca-runtime-state-fields.ts
src/main/runtime/orca-runtime-stop-exact-terminals-for-worktree.ts
src/main/runtime/orca-runtime-stop-requested-pty-ids.ts
src/main/runtime/orca-runtime-stop-terminals-for-worktree.ts
src/main/runtime/orca-runtime-terminal-create-deduplication.ts
src/main/runtime/orca-runtime-terminal-drivers.ts
src/main/runtime/orca-runtime-touch-mobile-session-tabs-for-worktree.ts
src/main/runtime/orca-runtime-verify-orchestration-compatibility-caller.ts
+5 -3
View File
@@ -6,6 +6,8 @@ import type { GlobalSettings } from '../../shared/global-settings-types'
import type { FloatingTerminalCwdRequest } from '../../shared/ui-chrome-types'
import type { Store } from '../persistence'
type FloatingTerminalSettings = Pick<GlobalSettings, 'floatingTerminalTrustedCwds'>
const FLOATING_WORKSPACE_DIRNAME = 'floating-workspace'
function expandHomePath(input: string, home: string): string {
@@ -41,7 +43,7 @@ async function canonicalizeAccessibleDirectory(dirPath: string): Promise<string
}
}
function getTrustedFloatingWorkspaceDirectories(settings: GlobalSettings): Set<string> {
function getTrustedFloatingWorkspaceDirectories(settings: FloatingTerminalSettings): Set<string> {
return new Set(
(settings.floatingTerminalTrustedCwds ?? [])
.map((trustedPath) => trustedPath.trim())
@@ -63,7 +65,7 @@ async function getPreservedTrustedFloatingWorkspaceDirectories(
function isTrustedFloatingWorkspaceDirectory(
canonicalDirPath: string,
settings: GlobalSettings
settings: FloatingTerminalSettings
): boolean {
return getTrustedFloatingWorkspaceDirectories(settings).has(path.resolve(canonicalDirPath))
}
@@ -81,7 +83,7 @@ export async function ensureDefaultFloatingWorkspacePath(): Promise<string> {
}
export async function resolveFloatingTerminalCwd(
store: Store,
store: { getSettings(): FloatingTerminalSettings },
args?: FloatingTerminalCwdRequest
): Promise<string> {
const configuredPath = typeof args?.path === 'string' ? args.path.trim() : ''
@@ -82,6 +82,62 @@ describe('materializeWorktreePushTargetRemote', () => {
])
})
it('preserves the legacy null-store failure after existing-remote adoption work', async () => {
const commands: string[][] = []
gitExecFileAsyncMock.mockImplementation(async (args: string[]) => {
commands.push(args)
if (args[0] === 'remote' && args[1] === 'get-url') {
return { stdout: `${FORK_URL}\n`, stderr: '' }
}
if (args[0] === 'config' && args[1] === '--get-all') {
throw new Error('no such section')
}
if (args[0] === 'symbolic-ref') {
return { stdout: 'contributor/fix\n', stderr: '' }
}
return { stdout: '', stderr: '' }
})
await expect(
materializeWorktreePushTargetRemote(REPO_PATH, forkTarget(), null, 'repo-1')
).rejects.toBeInstanceOf(TypeError)
expect(commands).toEqual([
['remote', 'get-url', FORK_REMOTE],
['config', '--get-all', `remote.${FORK_REMOTE}.fetch`],
[
'config',
'--add',
`remote.${FORK_REMOTE}.fetch`,
`+refs/heads/contributor/fix*:refs/remotes/${FORK_REMOTE}/contributor/fix*`
],
['config', `remote.${FORK_REMOTE}.tagOpt`, '--no-tags'],
['rev-parse', '--verify', '--quiet', `refs/remotes/${FORK_REMOTE}/contributor/fix`],
['symbolic-ref', '--short', 'HEAD'],
['branch', '--set-upstream-to', `${FORK_REMOTE}/contributor/fix`, 'contributor/fix']
])
})
it('accepts a null store when both persistence identifiers are omitted', async () => {
gitExecFileAsyncMock.mockImplementation(async (args: string[]) => {
if (args[0] === 'remote' && args[1] === 'get-url') {
return { stdout: `${FORK_URL}\n`, stderr: '' }
}
if (args[0] === 'config' && args[1] === '--get-all') {
throw new Error('no such section')
}
if (args[0] === 'symbolic-ref') {
return { stdout: 'contributor/fix\n', stderr: '' }
}
return { stdout: '', stderr: '' }
})
const target = forkTarget()
await expect(materializeWorktreePushTargetRemote(REPO_PATH, target, null)).resolves.toBe(target)
expect(gitExecFileAsyncMock).toHaveBeenLastCalledWith(
['branch', '--set-upstream-to', `${FORK_REMOTE}/${target.branchName}`, 'contributor/fix'],
{ cwd: REPO_PATH }
)
})
it('materializes the remote (add + provenance + fetch) when the probe misses', async () => {
gitExecFileAsyncMock.mockImplementation(async (args: string[]) => {
if (args[0] === 'remote' && args[1] === 'get-url') {
+6 -5
View File
@@ -641,7 +641,7 @@ async function getSelectedHostedReviewForBranch(
export async function prepareWorktreePushTarget(
repoPath: string,
target: GitPushTarget,
store?: WorktreePushTargetStore,
store?: WorktreePushTargetStore | null,
repoId?: string,
gitOptions: { wslDistro?: string } = {}
): Promise<GitPushTarget> {
@@ -686,7 +686,7 @@ export async function prepareWorktreePushTarget(
export async function materializeWorktreePushTargetRemote(
repoPath: string,
target: GitPushTarget,
store?: WorktreePushTargetStore,
store?: WorktreePushTargetStore | null,
repoId?: string,
gitOptions: { wslDistro?: string } = {},
worktreeId?: string
@@ -757,7 +757,7 @@ async function adoptExistingForkRemoteForBranch(
repoPath: string,
target: GitPushTarget,
gitOptions: { wslDistro?: string },
store: WorktreePushTargetStore | undefined,
store: WorktreePushTargetStore | null | undefined,
repoId: string | undefined,
worktreeId: string | undefined
): Promise<GitPushTarget> {
@@ -791,7 +791,8 @@ async function adoptExistingForkRemoteForBranch(
const owned =
store !== undefined &&
ownerRepoId !== undefined &&
isPushTargetRemoteCreatedByKnownWorktree(store, restored, ownerRepoId)
// SAFETY: Legacy null keeps this branch's original failure rather than introducing a fallback.
isPushTargetRemoteCreatedByKnownWorktree(store!, restored, ownerRepoId)
const adopted = owned ? { ...restored, remoteCreated: true } : restored
persistMaterializedPushTargetIfCreated(store, worktreeId, adopted)
return adopted
@@ -831,7 +832,7 @@ function runForkRemoteAdoption<T>(
// predates `markRemoteOrcaCreated` (no git-config marker either). `setWorktreeMeta` is
// optional on `WorktreePushTargetStore` so narrow test/reconciliation stores keep compiling.
function persistMaterializedPushTargetIfCreated(
store: WorktreePushTargetStore | undefined,
store: WorktreePushTargetStore | null | undefined,
worktreeId: string | undefined,
target: GitPushTarget
): void {
@@ -22,7 +22,7 @@ import { getLatestPtyTitle } from './runtime-worktree-status-projection'
import type { PtyLivenessVerdict } from '../../shared/pty-liveness-verdict'
export abstract class OrcaRuntimeWithAdoptTerminalOrphansFromInventory extends OrcaRuntimeWithSubscribeToTerminalResize {
protected abstract assertGraphReady(): void
abstract assertGraphReady(): void
protected async adoptTerminalOrphansFromInventoryUnderMutation(
request: RuntimeTerminalOrphanAdoptionRequest,
@@ -1,4 +1,5 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import type { BrowserWindow } from 'electron'
import type { TerminalWorkspaceLaunchScope } from './runtime-legacy-worker-terminal-recovery-types'
import { OrcaRuntimeWithGetAgentSessionExecutionNamespace } from './orca-runtime-get-agent-session-execution-namespace'
import type {
RuntimeAgentSessionRpcCaller,
@@ -27,7 +28,30 @@ import {
import { agentStartedTelemetry } from '../agent-launch/agent-started-telemetry'
import { withAgentSessionAccountEnv } from './agent-session-account-env'
export class OrcaRuntimeWithCreateAgentSession extends OrcaRuntimeWithGetAgentSessionExecutionNamespace {
export abstract class OrcaRuntimeWithCreateAgentSession extends OrcaRuntimeWithGetAgentSessionExecutionNamespace {
abstract resolveWorkspaceTerminalStartupCwd(
workspace: Pick<TerminalWorkspaceLaunchScope, 'path'>,
requestedCwd?: string | null
): string | undefined
protected abstract buildTerminalWorkspaceEnv(
scope: TerminalWorkspaceLaunchScope,
baseEnv: Record<string, string>,
paneKey: string,
tabId: string,
agentTeamsEnv?: Record<string, string>
): Promise<Record<string, string>>
abstract getAuthoritativeWindow(): BrowserWindow
abstract waitForTerminalHandle(tabId: string, timeoutMs?: number): Promise<string>
protected abstract reconcileRemoteTerminalCreate(
worktreeId: string,
terminalHandle: string,
connectionId?: string | null
): Promise<RuntimeTerminalCreate | null>
async createAgentSession(
request: RuntimeCreateAgentSessionRequest,
caller: RuntimeAgentSessionRpcCaller = {}
@@ -1,6 +1,5 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import * as dependencies from './orca-runtime-create-terminal-dependencies'
import type { OrcaRuntimeWithCreateTerminal } from './orca-runtime-create-terminal'
import type { OrcaRuntimeWithCreateTerminal } from './terminal/launch/terminal-create'
import type { RuntimeTerminalPresentation } from '../../shared/runtime-types'
// A create with no workspace lands in whatever the window is showing, so only the window can make it.
@@ -32,7 +32,7 @@ class DefaultTabRuntime extends OrcaRuntimeService {
super(store)
}
protected override async resolveTerminalWorkspaceLaunchScope(): Promise<TerminalWorkspaceLaunchScope> {
override async resolveTerminalWorkspaceLaunchScope(): Promise<TerminalWorkspaceLaunchScope> {
return {
id: WORKTREE_ID,
path: '/repo/app',
@@ -35,7 +35,7 @@ class MigratedPaneRuntime extends OrcaRuntimeService {
super(store)
}
protected override async resolveTerminalWorkspaceLaunchScope(): Promise<TerminalWorkspaceLaunchScope> {
override async resolveTerminalWorkspaceLaunchScope(): Promise<TerminalWorkspaceLaunchScope> {
return {
id: WORKTREE_ID,
path: worktreePath,
@@ -60,7 +60,7 @@ export abstract class OrcaRuntimeWithPreservedBranchCleanup extends OrcaRuntimeW
folderWorkspace: FolderWorkspace
): ResolvedWorktree
protected abstract resolveTerminalWorkspaceLaunchScope(
abstract resolveTerminalWorkspaceLaunchScope(
selector: string,
createdWorktree?: Worktree
): Promise<TerminalWorkspaceLaunchScope>
@@ -1,5 +1,5 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import type { OrcaRuntimeWithCreateTerminal } from './orca-runtime-create-terminal'
import type { OrcaRuntimeWithCreateTerminal } from './terminal/launch/terminal-create'
import { OrcaRuntimeWithGetTerminalInteractiveWait } from './terminal/wait/terminal-interactive-wait'
import type {
RuntimeTerminalRead,
@@ -1,5 +1,5 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithSplitPtyBackedTerminal } from './orca-runtime-split-pty-backed-terminal'
import { OrcaRuntimeWithSplitPtyBackedTerminal } from './terminal/launch/terminal-split-surface'
import {
resolveTerminalSessionWorktreeId,
runtimeWorktreeIdsEqual
@@ -25,7 +25,7 @@ export class OrcaRuntimeWithResolveWaiter extends OrcaRuntimeWithDeliverPendingM
return `${tabId}::${leafId}`
}
protected getAuthoritativeWindow(): BrowserWindow {
getAuthoritativeWindow(): BrowserWindow {
const win = this.getAvailableAuthoritativeWindow()
if (!win || win.isDestroyed()) {
throw new Error('No renderer window available')
+1 -1
View File
@@ -289,7 +289,7 @@ export class OrcaRuntimeWithRuntimeId {
// ptyId keeps active TUI redraws independent of the total open terminal count.
protected leavesByPtyId = new Map<string, RuntimeLeafRecord[]>()
protected handles = new Map<string, TerminalHandleRecord>()
handles = new Map<string, TerminalHandleRecord>()
protected handleByLeafKey = new Map<string, string>()
@@ -1,6 +1,9 @@
import type { TerminalWorkspaceLaunchScope } from './runtime-legacy-worker-terminal-recovery-types'
import type { RuntimePtyController } from './runtime-pty-controller-contract'
import { describe, expect, it, vi } from 'vitest'
import type { PtyProcessInfo } from '../providers/pty-provider-contract'
import type { RuntimeTerminalCreate } from '../../shared/runtime-types'
import type { RuntimeTerminalSplit } from '../../shared/runtime-terminal-contracts'
import { OrcaRuntimeService } from './orca-runtime'
import { deriveRemoteRuntimeTerminalCreateHandle } from './remote-runtime-terminal-create-identity'
import { RemoteRuntimeTerminalCreateIdempotency } from './remote-runtime-terminal-create-idempotency'
@@ -380,3 +383,401 @@ describe('terminal create reconciliation scopes inventory to the owning executio
expect(listProcesses).toHaveBeenCalledWith('local')
})
})
function scope(): TerminalWorkspaceLaunchScope {
return {
id: 'repo::workspace',
path: '/workspace',
connectionId: null,
repo: null,
folderWorkspace: null
}
}
function replacement(): never {
throw new Error('an argument getter replaced an already captured runtime method')
}
describe('launch runtime dispatch and allocation phases', () => {
it('retains native async method metadata on the original runtime frame', () => {
const runtime = new OrcaRuntimeService(null)
expect(runtime.dedupeTerminalCreate.constructor.name).toBe('AsyncFunction')
expect(runtime.dedupeTerminalCreate.length).toBe(5)
expect(runtime.dedupeWorktreeCreate.constructor.name).toBe('Function')
expect(runtime.dedupeWorktreeCreate.length).toBe(3)
})
it('retains first-Promise behavior when caller operation keys collide', async () => {
const runtime = new OrcaRuntimeService(null)
const firstFactory = vi.fn(async () => ({ worktree: 'first' }))
const secondFactory = vi.fn(async () => ({ agentLaunch: 'second' }))
const first = runtime.dedupeWorktreeCreate('repo', 'agent.launch:mutation', firstFactory)
const second = runtime.dedupeWorktreeCreate('repo', 'agent.launch:mutation', secondFactory)
expect(second).toBe(first)
await expect(first).resolves.toEqual({ worktree: 'first' })
expect(firstFactory).toHaveBeenCalledTimes(1)
expect(secondFactory).not.toHaveBeenCalled()
})
it('captures private agent-session reconciliation before identity getters', async () => {
const runtime = new OrcaRuntimeService(null)
const result = createdTerminal('reclaimed')
const events: string[] = []
Object.defineProperty(runtime, 'reconcileRemoteTerminalCreate', {
configurable: true,
get: () => {
events.push('read-reconcile')
return async function (this: OrcaRuntimeService, ...args: unknown[]) {
expect(this).toBe(runtime)
expect(args).toEqual(['worktree-1', 'reclaimed', null])
return result
}
}
})
const identity = {
get worktreeId() {
events.push('read-worktree')
Object.defineProperty(runtime, 'reconcileRemoteTerminalCreate', { value: replacement })
return 'worktree-1'
},
terminalHandle: 'reclaimed',
connectionId: null
}
await expect(runtime['reclaimFencedAgentSessionSpawn'](identity)).resolves.toBe(result)
expect(events).toEqual(['read-reconcile', 'read-worktree'])
})
it('retains direct spawn failure and withdrawal after awaited admission removes spawn', async () => {
const runtime = new OrcaRuntimeService(null)
const entered = Promise.withResolvers<void>()
const ready = Promise.withResolvers<void>()
const events: string[] = []
const spawn = vi.fn(async () => {
throw new Error('removed spawn must not run')
})
const controller: Pick<RuntimePtyController, 'spawn'> = { spawn }
const store = {
admitTerminalPane: async function () {
expect(this).toBe(store)
events.push('admit')
entered.resolve()
await ready.promise
delete controller.spawn
events.push('removed')
return 'admitted'
},
withdrawTerminalPane: vi.fn(async function (this: typeof store): Promise<void> {
expect(this).toBe(store)
events.push('withdraw')
})
}
Object.defineProperty(runtime, 'store', { value: store })
Object.defineProperty(runtime, 'ptyController', { value: controller })
Object.defineProperty(runtime, 'getAvailableAuthoritativeWindow', { value: () => null })
Object.defineProperty(runtime, 'resolveTerminalWorkspaceLaunchScope', {
value: async () => scope()
})
Object.defineProperty(runtime, 'resolveAgentTerminalCreateOptions', {
value: async (_workspace: unknown, opts: unknown) => opts
})
Object.defineProperty(runtime, 'buildTerminalWorkspaceEnv', { value: async () => ({}) })
const pending = runtime.createTerminal('workspace')
await entered.promise
expect(events).toEqual(['admit'])
expect(store.withdrawTerminalPane).not.toHaveBeenCalled()
ready.resolve()
await expect(pending).rejects.toBeInstanceOf(TypeError)
expect(events).toEqual(['admit', 'removed', 'withdraw'])
expect(store.withdrawTerminalPane).toHaveBeenCalledTimes(1)
expect(spawn).not.toHaveBeenCalled()
})
it('reenters the split override and captures it before the PTY argument getter', async () => {
const runtime = new OrcaRuntimeService(null)
const pty = runtime['recordPtyWorktree']('pty', 'repo::workspace')
const result: RuntimeTerminalSplit = {
handle: 'split',
tabId: 'tab',
leafId: 'leaf',
paneRuntimeId: 1
}
const events: string[] = []
Object.defineProperty(runtime, 'splitPtyBackedTerminal', {
configurable: true,
get: () => {
events.push('read-split')
return async function (
this: OrcaRuntimeService,
actual: unknown
): Promise<RuntimeTerminalSplit> {
expect(this).toBe(runtime)
expect(actual).toBe(pty)
return result
}
}
})
Object.defineProperty(runtime, 'getLivePtyForHandle', {
value: () => ({
record: null,
get pty() {
events.push('read-pty')
Object.defineProperty(runtime, 'splitPtyBackedTerminal', { value: replacement })
return pty
}
})
})
await expect(runtime.splitTerminal('handle')).resolves.toBe(result)
expect(events).toEqual(['read-split', 'read-pty'])
})
it('reenters workspace target resolution on the runtime', async () => {
const runtime = new OrcaRuntimeService(null)
const workspace = scope()
Object.defineProperty(runtime, 'resolveTerminalWorkspaceLaunchTarget', {
value: async function (this: OrcaRuntimeService, selector: string) {
expect(this).toBe(runtime)
expect(selector).toBe('folder')
return { scope: workspace, managedWorktree: null }
}
})
await expect(runtime['resolveTerminalWorkspaceLaunchScope']('folder')).resolves.toBe(workspace)
})
it('reads reconciliation and its canonical cache after workspace resolution', async () => {
const runtime = new OrcaRuntimeService(null)
const ready = Promise.withResolvers<TerminalWorkspaceLaunchScope>()
const result: RuntimeTerminalCreate = {
handle: 'adopted',
worktreeId: 'repo::workspace',
title: null
}
Object.defineProperty(runtime, 'resolveTerminalWorkspaceLaunchScope', {
value: () => ready.promise
})
const run = vi.fn(async () => result)
const pending = runtime.dedupeTerminalCreate('device', 'workspace', 'mutation', true, run)
const events: string[] = []
Object.defineProperty(runtime, 'reconcileRemoteTerminalCreate', {
value: async function (
this: OrcaRuntimeService,
worktreeId: string,
_handle: string,
connection: null
) {
expect(this).toBe(runtime)
expect(worktreeId).toBe('repo::workspace')
expect(connection).toBeNull()
events.push('reconcile')
return result
}
})
const cache = runtime['terminalCreateIdempotency']
Object.defineProperty(runtime, 'terminalCreateIdempotency', {
get: () => {
events.push('read-cache')
return cache
}
})
ready.resolve(scope())
await expect(pending).resolves.toBe(result)
expect(events).toEqual(['read-cache', 'reconcile'])
expect(run).not.toHaveBeenCalled()
})
it('captures startup and create overrides before option getters', async () => {
const runtime = new OrcaRuntimeService(null)
const repo = {
id: 'repo',
path: '/workspace',
displayName: 'repo',
badgeColor: '#000',
addedAt: 0
}
const terminal: RuntimeTerminalCreate = {
handle: 'terminal',
worktreeId: 'repo::workspace',
title: null
}
Object.defineProperty(runtime, 'store', {
value: { getRepos: () => [repo], getRepo: () => repo }
})
Object.defineProperty(runtime, 'resolveWorktreeSelector', {
value: async () => ({ id: 'repo::workspace', repoId: 'repo', path: '/workspace' })
})
const events: string[] = []
Object.defineProperty(runtime, 'buildStartupForAgent', {
configurable: true,
get: () => {
events.push('read-startup')
return function (this: OrcaRuntimeService) {
expect(this).toBe(runtime)
return { agent: 'codex', startup: { command: 'codex' } }
}
}
})
Object.defineProperty(runtime, 'createTerminal', {
configurable: true,
get: () => {
events.push('read-create')
return async function (this: OrcaRuntimeService) {
expect(this).toBe(runtime)
return terminal
}
}
})
await expect(
runtime.launchAgentTerminal('workspace', {
get agent(): 'codex' {
events.push('read-agent')
Object.defineProperty(runtime, 'buildStartupForAgent', { value: replacement })
return 'codex'
},
prompt: 'prompt',
get title(): string {
events.push('read-title')
Object.defineProperty(runtime, 'createTerminal', { value: replacement })
return 'title'
}
})
).resolves.toBe(terminal)
expect(events).toEqual(['read-startup', 'read-agent', 'read-create', 'read-title'])
})
it('captures admission store and controller before spawn argument getters', async () => {
const runtime = new OrcaRuntimeService(null)
const expected = new Error('captured controller refusal')
const admission = vi.fn(async () => undefined)
const originalStore = { admitTerminalPane: admission }
let currentStore = originalStore
const originalController = {
spawn: async () => {
throw expected
}
}
let currentController = originalController
Object.defineProperty(runtime, 'store', { get: () => currentStore })
Object.defineProperty(runtime, 'ptyController', { get: () => currentController })
Object.defineProperty(runtime, 'getAvailableAuthoritativeWindow', { value: () => null })
Object.defineProperty(runtime, 'resolveTerminalWorkspaceLaunchScope', {
value: async () => scope()
})
Object.defineProperty(runtime, 'resolveAgentTerminalCreateOptions', {
value: async (_workspace: unknown, opts: unknown) => opts
})
Object.defineProperty(runtime, 'buildTerminalWorkspaceEnv', { value: async () => ({}) })
await expect(
runtime.createTerminal('workspace', {
get resumeProviderSession() {
currentStore = {
admitTerminalPane: vi.fn(async () => {
throw new Error('late store')
})
}
currentController = {
spawn: async () => {
throw new Error('late controller')
}
}
return undefined
}
})
).rejects.toBe(expected)
expect(admission).toHaveBeenCalledTimes(1)
})
it('rereads the canonical mobile mutation map after creation and in failure cleanup', async () => {
const runtime = new OrcaRuntimeService(null)
const first = new Map<string, Promise<never>>()
const second = new Map<string, Promise<never>>()
let current = first
const reads: string[] = []
Object.defineProperty(runtime, 'mobileTerminalCreateByMutationId', {
get: () => {
reads.push(current === first ? 'first' : 'second')
return current
}
})
const ready = Promise.withResolvers<never>()
const expected = new Error('creation refusal')
Object.defineProperty(runtime, 'runCreateMobileSessionTerminal', {
value: () => {
current = second
return ready.promise
}
})
const pending = runtime.createMobileSessionTerminal('workspace', {
clientMutationId: 'mutation',
select: false
})
expect(first.size).toBe(0)
expect(second.size).toBe(1)
ready.reject(expected)
await expect(pending).rejects.toBe(expected)
expect(second.size).toBe(0)
expect(reads).toEqual(['first', 'second', 'second', 'second'])
})
it('checks graph readiness on the runtime before resolving its desktop window', async () => {
const runtime = new OrcaRuntimeService(null)
const expected = new Error('desktop window refusal')
const events: string[] = []
Object.defineProperty(runtime, 'getAvailableAuthoritativeWindow', { value: () => null })
Object.defineProperty(runtime, 'assertGraphReady', {
get: () => {
events.push('read-ready')
return function (this: OrcaRuntimeService) {
expect(this).toBe(runtime)
events.push('invoke-ready')
}
}
})
Object.defineProperty(runtime, 'getAuthoritativeWindow', {
value: () => {
events.push('read-window')
throw expected
}
})
await expect(runtime.createTerminal()).rejects.toBe(expected)
expect(events).toEqual(['read-ready', 'invoke-ready', 'read-window'])
})
it('retains the canonical cache allocations after their original preceding clocks', () => {
const events: { kind: 'map' | 'clock'; value?: object; stack: string }[] = []
const OriginalMap = Map
const originalNow = Date.now
class TracedMap<Key, Value> extends OriginalMap<Key, Value> {
constructor(entries?: Iterable<readonly [Key, Value]> | null) {
super(entries)
events.push({
kind: 'map',
value: this,
stack: new Error('allocation phase trace').stack ?? ''
})
}
}
vi.stubGlobal('Map', TracedMap)
const clock = vi.spyOn(Date, 'now').mockImplementation(() => {
events.push({ kind: 'clock', stack: new Error('allocation phase trace').stack ?? '' })
return originalNow()
})
try {
const runtime = new OrcaRuntimeService(null)
const mobileCache = runtime['mobileTerminalCreateByMutationId']
const cacheIndex = events.findIndex((event) => event.value === mobileCache)
const rootClock = events.findIndex((event) => event.kind === 'clock')
expect(cacheIndex).toBeGreaterThanOrEqual(0)
expect(cacheIndex).toBeGreaterThan(rootClock)
expect(
events.filter(
(event) =>
event.kind === 'map' &&
/terminal\/launch\/(?:mobile-terminal-create|terminal-create-identity)\.ts/.test(
event.stack.replaceAll('\\', '/')
)
)
).toEqual([])
} finally {
clock.mockRestore()
vi.unstubAllGlobals()
}
})
})
@@ -1,6 +1,6 @@
/* eslint-disable unicorn/no-useless-spread */
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithCreateRuntimeOwnedMobileSessionTerminal } from './orca-runtime-create-runtime-owned-mobile-session-terminal'
import { OrcaRuntimeWithCreateRuntimeOwnedMobileSessionTerminal } from './terminal/launch/mobile-terminal-owned-create'
import type {
RuntimeMobileSessionCreateTerminalResult,
RuntimeMobileSessionTerminalClientTab
+3 -2
View File
@@ -61,7 +61,7 @@ export async function withdrawRuntimePane(
*/
export async function spawnInAdmittedPane(
store: RuntimeStore | null | undefined,
controller: Required<Pick<RuntimePtyController, 'spawn'>>,
controller: Pick<RuntimePtyController, 'spawn'>,
args: AdmittedSpawnArgs
): ReturnType<Spawn> {
const outcome = await store?.admitTerminalPane?.(admissionFor(args), hostIdOf(args))
@@ -72,7 +72,8 @@ export async function spawnInAdmittedPane(
const { groupId: _groupId, ...spawnArgs } = args
let result: Awaited<ReturnType<Spawn>>
try {
result = await controller.spawn(spawnArgs)
// SAFETY: Callers require spawn; a lost capability during admission keeps the original failure.
result = await controller.spawn!(spawnArgs)
} catch (error) {
if (outcome === 'admitted') {
await withdrawRuntimePane(store, args)
@@ -111,6 +111,8 @@ export type RuntimeStore = {
// Read by the launch-line carry rule to name the shell a local line is typed into.
terminalDefaultShell?: GlobalSettings['terminalDefaultShell']
floatingTerminalEnabled?: GlobalSettings['floatingTerminalEnabled']
floatingTerminalCwd?: GlobalSettings['floatingTerminalCwd']
floatingTerminalTrustedCwds?: GlobalSettings['floatingTerminalTrustedCwds']
agentStatusHooksEnabled?: GlobalSettings['agentStatusHooksEnabled']
terminalCopyTrimsGutter?: GlobalSettings['terminalCopyTrimsGutter']
experimentalNativeChat?: GlobalSettings['experimentalNativeChat']
@@ -2,7 +2,10 @@ import { materializeWorktreePushTargetRemote } from '../ipc/worktree-remote'
import { getLocalProjectWorktreeGitOptions } from '../project-runtime-git-options'
import type { GitPushTarget } from '../../shared/worktree/types'
import type { Repo } from '../../shared/repo-types'
import type { Store } from '../persistence'
import type { WorktreePushTargetStore } from '../ipc/worktree-push-target-cleanup'
import type { ProjectRuntimeResolutionStore } from '../local-project-runtime-resolution'
type TerminalPushTargetStore = WorktreePushTargetStore & ProjectRuntimeResolutionStore
// Why (#17828): a fork-PR remote deferred at worktree-create time must exist before an
// autonomous agent's raw git commands run in a freshly opened terminal -- "sync through
@@ -13,7 +16,7 @@ export function triggerTerminalSpawnPushTargetMaterialization(
worktreePath: string,
pushTarget: GitPushTarget | undefined,
repo: Repo | null | undefined,
store: Store | undefined,
store: TerminalPushTargetStore | null | undefined,
repoId?: string,
worktreeId?: string
): void {
@@ -37,7 +40,7 @@ export function triggerTerminalSpawnPushTargetMaterialization(
}
function localGitOptionsForTerminalSpawn(
store: Store | undefined,
store: ProjectRuntimeResolutionStore | null | undefined,
repo: Repo | null | undefined
): { wslDistro?: string } {
if (!store || !repo) {
@@ -1,4 +1,4 @@
import type { OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree as ResolveBrowserNetworkExecutionHostForWorktreeMethods } from '../orca-runtime-resolve-browser-network-execution-host-for-worktree'
import type { OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree as ResolveBrowserNetworkExecutionHostForWorktreeMethods } from '../terminal/launch/terminal-workspace-scope'
import { OrcaRuntimeWithHasTerminalsForWorktree } from './session-graph-reload-lifecycle'
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../../shared/runtime-types'
import type { FolderWorkspace } from '../../../shared/folder-workspace-types'
@@ -65,7 +65,7 @@ export abstract class OrcaRuntimeWithTransitionGraphReloadToTerminalState extend
this.markSessionTabsInventoryPublished()
}
protected assertGraphReady(): void {
assertGraphReady(): void {
if (this.graphStatus !== 'ready') {
throw new Error('runtime_unavailable')
}
@@ -134,7 +134,7 @@ export abstract class OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobile
}
}
protected waitForTerminalHandle(tabId: string, timeoutMs = 10_000): Promise<string> {
waitForTerminalHandle(tabId: string, timeoutMs = 10_000): Promise<string> {
const existing = this.resolveHandleForTab(tabId)
if (existing) {
return Promise.resolve(existing)
@@ -1,6 +1,6 @@
import type { RuntimeSessionTabsInventoryPublication as SessionTabsInventoryPublicationMethods } from './session-tabs-inventory-publication'
import type { OrcaRuntimeWithScheduleMobileSessionTabsChanged as ScheduleMobileSessionTabsChangedMethods } from '../orca-runtime-schedule-mobile-session-tabs-changed'
import type { OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree as ResolveBrowserNetworkExecutionHostForWorktreeMethods } from '../orca-runtime-resolve-browser-network-execution-host-for-worktree'
import type { OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree as ResolveBrowserNetworkExecutionHostForWorktreeMethods } from '../terminal/launch/terminal-workspace-scope'
import type { OrcaRuntimeWithHydrateHeadlessMobileSessionTabsFromWorkspaceSession as HydrateHeadlessMobileSessionTabsFromWorkspaceSessionMethods } from './mobile-session-hydration'
import type { OrcaRuntimeWithBuildHeadlessMobileSessionBrowserTabs as BuildHeadlessMobileSessionBrowserTabsMethods } from '../orca-runtime-build-headless-mobile-session-browser-tabs'
import type { OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals as RestoreLivePairedRendererSessionOwnedMobileTerminalsMethods } from './renderer-session-terminal-rescue'
@@ -1,3 +1,4 @@
import type { RuntimePtyController } from '../../runtime-pty-controller-contract'
import {
addClaudeTeammateModeAuto,
addClaudeTeammateModeInProcess,
@@ -13,7 +14,10 @@ export async function buildRuntimeAgentTeamsLaunchPlan(args: {
claudeAgentTeamsSourceCommand?: string
claudeAgentTeamsMode?: ClaudeAgentTeamsMode
baseEnv: Record<string, string | undefined>
adoptedBeforeLaunch: boolean
adoptedBeforeLaunch:
| boolean
| Awaited<ReturnType<NonNullable<RuntimePtyController['adoptStablePane']>>>
| undefined
createTeamEnv: (shimDir: string, shimBin: string) => Record<string, string>
}): Promise<{
plan: Awaited<ReturnType<typeof buildClaudeAgentTeamsLaunchPlan>> | undefined
@@ -1,14 +1,29 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithCreateTerminal } from './orca-runtime-create-terminal'
import type { WorktreeStartupLaunch } from '../../shared/worktree/launch-types'
import type { TuiAgent } from '../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../shared/agent-session-resume'
import type { RuntimeNavigationTarget } from '../../shared/runtime-navigation'
import type { RuntimeMobileSessionCreateTerminalResult } from '../../shared/runtime-types'
import { navigationTargetsHost } from '../../shared/runtime-navigation'
import { MOBILE_TERMINAL_CREATE_RESULT_TTL_MS } from './orca-runtime-core'
import type { MobileTerminalCreateOptions } from './mobile-terminal-renderer-create'
import type { RuntimeMobileSessionTabsResult } from '../../../../shared/runtime-session-contracts'
import { OrcaRuntimeWithCreateTerminal } from './terminal-create'
import type { WorktreeStartupLaunch } from '../../../../shared/worktree/launch-types'
import type { TuiAgent } from '../../../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../../../shared/agent-session-resume'
import type { RuntimeNavigationTarget } from '../../../../shared/runtime-navigation'
import type { RuntimeMobileSessionCreateTerminalResult } from '../../../../shared/runtime-types'
import { navigationTargetsHost } from '../../../../shared/runtime-navigation'
import { MOBILE_TERMINAL_CREATE_RESULT_TTL_MS } from '../../orca-runtime-core'
export abstract class OrcaRuntimeWithCreateMobileSessionTerminal extends OrcaRuntimeWithCreateTerminal {
protected abstract runCreateMobileSessionTerminal(
worktreeSelector: string,
opts?: MobileTerminalCreateOptions
): Promise<RuntimeMobileSessionCreateTerminalResult>
protected abstract getValidatedExplicitWorktreeIdSelector(
selector: string | undefined
): string | null
protected abstract getMobileSessionTabsForWorktree(
worktreeId: string,
clientNavigationId?: string
): RuntimeMobileSessionTabsResult
export class OrcaRuntimeWithCreateMobileSessionTerminal extends OrcaRuntimeWithCreateTerminal {
async createMobileSessionTerminal(
worktreeSelector: string,
opts: {
@@ -1,28 +1,45 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithResolveMobileSessionTerminalCommand } from './orca-runtime-resolve-mobile-session-terminal-command'
import type { WorktreeStartupLaunch } from '../../shared/worktree/launch-types'
import type { TuiAgent } from '../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../shared/agent-session-resume'
import type { AgentLaunchRuntime } from '../../shared/agent-launch-runtime'
import { OrcaRuntimeWithResolveMobileSessionTerminalCommand } from './mobile-terminal-startup'
import type { WorktreeStartupLaunch } from '../../../../shared/worktree/launch-types'
import type { TuiAgent } from '../../../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../../../shared/agent-session-resume'
import type { AgentLaunchRuntime } from '../../../../shared/agent-launch-runtime'
import type {
RuntimeMobileSessionCreateTerminalResult,
RuntimeMobileSessionTabsSnapshot,
RuntimeMobileSessionTerminalTab
} from '../../shared/runtime-types'
} from '../../../../shared/runtime-types'
import { randomUUID } from 'node:crypto'
import { copySleepingAgentLaunchConfig } from './runtime-agent-launch-resolution'
import { deriveRemoteRuntimeTerminalCreateHandle } from './remote-runtime-terminal-create-identity'
import { parsePaneKey } from '../../shared/stable-pane-id'
import { placeCreatedSessionTab } from '../../shared/session-tab-placement'
import { copySleepingAgentLaunchConfig } from '../../runtime-agent-launch-resolution'
import { deriveRemoteRuntimeTerminalCreateHandle } from '../../remote-runtime-terminal-create-identity'
import { parsePaneKey } from '../../../../shared/stable-pane-id'
import { placeCreatedSessionTab } from '../../../../shared/session-tab-placement'
import {
buildHeadlessMobileSessionTabGroups,
buildMaterializedHeadlessParentLayout,
getHeadlessMobileSessionGroupId
} from './mobile-session-layout-projection'
} from '../../mobile-session-layout-projection'
const OWNED_MOBILE_DISPATCH_RECIPE_TTL_MS = 15 * 60_000
export class OrcaRuntimeWithCreateRuntimeOwnedMobileSessionTerminal extends OrcaRuntimeWithResolveMobileSessionTerminalCommand {
export type OwnedMobileTerminalCreateOptions = {
command?: string
cwd?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
identity?: { tabId: string; leafId: string; sessionId?: string }
createMutation?: { clientIdentity: string; id: string }
launchAgent?: TuiAgent
viewMode?: 'terminal' | 'chat'
targetGroupId?: string
supportsSplitGroupPlacement?: boolean
launchConfig?: SleepingAgentLaunchConfig
launchRuntime?: AgentLaunchRuntime
signal?: AbortSignal
refuseSleptWorktree?: boolean
}
export abstract class OrcaRuntimeWithCreateRuntimeOwnedMobileSessionTerminal extends OrcaRuntimeWithResolveMobileSessionTerminalCommand {
private readonly ownedMobileDispatchRecipes = new Map<
string,
{
@@ -46,23 +63,7 @@ export class OrcaRuntimeWithCreateRuntimeOwnedMobileSessionTerminal extends Orca
worktreeId: string,
activate: boolean,
afterTabId?: string,
opts: {
command?: string
cwd?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
identity?: { tabId: string; leafId: string; sessionId?: string }
createMutation?: { clientIdentity: string; id: string }
launchAgent?: TuiAgent
viewMode?: 'terminal' | 'chat'
targetGroupId?: string
supportsSplitGroupPlacement?: boolean
launchConfig?: SleepingAgentLaunchConfig
launchRuntime?: AgentLaunchRuntime
signal?: AbortSignal
refuseSleptWorktree?: boolean
} = {}
opts: OwnedMobileTerminalCreateOptions = {}
): Promise<RuntimeMobileSessionCreateTerminalResult> {
this.pruneOwnedMobileDispatchRecipes()
const workspace = await this.resolveTerminalWorkspaceLaunchScope(`id:${worktreeId}`)
@@ -1,42 +1,96 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithCreateMobileSessionTerminal } from './orca-runtime-create-mobile-session-terminal'
import type { WorktreeStartupLaunch } from '../../shared/worktree/launch-types'
import type { TuiAgent } from '../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../shared/agent-session-resume'
import type { RuntimeMobileSessionCreateTerminalResult } from '../../shared/runtime-types'
import type { MobileTerminalCommandOptions, MobileTerminalCommand } from './mobile-terminal-startup'
import type { OwnedMobileTerminalCreateOptions } from './mobile-terminal-owned-create'
import type { RuntimePtyWorktreeRecord } from '../../runtime-terminal-state-records'
import type { TerminalWorkspaceLaunchScope } from '../../runtime-legacy-worker-terminal-recovery-types'
import { OrcaRuntimeWithCreateMobileSessionTerminal } from './mobile-terminal-create'
import type { WorktreeStartupLaunch } from '../../../../shared/worktree/launch-types'
import type { TuiAgent } from '../../../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../../../shared/agent-session-resume'
import type { RuntimeMobileSessionCreateTerminalResult } from '../../../../shared/runtime-types'
import { randomUUID } from 'node:crypto'
import { getRuntimeDesktopSurface } from './runtime-desktop-surface'
import { getRuntimeDesktopSurface } from '../../runtime-desktop-surface'
import type { IpcMainEvent } from 'electron'
import {
MOBILE_TERMINAL_READY_FALLBACK_MS,
MOBILE_TERMINAL_SURFACE_TIMEOUT_MS,
isClientDisconnectedError
} from './orca-runtime-core'
import { rendererPublicationThrottle } from '../window/renderer-publication-throttle'
import { deterministicAgentSessionUuid } from './runtime-agent-launch-resolution'
} from '../../orca-runtime-core'
import { rendererPublicationThrottle } from '../../../window/renderer-publication-throttle'
import { deterministicAgentSessionUuid } from '../../runtime-agent-launch-resolution'
export type MobileTerminalCreateOptions = {
afterTabId?: string
targetGroupId?: string
command?: string
cwd?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
agent?: TuiAgent
agentPrompt?: string
launchConfig?: SleepingAgentLaunchConfig
launchAgent?: TuiAgent
viewMode?: 'terminal' | 'chat'
activate?: boolean
clientNavigationId?: string
clientMutationId?: string
supportsSplitGroupPlacement?: boolean
signal?: AbortSignal
}
export abstract class OrcaRuntimeWithRunCreateMobileSessionTerminal extends OrcaRuntimeWithCreateMobileSessionTerminal {
protected abstract captureReadyGraphEpoch(): number
protected abstract resolveMobileSessionTerminalCommand(
workspace: TerminalWorkspaceLaunchScope,
opts: MobileTerminalCommandOptions
): Promise<MobileTerminalCommand>
protected abstract assertStableReadyGraph(expectedGraphEpoch: number): void
protected abstract createRuntimeOwnedMobileSessionTerminal(
worktreeId: string,
activate: boolean,
afterTabId?: string,
opts?: OwnedMobileTerminalCreateOptions
): Promise<RuntimeMobileSessionCreateTerminalResult>
protected abstract ensurePtyBackedMobileSurfaceForRendererTab(
worktreeId: string,
tabId: string
): RuntimeMobileSessionCreateTerminalResult | null
protected abstract waitForMobileTerminalSurface(
worktreeId: string,
parentTabId: string,
options?: { timeoutMs?: number; requireReady?: boolean; signal?: AbortSignal }
): Promise<RuntimeMobileSessionCreateTerminalResult>
protected abstract isReadyMobileTerminalSurface(
surface: RuntimeMobileSessionCreateTerminalResult | null
): boolean
protected abstract deliverPendingStartupCommandToBareRendererPty(
worktreeId: string,
tabId: string
): void
protected abstract findMobileTerminalSurface(
worktreeId: string,
parentTabId: string,
options?: { requireReady?: boolean }
): RuntimeMobileSessionCreateTerminalResult | null
protected abstract findLiveRegisteredPtyForRendererTab(
worktreeId: string,
tabId: string
): RuntimePtyWorktreeRecord | null
protected abstract hasLiveShellForRendererTab(worktreeId: string, tabId: string): boolean
export class OrcaRuntimeWithRunCreateMobileSessionTerminal extends OrcaRuntimeWithCreateMobileSessionTerminal {
protected async runCreateMobileSessionTerminal(
worktreeSelector: string,
opts: {
afterTabId?: string
targetGroupId?: string
command?: string
cwd?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
agent?: TuiAgent
agentPrompt?: string
launchConfig?: SleepingAgentLaunchConfig
launchAgent?: TuiAgent
viewMode?: 'terminal' | 'chat'
activate?: boolean
clientNavigationId?: string
clientMutationId?: string
supportsSplitGroupPlacement?: boolean
signal?: AbortSignal
} = {}
opts: MobileTerminalCreateOptions = {}
): Promise<RuntimeMobileSessionCreateTerminalResult> {
const pairedCreate = Boolean(opts.clientNavigationId)
const graphEpoch = this.captureReadyGraphEpoch()
@@ -1,36 +1,43 @@
import { OrcaRuntimeWithRunCreateMobileSessionTerminal } from './orca-runtime-run-create-mobile-session-terminal'
import type { TerminalWorkspaceLaunchScope } from './runtime-legacy-worker-terminal-recovery-types'
import type { WorktreeStartupLaunch } from '../../shared/worktree/launch-types'
import type { TuiAgent } from '../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../shared/agent-session-resume'
import { isTuiAgentEnabled } from '../../shared/tui-agent-selection'
import { buildAgentStartupPlan } from '../../shared/tui-agent-startup'
import { resolveAgentStartupPlanInputs } from '../../shared/agent-startup-plan-inputs'
import { agentLaunchQuotingShell, type AgentLaunchRuntime } from '../../shared/agent-launch-runtime'
import { OrcaRuntimeWithRunCreateMobileSessionTerminal } from './mobile-terminal-renderer-create'
import type { TerminalWorkspaceLaunchScope } from '../../runtime-legacy-worker-terminal-recovery-types'
import type { WorktreeStartupLaunch } from '../../../../shared/worktree/launch-types'
import type { TuiAgent } from '../../../../shared/tui-agent'
import type { SleepingAgentLaunchConfig } from '../../../../shared/agent-session-resume'
import { isTuiAgentEnabled } from '../../../../shared/tui-agent-selection'
import { buildAgentStartupPlan } from '../../../../shared/tui-agent-startup'
import { resolveAgentStartupPlanInputs } from '../../../../shared/agent-startup-plan-inputs'
import {
agentLaunchQuotingShell,
type AgentLaunchRuntime
} from '../../../../shared/agent-launch-runtime'
export type MobileTerminalCommandOptions = {
command?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
agent?: TuiAgent
agentPrompt?: string
launchConfig?: SleepingAgentLaunchConfig
launchAgent?: TuiAgent
}
export type MobileTerminalCommand = {
command?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
launchConfig?: SleepingAgentLaunchConfig
launchAgent?: TuiAgent
/** What the command was quoted for; the create spawns with it. */
launchRuntime?: AgentLaunchRuntime
}
export abstract class OrcaRuntimeWithResolveMobileSessionTerminalCommand extends OrcaRuntimeWithRunCreateMobileSessionTerminal {
protected async resolveMobileSessionTerminalCommand(
workspace: TerminalWorkspaceLaunchScope,
opts: {
command?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
agent?: TuiAgent
agentPrompt?: string
launchConfig?: SleepingAgentLaunchConfig
launchAgent?: TuiAgent
}
): Promise<{
command?: string
env?: Record<string, string>
envToDelete?: string[]
startupCommandDelivery?: WorktreeStartupLaunch['startupCommandDelivery']
launchConfig?: SleepingAgentLaunchConfig
launchAgent?: TuiAgent
/** What the command was quoted for; the create spawns with it. */
launchRuntime?: AgentLaunchRuntime
}> {
opts: MobileTerminalCommandOptions
): Promise<MobileTerminalCommand> {
if (opts.command || !opts.agent) {
return {
command: opts.command,
@@ -1,21 +1,20 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithCreateAgentSession } from './orca-runtime-create-agent-session'
import type { RuntimeTerminalCreate } from '../../shared/runtime-types'
import { WORKTREE_CREATE_RESULT_TTL_MS } from './orca-runtime-core'
import { deriveRemoteRuntimeTerminalCreateHandle } from './remote-runtime-terminal-create-identity'
import { withTimeoutResult } from './runtime-async-boundaries'
import { PTY_CONTROLLER_LIST_TIMEOUT_MS } from './orca-runtime-postlude'
import { inferWorktreeIdFromPtyId } from './runtime-worktree-path-identity'
import { getRegisteredSshState } from '../ssh/ssh-target-registry'
import { OrcaRuntimeWithCreateAgentSession } from '../../orca-runtime-create-agent-session'
import type { RuntimeTerminalCreate } from '../../../../shared/runtime-types'
import { WORKTREE_CREATE_RESULT_TTL_MS } from '../../orca-runtime-core'
import { deriveRemoteRuntimeTerminalCreateHandle } from '../../remote-runtime-terminal-create-identity'
import { withTimeoutResult } from '../../runtime-async-boundaries'
import { PTY_CONTROLLER_LIST_TIMEOUT_MS } from '../../orca-runtime-postlude'
import { inferWorktreeIdFromPtyId } from '../../runtime-worktree-path-identity'
import { getRegisteredSshState } from '../../../ssh/ssh-target-registry'
import {
getConnectionExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
toSshExecutionHostId
} from '../../shared/execution-host'
import { resolveWorktreeLaunchHost } from './worktree-launch-host-repo'
import type { TuiAgent } from '../../shared/tui-agent'
} from '../../../../shared/execution-host'
import { resolveWorktreeLaunchHost } from '../../worktree-launch-host-repo'
import type { TuiAgent } from '../../../../shared/tui-agent'
export class OrcaRuntimeWithTerminalCreateDeduplication extends OrcaRuntimeWithCreateAgentSession {
export abstract class OrcaRuntimeWithTerminalCreateDeduplication extends OrcaRuntimeWithCreateAgentSession {
async dedupeTerminalCreate(
clientIdentity: string,
worktreeSelector: string | undefined,
@@ -126,7 +125,7 @@ export class OrcaRuntimeWithTerminalCreateDeduplication extends OrcaRuntimeWithC
}
}
protected getPtyExecutionHostMetadata(
getPtyExecutionHostMetadata(
ptyId: string | null
): Pick<RuntimeTerminalCreate, 'executionHostId' | 'hostPlatform' | 'incarnationId'> {
if (!ptyId) {
@@ -207,6 +206,7 @@ export class OrcaRuntimeWithTerminalCreateDeduplication extends OrcaRuntimeWithC
const key = `${repoSelector}\0${clientMutationId}`
const inflight = this.worktreeCreateByMutationId.get(key)
if (inflight) {
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: Callers must use one operation/result type per repo and mutation key.
return inflight as Promise<T>
}
const created = run()
@@ -1,14 +1,13 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithTerminalCreateDeduplication } from './orca-runtime-terminal-create-deduplication'
import * as dependencies from './orca-runtime-create-terminal-dependencies'
import { createDesktopTerminal } from './orca-runtime-create-terminal-desktop'
import { buildRuntimeAgentTeamsLaunchPlan } from './terminal/launch/agent-teams-launch-plan'
import { createIdempotentCallback } from './orca-runtime-report-pty-spawn-commit'
import { recordPtySurface, spawnSurfaceClaimSequence } from './pty-recorded-surface-topology'
import { agentLaunchTokenFor } from '../agent-launch/agent-launch-token'
import { migratedPaneRestoreHint } from './migrated-pane-restore-cwd'
import { OrcaRuntimeWithTerminalCreateDeduplication } from './terminal-create-deduplication'
import * as dependencies from '../../orca-runtime-create-terminal-dependencies'
import { createDesktopTerminal } from '../../orca-runtime-create-terminal-desktop'
import { buildRuntimeAgentTeamsLaunchPlan } from './agent-teams-launch-plan'
import { createIdempotentCallback } from '../../orca-runtime-report-pty-spawn-commit'
import { recordPtySurface, spawnSurfaceClaimSequence } from '../../pty-recorded-surface-topology'
import { agentLaunchTokenFor } from '../../../agent-launch/agent-launch-token'
import { migratedPaneRestoreHint } from '../../migrated-pane-restore-cwd'
export class OrcaRuntimeWithCreateTerminal extends OrcaRuntimeWithTerminalCreateDeduplication {
export abstract class OrcaRuntimeWithCreateTerminal extends OrcaRuntimeWithTerminalCreateDeduplication {
async createTerminal(
worktreeSelector?: string,
opts: dependencies.TerminalCreateOptions = {},
@@ -85,7 +84,7 @@ export class OrcaRuntimeWithCreateTerminal extends OrcaRuntimeWithTerminalCreate
...launchOpts.env,
...(launchToken ? { ORCA_AGENT_LAUNCH_TOKEN: launchToken } : {})
}
let agentTeamsPlan: Awaited<ReturnType<typeof dependencies.buildClaudeAgentTeamsLaunchPlan>>
let agentTeamsPlan: Awaited<ReturnType<typeof buildRuntimeAgentTeamsLaunchPlan>>['plan']
let sequencedStartupCommand: string | undefined
let effectiveLaunchConfig = launchOpts.launchConfig
try {
@@ -1,7 +1,10 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithRegisterPty } from './orca-runtime-register-pty'
import { OrcaRuntimeWithRegisterPty } from '../../orca-runtime-register-pty'
export abstract class OrcaRuntimeWithPreparePtyExecutionContext extends OrcaRuntimeWithRegisterPty {
protected abstract disposeHeadlessTerminal(ptyId: string): void
protected abstract replaceHeadlessTerminalAfterExecutionContextChange(ptyId: string): void
export class OrcaRuntimeWithPreparePtyExecutionContext extends OrcaRuntimeWithRegisterPty {
preparePtyExecutionContext(
ptyId: string,
wslDistro: string | null,
@@ -1,30 +1,40 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithSplitTerminal } from './orca-runtime-split-terminal'
import type { RuntimePtyWorktreeRecord } from './runtime-terminal-state-records'
import type { TerminalPaneSplitSource } from '../../shared/feature-education-telemetry'
import type { RuntimeTerminalSplit } from '../../shared/runtime-types'
import { makePaneKey, parsePaneKey } from '../../shared/stable-pane-id'
import { recordPtySurface, spawnSurfaceClaimSequence } from './pty-recorded-surface-topology'
import { OrcaRuntimeWithSplitTerminal } from './terminal-split'
import type { OrcaRuntimeWithResolveTerminalSplitSourceAuthority } from '../../orca-runtime-resolve-terminal-split-source-authority'
import type { RuntimePtyWorktreeRecord } from '../../runtime-terminal-state-records'
import type { TerminalPaneSplitSource } from '../../../../shared/feature-education-telemetry'
import type { RuntimeTerminalSplit } from '../../../../shared/runtime-types'
import { makePaneKey, parsePaneKey } from '../../../../shared/stable-pane-id'
import { recordPtySurface, spawnSurfaceClaimSequence } from '../../pty-recorded-surface-topology'
import { randomUUID } from 'node:crypto'
import { runtimeSplitPlacement } from './runtime-terminal-spawn-placement'
import { REJECTED_SPLIT_PTY_STOP_TIMEOUT_MS, ownerSurfacing } from './orca-runtime-core'
import type { Worktree } from '../../shared/worktree/types'
import { spawnInAdmittedPane, withdrawRuntimePane } from './runtime-pane-admission'
import { runtimeSplitPlacement } from '../../runtime-terminal-spawn-placement'
import { REJECTED_SPLIT_PTY_STOP_TIMEOUT_MS, ownerSurfacing } from '../../orca-runtime-core'
import type { Worktree } from '../../../../shared/worktree/types'
import { spawnInAdmittedPane, withdrawRuntimePane } from '../../runtime-pane-admission'
export type TerminalSplitOptions = {
direction?: 'horizontal' | 'vertical'
command?: string
env?: Record<string, string>
envToDelete?: string[]
activate?: boolean
// Why: same split as createTerminal — adopt the pane without revealing its
// workspace, for splits the user never asked to see.
surfaceOwner?: false
telemetrySource?: TerminalPaneSplitSource
}
export abstract class OrcaRuntimeWithSplitPtyBackedTerminal extends OrcaRuntimeWithSplitTerminal {
protected abstract resolveTerminalSplitSourceAuthority(
...args: Parameters<
OrcaRuntimeWithResolveTerminalSplitSourceAuthority['resolveTerminalSplitSourceAuthority']
>
): ReturnType<
OrcaRuntimeWithResolveTerminalSplitSourceAuthority['resolveTerminalSplitSourceAuthority']
>
export class OrcaRuntimeWithSplitPtyBackedTerminal extends OrcaRuntimeWithSplitTerminal {
protected async splitPtyBackedTerminal(
pty: RuntimePtyWorktreeRecord,
opts: {
direction?: 'horizontal' | 'vertical'
command?: string
env?: Record<string, string>
envToDelete?: string[]
activate?: boolean
// Why: same split as createTerminal — adopt the pane without revealing its
// workspace, for splits the user never asked to see.
surfaceOwner?: false
telemetrySource?: TerminalPaneSplitSource
} = {},
opts: TerminalSplitOptions = {},
createdWorktree?: Worktree
): Promise<RuntimeTerminalSplit> {
if (!this.ptyController?.spawn) {
@@ -57,7 +67,7 @@ export class OrcaRuntimeWithSplitPtyBackedTerminal extends OrcaRuntimeWithSplitT
const leafId = randomUUID()
const preAllocatedHandle = this.createPreAllocatedTerminalHandle()
const paneKey = makePaneKey(parentTabId, leafId)
const splitArgs = {
const splitArgs: Parameters<typeof spawnInAdmittedPane>[2] = {
cols: 120,
rows: 40,
cwd: workspace.path,
@@ -1,11 +1,24 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithStopExplicitlyClosedTabPtys } from './session-tabs/explicit-terminal-close-stops'
import type { TerminalPaneSplitSource } from '../../shared/feature-education-telemetry'
import type { RuntimeTerminalSplit } from '../../shared/runtime-types'
import type { TerminalSplitOptions } from './terminal-split-surface'
import type { RuntimePtyWorktreeRecord } from '../../runtime-terminal-state-records'
import { OrcaRuntimeWithStopExplicitlyClosedTabPtys } from '../../session-tabs/explicit-terminal-close-stops'
import type { TerminalPaneSplitSource } from '../../../../shared/feature-education-telemetry'
import type { RuntimeTerminalSplit } from '../../../../shared/runtime-types'
import { randomUUID } from 'node:crypto'
import type { Worktree } from '../../shared/worktree/types'
import type { Worktree } from '../../../../shared/worktree/types'
export abstract class OrcaRuntimeWithSplitTerminal extends OrcaRuntimeWithStopExplicitlyClosedTabPtys {
protected abstract splitPtyBackedTerminal(
pty: RuntimePtyWorktreeRecord,
opts?: TerminalSplitOptions,
createdWorktree?: Worktree
): Promise<RuntimeTerminalSplit>
protected abstract waitForLeafInTab(
tabId: string,
leafId: string,
timeoutMs?: number
): Promise<string>
export class OrcaRuntimeWithSplitTerminal extends OrcaRuntimeWithStopExplicitlyClosedTabPtys {
async splitTerminal(
handle: string,
opts: {
@@ -1,38 +1,37 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithTransitionGraphReloadToTerminalState } from './session-graph/session-graph-authority'
import type { ExecutionHostId } from '../../shared/execution-host'
import { OrcaRuntimeWithTransitionGraphReloadToTerminalState } from '../../session-graph/session-graph-authority'
import type { ExecutionHostId } from '../../../../shared/execution-host'
import {
floatingWorkspaceToWorktree,
isFloatingWorkspaceSelector
} from '../../shared/floating-workspace-worktree'
import { resolveFloatingTerminalCwd } from '../ipc/floating-workspace-directory'
import type { BrowserNetworkExecutionHost } from '../../shared/browser-client-host-protocol'
} from '../../../../shared/floating-workspace-worktree'
import { resolveFloatingTerminalCwd } from '../../../ipc/floating-workspace-directory'
import type { BrowserNetworkExecutionHost } from '../../../../shared/browser-client-host-protocol'
import {
LOCAL_EXECUTION_HOST_ID,
getWorktreeExecutionHostId,
parseExecutionHostId
} from '../../shared/execution-host'
import { resolveRuntimeBrowserNetworkExecutionHost } from './runtime-browser-network-execution-host'
import { resolveLocalProjectRuntimeForWorktreeId } from '../local-project-runtime-resolution'
import { getRegisteredSshState } from '../ssh/ssh-target-registry'
import { resolveWorktreeLaunchHost } from './worktree-launch-host-repo'
import { folderWorkspaceKey, parseWorkspaceKey } from '../../shared/workspace-scope'
import type { FolderWorkspace } from '../../shared/folder-workspace-types'
import type { ResolvedWorktree } from './runtime-worktree-path-identity'
import type { Worktree } from '../../shared/worktree/types'
import { folderWorkspaceToWorktree } from '../../shared/folder-workspace-worktree'
import type { TerminalWorkspaceLaunchScope } from './runtime-legacy-worker-terminal-recovery-types'
import { resolveTerminalStartupCwd } from '../../shared/terminal-startup-cwd'
import type { ResolvedTerminalWorkspaceLaunchTarget } from './orca-runtime-core'
import { AGENT_HOOK_RUNTIME_ENV_KEYS } from './orca-runtime-core'
import { ensureJcodeRuntimeDir } from '../../shared/jcode-runtime-dir'
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../shared/constants'
} from '../../../../shared/execution-host'
import { resolveRuntimeBrowserNetworkExecutionHost } from '../../runtime-browser-network-execution-host'
import { resolveLocalProjectRuntimeForWorktreeId } from '../../../local-project-runtime-resolution'
import { getRegisteredSshState } from '../../../ssh/ssh-target-registry'
import { resolveWorktreeLaunchHost } from '../../worktree-launch-host-repo'
import { folderWorkspaceKey, parseWorkspaceKey } from '../../../../shared/workspace-scope'
import type { FolderWorkspace } from '../../../../shared/folder-workspace-types'
import type { ResolvedWorktree } from '../../runtime-worktree-path-identity'
import type { Worktree } from '../../../../shared/worktree/types'
import { folderWorkspaceToWorktree } from '../../../../shared/folder-workspace-worktree'
import type { TerminalWorkspaceLaunchScope } from '../../runtime-legacy-worker-terminal-recovery-types'
import { resolveTerminalStartupCwd } from '../../../../shared/terminal-startup-cwd'
import type { ResolvedTerminalWorkspaceLaunchTarget } from '../../orca-runtime-core'
import { AGENT_HOOK_RUNTIME_ENV_KEYS } from '../../orca-runtime-core'
import { ensureJcodeRuntimeDir } from '../../../../shared/jcode-runtime-dir'
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../../shared/constants'
import { homedir } from 'node:os'
import { getExplicitWorktreeIdSelector } from './runtime-worktree-selection'
import { WORKTREE_ID_SEPARATOR } from '../../shared/worktree/id'
import { WorktreeIdRequiresFullPathError } from './runtime-worktree-lineage-resolution'
import { triggerTerminalSpawnPushTargetMaterialization } from './runtime-terminal-spawn-push-target-materialization'
import { resolveCreatedWorktreeTerminalTarget } from './runtime-created-worktree-terminal-target'
import { getExplicitWorktreeIdSelector } from '../../runtime-worktree-selection'
import { WORKTREE_ID_SEPARATOR } from '../../../../shared/worktree/id'
import { WorktreeIdRequiresFullPathError } from '../../runtime-worktree-lineage-resolution'
import { triggerTerminalSpawnPushTargetMaterialization } from '../../runtime-terminal-spawn-push-target-materialization'
import { resolveCreatedWorktreeTerminalTarget } from '../../runtime-created-worktree-terminal-target'
// Why: folder and floating workspaces have no worktree row, so no parent, children or lineage.
function withoutWorktreeLineage(worktree: Worktree): ResolvedWorktree {
@@ -51,7 +50,7 @@ function withoutWorktreeLineage(worktree: Worktree): ResolvedWorktree {
}
}
export class OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree extends OrcaRuntimeWithTransitionGraphReloadToTerminalState {
export abstract class OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree extends OrcaRuntimeWithTransitionGraphReloadToTerminalState {
protected resolveBrowserNetworkExecutionHostForWorktree(worktree?: {
id: string
repoId?: string
@@ -105,14 +104,14 @@ export class OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree extend
return withoutWorktreeLineage(folderWorkspaceToWorktree(folderWorkspace))
}
protected resolveWorkspaceTerminalStartupCwd(
resolveWorkspaceTerminalStartupCwd(
workspace: Pick<TerminalWorkspaceLaunchScope, 'path'>,
requestedCwd?: string | null
): string | undefined {
return resolveTerminalStartupCwd(workspace.path, requestedCwd)
}
protected async resolveTerminalWorkspaceLaunchScope(
async resolveTerminalWorkspaceLaunchScope(
selector: string,
createdWorktree?: Worktree
): Promise<TerminalWorkspaceLaunchScope> {
@@ -5,7 +5,7 @@ import type {
RuntimePtyTitleTrackerEntry
} from '../../runtime-terminal-state-records'
import type { RuntimeSyncedLeaf } from '../../../../shared/runtime-types'
import { OrcaRuntimeWithPreparePtyExecutionContext } from '../../orca-runtime-prepare-pty-execution-context'
import { OrcaRuntimeWithPreparePtyExecutionContext } from '../launch/terminal-execution-context'
import { advertisedUrlWatcher } from '../../../ports/advertised-url-watcher'
import { appendNormalizedToTailBuffer } from '../../terminal-tail-buffer'
import { normalizeTerminalChunk } from '../../terminal-ansi-normalization'
@@ -22,7 +22,6 @@ import type { TerminalTitleFactMeta } from '../../../../shared/terminal-output-s
export abstract class OrcaRuntimeWithEmitDaemonPtyTransientFact extends OrcaRuntimeWithScheduleWaitBlockedCheck {
protected abstract retirePtyAgentLaunchAuthority(ptyId: string): void
protected abstract disposeHeadlessTerminal(ptyId: string): void
/** A transient fact the daemon detected while it held scan authority —
* emitted through the same fact channel as byte-scanned facts. Arrives
@@ -251,7 +251,7 @@ export abstract class OrcaRuntimeWithResolveWorktreeRemovalTarget extends OrcaRu
return { handle, tabId: leaf.tabId, title }
}
protected async resolveAgentTerminalCreateOptions(
async resolveAgentTerminalCreateOptions(
workspace: TerminalWorkspaceLaunchScope,
opts: TerminalCreateOptions
): Promise<TerminalCreateOptions> {
@@ -1,4 +1,4 @@
import { OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree } from '../orca-runtime-resolve-browser-network-execution-host-for-worktree'
import { OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree } from '../terminal/launch/terminal-workspace-scope'
import type { ResolvedWorktree } from '../runtime-worktree-path-identity'
import { splitWorktreeIdForFilesystem, worktreeIdComparisonKey } from '../../../shared/worktree/id'
import { branchSelectorMatches, runtimePathsEqual } from '../runtime-worktree-path-identity'