mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 01:27:35 +00:00
refactor: check PTY inventory and lifecycle dispatch (#27825)
This commit is contained in:
@@ -18,11 +18,9 @@ src/main/runtime/orca-runtime-get-runtime-id.ts
|
||||
src/main/runtime/orca-runtime-get-worktree-ps.ts
|
||||
src/main/runtime/orca-runtime-has-exact-persisted-terminal-surface-identity.ts
|
||||
src/main/runtime/orca-runtime-has-live-or-persisted-serve-or-ssh-owned-pty-binding.ts
|
||||
src/main/runtime/orca-runtime-invalidate-all-handles-for-pty.ts
|
||||
src/main/runtime/orca-runtime-linear-commands.ts
|
||||
src/main/runtime/orca-runtime-list-managed-worktrees.ts
|
||||
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-preserved-branch-cleanup.ts
|
||||
@@ -30,10 +28,7 @@ src/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.ts
|
||||
src/main/runtime/orca-runtime-pty-foreground-process-reads.ts
|
||||
src/main/runtime/orca-runtime-publish-pty-backed-mobile-session-terminal.ts
|
||||
src/main/runtime/orca-runtime-reconcile-headless-mobile-session-browser-tabs.ts
|
||||
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-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
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { describe, expect, it, vi, afterEach } from 'vitest'
|
||||
import { OrcaRuntimeService } from '../orca-runtime-test-mocks.spec'
|
||||
import { TEST_WORKTREE_PATH, store } from '../orca-runtime-test-fixtures.spec'
|
||||
import { OrcaRuntimeWithRuntimeId } from '../orca-runtime-runtime-id'
|
||||
import { OrcaRuntimeWithStateFields } from '../orca-runtime-state-fields'
|
||||
import { OrchestrationDb } from '../orchestration/db/orchestration-db'
|
||||
|
||||
// `agent.launch` settles a launch as failed only when its create threw before this hook ran.
|
||||
describe('OrcaRuntimeService createTerminal spawn dispatch', () => {
|
||||
@@ -68,3 +71,335 @@ describe('OrcaRuntimeService createTerminal spawn dispatch', () => {
|
||||
expect(dispatched).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('PTY registration dispatch characterization', () => {
|
||||
type PtyRegistrationBinding = NonNullable<Parameters<OrcaRuntimeService['registerPty']>[3]>
|
||||
const TAB_ID = '11111111-1111-4111-8111-111111111111'
|
||||
const LEAF_ID = '22222222-2222-4222-8222-222222222222'
|
||||
const PTY_ID = 'pty-dispatch'
|
||||
const WORKTREE_ID = 'repo::/tmp/dispatch'
|
||||
const databases: OrchestrationDb[] = []
|
||||
|
||||
afterEach(() => {
|
||||
for (const db of databases.splice(0)) {
|
||||
db.close()
|
||||
}
|
||||
})
|
||||
|
||||
class DispatchRuntime extends OrcaRuntimeService {
|
||||
constructor() {
|
||||
super(null)
|
||||
this.ensurePtyBackedMobileSurfaceForRendererTab = () => null
|
||||
this.touchMobileSessionSnapshotsForPty = () => {}
|
||||
}
|
||||
|
||||
replaceAdmission(assertion: (ptyId: string, incarnationId?: string) => void): void {
|
||||
this.assertPtyDidNotExitBeforeRegistration = assertion
|
||||
}
|
||||
|
||||
replaceHostScope(
|
||||
resolve: () => { kind: 'local'; hostId: 'local'; toJSON(): { kind: 'local' } } | null
|
||||
): void {
|
||||
this.getOrchestrationCompatibilityHostScope = resolve
|
||||
}
|
||||
|
||||
setDatabase(db: OrchestrationDb | null): void {
|
||||
this._orchestrationDb = db
|
||||
}
|
||||
|
||||
get record() {
|
||||
return this.recordPtyWorktree
|
||||
}
|
||||
|
||||
set record(value: typeof this.recordPtyWorktree) {
|
||||
this.recordPtyWorktree = value
|
||||
}
|
||||
|
||||
get pendingCreates() {
|
||||
return this.pendingMobileTerminalCreatesByKey
|
||||
}
|
||||
|
||||
get replacementFences() {
|
||||
return this.pendingPtyHandleReplacementFences
|
||||
}
|
||||
}
|
||||
|
||||
function binding(): PtyRegistrationBinding {
|
||||
return { tabId: TAB_ID, leafId: LEAF_ID, incarnationId: 'dispatch-incarnation' }
|
||||
}
|
||||
|
||||
function register(runtime: DispatchRuntime, tab: PtyRegistrationBinding): void {
|
||||
runtime.registerPty(PTY_ID, WORKTREE_ID, null, tab)
|
||||
}
|
||||
|
||||
describe('PTY runtime dispatch', () => {
|
||||
it('constructs supported early layers and keeps lifecycle cells available to the full runtime', () => {
|
||||
// Earlier constructors already require this browser callback.
|
||||
abstract class EarlyStateRuntime extends OrcaRuntimeWithStateFields {
|
||||
protected markHeadlessBrowserSessionTabActive(): void {}
|
||||
}
|
||||
const cells: boolean[] = []
|
||||
class ConstructorRuntime extends OrcaRuntimeService {
|
||||
protected get canonicalFetchKeyCache(): ReadonlyMap<string, string> {
|
||||
cells.push(
|
||||
this.stopRequestedPtyIds instanceof Set,
|
||||
this.ptyExitListenersByPtyId instanceof Map
|
||||
)
|
||||
return super.canonicalFetchKeyCache
|
||||
}
|
||||
}
|
||||
const runtimes: unknown[] = [
|
||||
new OrcaRuntimeWithRuntimeId(),
|
||||
new ConstructorRuntime(),
|
||||
new ConstructorRuntime(null),
|
||||
Reflect.construct(EarlyStateRuntime, [null])
|
||||
]
|
||||
expect(runtimes).toHaveLength(4)
|
||||
expect(cells).toEqual([true, true, true, true])
|
||||
})
|
||||
|
||||
it('captures the admission method before reading the incarnation', () => {
|
||||
const runtime = new DispatchRuntime()
|
||||
runtime.replaceAdmission(function (this: DispatchRuntime) {
|
||||
expect(this).toBe(runtime)
|
||||
throw new Error('captured admission')
|
||||
})
|
||||
const tab = binding()
|
||||
Object.defineProperty(tab, 'incarnationId', {
|
||||
get() {
|
||||
runtime.replaceAdmission(() => {
|
||||
throw new Error('late admission')
|
||||
})
|
||||
return 'dispatch-incarnation'
|
||||
}
|
||||
})
|
||||
expect(() => register(runtime, tab)).toThrow('captured admission')
|
||||
})
|
||||
|
||||
it('captures the record method before evaluating its state object', () => {
|
||||
const runtime = new DispatchRuntime()
|
||||
let reads = 0
|
||||
runtime.record = function (this: DispatchRuntime) {
|
||||
expect(this).toBe(runtime)
|
||||
throw new Error('captured record')
|
||||
}
|
||||
const tab = binding()
|
||||
Object.defineProperty(tab, 'tabId', {
|
||||
get() {
|
||||
if (++reads === 3) {
|
||||
runtime.record = () => {
|
||||
throw new Error('late record')
|
||||
}
|
||||
}
|
||||
return TAB_ID
|
||||
}
|
||||
})
|
||||
expect(() => register(runtime, tab)).toThrow('captured record')
|
||||
})
|
||||
|
||||
it('skips database payload serialization when no database exists', () => {
|
||||
const runtime = new DispatchRuntime()
|
||||
let serializations = 0
|
||||
runtime.replaceHostScope(() => ({
|
||||
kind: 'local',
|
||||
hostId: 'local',
|
||||
toJSON() {
|
||||
serializations++
|
||||
return { kind: 'local' }
|
||||
}
|
||||
}))
|
||||
register(runtime, binding())
|
||||
expect(serializations).toBe(0)
|
||||
})
|
||||
|
||||
it('skips a throwing database payload when no database exists', () => {
|
||||
const runtime = new DispatchRuntime()
|
||||
runtime.replaceHostScope(() => ({
|
||||
kind: 'local',
|
||||
hostId: 'local',
|
||||
toJSON() {
|
||||
throw new Error('absent database payload')
|
||||
}
|
||||
}))
|
||||
expect(() => register(runtime, binding())).not.toThrow()
|
||||
})
|
||||
|
||||
it('keeps the database method and receiver captured before its payload', () => {
|
||||
const runtime = new DispatchRuntime()
|
||||
const captured = new OrchestrationDb(':memory:')
|
||||
const replacement = new OrchestrationDb(':memory:')
|
||||
databases.push(captured, replacement)
|
||||
const calls: string[] = []
|
||||
captured.retainReplacedWorkerTerminalResources = function () {
|
||||
expect(this).toBe(captured)
|
||||
calls.push('captured database')
|
||||
return 0
|
||||
}
|
||||
replacement.retainReplacedWorkerTerminalResources = () => calls.push('late database')
|
||||
runtime.setDatabase(captured)
|
||||
runtime.replaceHostScope(() => ({
|
||||
kind: 'local',
|
||||
hostId: 'local',
|
||||
toJSON() {
|
||||
runtime.setDatabase(replacement)
|
||||
return { kind: 'local' }
|
||||
}
|
||||
}))
|
||||
register(runtime, binding())
|
||||
expect(calls).toEqual(['captured database'])
|
||||
})
|
||||
|
||||
it('captures the canonical map method before a binding getter changes it', () => {
|
||||
const runtime = new DispatchRuntime()
|
||||
let reads = 0
|
||||
const calls: string[] = []
|
||||
const map = runtime.pendingCreates
|
||||
map.has = () => {
|
||||
calls.push('captured map')
|
||||
return true
|
||||
}
|
||||
const tab = binding()
|
||||
Object.defineProperty(tab, 'tabId', {
|
||||
get() {
|
||||
if (++reads === 3) {
|
||||
map.has = () => {
|
||||
calls.push('late map')
|
||||
return false
|
||||
}
|
||||
}
|
||||
return TAB_ID
|
||||
}
|
||||
})
|
||||
runtime.replaceHostScope(() => null)
|
||||
register(runtime, tab)
|
||||
expect(calls).toEqual(['captured map'])
|
||||
})
|
||||
|
||||
it('completes the captured replacement fence without another map lookup', () => {
|
||||
const runtime = new DispatchRuntime()
|
||||
let recorded = false
|
||||
let captured = false
|
||||
let reads = 0
|
||||
const map = runtime.replacementFences
|
||||
const originalGet = map.get.bind(map)
|
||||
const first = {
|
||||
incarnationId: 'first',
|
||||
staleHandles: new Set<string>(),
|
||||
pendingRegistration: false
|
||||
}
|
||||
const replacement = {
|
||||
incarnationId: 'second',
|
||||
staleHandles: new Set<string>(),
|
||||
pendingRegistration: true
|
||||
}
|
||||
map.set(PTY_ID, first)
|
||||
map.get = function (id) {
|
||||
reads++
|
||||
const value = originalGet(id)
|
||||
if (recorded) {
|
||||
captured = true
|
||||
}
|
||||
return value
|
||||
}
|
||||
const record = runtime.record
|
||||
runtime.record = function (...args) {
|
||||
const value = record.apply(runtime, args)
|
||||
recorded = true
|
||||
return value
|
||||
}
|
||||
runtime.replaceHostScope(() => null)
|
||||
const tab = binding()
|
||||
Object.defineProperty(tab, 'incarnationId', {
|
||||
get() {
|
||||
if (captured) {
|
||||
map.set(PTY_ID, replacement)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
})
|
||||
register(runtime, tab)
|
||||
expect(reads).toBe(2)
|
||||
expect(replacement.pendingRegistration).toBe(true)
|
||||
})
|
||||
|
||||
it('initializes original lifecycle state before the base constructor getter', () => {
|
||||
const observations: boolean[] = []
|
||||
class ConstructorRuntime extends OrcaRuntimeService {
|
||||
protected get canonicalFetchKeyCache(): ReadonlyMap<string, string> {
|
||||
observations.push(
|
||||
this.earlyExitedPtyIncarnations instanceof Map,
|
||||
this.pendingPtyRegistrationIncarnations instanceof Map,
|
||||
this.ptyLivenessVerdictByPtyId instanceof Map,
|
||||
this.ptyExitListenersByPtyId instanceof Map,
|
||||
this.stopRequestedPtyIds instanceof Set,
|
||||
this.ptyControllerInventoryGenerationByProvider instanceof Map,
|
||||
this.ptyLivenessObservationSequence === 0,
|
||||
this.ptyControllerInventorySequence === 0,
|
||||
this.ptyControllerAggregateInventoryGeneration === 0
|
||||
)
|
||||
this.markPtyStopRequested(PTY_ID)
|
||||
expect(this.isPtyStopRequested(PTY_ID)).toBe(true)
|
||||
return new Map()
|
||||
}
|
||||
}
|
||||
expect(() => new ConstructorRuntime(null)).not.toThrow()
|
||||
expect(observations).toEqual(Array<boolean>(9).fill(true))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('PTY inventory construction characterization', () => {
|
||||
const PTY_ID = 'pty-constructor-probe'
|
||||
|
||||
describe('PTY methods during runtime construction', () => {
|
||||
it('keeps registration fences and liveness on the original canonical state', async () => {
|
||||
const pending: Promise<unknown>[] = []
|
||||
let seamCalls = 0
|
||||
class ConstructorRuntime extends OrcaRuntimeService {
|
||||
protected get canonicalFetchKeyCache(): ReadonlyMap<string, string> {
|
||||
seamCalls++
|
||||
this.beginPtyRegistration(PTY_ID, 'incarnation')
|
||||
expect(this.pendingPtyRegistrationIncarnations.get(PTY_ID)).toBe('incarnation')
|
||||
this.cancelPendingPtyRegistration(PTY_ID, 'incarnation')
|
||||
expect(this.pendingPtyRegistrationIncarnations.has(PTY_ID)).toBe(false)
|
||||
this.assertPtyRegistrationAllowed(PTY_ID, 'incarnation')
|
||||
this.releaseRejectedPtyRegistrationFence(PTY_ID, 'incarnation')
|
||||
this.acceptPtyIncarnationForExit(PTY_ID, 'incarnation')
|
||||
this.markPtyStopRequested(PTY_ID)
|
||||
expect(this.isPtyStopRequested(PTY_ID)).toBe(true)
|
||||
this.markPtyLivenessLive(PTY_ID)
|
||||
expect(this.getPtyLivenessVerdict(PTY_ID)).toEqual({ status: 'live', ptyIds: [PTY_ID] })
|
||||
this.markPtyLivenessUnverifiable(PTY_ID, 'host unavailable')
|
||||
expect(this.getPtyLivenessVerdict(PTY_ID)).toEqual({
|
||||
status: 'unverifiable',
|
||||
reason: 'host unavailable'
|
||||
})
|
||||
this.forgetPtyLivenessVerdict(PTY_ID)
|
||||
expect(this.getPtyLivenessVerdict(PTY_ID)).toBeNull()
|
||||
expect(this.getTerminalPtyIdForHandle('missing')).toBeNull()
|
||||
expect(this.getAgentProviderSessionRows()).toEqual([])
|
||||
expect(this.getAgentStatusRowsForPane('missing')).toEqual([])
|
||||
pending.push(
|
||||
this.confirmTerminalShellAlone(PTY_ID).then((value) => expect(value).toBe(false))
|
||||
)
|
||||
pending.push(
|
||||
this.refreshPtyWorktreeRecordsFromController([]).then((value) =>
|
||||
expect(value).toBeNull()
|
||||
)
|
||||
)
|
||||
pending.push(
|
||||
this.refreshPtyWorktreeRecordsWithControllerInventory([]).then((value) =>
|
||||
expect(value).toBeNull()
|
||||
)
|
||||
)
|
||||
this.invalidatePtyControllerInventoryForLifecycle(PTY_ID)
|
||||
expect(this.ptyControllerInventorySequence).toBe(1)
|
||||
return super.canonicalFetchKeyCache
|
||||
}
|
||||
}
|
||||
expect(() => new ConstructorRuntime(null)).not.toThrow()
|
||||
expect(seamCalls).toBe(1)
|
||||
await Promise.all(pending)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OrcaRuntimeWithRegisterPty } from '../../orca-runtime-register-pty'
|
||||
import { OrcaRuntimeWithRegisterPty } from '../lifecycle/pty-registration'
|
||||
|
||||
export abstract class OrcaRuntimeWithPreparePtyExecutionContext extends OrcaRuntimeWithRegisterPty {
|
||||
protected abstract disposeHeadlessTerminal(ptyId: string): void
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OrcaRuntimeWithOnPtyExit } from '../../orca-runtime-on-pty-exit'
|
||||
import { OrcaRuntimeWithOnPtyExit } from '../lifecycle/pty-exit-lifecycle'
|
||||
import type { PtyLivenessVerdict } from '../../../../shared/pty-liveness-verdict'
|
||||
import type { DriverState } from '../../orca-runtime-core'
|
||||
import type { TerminalInputKind } from '../../../../shared/terminal-input-kind'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory } from '../../orca-runtime-refresh-pty-worktree-records-with-controller-inventory'
|
||||
import { OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory } from './pty-controller-inventory-refresh'
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../../shared/constants'
|
||||
import { indexFloatingSnapshotPtyBindings } from '../../floating-snapshot-pty-bindings'
|
||||
import type {
|
||||
|
||||
+18
-19
@@ -1,39 +1,38 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithRefreshPtyWorktreeRecordsFromController } from './orca-runtime-refresh-pty-worktree-records-from-controller'
|
||||
import type { ResolvedWorktree } from './runtime-worktree-path-identity'
|
||||
import type * as PtyControllerContract from './runtime-pty-controller-contract'
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../shared/constants'
|
||||
import { OrcaRuntimeWithRefreshPtyWorktreeRecordsFromController } from './pty-worktree-refresh'
|
||||
import type { ResolvedWorktree } from '../../runtime-worktree-path-identity'
|
||||
import type * as PtyControllerContract from '../../runtime-pty-controller-contract'
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../../shared/constants'
|
||||
import {
|
||||
type ExecutionHostId,
|
||||
getConnectionExecutionHostId,
|
||||
LOCAL_EXECUTION_HOST_ID,
|
||||
parseExecutionHostId
|
||||
} from '../../shared/execution-host'
|
||||
} from '../../../../shared/execution-host'
|
||||
import {
|
||||
PTY_CONTROLLER_LIST_PROVIDER_MARGIN_MS,
|
||||
PTY_CONTROLLER_LIST_TIMEOUT_MS
|
||||
} from './orca-runtime-postlude'
|
||||
import type { ExecutionHostId } from '../../shared/execution-host'
|
||||
import { pruneOldestMapEntry } from './prune-oldest-map-entry'
|
||||
import { withTimeoutResult } from './runtime-async-boundaries'
|
||||
import { getPtyExecutionHost } from '../../shared/terminal-execution-host'
|
||||
} from '../../orca-runtime-postlude'
|
||||
import { pruneOldestMapEntry } from '../../prune-oldest-map-entry'
|
||||
import { withTimeoutResult } from '../../runtime-async-boundaries'
|
||||
import { getPtyExecutionHost } from '../../../../shared/terminal-execution-host'
|
||||
import {
|
||||
createIncrementalResolvedWorktreeLookup,
|
||||
findResolvedWorktreeIdForPath,
|
||||
inferWorktreeIdFromPtyId,
|
||||
runtimeWorktreeIdsEqual
|
||||
} from './runtime-worktree-path-identity'
|
||||
} from '../../runtime-worktree-path-identity'
|
||||
import {
|
||||
indexPersistedPtySurfaceBindings,
|
||||
indexPersistedPtyWorktreeBindings,
|
||||
type PersistedPtyBindingIndexes
|
||||
} from './runtime-worktree-binding-index'
|
||||
import { parseAppSshPtyId } from '../../shared/ssh-pty-id'
|
||||
import { indexFloatingSnapshotPtyBindings } from './floating-snapshot-pty-bindings'
|
||||
import { NO_OBSERVING_PROVIDER_REASON } from '../../shared/pty-liveness-verdict'
|
||||
import { buildControllerTerminalIdentities } from './orca-runtime-build-controller-terminal-identities'
|
||||
import { retireOrchestrationAuthorityAbsentFromInventory } from './runtime-restored-orchestration-authority-sweep'
|
||||
} from '../../runtime-worktree-binding-index'
|
||||
import { parseAppSshPtyId } from '../../../../shared/ssh-pty-id'
|
||||
import { indexFloatingSnapshotPtyBindings } from '../../floating-snapshot-pty-bindings'
|
||||
import { NO_OBSERVING_PROVIDER_REASON } from '../../../../shared/pty-liveness-verdict'
|
||||
import { buildControllerTerminalIdentities } from '../../orca-runtime-build-controller-terminal-identities'
|
||||
import { retireOrchestrationAuthorityAbsentFromInventory } from '../../runtime-restored-orchestration-authority-sweep'
|
||||
|
||||
export class OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory extends OrcaRuntimeWithRefreshPtyWorktreeRecordsFromController {
|
||||
export abstract class OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory extends OrcaRuntimeWithRefreshPtyWorktreeRecordsFromController {
|
||||
protected async refreshPtyWorktreeRecordsWithControllerInventory(
|
||||
resolvedWorktrees: ResolvedWorktree[],
|
||||
targetWorktreeId: string | null = null,
|
||||
+33
-10
@@ -1,17 +1,40 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithOnClientDisconnected } from './terminal/layout/terminal-client-disconnect'
|
||||
import type { PtyIncarnationId } from '../../shared/pty-incarnation'
|
||||
import type { TerminalExitCause } from '../../shared/terminal-exit-cause'
|
||||
import { OrcaRuntimeWithOnClientDisconnected } from '../layout/terminal-client-disconnect'
|
||||
import type { PtyIncarnationId } from '../../../../shared/pty-incarnation'
|
||||
import type { TerminalExitCause } from '../../../../shared/terminal-exit-cause'
|
||||
import {
|
||||
OPERATOR_CLOSE_EXIT_CAUSE,
|
||||
resolveUnreportedExitCause
|
||||
} from '../../shared/terminal-exit-cause'
|
||||
import { SSH_EXIT_UNCONFIRMED_REASON } from '../../shared/pty-liveness-verdict'
|
||||
import type { RetiredTerminalSurface } from './mobile-session-terminal-retirement'
|
||||
import { parsePaneKey } from '../../shared/stable-pane-id'
|
||||
import { advertisedUrlWatcher } from '../ports/advertised-url-watcher'
|
||||
} from '../../../../shared/terminal-exit-cause'
|
||||
import { SSH_EXIT_UNCONFIRMED_REASON } from '../../../../shared/pty-liveness-verdict'
|
||||
import type { RetiredTerminalSurface } from '../../mobile-session-terminal-retirement'
|
||||
import { parsePaneKey } from '../../../../shared/stable-pane-id'
|
||||
import { advertisedUrlWatcher } from '../../../ports/advertised-url-watcher'
|
||||
import type { PtyLivenessVerdict } from '../../../../shared/pty-liveness-verdict'
|
||||
import type {
|
||||
RuntimePtyWorktreeRecord,
|
||||
RuntimeLeafRecord
|
||||
} from '../../runtime-terminal-state-records'
|
||||
|
||||
export abstract class OrcaRuntimeWithOnPtyExit extends OrcaRuntimeWithOnClientDisconnected {
|
||||
protected abstract pruneDisconnectedPtyRecords(): void
|
||||
|
||||
protected abstract failActiveDispatchOnExit(
|
||||
handle: string,
|
||||
paneKey: string | null,
|
||||
exitCode: number,
|
||||
cause: TerminalExitCause
|
||||
): void
|
||||
|
||||
protected abstract resolveExitWaiters(leaf: RuntimeLeafRecord): void
|
||||
|
||||
protected abstract pruneDisconnectedPtyTranscript(pty: RuntimePtyWorktreeRecord): void
|
||||
|
||||
protected abstract resolvePtyExitWaiters(pty: RuntimePtyWorktreeRecord, ptyId: string): void
|
||||
|
||||
protected abstract cancelPendingDriverMutations(ptyId: string): void
|
||||
|
||||
protected abstract rememberPtyLivenessVerdict(ptyId: string, verdict: PtyLivenessVerdict): void
|
||||
|
||||
export class OrcaRuntimeWithOnPtyExit extends OrcaRuntimeWithOnClientDisconnected {
|
||||
onPtyExit(
|
||||
ptyId: string,
|
||||
exitCode: number,
|
||||
+13
-6
@@ -1,10 +1,17 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithResolveKnownWorkspaceFileTarget } from './orca-runtime-resolve-known-workspace-file-target'
|
||||
import type { PtyIncarnationId } from '../../shared/pty-incarnation'
|
||||
import { getPtyExecutionHost } from '../../shared/terminal-execution-host'
|
||||
import { getConnectionExecutionHostId, parseExecutionHostId } from '../../shared/execution-host'
|
||||
import { OrcaRuntimeWithResolveKnownWorkspaceFileTarget } from '../../orca-runtime-resolve-known-workspace-file-target'
|
||||
import type { PtyIncarnationId } from '../../../../shared/pty-incarnation'
|
||||
import { getPtyExecutionHost } from '../../../../shared/terminal-execution-host'
|
||||
import {
|
||||
getConnectionExecutionHostId,
|
||||
parseExecutionHostId
|
||||
} from '../../../../shared/execution-host'
|
||||
import type { RuntimePtyWorktreeRecord } from '../../runtime-terminal-state-records'
|
||||
|
||||
export abstract class OrcaRuntimeWithInvalidateAllHandlesForPty extends OrcaRuntimeWithResolveKnownWorkspaceFileTarget {
|
||||
protected abstract getOrCreatePtyWorktreeRecord(ptyId: string): RuntimePtyWorktreeRecord | null
|
||||
|
||||
protected abstract rejectWaitersForHandle(handle: string, code: string): void
|
||||
|
||||
export class OrcaRuntimeWithInvalidateAllHandlesForPty extends OrcaRuntimeWithResolveKnownWorkspaceFileTarget {
|
||||
protected invalidateAllHandlesForPty(ptyId: string, preserveHandle?: string): Set<string> {
|
||||
const incarnationHandle = this.handleByPtyIncarnation.get(ptyId)?.handle
|
||||
const preallocatedHandle = this.handleByPtyId.get(ptyId)
|
||||
+20
-9
@@ -1,13 +1,24 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithInvalidateAllHandlesForPty } from './orca-runtime-invalidate-all-handles-for-pty'
|
||||
import type { PtyIncarnationId } from '../../shared/pty-incarnation'
|
||||
import type { TuiAgent } from '../../shared/tui-agent'
|
||||
import { isValidTerminalTabId } from '../../shared/terminal-tab-id'
|
||||
import { isTerminalLeafId, makePaneKey } from '../../shared/stable-pane-id'
|
||||
import { isTuiAgent } from '../../shared/tui-agent-config'
|
||||
import { spawnSurfaceClaimSequence } from './pty-recorded-surface-topology'
|
||||
import { OrcaRuntimeWithInvalidateAllHandlesForPty } from './pty-handle-invalidation'
|
||||
import type { PtyIncarnationId } from '../../../../shared/pty-incarnation'
|
||||
import type { TuiAgent } from '../../../../shared/tui-agent'
|
||||
import { isValidTerminalTabId } from '../../../../shared/terminal-tab-id'
|
||||
import { isTerminalLeafId, makePaneKey } from '../../../../shared/stable-pane-id'
|
||||
import { isTuiAgent } from '../../../../shared/tui-agent-config'
|
||||
import { spawnSurfaceClaimSequence } from '../../pty-recorded-surface-topology'
|
||||
import type { RuntimePtyWorktreeRecord } from '../../runtime-terminal-state-records'
|
||||
import type { OrchestrationCompatibilityTerminalAuthority } from '../../runtime-terminal-contracts'
|
||||
import type { RuntimeMobileSessionCreateTerminalResult } from '../../../../shared/runtime-session-contracts'
|
||||
|
||||
export abstract class OrcaRuntimeWithRegisterPty extends OrcaRuntimeWithInvalidateAllHandlesForPty {
|
||||
protected abstract ensurePtyBackedMobileSurfaceForRendererTab(
|
||||
worktreeId: string,
|
||||
tabId: string
|
||||
): RuntimeMobileSessionCreateTerminalResult | null
|
||||
|
||||
protected abstract getOrchestrationCompatibilityHostScope(
|
||||
pty: RuntimePtyWorktreeRecord
|
||||
): OrchestrationCompatibilityTerminalAuthority['hostScope'] | null
|
||||
|
||||
export class OrcaRuntimeWithRegisterPty extends OrcaRuntimeWithInvalidateAllHandlesForPty {
|
||||
registerPty(
|
||||
ptyId: string,
|
||||
worktreeId: string,
|
||||
+5
-4
@@ -1,8 +1,9 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithRecordPtyWorktree } from './terminal/identity/pty-worktree-record'
|
||||
import type { ResolvedWorktree } from './runtime-worktree-path-identity'
|
||||
import { OrcaRuntimeWithRecordPtyWorktree } from '../identity/pty-worktree-record'
|
||||
import type { ResolvedWorktree } from '../../runtime-worktree-path-identity'
|
||||
|
||||
export abstract class OrcaRuntimeWithRefreshPtyWorktreeRecordsFromController extends OrcaRuntimeWithRecordPtyWorktree {
|
||||
protected abstract refreshFloatingWorkspacePtyLiveness(): Set<string> | null
|
||||
|
||||
export class OrcaRuntimeWithRefreshPtyWorktreeRecordsFromController extends OrcaRuntimeWithRecordPtyWorktree {
|
||||
/** Synchronizes PTY tracking records with running daemon sessions, querying their foreground agent states. */
|
||||
protected async refreshPtyWorktreeRecordsFromController(
|
||||
resolvedWorktrees: ResolvedWorktree[],
|
||||
Reference in New Issue
Block a user