mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
refactor(runtime): check session graphs and tab lifecycle (#27694)
This commit is contained in:
@@ -54,12 +54,12 @@
|
||||
3 src/main/runtime/mobile-session-layout-projection.ts
|
||||
2 src/main/runtime/orca-runtime-adopt-terminal-orphans-from-inventory.ts
|
||||
2 src/main/runtime/orca-runtime-apply-mobile-session-tab-navigation.ts
|
||||
2 src/main/runtime/orca-runtime-attach-window.ts
|
||||
2 src/main/runtime/session-graph/session-graph-promotion.ts
|
||||
2 src/main/runtime/orca-runtime-build-headless-mobile-session-browser-tabs.ts
|
||||
1 src/main/runtime/orca-runtime-close-structured-agent-session-tab.ts
|
||||
1 src/main/runtime/session-tabs/structured-session-tab-close.ts
|
||||
1 src/main/runtime/orca-runtime-get-runtime-id.ts
|
||||
2 src/main/runtime/orca-runtime-persist-headless-terminal-title.ts
|
||||
1 src/main/runtime/orca-runtime-persist-terminal-surface-retirements.ts
|
||||
1 src/main/runtime/session-tabs/terminal-surface-retirements.ts
|
||||
1 src/main/runtime/orca-runtime-pty-foreground-process-reads.ts
|
||||
3 src/main/runtime/orca-runtime-stop-terminals-for-worktree.ts
|
||||
1 src/main/runtime/orca-runtime-terminal-drivers.ts
|
||||
|
||||
@@ -37,7 +37,10 @@ const STACK_WRITERS = [
|
||||
'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/orca-runtime-sync-window-graph.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',
|
||||
'src/main/runtime/session-tabs/mobile-session-preservation.ts',
|
||||
'src/main/runtime/mobile-session-layout-projection.ts',
|
||||
'src/main/runtime/headless-runtime-graph.ts',
|
||||
'src/main/persistence/loading-store/session-host-partitions.ts',
|
||||
|
||||
@@ -38,6 +38,10 @@ const LAYOUT_ORACLE_PREFIXES = [
|
||||
'src/main/runtime/terminal-surface-close.ts',
|
||||
'src/main/runtime/terminal/output/terminal-derived-agent-facts.ts',
|
||||
'src/main/runtime/terminal/output/terminal-output-generation.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',
|
||||
'src/main/runtime/session-tabs/mobile-session-preservation.ts',
|
||||
'src/renderer/src/components/terminal/terminal-tab-actions.ts',
|
||||
'src/renderer/src/components/tab-bar/web-runtime-tab-move-mirror.ts',
|
||||
'src/shared/rpc-contract/workspace-layout-params.ts',
|
||||
|
||||
@@ -5,13 +5,9 @@
|
||||
# Regenerate/prune: pnpm check:ts-nocheck-ratchet --prune (removes stale entries only)
|
||||
src/main/runtime/orca-runtime-adopt-terminal-orphans-from-inventory.ts
|
||||
src/main/runtime/orca-runtime-apply-mobile-session-tab-navigation.ts
|
||||
src/main/runtime/orca-runtime-attach-window.ts
|
||||
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-headless-mobile-terminal-tab.ts
|
||||
src/main/runtime/orca-runtime-close-mobile-session-tab.ts
|
||||
src/main/runtime/orca-runtime-close-structured-agent-session-tab.ts
|
||||
src/main/runtime/orca-runtime-collect-mobile-visible-graph-changed-worktrees.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
|
||||
@@ -26,29 +22,23 @@ src/main/runtime/orca-runtime-focus-terminal.ts
|
||||
src/main/runtime/orca-runtime-get-agent-session-execution-namespace.ts
|
||||
src/main/runtime/orca-runtime-get-pty-record-for-pane-key.ts
|
||||
src/main/runtime/orca-runtime-get-runtime-id.ts
|
||||
src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts
|
||||
src/main/runtime/orca-runtime-get-worktree-ps.ts
|
||||
src/main/runtime/orca-runtime-get-worktree-terminal-provisioning-host.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-has-terminals-for-worktree.ts
|
||||
src/main/runtime/orca-runtime-hydrate-headless-mobile-session-tabs-from-workspace-session.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-merge-preserved-headless-mobile-session-tabs.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-persist-terminal-surface-retirements.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
|
||||
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-floating-workspace-pty-liveness.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
|
||||
@@ -57,8 +47,6 @@ src/main/runtime/orca-runtime-resolve-browser-network-execution-host-for-worktre
|
||||
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-restore-live-paired-renderer-session-owned-mobile-terminals.ts
|
||||
src/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.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
|
||||
@@ -68,16 +56,11 @@ 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-explicitly-closed-tab-ptys.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-stored-mobile-snapshot-has-stale-preserved-tab.ts
|
||||
src/main/runtime/orca-runtime-sync-mobile-session-tabs.ts
|
||||
src/main/runtime/orca-runtime-sync-window-graph.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-transition-graph-reload-to-terminal-state.ts
|
||||
src/main/runtime/orca-runtime-verify-orchestration-compatibility-caller.ts
|
||||
src/main/runtime/orca-runtime-wait-for-leaf-pty-id.ts
|
||||
src/main/runtime/orca-runtime-wait-for-mobile-terminal-surface.ts
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import { AGENT_TRUST_KEYED_BY_START_FOLDER } from './execution-host-workspace-trust'
|
||||
|
||||
type AgentWorkspaceTrustSetting =
|
||||
| Pick<GlobalSettings, 'agentWorkspaceTrustEnabled'>
|
||||
| Partial<Pick<GlobalSettings, 'agentWorkspaceTrustEnabled'>>
|
||||
| null
|
||||
| undefined
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host'
|
||||
import type { TerminalPaneLayoutNode } from '../../../shared/terminal-tab-types'
|
||||
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
|
||||
import { TEST_LEAF_1, TEST_LEAF_2 } from '../../persistence-session-fixtures'
|
||||
import type { OrcaRuntimeWithCloseHeadlessMobileTerminalTab } from '../../runtime/orca-runtime-close-headless-mobile-terminal-tab'
|
||||
import type { OrcaRuntimeWithCloseHeadlessMobileTerminalTab } from '../../runtime/session-tabs/headless-terminal-tab-close'
|
||||
import { OrcaRuntimeService } from '../../runtime/orca-runtime'
|
||||
import type { Store } from '../loading-store/store'
|
||||
import { closeLeafOrTab } from './terminal-topology-commit'
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithNotifySshStateChanged } from './orca-runtime-notify-ssh-state-changed'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../shared/runtime-types'
|
||||
import type { ExecutionHostId } from '../../shared/execution-host'
|
||||
import type { WorkspaceSessionState } from '../../shared/workspace-session-state-types'
|
||||
import type { RuntimePtyWorktreeRecord } from './runtime-terminal-state-records'
|
||||
|
||||
export class OrcaRuntimeWithAttachWindow extends OrcaRuntimeWithNotifySshStateChanged {
|
||||
attachWindow(windowId: number): void {
|
||||
if (this.authoritativeWindowId === HEADLESS_RUNTIME_WINDOW_ID) {
|
||||
if (
|
||||
this.pendingHeadlessPromotionWindowId !== null &&
|
||||
windowId !== this.pendingHeadlessPromotionWindowId
|
||||
) {
|
||||
return
|
||||
}
|
||||
// Why: promotion is a renderer reload of the same graph owner, not a new
|
||||
// runtime; stale handles must transition before the real window publishes.
|
||||
this.persistWindowlessPtyBindingsForDesktopAttach()
|
||||
this.pendingHeadlessPromotionWindowId = windowId
|
||||
this.authoritativeWindowId = windowId
|
||||
this.beginGraphReload(windowId)
|
||||
return
|
||||
}
|
||||
if (this.authoritativeWindowId === null) {
|
||||
// Why: a promoted serve can close and later reopen its window while new
|
||||
// background PTYs keep arriving; every windowless gap needs this handoff.
|
||||
this.persistWindowlessPtyBindingsForDesktopAttach()
|
||||
this.authoritativeWindowId = windowId
|
||||
}
|
||||
}
|
||||
|
||||
protected persistWindowlessPtyBindingsForDesktopAttach(): void {
|
||||
if (!this.store?.getWorkspaceSession || !this.store.setWorkspaceSession) {
|
||||
return
|
||||
}
|
||||
const partitions = new Map<
|
||||
ExecutionHostId,
|
||||
{ session: WorkspaceSessionState; ptys: RuntimePtyWorktreeRecord[] }
|
||||
>()
|
||||
for (const pty of this.ptysById.values()) {
|
||||
if (!pty.connected || !pty.tabId) {
|
||||
continue
|
||||
}
|
||||
const hostId = this.getWorkspaceSessionHostIdForWorktree(pty.worktreeId)
|
||||
const session = this.store.getWorkspaceSession(hostId)
|
||||
const tab = session.tabsByWorktree[pty.worktreeId]?.find(
|
||||
(candidate) => candidate.id === pty.tabId
|
||||
)
|
||||
if (!tab) {
|
||||
continue
|
||||
}
|
||||
const layoutPtyIds = Object.values(
|
||||
session.terminalLayoutsByTabId[pty.tabId]?.ptyIdsByLeafId ?? {}
|
||||
)
|
||||
if (tab.ptyId !== pty.ptyId && !layoutPtyIds.includes(pty.ptyId)) {
|
||||
continue
|
||||
}
|
||||
const partition = partitions.get(hostId) ?? { session, ptys: [] }
|
||||
partition.ptys.push(pty)
|
||||
partitions.set(hostId, partition)
|
||||
}
|
||||
|
||||
for (const [hostId, { session, ptys }] of partitions) {
|
||||
// Why: windowless SSH PTYs must be handed to the desktop through their SSH partition, never the local session.
|
||||
const activeWorktreeIdsOnShutdown = [
|
||||
...new Set([
|
||||
...(session.activeWorktreeIdsOnShutdown ?? []),
|
||||
...ptys.map((pty) => pty.worktreeId)
|
||||
])
|
||||
]
|
||||
const activeConnectionIdsAtShutdown = [
|
||||
...new Set([
|
||||
...(session.activeConnectionIdsAtShutdown ?? []),
|
||||
...ptys
|
||||
.map((pty) => pty.connectionId)
|
||||
.filter((connectionId): connectionId is string => connectionId !== null)
|
||||
])
|
||||
]
|
||||
const remoteSessionIdsByTabId = { ...session.remoteSessionIdsByTabId }
|
||||
for (const pty of ptys) {
|
||||
if (pty.connectionId && pty.tabId) {
|
||||
remoteSessionIdsByTabId[pty.tabId] = pty.ptyId
|
||||
}
|
||||
}
|
||||
|
||||
this.store.setWorkspaceSession(
|
||||
{
|
||||
...session,
|
||||
activeWorktreeIdsOnShutdown,
|
||||
...(activeConnectionIdsAtShutdown.length > 0 ? { activeConnectionIdsAtShutdown } : {}),
|
||||
...(Object.keys(remoteSessionIdsByTabId).length > 0 ? { remoteSessionIdsByTabId } : {})
|
||||
},
|
||||
hostId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithPersistTerminalSurfaceRetirements } from './orca-runtime-persist-terminal-surface-retirements'
|
||||
import { OrcaRuntimeWithPersistTerminalSurfaceRetirements } from './session-tabs/terminal-surface-retirements'
|
||||
import type {
|
||||
RuntimeMobileSessionBrowserTab,
|
||||
RuntimeMobileSessionTabsResult,
|
||||
|
||||
@@ -33,7 +33,7 @@ import type { ResolvedWorktree } from './runtime-worktree-path-identity'
|
||||
import type { Repo } from '../../shared/repo-types'
|
||||
|
||||
export abstract class OrcaRuntimeWithFileCommands extends OrcaRuntimeWithPreservedBranchCleanup {
|
||||
protected abstract requireStore(): RuntimeStore
|
||||
abstract requireStore(): RuntimeStore
|
||||
|
||||
protected abstract resolveWorktreeSelector(selector: string): Promise<ResolvedWorktree>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce } from './orca-runtime-restore-structured-agent-session-tabs-once'
|
||||
import { OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce } from './session-tabs/structured-session-tab-restoration'
|
||||
import { DEFAULT_WORKTREE_LIST_LIMIT } from './orca-runtime-postlude'
|
||||
import type { RuntimeWorktreeListResult } from '../../shared/runtime-types'
|
||||
import type { DetectedWorktreeListResult, Worktree } from '../../shared/worktree/types'
|
||||
|
||||
@@ -194,7 +194,7 @@ export abstract class OrcaRuntimeWithPersistHeadlessTerminalTitle extends Runtim
|
||||
// Why: same defect as `resolveRuntimeGitTarget` above, in ~30 filesystem dispatches. `getRepo(id)`
|
||||
// is host-blind and never read `worktree.hostId`, and the `connectionId` it returned spelled
|
||||
// "runtime host", "unresolved" and "genuinely local" all as `undefined` (#11163).
|
||||
protected async resolveRuntimeFileTarget(worktreeSelector: string): Promise<{
|
||||
async resolveRuntimeFileTarget(worktreeSelector: string): Promise<{
|
||||
worktree: ResolvedWorktree
|
||||
executionHostId: ExecutionHostId
|
||||
}> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithHydrateHeadlessMobileSessionTabsFromWorkspaceSession } from './orca-runtime-hydrate-headless-mobile-session-tabs-from-workspace-session'
|
||||
import { OrcaRuntimeWithHydrateHeadlessMobileSessionTabsFromWorkspaceSession } from './session-tabs/mobile-session-hydration'
|
||||
import type {
|
||||
RuntimeMobileSessionBrowserTab,
|
||||
RuntimeMobileSessionSnapshotTab,
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithTransitionGraphReloadToTerminalState } from './orca-runtime-transition-graph-reload-to-terminal-state'
|
||||
import { OrcaRuntimeWithTransitionGraphReloadToTerminalState } from './session-graph/session-graph-authority'
|
||||
import type { ExecutionHostId } from '../../shared/execution-host'
|
||||
import {
|
||||
floatingWorkspaceToWorktree,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab } from './orca-runtime-stored-mobile-snapshot-has-stale-preserved-tab'
|
||||
import { OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab } from './session-tabs/mobile-session-publication-preservation'
|
||||
import type {
|
||||
BrowserTabInfo,
|
||||
RuntimeMobileSessionClientTab,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithStopExplicitlyClosedTabPtys } from './orca-runtime-stop-explicitly-closed-tab-ptys'
|
||||
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'
|
||||
|
||||
@@ -149,7 +149,7 @@ class RemovalRuntime extends OrcaRuntimeService {
|
||||
return super.localRemovalJobHost(runtimeStore)
|
||||
}
|
||||
|
||||
protected override requireStore(): RuntimeStore {
|
||||
override requireStore(): RuntimeStore {
|
||||
if (this.stopAtStore) {
|
||||
throw this.helperFailure
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals } from './orca-runtime-restore-live-paired-renderer-session-owned-mobile-terminals'
|
||||
import { OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals } from './session-tabs/renderer-session-terminal-rescue'
|
||||
import type { TerminalOscLinkRange } from '../../shared/terminal-osc-link-ranges'
|
||||
|
||||
export class OrcaRuntimeWithWaitForLeafPtyId extends OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { isRemoteRuntimePtyId } from '../../shared/remote-runtime-pty-id'
|
||||
import { OrcaRuntimeWithRefreshFloatingWorkspacePtyLiveness } from './orca-runtime-refresh-floating-workspace-pty-liveness'
|
||||
import { OrcaRuntimeWithRefreshFloatingWorkspacePtyLiveness } from './terminal/lifecycle/floating-session-liveness'
|
||||
import { writeOrchestrationPointerWithSettlement } from './orchestration/mailbox-pointer-pty-write'
|
||||
import type { WriteSettlement } from '../../shared/pty-write-settlement'
|
||||
import type { RuntimeLeafRecord } from './runtime-terminal-state-records'
|
||||
|
||||
@@ -3,7 +3,7 @@ import type {
|
||||
RuntimeMobileSessionBrowserTab,
|
||||
RuntimeMobileSessionTabsSnapshot
|
||||
} from '../../shared/runtime-types'
|
||||
import { OrcaRuntimeWithCloseStructuredAgentSessionTab } from './orca-runtime-close-structured-agent-session-tab'
|
||||
import { OrcaRuntimeWithCloseStructuredAgentSessionTab } from './session-tabs/structured-session-tab-close'
|
||||
import { OrcaRuntimeWithReconcileHeadlessMobileSessionBrowserTabs } from './orca-runtime-reconcile-headless-mobile-session-browser-tabs'
|
||||
|
||||
const rendererPage: RuntimeMobileSessionBrowserTab = {
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('runtime migration catalog capabilities', () => {
|
||||
it('re-enters requireStore after checking the captured store capabilities', () => {
|
||||
const seen: OrcaRuntimeService[] = []
|
||||
class Probe extends OrcaRuntimeService {
|
||||
protected override requireStore(): RuntimeStore {
|
||||
override requireStore(): RuntimeStore {
|
||||
seen.push(this)
|
||||
return super.requireStore()
|
||||
}
|
||||
@@ -41,7 +41,7 @@ describe('runtime migration catalog capabilities', () => {
|
||||
it('retains the native missing-method error on a different returned store', () => {
|
||||
const seen: OrcaRuntimeService[] = []
|
||||
class Probe extends OrcaRuntimeService {
|
||||
protected override requireStore(): RuntimeStore {
|
||||
override requireStore(): RuntimeStore {
|
||||
seen.push(this)
|
||||
return store
|
||||
}
|
||||
@@ -54,7 +54,7 @@ describe('runtime migration catalog capabilities', () => {
|
||||
it('mutates the returned store before its native missing-flush rejection', async () => {
|
||||
const stage = vi.fn(() => staged)
|
||||
class Probe extends OrcaRuntimeService {
|
||||
protected override requireStore(): RuntimeStore {
|
||||
override requireStore(): RuntimeStore {
|
||||
return { ...store, stageOrcadMigrationCatalog: stage }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,8 @@ export type RuntimeStore = {
|
||||
getMobileClientTabSelections?: Store['getMobileClientTabSelections']
|
||||
setMobileClientTabSelections?: Store['setMobileClientTabSelections']
|
||||
getSettings(): {
|
||||
agentWorkspaceTrustEnabled?: GlobalSettings['agentWorkspaceTrustEnabled']
|
||||
codexManagedAccounts?: GlobalSettings['codexManagedAccounts']
|
||||
nestedWorkerMaxDepth?: GlobalSettings['nestedWorkerMaxDepth']
|
||||
workspaceDir: string
|
||||
nestWorkspaces: boolean
|
||||
|
||||
+23
-15
@@ -1,23 +1,31 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithHasTerminalsForWorktree } from './orca-runtime-has-terminals-for-worktree'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../shared/runtime-types'
|
||||
import type { FolderWorkspace } from '../../shared/folder-workspace-types'
|
||||
import type { OrcaRuntimeWithResolveBrowserNetworkExecutionHostForWorktree as ResolveBrowserNetworkExecutionHostForWorktreeMethods } from '../orca-runtime-resolve-browser-network-execution-host-for-worktree'
|
||||
import { OrcaRuntimeWithHasTerminalsForWorktree } from './session-graph-reload-lifecycle'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../../shared/runtime-types'
|
||||
import type { FolderWorkspace } from '../../../shared/folder-workspace-types'
|
||||
import {
|
||||
assertFolderWorkspacePathUsable,
|
||||
getFolderWorkspacePathStatus,
|
||||
inferFolderWorkspacePathConnection
|
||||
} from '../project-groups/folder-workspace-path-status'
|
||||
import type { TerminalWorkspaceLaunchScope } from './runtime-legacy-worker-terminal-recovery-types'
|
||||
import { folderWorkspaceKey, parseWorkspaceKey } from '../../shared/workspace-scope'
|
||||
import type { ResolvedWorktree } from './runtime-worktree-path-identity'
|
||||
import type { BrowserExecutionHostKeyResolution } from './runtime-browser-client-page-adoption'
|
||||
import { browserNetworkExecutionHostKey } from '../browser/browser-network-execution-route'
|
||||
import type { ClientHostedBrowserRpcRoute } from './runtime-browser-client-automation'
|
||||
import { routeRuntimeBrowserClientAutomation } from './runtime-browser-client-automation'
|
||||
import { getRuntimeBrowserPageRegistry } from './runtime-browser-page-registry'
|
||||
import { getBrowserHostLeaseRegistry } from './browser-host-lease-registry-instance'
|
||||
} from '../../project-groups/folder-workspace-path-status'
|
||||
import type { TerminalWorkspaceLaunchScope } from '../runtime-legacy-worker-terminal-recovery-types'
|
||||
import { folderWorkspaceKey, parseWorkspaceKey } from '../../../shared/workspace-scope'
|
||||
import type { ResolvedWorktree } from '../runtime-worktree-path-identity'
|
||||
import type { BrowserExecutionHostKeyResolution } from '../runtime-browser-client-page-adoption'
|
||||
import { browserNetworkExecutionHostKey } from '../../browser/browser-network-execution-route'
|
||||
import type { ClientHostedBrowserRpcRoute } from '../runtime-browser-client-automation'
|
||||
import { routeRuntimeBrowserClientAutomation } from '../runtime-browser-client-automation'
|
||||
import { getRuntimeBrowserPageRegistry } from '../runtime-browser-page-registry'
|
||||
import { getBrowserHostLeaseRegistry } from '../browser-host-lease-registry-instance'
|
||||
|
||||
export abstract class OrcaRuntimeWithTransitionGraphReloadToTerminalState extends OrcaRuntimeWithHasTerminalsForWorktree {
|
||||
protected abstract resolveBrowserNetworkExecutionHostForWorktree(
|
||||
...args: Parameters<
|
||||
ResolveBrowserNetworkExecutionHostForWorktreeMethods['resolveBrowserNetworkExecutionHostForWorktree']
|
||||
>
|
||||
): ReturnType<
|
||||
ResolveBrowserNetworkExecutionHostForWorktreeMethods['resolveBrowserNetworkExecutionHostForWorktree']
|
||||
>
|
||||
|
||||
export class OrcaRuntimeWithTransitionGraphReloadToTerminalState extends OrcaRuntimeWithHasTerminalsForWorktree {
|
||||
protected transitionGraphReloadToTerminalState(windowId: number): void {
|
||||
if (this.shouldRestoreHeadlessGraph(windowId)) {
|
||||
this.restoreHeadlessGraphAuthority()
|
||||
@@ -0,0 +1,192 @@
|
||||
import type { OrcaRuntimeWithHasTerminalsForWorktree as HasTerminalsForWorktreeMethods } from './session-graph-reload-lifecycle'
|
||||
import type { OrcaRuntimeWithBindPtyIncarnationHandle as BindPtyIncarnationHandleMethods } from '../terminal/identity/terminal-handle-bindings'
|
||||
import type { OrcaRuntimeWithResolveExitWaiters as ResolveExitWaitersMethods } from '../terminal/wait/terminal-wait-settlements'
|
||||
import type { OrcaRuntimeWithCollectMobileVisibleGraphChangedWorktrees as CollectMobileVisibleGraphChangedWorktreesMethods } from '../session-tabs/session-tabs-inventory'
|
||||
import type { OrcaRuntimeWithGetPtyRecordForPaneKey as GetPtyRecordForPaneKeyMethods } from '../orca-runtime-get-pty-record-for-pane-key'
|
||||
import type { OrcaRuntimeWithResolveWaiter as ResolveWaiterMethods } from '../orca-runtime-resolve-waiter'
|
||||
import type { OrcaRuntimeWithMarkPtyLivenessUnverifiable as MarkPtyLivenessUnverifiableMethods } from '../terminal/layout/terminal-input-floor'
|
||||
import type { OrcaRuntimeWithRecordPtyWorktree as RecordPtyWorktreeMethods } from '../terminal/identity/pty-worktree-record'
|
||||
import type { RuntimeSessionTabsInventoryPublication as SessionTabsInventoryPublicationMethods } from '../session-tabs/session-tabs-inventory-publication'
|
||||
import type { OrcaRuntimeWithRefreshFloatingWorkspacePtyLiveness as RefreshFloatingWorkspacePtyLivenessMethods } from '../terminal/lifecycle/floating-session-liveness'
|
||||
import type { OrcaRuntimeWithTouchMobileSessionTabsForWorktree as TouchMobileSessionTabsForWorktreeMethods } from '../orca-runtime-touch-mobile-session-tabs-for-worktree'
|
||||
import type { OrcaRuntimeWithScheduleMobileSessionTabsChanged as ScheduleMobileSessionTabsChangedMethods } from '../orca-runtime-schedule-mobile-session-tabs-changed'
|
||||
import type { OrcaRuntimeWithSyncMobileSessionTabs as SyncMobileSessionTabsMethods } from '../session-tabs/mobile-session-reconciliation'
|
||||
import { OrcaRuntimeWithNotifySshStateChanged } from '../orca-runtime-notify-ssh-state-changed'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../../shared/runtime-types'
|
||||
import type { ExecutionHostId } from '../../../shared/execution-host'
|
||||
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
|
||||
import type { RuntimePtyWorktreeRecord } from '../runtime-terminal-state-records'
|
||||
|
||||
export abstract class OrcaRuntimeWithAttachWindow extends OrcaRuntimeWithNotifySshStateChanged {
|
||||
protected abstract beginGraphReload(
|
||||
...args: Parameters<HasTerminalsForWorktreeMethods['beginGraphReload']>
|
||||
): ReturnType<HasTerminalsForWorktreeMethods['beginGraphReload']>
|
||||
|
||||
protected abstract adoptFirstPtyForLeafHandle(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['adoptFirstPtyForLeafHandle']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['adoptFirstPtyForLeafHandle']>
|
||||
|
||||
protected abstract adoptPreAllocatedHandle(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['adoptPreAllocatedHandle']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['adoptPreAllocatedHandle']>
|
||||
|
||||
protected abstract checkDeliverySettledAndArmRecheck(
|
||||
...args: Parameters<ResolveExitWaitersMethods['checkDeliverySettledAndArmRecheck']>
|
||||
): ReturnType<ResolveExitWaitersMethods['checkDeliverySettledAndArmRecheck']>
|
||||
|
||||
protected abstract collectMobileVisibleGraphChangedWorktrees(
|
||||
...args: Parameters<
|
||||
CollectMobileVisibleGraphChangedWorktreesMethods['collectMobileVisibleGraphChangedWorktrees']
|
||||
>
|
||||
): ReturnType<
|
||||
CollectMobileVisibleGraphChangedWorktreesMethods['collectMobileVisibleGraphChangedWorktrees']
|
||||
>
|
||||
|
||||
protected abstract deliverPendingMessagesForLeaf(
|
||||
...args: Parameters<GetPtyRecordForPaneKeyMethods['deliverPendingMessagesForLeaf']>
|
||||
): ReturnType<GetPtyRecordForPaneKeyMethods['deliverPendingMessagesForLeaf']>
|
||||
|
||||
protected abstract getLeafKey(
|
||||
...args: Parameters<ResolveWaiterMethods['getLeafKey']>
|
||||
): ReturnType<ResolveWaiterMethods['getLeafKey']>
|
||||
|
||||
abstract getPtyLivenessVerdict(
|
||||
...args: Parameters<MarkPtyLivenessUnverifiableMethods['getPtyLivenessVerdict']>
|
||||
): ReturnType<MarkPtyLivenessUnverifiableMethods['getPtyLivenessVerdict']>
|
||||
|
||||
protected abstract invalidateLeafHandle(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['invalidateLeafHandle']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['invalidateLeafHandle']>
|
||||
|
||||
protected abstract makeRuntimePaneKey(
|
||||
...args: Parameters<RecordPtyWorktreeMethods['makeRuntimePaneKey']>
|
||||
): ReturnType<RecordPtyWorktreeMethods['makeRuntimePaneKey']>
|
||||
|
||||
abstract markGraphReady(
|
||||
...args: Parameters<HasTerminalsForWorktreeMethods['markGraphReady']>
|
||||
): ReturnType<HasTerminalsForWorktreeMethods['markGraphReady']>
|
||||
|
||||
protected abstract markSessionTabsInventoryPublished(
|
||||
...args: Parameters<SessionTabsInventoryPublicationMethods['markSessionTabsInventoryPublished']>
|
||||
): ReturnType<SessionTabsInventoryPublicationMethods['markSessionTabsInventoryPublished']>
|
||||
|
||||
protected abstract nextTitleObservationSequence(
|
||||
...args: Parameters<GetPtyRecordForPaneKeyMethods['nextTitleObservationSequence']>
|
||||
): ReturnType<GetPtyRecordForPaneKeyMethods['nextTitleObservationSequence']>
|
||||
|
||||
protected abstract rebuildLeafPtyIndex(
|
||||
...args: Parameters<RefreshFloatingWorkspacePtyLivenessMethods['rebuildLeafPtyIndex']>
|
||||
): ReturnType<RefreshFloatingWorkspacePtyLivenessMethods['rebuildLeafPtyIndex']>
|
||||
|
||||
protected abstract reconcileMobileSessionRetirementFences(
|
||||
...args: Parameters<
|
||||
TouchMobileSessionTabsForWorktreeMethods['reconcileMobileSessionRetirementFences']
|
||||
>
|
||||
): ReturnType<TouchMobileSessionTabsForWorktreeMethods['reconcileMobileSessionRetirementFences']>
|
||||
|
||||
protected abstract reconcilePtyIncarnationHandles(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['reconcilePtyIncarnationHandles']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['reconcilePtyIncarnationHandles']>
|
||||
|
||||
protected abstract recordPtyWorktree(
|
||||
...args: Parameters<RecordPtyWorktreeMethods['recordPtyWorktree']>
|
||||
): ReturnType<RecordPtyWorktreeMethods['recordPtyWorktree']>
|
||||
|
||||
protected abstract scheduleMobileSessionTabsChanged(
|
||||
...args: Parameters<ScheduleMobileSessionTabsChangedMethods['scheduleMobileSessionTabsChanged']>
|
||||
): ReturnType<ScheduleMobileSessionTabsChangedMethods['scheduleMobileSessionTabsChanged']>
|
||||
|
||||
protected abstract syncMobileSessionTabs(
|
||||
...args: Parameters<SyncMobileSessionTabsMethods['syncMobileSessionTabs']>
|
||||
): ReturnType<SyncMobileSessionTabsMethods['syncMobileSessionTabs']>
|
||||
|
||||
attachWindow(windowId: number): void {
|
||||
if (this.authoritativeWindowId === HEADLESS_RUNTIME_WINDOW_ID) {
|
||||
if (
|
||||
this.pendingHeadlessPromotionWindowId !== null &&
|
||||
windowId !== this.pendingHeadlessPromotionWindowId
|
||||
) {
|
||||
return
|
||||
}
|
||||
// Why: promotion is a renderer reload of the same graph owner, not a new
|
||||
// runtime; stale handles must transition before the real window publishes.
|
||||
this.persistWindowlessPtyBindingsForDesktopAttach()
|
||||
this.pendingHeadlessPromotionWindowId = windowId
|
||||
this.authoritativeWindowId = windowId
|
||||
this.beginGraphReload(windowId)
|
||||
return
|
||||
}
|
||||
if (this.authoritativeWindowId === null) {
|
||||
// Why: a promoted serve can close and later reopen its window while new
|
||||
// background PTYs keep arriving; every windowless gap needs this handoff.
|
||||
this.persistWindowlessPtyBindingsForDesktopAttach()
|
||||
this.authoritativeWindowId = windowId
|
||||
}
|
||||
}
|
||||
|
||||
protected persistWindowlessPtyBindingsForDesktopAttach(): void {
|
||||
if (!this.store?.getWorkspaceSession || !this.store.setWorkspaceSession) {
|
||||
return
|
||||
}
|
||||
const partitions = new Map<
|
||||
ExecutionHostId,
|
||||
{ session: WorkspaceSessionState; ptys: RuntimePtyWorktreeRecord[] }
|
||||
>()
|
||||
for (const pty of this.ptysById.values()) {
|
||||
if (!pty.connected || !pty.tabId) {
|
||||
continue
|
||||
}
|
||||
const hostId = this.getWorkspaceSessionHostIdForWorktree(pty.worktreeId)
|
||||
const session = this.store.getWorkspaceSession(hostId)
|
||||
const tab = session.tabsByWorktree[pty.worktreeId]?.find(
|
||||
(candidate) => candidate.id === pty.tabId
|
||||
)
|
||||
if (!tab) {
|
||||
continue
|
||||
}
|
||||
const layoutPtyIds = Object.values(
|
||||
session.terminalLayoutsByTabId[pty.tabId]?.ptyIdsByLeafId ?? {}
|
||||
)
|
||||
if (tab.ptyId !== pty.ptyId && !layoutPtyIds.includes(pty.ptyId)) {
|
||||
continue
|
||||
}
|
||||
const partition = partitions.get(hostId) ?? { session, ptys: [] }
|
||||
partition.ptys.push(pty)
|
||||
partitions.set(hostId, partition)
|
||||
}
|
||||
|
||||
for (const [hostId, { session, ptys }] of partitions) {
|
||||
// Why: windowless SSH PTYs must be handed to the desktop through their SSH partition, never the local session.
|
||||
const activeWorktreeIdsOnShutdown = [
|
||||
...new Set([
|
||||
...(session.activeWorktreeIdsOnShutdown ?? []),
|
||||
...ptys.map((pty) => pty.worktreeId)
|
||||
])
|
||||
]
|
||||
const activeConnectionIdsAtShutdown = [
|
||||
...new Set([
|
||||
...(session.activeConnectionIdsAtShutdown ?? []),
|
||||
...ptys
|
||||
.map((pty) => pty.connectionId)
|
||||
.filter((connectionId): connectionId is string => connectionId !== null)
|
||||
])
|
||||
]
|
||||
const remoteSessionIdsByTabId = { ...session.remoteSessionIdsByTabId }
|
||||
for (const pty of ptys) {
|
||||
if (pty.connectionId && pty.tabId) {
|
||||
remoteSessionIdsByTabId[pty.tabId] = pty.ptyId
|
||||
}
|
||||
}
|
||||
|
||||
this.store.setWorkspaceSession(
|
||||
{
|
||||
...session,
|
||||
activeWorktreeIdsOnShutdown,
|
||||
...(activeConnectionIdsAtShutdown.length > 0 ? { activeConnectionIdsAtShutdown } : {}),
|
||||
...(Object.keys(remoteSessionIdsByTabId).length > 0 ? { remoteSessionIdsByTabId } : {})
|
||||
},
|
||||
hostId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
-5
@@ -1,9 +1,59 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithStopExactTerminalsForWorktree } from './orca-runtime-stop-exact-terminals-for-worktree'
|
||||
import type { RuntimeRendererReloadFence } from './orca-runtime-core'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../shared/runtime-types'
|
||||
import type { OrcaRuntimeWithTransitionGraphReloadToTerminalState as TransitionGraphReloadToTerminalStateMethods } from './session-graph-authority'
|
||||
import type { OrcaRuntimeWithBindPtyIncarnationHandle as BindPtyIncarnationHandleMethods } from '../terminal/identity/terminal-handle-bindings'
|
||||
import type { OrcaRuntimeWithResolveWaiter as ResolveWaiterMethods } from '../orca-runtime-resolve-waiter'
|
||||
import { OrcaRuntimeWithStopExactTerminalsForWorktree } from '../orca-runtime-stop-exact-terminals-for-worktree'
|
||||
import type { RuntimeRendererReloadFence } from '../orca-runtime-core'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../../shared/runtime-types'
|
||||
|
||||
export abstract class OrcaRuntimeWithHasTerminalsForWorktree extends OrcaRuntimeWithStopExactTerminalsForWorktree {
|
||||
protected abstract assertStableReadyGraph(
|
||||
...args: Parameters<TransitionGraphReloadToTerminalStateMethods['assertStableReadyGraph']>
|
||||
): ReturnType<TransitionGraphReloadToTerminalStateMethods['assertStableReadyGraph']>
|
||||
|
||||
protected abstract captureReadyGraphEpoch(
|
||||
...args: Parameters<TransitionGraphReloadToTerminalStateMethods['captureReadyGraphEpoch']>
|
||||
): ReturnType<TransitionGraphReloadToTerminalStateMethods['captureReadyGraphEpoch']>
|
||||
|
||||
protected abstract clearPtyIncarnationHandles(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['clearPtyIncarnationHandles']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['clearPtyIncarnationHandles']>
|
||||
|
||||
protected abstract invalidatePtyIncarnationHandle(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['invalidatePtyIncarnationHandle']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['invalidatePtyIncarnationHandle']>
|
||||
|
||||
protected abstract refreshWritableFlags(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['refreshWritableFlags']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['refreshWritableFlags']>
|
||||
|
||||
protected abstract rejectAllWaiters(
|
||||
...args: Parameters<ResolveWaiterMethods['rejectAllWaiters']>
|
||||
): ReturnType<ResolveWaiterMethods['rejectAllWaiters']>
|
||||
|
||||
protected abstract rejectWaitersForHandle(
|
||||
...args: Parameters<ResolveWaiterMethods['rejectWaitersForHandle']>
|
||||
): ReturnType<ResolveWaiterMethods['rejectWaitersForHandle']>
|
||||
|
||||
protected abstract rememberDetachedPreAllocatedLeaves(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['rememberDetachedPreAllocatedLeaves']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['rememberDetachedPreAllocatedLeaves']>
|
||||
|
||||
protected abstract restoreHeadlessGraphAuthority(
|
||||
...args: Parameters<
|
||||
TransitionGraphReloadToTerminalStateMethods['restoreHeadlessGraphAuthority']
|
||||
>
|
||||
): ReturnType<TransitionGraphReloadToTerminalStateMethods['restoreHeadlessGraphAuthority']>
|
||||
|
||||
protected abstract shouldRestoreHeadlessGraph(
|
||||
...args: Parameters<TransitionGraphReloadToTerminalStateMethods['shouldRestoreHeadlessGraph']>
|
||||
): ReturnType<TransitionGraphReloadToTerminalStateMethods['shouldRestoreHeadlessGraph']>
|
||||
|
||||
protected abstract transitionGraphReloadToTerminalState(
|
||||
...args: Parameters<
|
||||
TransitionGraphReloadToTerminalStateMethods['transitionGraphReloadToTerminalState']
|
||||
>
|
||||
): ReturnType<TransitionGraphReloadToTerminalStateMethods['transitionGraphReloadToTerminalState']>
|
||||
|
||||
export class OrcaRuntimeWithHasTerminalsForWorktree extends OrcaRuntimeWithStopExactTerminalsForWorktree {
|
||||
async hasTerminalsForWorktree(worktreeSelector: string): Promise<boolean> {
|
||||
const graphEpoch = this.captureReadyGraphEpoch()
|
||||
const worktree = await this.resolveWorktreeSelector(worktreeSelector)
|
||||
+8
-6
@@ -1,14 +1,13 @@
|
||||
/* eslint-disable unicorn/no-useless-spread */
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithAttachWindow } from './orca-runtime-attach-window'
|
||||
import { OrcaRuntimeWithAttachWindow } from './session-graph-promotion'
|
||||
import type {
|
||||
RuntimeRendererSyncWindowGraph,
|
||||
RuntimeSyncedTab,
|
||||
RuntimeSyncWindowGraph,
|
||||
RuntimeSyncWindowGraphResult
|
||||
} from '../../shared/runtime-types'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../shared/runtime-types'
|
||||
import type { RuntimeLeafRecord } from './runtime-terminal-state-records'
|
||||
} from '../../../shared/runtime-session-contracts'
|
||||
import { HEADLESS_RUNTIME_WINDOW_ID } from '../../../shared/runtime-types'
|
||||
import type { RuntimeLeafRecord } from '../runtime-terminal-state-records'
|
||||
|
||||
/** The runtime indexes graph tabs by bare id, so duplicate ids cannot be routed safely. */
|
||||
function assertUniqueRuntimeGraphTabIds(tabs: readonly RuntimeSyncedTab[]): void {
|
||||
@@ -21,7 +20,10 @@ function assertUniqueRuntimeGraphTabIds(tabs: readonly RuntimeSyncedTab[]): void
|
||||
}
|
||||
}
|
||||
|
||||
export class OrcaRuntimeWithSyncWindowGraph extends OrcaRuntimeWithAttachWindow {
|
||||
export abstract class OrcaRuntimeWithSyncWindowGraph extends OrcaRuntimeWithAttachWindow {
|
||||
declare protected terminalGroupGridSizes?: RuntimeSyncWindowGraph['terminalGroupGridSizes']
|
||||
declare protected singleGroupWorkspaceGridSize?: RuntimeSyncWindowGraph['singleGroupWorkspaceGridSize']
|
||||
|
||||
shouldRelayTerminalBrowserOpens(): boolean {
|
||||
return this.authoritativeWindowId === HEADLESS_RUNTIME_WINDOW_ID
|
||||
}
|
||||
+8
-9
@@ -1,18 +1,17 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithFocusTerminal } from './orca-runtime-focus-terminal'
|
||||
import { EXPLICIT_TERMINAL_CLOSE_STOP_TIMEOUT_MS } from './orca-runtime-core'
|
||||
import { SSH_PROVIDER_UNREGISTERED_REASON } from '../../shared/pty-liveness-verdict'
|
||||
import type { RuntimeTerminalClose } from '../../shared/runtime-types'
|
||||
import type { RuntimePtyTabCloseAuthority } from './runtime-terminal-state-records'
|
||||
import { parsePaneKey } from '../../shared/stable-pane-id'
|
||||
import { errorMessage } from '../../shared/error-message'
|
||||
import { OrcaRuntimeWithFocusTerminal } from '../orca-runtime-focus-terminal'
|
||||
import { EXPLICIT_TERMINAL_CLOSE_STOP_TIMEOUT_MS } from '../orca-runtime-core'
|
||||
import { SSH_PROVIDER_UNREGISTERED_REASON } from '../../../shared/pty-liveness-verdict'
|
||||
import type { RuntimeTerminalClose } from '../../../shared/runtime-types'
|
||||
import type { RuntimePtyTabCloseAuthority } from '../runtime-terminal-state-records'
|
||||
import { parsePaneKey } from '../../../shared/stable-pane-id'
|
||||
import { errorMessage } from '../../../shared/error-message'
|
||||
|
||||
/** How an explicit close's stop of its addressed PTY ended. */
|
||||
type ExplicitCloseStop = { stopped: boolean }
|
||||
|
||||
const NO_STOP: ExplicitCloseStop = { stopped: false }
|
||||
|
||||
export class OrcaRuntimeWithStopExplicitlyClosedTabPtys extends OrcaRuntimeWithFocusTerminal {
|
||||
export abstract class OrcaRuntimeWithStopExplicitlyClosedTabPtys extends OrcaRuntimeWithFocusTerminal {
|
||||
protected async stopExplicitlyClosedTabPtys(
|
||||
ptyIds: readonly string[],
|
||||
addressedPtyId: string
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OrcaRuntimeWithCloseHeadlessMobileTerminalTab } from '../orca-runtime-close-headless-mobile-terminal-tab'
|
||||
import { OrcaRuntimeWithCloseHeadlessMobileTerminalTab } from './headless-terminal-tab-close'
|
||||
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
|
||||
import type { RuntimeMobileSessionTabsSnapshot } from '../../../shared/runtime-session-contracts'
|
||||
import type { RuntimeMobileSessionSnapshotTab } from '../../../shared/runtime-mobile-session-tab-contracts'
|
||||
|
||||
+49
-10
@@ -1,19 +1,58 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithCloseStructuredAgentSessionTab } from './orca-runtime-close-structured-agent-session-tab'
|
||||
import type { RuntimeHeadlessTabProperties as HeadlessTabPropertiesMethods } from './headless-tab-properties'
|
||||
import type { RuntimeHeadlessTabGroups as HeadlessTabGroupsMethods } from './headless-tab-group-moves'
|
||||
import type { OrcaRuntimeWithPersistHeadlessTerminalTitle as PersistHeadlessTerminalTitleMethods } from '../orca-runtime-persist-headless-terminal-title'
|
||||
import type { OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals as RestoreLivePairedRendererSessionOwnedMobileTerminalsMethods } from './renderer-session-terminal-rescue'
|
||||
import { OrcaRuntimeWithCloseStructuredAgentSessionTab } from './structured-session-tab-close'
|
||||
import type {
|
||||
RuntimeMobileSessionTabMove,
|
||||
RuntimeMobileSessionTabMoveResult,
|
||||
RuntimeMobileSessionTabsSnapshot,
|
||||
RuntimeMobileSessionTerminalTab
|
||||
} from '../../shared/runtime-types'
|
||||
import { parseAppSshPtyId } from '../../shared/ssh-pty-id'
|
||||
import { buildHeadlessMobileSessionTabGroups } from './mobile-session-layout-projection'
|
||||
import { appendRetiredTerminalSurfaceProofs } from './mobile-session-terminal-retirement-proof'
|
||||
import type { RuntimePtyWorktreeRecord } from './runtime-terminal-state-records'
|
||||
import type { TerminalPaneLayoutNode } from '../../shared/terminal-tab-types'
|
||||
import type { RuntimeSessionTabCloseReason } from '../../shared/runtime-session-contracts'
|
||||
} from '../../../shared/runtime-types'
|
||||
import { parseAppSshPtyId } from '../../../shared/ssh-pty-id'
|
||||
import { buildHeadlessMobileSessionTabGroups } from '../mobile-session-layout-projection'
|
||||
import { appendRetiredTerminalSurfaceProofs } from '../mobile-session-terminal-retirement-proof'
|
||||
import type { RuntimePtyWorktreeRecord } from '../runtime-terminal-state-records'
|
||||
import type { TerminalPaneLayoutNode } from '../../../shared/terminal-tab-types'
|
||||
import type { RuntimeSessionTabCloseReason } from '../../../shared/runtime-session-contracts'
|
||||
|
||||
export abstract class OrcaRuntimeWithCloseHeadlessMobileTerminalTab extends OrcaRuntimeWithCloseStructuredAgentSessionTab {
|
||||
protected abstract applyHeadlessSessionTabPropsToSnapshot(
|
||||
...args: Parameters<HeadlessTabPropertiesMethods['applyHeadlessSessionTabPropsToSnapshot']>
|
||||
): ReturnType<HeadlessTabPropertiesMethods['applyHeadlessSessionTabPropsToSnapshot']>
|
||||
|
||||
protected abstract applyHeadlessTerminalPaneLayoutToSnapshot(
|
||||
...args: Parameters<HeadlessTabPropertiesMethods['applyHeadlessTerminalPaneLayoutToSnapshot']>
|
||||
): ReturnType<HeadlessTabPropertiesMethods['applyHeadlessTerminalPaneLayoutToSnapshot']>
|
||||
|
||||
protected abstract moveHeadlessMobileSessionTab(
|
||||
...args: Parameters<HeadlessTabGroupsMethods['moveHeadlessMobileSessionTab']>
|
||||
): ReturnType<HeadlessTabGroupsMethods['moveHeadlessMobileSessionTab']>
|
||||
|
||||
protected abstract normalizeMobileSessionTabOrder(
|
||||
...args: Parameters<PersistHeadlessTerminalTitleMethods['normalizeMobileSessionTabOrder']>
|
||||
): ReturnType<PersistHeadlessTerminalTitleMethods['normalizeMobileSessionTabOrder']>
|
||||
|
||||
protected abstract persistHeadlessSessionTabProps(
|
||||
...args: Parameters<HeadlessTabPropertiesMethods['persistHeadlessSessionTabProps']>
|
||||
): ReturnType<HeadlessTabPropertiesMethods['persistHeadlessSessionTabProps']>
|
||||
|
||||
protected abstract persistHeadlessTerminalPaneLayout(
|
||||
...args: Parameters<HeadlessTabPropertiesMethods['persistHeadlessTerminalPaneLayout']>
|
||||
): ReturnType<HeadlessTabPropertiesMethods['persistHeadlessTerminalPaneLayout']>
|
||||
|
||||
protected abstract resolveMobileSessionHostTabId(
|
||||
...args: Parameters<PersistHeadlessTerminalTitleMethods['resolveMobileSessionHostTabId']>
|
||||
): ReturnType<PersistHeadlessTerminalTitleMethods['resolveMobileSessionHostTabId']>
|
||||
|
||||
protected abstract setPairedRendererSessionOwnership(
|
||||
...args: Parameters<
|
||||
RestoreLivePairedRendererSessionOwnedMobileTerminalsMethods['setPairedRendererSessionOwnership']
|
||||
>
|
||||
): ReturnType<
|
||||
RestoreLivePairedRendererSessionOwnedMobileTerminalsMethods['setPairedRendererSessionOwnership']
|
||||
>
|
||||
|
||||
export class OrcaRuntimeWithCloseHeadlessMobileTerminalTab extends OrcaRuntimeWithCloseStructuredAgentSessionTab {
|
||||
protected async closeHeadlessMobileTerminalTab(
|
||||
worktreeId: string,
|
||||
snapshot: RuntimeMobileSessionTabsSnapshot,
|
||||
+74
-12
@@ -1,35 +1,97 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import type { OrcaRuntimeWithBuildHeadlessMobileSessionBrowserTabs as BuildHeadlessMobileSessionBrowserTabsMethods } from '../orca-runtime-build-headless-mobile-session-browser-tabs'
|
||||
import type { OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab as StoredMobileSnapshotHasStalePreservedTabMethods } from './mobile-session-publication-preservation'
|
||||
import type { OrcaRuntimeWithReconcileHeadlessMobileSessionBrowserTabs as ReconcileHeadlessMobileSessionBrowserTabsMethods } from '../orca-runtime-reconcile-headless-mobile-session-browser-tabs'
|
||||
import type { BrowserWindow } from 'electron'
|
||||
import { RuntimeSessionTabsInventoryPublication } from './session-tabs/session-tabs-inventory-publication'
|
||||
import type { WorkspaceSessionState } from '../../shared/workspace-session-state-types'
|
||||
import { getRuntimeBrowserPageRegistry } from './runtime-browser-page-registry'
|
||||
import { splitWorktreeIdForFilesystem } from '../../shared/worktree/id'
|
||||
import { buildHeadlessMobileSessionTerminalTabs } from './mobile-session-terminal-projection'
|
||||
import { buildHeadlessMobileSessionEditorTabs } from './mobile-session-editor-projection'
|
||||
import { RuntimeSessionTabsInventoryPublication } from './session-tabs-inventory-publication'
|
||||
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
|
||||
import { getRuntimeBrowserPageRegistry } from '../runtime-browser-page-registry'
|
||||
import { splitWorktreeIdForFilesystem } from '../../../shared/worktree/id'
|
||||
import { buildHeadlessMobileSessionTerminalTabs } from '../mobile-session-terminal-projection'
|
||||
import { buildHeadlessMobileSessionEditorTabs } from '../mobile-session-editor-projection'
|
||||
import type {
|
||||
RuntimeMobileSessionSnapshotTab,
|
||||
RuntimeMobileSessionTabGroup,
|
||||
RuntimeMobileSessionTabsSnapshot,
|
||||
RuntimeMobileSessionTerminalTab
|
||||
} from '../../shared/runtime-types'
|
||||
} from '../../../shared/runtime-types'
|
||||
import {
|
||||
collectHeadlessParentTabOrder,
|
||||
distributeHeadlessTabsAcrossGroups,
|
||||
getHeadlessMobileSessionGroupId,
|
||||
pickHeadlessActiveTerminalTab,
|
||||
pickRestoredActiveGroupId
|
||||
} from './mobile-session-layout-projection'
|
||||
} from '../mobile-session-layout-projection'
|
||||
import {
|
||||
mergeMobileSessionSnapshotTabs,
|
||||
mergeMobileSessionTabGroups
|
||||
} from './mobile-session-tab-merge'
|
||||
} from '../mobile-session-tab-merge'
|
||||
import {
|
||||
appendBrowserTabOrder,
|
||||
collectBrowserGroupAssignment
|
||||
} from './mobile-session-browser-group-projection'
|
||||
import { headlessMobileSnapshotContentUnchanged } from './mobile-session-snapshot-equality'
|
||||
} from '../mobile-session-browser-group-projection'
|
||||
import { headlessMobileSnapshotContentUnchanged } from '../mobile-session-snapshot-equality'
|
||||
|
||||
export abstract class OrcaRuntimeWithHydrateHeadlessMobileSessionTabsFromWorkspaceSession extends RuntimeSessionTabsInventoryPublication {
|
||||
protected abstract buildHeadlessMobileSessionBrowserTabs(
|
||||
...args: Parameters<
|
||||
BuildHeadlessMobileSessionBrowserTabsMethods['buildHeadlessMobileSessionBrowserTabs']
|
||||
>
|
||||
): ReturnType<
|
||||
BuildHeadlessMobileSessionBrowserTabsMethods['buildHeadlessMobileSessionBrowserTabs']
|
||||
>
|
||||
|
||||
protected abstract getMergedMobileSessionPublicationEpoch(
|
||||
...args: Parameters<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['getMergedMobileSessionPublicationEpoch']
|
||||
>
|
||||
): ReturnType<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['getMergedMobileSessionPublicationEpoch']
|
||||
>
|
||||
|
||||
protected abstract hasRecentExpiredSshLeasePane(
|
||||
...args: Parameters<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['hasRecentExpiredSshLeasePane']
|
||||
>
|
||||
): ReturnType<ReconcileHeadlessMobileSessionBrowserTabsMethods['hasRecentExpiredSshLeasePane']>
|
||||
|
||||
protected abstract hasServeOrSshOwnedBinding(
|
||||
...args: Parameters<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['hasServeOrSshOwnedBinding']
|
||||
>
|
||||
): ReturnType<ReconcileHeadlessMobileSessionBrowserTabsMethods['hasServeOrSshOwnedBinding']>
|
||||
|
||||
protected abstract isHeadlessBuiltMobileSessionPublicationBase(
|
||||
...args: Parameters<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['isHeadlessBuiltMobileSessionPublicationBase']
|
||||
>
|
||||
): ReturnType<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['isHeadlessBuiltMobileSessionPublicationBase']
|
||||
>
|
||||
|
||||
protected abstract reconcileHeadlessMobileSessionBrowserTabs(
|
||||
...args: Parameters<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['reconcileHeadlessMobileSessionBrowserTabs']
|
||||
>
|
||||
): ReturnType<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['reconcileHeadlessMobileSessionBrowserTabs']
|
||||
>
|
||||
|
||||
protected abstract workspaceSessionHasRuntimeOwnedPtyCandidate(
|
||||
...args: Parameters<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['workspaceSessionHasRuntimeOwnedPtyCandidate']
|
||||
>
|
||||
): ReturnType<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['workspaceSessionHasRuntimeOwnedPtyCandidate']
|
||||
>
|
||||
|
||||
protected abstract workspaceSessionWorktreeHasRuntimeOwnedPtyCandidate(
|
||||
...args: Parameters<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['workspaceSessionWorktreeHasRuntimeOwnedPtyCandidate']
|
||||
>
|
||||
): ReturnType<
|
||||
ReconcileHeadlessMobileSessionBrowserTabsMethods['workspaceSessionWorktreeHasRuntimeOwnedPtyCandidate']
|
||||
>
|
||||
|
||||
protected abstract getAvailableAuthoritativeWindow(): BrowserWindow | null
|
||||
|
||||
protected hydrateHeadlessMobileSessionTabsFromWorkspaceSession(
|
||||
+15
-7
@@ -1,20 +1,28 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithSyncMobileSessionTabs } from './orca-runtime-sync-mobile-session-tabs'
|
||||
import type { OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab as StoredMobileSnapshotHasStalePreservedTabMethods } from './mobile-session-publication-preservation'
|
||||
import { OrcaRuntimeWithSyncMobileSessionTabs } from './mobile-session-reconciliation'
|
||||
import type {
|
||||
RuntimeMobileSessionSnapshotTab,
|
||||
RuntimeMobileSessionTabGroup,
|
||||
RuntimeMobileSessionTabsSnapshot,
|
||||
RuntimeMobileSessionTerminalTab
|
||||
} from '../../shared/runtime-types'
|
||||
} from '../../../shared/runtime-types'
|
||||
import {
|
||||
getMobileSessionSnapshotTabIdentityKeys,
|
||||
mergeMobileSessionSnapshotTabs,
|
||||
mergeMobileSessionTabGroups
|
||||
} from './mobile-session-tab-merge'
|
||||
import { terminalLayoutContainsLeaf } from '../../shared/workspace-session-pane-ownership'
|
||||
import { getHeadlessMobileSessionGroupId } from './mobile-session-layout-projection'
|
||||
} from '../mobile-session-tab-merge'
|
||||
import { terminalLayoutContainsLeaf } from '../../../shared/workspace-session-pane-ownership'
|
||||
import { getHeadlessMobileSessionGroupId } from '../mobile-session-layout-projection'
|
||||
|
||||
export abstract class OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs extends OrcaRuntimeWithSyncMobileSessionTabs {
|
||||
protected abstract collectPreservedHeadlessMobileSessionTabs(
|
||||
...args: Parameters<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['collectPreservedHeadlessMobileSessionTabs']
|
||||
>
|
||||
): ReturnType<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['collectPreservedHeadlessMobileSessionTabs']
|
||||
>
|
||||
|
||||
export class OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs extends OrcaRuntimeWithSyncMobileSessionTabs {
|
||||
protected mergePreservedHeadlessMobileSessionTabs(
|
||||
snapshot: RuntimeMobileSessionTabsSnapshot,
|
||||
existing: RuntimeMobileSessionTabsSnapshot | undefined
|
||||
+17
-8
@@ -1,16 +1,25 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs } from './orca-runtime-merge-preserved-headless-mobile-session-tabs'
|
||||
import type { OrcaRuntimeWithScheduleMobileSessionTabsChanged as ScheduleMobileSessionTabsChangedMethods } from '../orca-runtime-schedule-mobile-session-tabs-changed'
|
||||
import { OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs } from './mobile-session-preservation'
|
||||
import type {
|
||||
RuntimeMobileSessionSnapshotTab,
|
||||
RuntimeMobileSessionTabsRemovedResult,
|
||||
RuntimeMobileSessionTabsSnapshot
|
||||
} from '../../shared/runtime-types'
|
||||
import { getMobileSessionSnapshotTabIdentityKeys } from './mobile-session-tab-merge'
|
||||
import { getRuntimeBrowserPageRegistry } from './runtime-browser-page-registry'
|
||||
import { sameRuntimeBrowserPlacement } from '../../shared/runtime-browser-placement'
|
||||
import type { ClientHostedBrowserRowsEvent } from '../../shared/client-hosted-browser-rows'
|
||||
} from '../../../shared/runtime-types'
|
||||
import { getMobileSessionSnapshotTabIdentityKeys } from '../mobile-session-tab-merge'
|
||||
import { getRuntimeBrowserPageRegistry } from '../runtime-browser-page-registry'
|
||||
import { sameRuntimeBrowserPlacement } from '../../../shared/runtime-browser-placement'
|
||||
import type { ClientHostedBrowserRowsEvent } from '../../../shared/client-hosted-browser-rows'
|
||||
|
||||
export abstract class OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab extends OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs {
|
||||
protected abstract getListedBrowserTabsByPageId(
|
||||
...args: Parameters<ScheduleMobileSessionTabsChangedMethods['getListedBrowserTabsByPageId']>
|
||||
): ReturnType<ScheduleMobileSessionTabsChangedMethods['getListedBrowserTabsByPageId']>
|
||||
protected abstract notifyMobileSessionTabsChangedNow(
|
||||
...args: Parameters<
|
||||
ScheduleMobileSessionTabsChangedMethods['notifyMobileSessionTabsChangedNow']
|
||||
>
|
||||
): ReturnType<ScheduleMobileSessionTabsChangedMethods['notifyMobileSessionTabsChangedNow']>
|
||||
|
||||
export class OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab extends OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs {
|
||||
// Why: the accepted-revision no-op gate must not fossilize preserved runtime
|
||||
// tabs. A stored merged snapshot's tabs absent from the accepted renderer
|
||||
// publication exist only via preservation; if any such tab no longer
|
||||
+39
-6
@@ -1,11 +1,44 @@
|
||||
import type { OrcaRuntimeWithMergePreservedHeadlessMobileSessionTabs as MergePreservedHeadlessMobileSessionTabsMethods } from './mobile-session-preservation'
|
||||
import type { OrcaRuntimeWithStoredMobileSnapshotHasStalePreservedTab as StoredMobileSnapshotHasStalePreservedTabMethods } from './mobile-session-publication-preservation'
|
||||
/* eslint-disable unicorn/no-useless-spread */
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithWriteOrchestrationPointerPty } from './orca-runtime-write-orchestration-pointer-pty'
|
||||
import type { RuntimeMobileSessionTabsSnapshot } from '../../shared/runtime-types'
|
||||
import type { WorkspaceSessionState } from '../../shared/workspace-session-state-types'
|
||||
import { getMobileSessionSnapshotTabIdentityKeys } from './mobile-session-tab-merge'
|
||||
import { OrcaRuntimeWithWriteOrchestrationPointerPty } from '../orca-runtime-write-orchestration-pointer-pty'
|
||||
import type { RuntimeMobileSessionTabsSnapshot } from '../../../shared/runtime-types'
|
||||
import type { WorkspaceSessionState } from '../../../shared/workspace-session-state-types'
|
||||
import { getMobileSessionSnapshotTabIdentityKeys } from '../mobile-session-tab-merge'
|
||||
|
||||
export abstract class OrcaRuntimeWithSyncMobileSessionTabs extends OrcaRuntimeWithWriteOrchestrationPointerPty {
|
||||
protected abstract buildPreservedHeadlessMobileSessionSnapshot(
|
||||
...args: Parameters<
|
||||
MergePreservedHeadlessMobileSessionTabsMethods['buildPreservedHeadlessMobileSessionSnapshot']
|
||||
>
|
||||
): ReturnType<
|
||||
MergePreservedHeadlessMobileSessionTabsMethods['buildPreservedHeadlessMobileSessionSnapshot']
|
||||
>
|
||||
|
||||
protected abstract mergePreservedHeadlessMobileSessionTabs(
|
||||
...args: Parameters<
|
||||
MergePreservedHeadlessMobileSessionTabsMethods['mergePreservedHeadlessMobileSessionTabs']
|
||||
>
|
||||
): ReturnType<
|
||||
MergePreservedHeadlessMobileSessionTabsMethods['mergePreservedHeadlessMobileSessionTabs']
|
||||
>
|
||||
|
||||
protected abstract releaseRuntimeSessionOwnershipForRendererRetiredTabs(
|
||||
...args: Parameters<
|
||||
MergePreservedHeadlessMobileSessionTabsMethods['releaseRuntimeSessionOwnershipForRendererRetiredTabs']
|
||||
>
|
||||
): ReturnType<
|
||||
MergePreservedHeadlessMobileSessionTabsMethods['releaseRuntimeSessionOwnershipForRendererRetiredTabs']
|
||||
>
|
||||
|
||||
protected abstract storedMobileSnapshotHasStalePreservedTab(
|
||||
...args: Parameters<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['storedMobileSnapshotHasStalePreservedTab']
|
||||
>
|
||||
): ReturnType<
|
||||
StoredMobileSnapshotHasStalePreservedTabMethods['storedMobileSnapshotHasStalePreservedTab']
|
||||
>
|
||||
|
||||
export class OrcaRuntimeWithSyncMobileSessionTabs extends OrcaRuntimeWithWriteOrchestrationPointerPty {
|
||||
// Returns the worktrees whose stored snapshot object changed during this
|
||||
// sync, so the caller can fan out only actually-changed worktrees.
|
||||
protected syncMobileSessionTabs(
|
||||
+11
-7
@@ -1,11 +1,15 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithWaitForMobileTerminalSurface } from './orca-runtime-wait-for-mobile-terminal-surface'
|
||||
import { runtimeWorktreeIdsEqual } from './runtime-worktree-path-identity'
|
||||
import { parsePaneKey } from '../../shared/stable-pane-id'
|
||||
import type { RuntimePtyWorktreeRecord } from './runtime-terminal-state-records'
|
||||
import type { RuntimeMobileSessionCreateTerminalResult } from '../../shared/runtime-types'
|
||||
import type { OrcaRuntimeWithWaitForLeafPtyId as WaitForLeafPtyIdMethods } from '../orca-runtime-wait-for-leaf-pty-id'
|
||||
import { OrcaRuntimeWithWaitForMobileTerminalSurface } from '../orca-runtime-wait-for-mobile-terminal-surface'
|
||||
import { runtimeWorktreeIdsEqual } from '../runtime-worktree-path-identity'
|
||||
import { parsePaneKey } from '../../../shared/stable-pane-id'
|
||||
import type { RuntimePtyWorktreeRecord } from '../runtime-terminal-state-records'
|
||||
import type { RuntimeMobileSessionCreateTerminalResult } from '../../../shared/runtime-types'
|
||||
|
||||
export abstract class OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals extends OrcaRuntimeWithWaitForMobileTerminalSurface {
|
||||
protected abstract resolveHandleForTab(
|
||||
...args: Parameters<WaitForLeafPtyIdMethods['resolveHandleForTab']>
|
||||
): ReturnType<WaitForLeafPtyIdMethods['resolveHandleForTab']>
|
||||
|
||||
export class OrcaRuntimeWithRestoreLivePairedRendererSessionOwnedMobileTerminals extends OrcaRuntimeWithWaitForMobileTerminalSurface {
|
||||
protected restoreLivePairedRendererSessionOwnedMobileTerminals(
|
||||
worktreeId: string | null,
|
||||
options: { missingSnapshotOnly?: boolean; notify?: boolean } = {}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { chatTabChangesMatchingIndex } from '../structured-agent-session-tab-index-seed'
|
||||
import { chatTabId, type ChatTabChange } from '../agent-session-tab-layout'
|
||||
import { structuredSessionTabRetired } from '../structured-worker-custody'
|
||||
import type { getStructuredAgentSessionHost } from '../../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
|
||||
type ChatTabOpen = Extract<ChatTabChange, { open: unknown }>['open']
|
||||
|
||||
/** Chat-tab changes that make each worktree's saved tabs match the restored sessions. */
|
||||
export function restoredChatTabChanges(
|
||||
savedTabsByWorktree: Parameters<typeof chatTabChangesMatchingIndex>[0],
|
||||
host: ReturnType<typeof getStructuredAgentSessionHost>,
|
||||
restored: readonly { workspaceId: string; sessionId: string; agent: ChatTabOpen['agent'] }[]
|
||||
): Map<string, ChatTabChange[]> {
|
||||
return chatTabChangesMatchingIndex(
|
||||
savedTabsByWorktree,
|
||||
restored.map((session) => ({
|
||||
worktreeId: session.workspaceId,
|
||||
open: {
|
||||
sessionId: session.sessionId,
|
||||
agent: session.agent,
|
||||
tabId: chatTabId(session.sessionId)
|
||||
}
|
||||
})),
|
||||
// A chat a newer Orca wrote is only unreadable here, so it keeps its tab.
|
||||
(sessionId) =>
|
||||
!!host &&
|
||||
structuredSessionTabRetired(host, sessionId) &&
|
||||
!host.deps?.store?.isSessionUnreadable?.(sessionId)
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type {
|
||||
RuntimeMobileSessionAgentTab,
|
||||
RuntimeMobileSessionTabGroup,
|
||||
RuntimeMobileSessionTabMove,
|
||||
RuntimeMobileSessionTabMoveResult,
|
||||
@@ -8,6 +9,8 @@ import type {
|
||||
import type { RuntimeMobileSessionSnapshotTab } from '../../../shared/runtime-mobile-session-tab-contracts'
|
||||
import type { TabGroupLayoutNode } from '../../../shared/tab-types'
|
||||
import { OrcaRuntimeService } from '../orca-runtime'
|
||||
import { setStructuredAgentSessionHost } from '../../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
import type { ResolvedWorktree } from '../runtime-worktree-path-identity'
|
||||
|
||||
function snapshot(): RuntimeMobileSessionTabsSnapshot {
|
||||
return {
|
||||
@@ -283,3 +286,326 @@ describe('original session tab runtime prototypes', () => {
|
||||
expect(topLevelId).toBe('tab')
|
||||
})
|
||||
})
|
||||
|
||||
class SessionRuntime extends OrcaRuntimeService {
|
||||
readonly refreshArgumentCounts: number[] = []
|
||||
readonly reloadRequests: number[] = []
|
||||
restoreRequests = 0
|
||||
restoreResult = Promise.resolve()
|
||||
|
||||
override async resolveWorktreeSelector(): Promise<ResolvedWorktree> {
|
||||
const git = {
|
||||
path: 'workspace',
|
||||
head: '',
|
||||
branch: 'selected',
|
||||
isBare: false,
|
||||
isMainWorktree: false
|
||||
}
|
||||
return {
|
||||
...git,
|
||||
git,
|
||||
id: 'workspace',
|
||||
repoId: 'repo',
|
||||
displayName: '',
|
||||
comment: '',
|
||||
linkedIssue: null,
|
||||
linkedPR: null,
|
||||
linkedLinearIssue: null,
|
||||
isArchived: false,
|
||||
isUnread: false,
|
||||
isPinned: false,
|
||||
sortOrder: 0,
|
||||
lastActivityAt: 0,
|
||||
parentWorktreeId: null,
|
||||
childWorktreeIds: [],
|
||||
lineage: null
|
||||
}
|
||||
}
|
||||
|
||||
protected override refreshMobileSessionPtyRecords(
|
||||
...args: Parameters<OrcaRuntimeService['refreshMobileSessionPtyRecords']>
|
||||
): Promise<Set<string> | null> {
|
||||
this.refreshArgumentCounts.push(args.length)
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
|
||||
protected override hydrateHeadlessMobileSessionTabsFromWorkspaceSession(): Set<string> {
|
||||
return new Set()
|
||||
}
|
||||
|
||||
protected override restoreLivePairedRendererSessionOwnedMobileTerminals(): void {}
|
||||
|
||||
protected override beginGraphReload(windowId: number): number {
|
||||
this.reloadRequests.push(windowId)
|
||||
return 77
|
||||
}
|
||||
|
||||
protected override hasPersistedStructuredAgentSessionStore(): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override prepareStructuredAgentSessionStartupRestoration(): Promise<void> {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
protected override restoreStructuredAgentSessionTabsOnce(): Promise<void> {
|
||||
this.restoreRequests += 1
|
||||
return this.restoreResult
|
||||
}
|
||||
|
||||
seedHeadlessSnapshot(snapshot: RuntimeMobileSessionTabsSnapshot): void {
|
||||
this.mobileSessionTabsByWorktree.set(snapshot.worktree, snapshot)
|
||||
}
|
||||
|
||||
setHostTabResolver(
|
||||
resolver: (snapshot: RuntimeMobileSessionTabsSnapshot, tabId: string) => string | null
|
||||
): void {
|
||||
this.resolveMobileSessionHostTabId = resolver
|
||||
}
|
||||
|
||||
restoreTabs(): Promise<void> {
|
||||
return this.restoreStructuredAgentSessionTabs()
|
||||
}
|
||||
|
||||
closeTab(tab: RuntimeMobileSessionAgentTab): Promise<void> {
|
||||
return this.closeStructuredAgentSessionTab(tab, 'user-close')
|
||||
}
|
||||
}
|
||||
|
||||
describe('session runtime reentry', () => {
|
||||
afterEach(() => setStructuredAgentSessionHost(null))
|
||||
|
||||
it('keeps omitted refresh arguments omitted after asynchronous workspace resolution', async () => {
|
||||
const runtime = new SessionRuntime()
|
||||
|
||||
await runtime.listMobileSessionTabs('selected')
|
||||
|
||||
expect(runtime.refreshArgumentCounts).toEqual([0])
|
||||
})
|
||||
|
||||
it('uses public methods replaced after construction', async () => {
|
||||
const runtime = new SessionRuntime()
|
||||
const list = vi.spyOn(runtime, 'listAllMobileSessionTabsWithChangeSequence').mockResolvedValue({
|
||||
snapshots: [],
|
||||
changeSequence: 73
|
||||
})
|
||||
const project = vi
|
||||
.spyOn(runtime, 'projectStructuredAgentSessionTab')
|
||||
.mockImplementation(() => {})
|
||||
const input = {
|
||||
workspaceId: 'workspace',
|
||||
sessionId: 'session',
|
||||
agent: 'claude',
|
||||
activate: false
|
||||
} satisfies Parameters<OrcaRuntimeService['publishStructuredAgentSessionTab']>[0]
|
||||
|
||||
await expect(runtime.listAllMobileSessionTabs('client')).resolves.toEqual([])
|
||||
await runtime.publishStructuredAgentSessionTab(input)
|
||||
|
||||
expect(list).toHaveBeenCalledExactlyOnceWith('client')
|
||||
expect(project).toHaveBeenCalledExactlyOnceWith(input)
|
||||
})
|
||||
|
||||
it('re-enters the protected graph reload override', () => {
|
||||
const runtime = new SessionRuntime()
|
||||
runtime.attachWindow(1)
|
||||
runtime.syncWindowGraph(1, { tabs: [], leaves: [] })
|
||||
|
||||
expect(runtime.markRendererReloading(1)).toEqual({ revision: 77, recovery: 'renderer' })
|
||||
expect(runtime.reloadRequests).toEqual([1])
|
||||
})
|
||||
|
||||
it('shares the protected asynchronous restoration operation', async () => {
|
||||
const runtime = new SessionRuntime()
|
||||
const gate = Promise.withResolvers<void>()
|
||||
runtime.restoreResult = gate.promise
|
||||
|
||||
const first = runtime.restoreTabs()
|
||||
const second = runtime.restoreTabs()
|
||||
|
||||
expect(first).toBe(second)
|
||||
expect(runtime.restoreRequests).toBe(1)
|
||||
gate.resolve()
|
||||
await first
|
||||
})
|
||||
|
||||
it('captures the headless callback before evaluating move arguments', async () => {
|
||||
const runtime = new SessionRuntime()
|
||||
const snapshot: RuntimeMobileSessionTabsSnapshot = {
|
||||
worktree: 'workspace',
|
||||
publicationEpoch: 'epoch',
|
||||
snapshotVersion: 1,
|
||||
activeGroupId: null,
|
||||
activeTabId: null,
|
||||
activeTabType: null,
|
||||
tabs: []
|
||||
}
|
||||
runtime.seedHeadlessSnapshot(snapshot)
|
||||
const first = vi.fn(function (
|
||||
this: OrcaRuntimeService,
|
||||
received: RuntimeMobileSessionTabsSnapshot,
|
||||
tabId: string
|
||||
) {
|
||||
expect(this).toBe(runtime)
|
||||
expect(received).toBe(snapshot)
|
||||
expect(tabId).toBe('tab')
|
||||
expect(arguments.length).toBe(2)
|
||||
return null
|
||||
})
|
||||
const replacement = vi.fn(function (
|
||||
this: OrcaRuntimeService,
|
||||
received: RuntimeMobileSessionTabsSnapshot,
|
||||
tabId: string
|
||||
) {
|
||||
expect(this).toBe(runtime)
|
||||
expect(received).toBe(snapshot)
|
||||
expect(tabId).toBe('tab')
|
||||
return null
|
||||
})
|
||||
runtime.setHostTabResolver(first)
|
||||
|
||||
await expect(
|
||||
runtime.moveMobileSessionTab('selected', {
|
||||
kind: 'reorder',
|
||||
get tabId() {
|
||||
runtime.setHostTabResolver(replacement)
|
||||
return 'tab'
|
||||
},
|
||||
targetGroupId: 'group',
|
||||
tabOrder: ['tab']
|
||||
})
|
||||
).rejects.toThrow('tab_not_found')
|
||||
|
||||
expect(first).toHaveBeenCalledExactlyOnceWith(snapshot, 'tab')
|
||||
expect(replacement).not.toHaveBeenCalled()
|
||||
await expect(
|
||||
runtime.moveMobileSessionTab('selected', {
|
||||
kind: 'reorder',
|
||||
tabId: 'tab',
|
||||
targetGroupId: 'group',
|
||||
tabOrder: ['tab']
|
||||
})
|
||||
).rejects.toThrow('tab_not_found')
|
||||
expect(replacement).toHaveBeenCalledExactlyOnceWith(snapshot, 'tab')
|
||||
})
|
||||
|
||||
it('captures the runtime callee before a tab getter replaces it', async () => {
|
||||
const runtime = new SessionRuntime()
|
||||
const first = vi.fn(function (this: OrcaRuntimeService, sessionId: string) {
|
||||
expect(this).toBe(runtime)
|
||||
expect(sessionId).toBe('session')
|
||||
return false
|
||||
})
|
||||
const replacement = vi.fn(() => false)
|
||||
runtime.retireStructuredAgentSessionTabFromSnapshot = first
|
||||
const tab: RuntimeMobileSessionAgentTab = {
|
||||
type: 'agent-session',
|
||||
id: 'agent-session:session',
|
||||
title: '',
|
||||
agent: 'claude',
|
||||
isActive: false,
|
||||
get sessionId() {
|
||||
runtime.retireStructuredAgentSessionTabFromSnapshot = replacement
|
||||
return 'session'
|
||||
}
|
||||
}
|
||||
|
||||
await runtime.closeTab(tab)
|
||||
|
||||
expect(first).toHaveBeenCalledOnce()
|
||||
expect(replacement).not.toHaveBeenCalled()
|
||||
await runtime.closeTab(tab)
|
||||
expect(replacement).toHaveBeenCalledExactlyOnceWith('session')
|
||||
})
|
||||
})
|
||||
|
||||
class GraphRuntime extends OrcaRuntimeService {
|
||||
get graphTabs() {
|
||||
return this.tabs
|
||||
}
|
||||
get graphLeaves() {
|
||||
return this.leaves
|
||||
}
|
||||
get graphLeavesByPtyId() {
|
||||
return this.leavesByPtyId
|
||||
}
|
||||
get graphAvailability() {
|
||||
return this.graphStatus
|
||||
}
|
||||
get graphEpoch() {
|
||||
return this.rendererGraphEpoch
|
||||
}
|
||||
get detachedLeaves() {
|
||||
return this.detachedPreAllocatedLeaves
|
||||
}
|
||||
get syncCallbacks() {
|
||||
return this.graphSyncCallbacks
|
||||
}
|
||||
}
|
||||
|
||||
const graph = {
|
||||
tabs: [{ tabId: 'tab', worktreeId: 'workspace', activeLeafId: 'leaf', layout: null, title: '' }],
|
||||
leaves: [
|
||||
{
|
||||
tabId: 'tab',
|
||||
worktreeId: 'workspace',
|
||||
leafId: 'leaf',
|
||||
paneRuntimeId: 1,
|
||||
ptyId: 'pty',
|
||||
paneTitle: null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
describe('runtime graph ownership', () => {
|
||||
it('shares detached preallocated leaves with terminal identity during renderer reload', async () => {
|
||||
const runtime = new GraphRuntime()
|
||||
const handle = runtime.preAllocateHandleForPty('pty')
|
||||
runtime.attachWindow(1)
|
||||
runtime.syncWindowGraph(1, graph)
|
||||
const leaf = runtime.graphLeaves.get('tab::leaf')
|
||||
|
||||
runtime.markRendererReloading(1)
|
||||
|
||||
expect(runtime.detachedLeaves.get('pty')).toBe(leaf)
|
||||
runtime.syncWindowGraph(1, { tabs: [], leaves: [] })
|
||||
runtime.onPtyData('pty', 'after omitted leaf\n', 100)
|
||||
await expect(runtime.readTerminal(handle)).resolves.toMatchObject({
|
||||
tail: ['after omitted leaf']
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps the installed graph and its PTY index in one per-runtime authority', () => {
|
||||
const first = new GraphRuntime()
|
||||
const second = new GraphRuntime()
|
||||
first.attachWindow(1)
|
||||
first.syncWindowGraph(1, graph)
|
||||
const leaf = first.graphLeavesByPtyId.get('pty')?.[0]
|
||||
expect(leaf).toBe(first.graphLeaves.get('tab::leaf'))
|
||||
expect(first.graphLeavesByPtyId.has('pty')).toBe(true)
|
||||
expect(second.graphLeavesByPtyId.has('pty')).toBe(false)
|
||||
expect(second.graphAvailability).toBe('unavailable')
|
||||
|
||||
first.markGraphUnavailable(1)
|
||||
expect(first.graphTabs.size).toBe(0)
|
||||
expect(first.graphLeaves.size).toBe(0)
|
||||
expect(first.graphLeavesByPtyId.has('pty')).toBe(false)
|
||||
expect(second.graphEpoch).toBe(0)
|
||||
})
|
||||
|
||||
it('drains the captured callback list when a callback changes registration', () => {
|
||||
const runtime = new GraphRuntime()
|
||||
runtime.attachWindow(1)
|
||||
const later = vi.fn()
|
||||
const original = vi.fn()
|
||||
runtime.syncCallbacks.push(() => {
|
||||
runtime.syncCallbacks.splice(1, 1)
|
||||
runtime.syncCallbacks.push(later)
|
||||
}, original)
|
||||
|
||||
runtime.syncWindowGraph(1, { tabs: [], leaves: [] })
|
||||
|
||||
expect(original).toHaveBeenCalledOnce()
|
||||
expect(later).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OrcaRuntimeWithCollectMobileVisibleGraphChangedWorktrees } from '../orca-runtime-collect-mobile-visible-graph-changed-worktrees'
|
||||
import { OrcaRuntimeWithCollectMobileVisibleGraphChangedWorktrees } from './session-tabs-inventory'
|
||||
|
||||
export abstract class RuntimeSessionTabsInventoryPublication extends OrcaRuntimeWithCollectMobileVisibleGraphChangedWorktrees {
|
||||
protected waitForSessionTabsInventoryPublication(signal?: AbortSignal): Promise<void> {
|
||||
|
||||
+78
-7
@@ -1,11 +1,82 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithSyncWindowGraph } from './orca-runtime-sync-window-graph'
|
||||
import type { RuntimeMobileSessionTabsResult, RuntimeSyncedTab } from '../../shared/runtime-types'
|
||||
import type { RuntimeLeafRecord } from './runtime-terminal-state-records'
|
||||
import type { PtyControllerInventory } from './runtime-pty-controller-contract'
|
||||
import { parseExecutionHostId } from '../../shared/execution-host'
|
||||
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 { 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'
|
||||
import type { OrcaRuntimeWithPruneMobileSessionTabGroupLayout as PruneMobileSessionTabGroupLayoutMethods } from '../orca-runtime-prune-mobile-session-tab-group-layout'
|
||||
import { OrcaRuntimeWithSyncWindowGraph } from '../session-graph/session-window-graph'
|
||||
import type {
|
||||
RuntimeMobileSessionTabsResult,
|
||||
RuntimeSyncedTab
|
||||
} from '../../../shared/runtime-types'
|
||||
import type { RuntimeLeafRecord } from '../runtime-terminal-state-records'
|
||||
import type { PtyControllerInventory } from '../runtime-pty-controller-contract'
|
||||
import { parseExecutionHostId } from '../../../shared/execution-host'
|
||||
|
||||
export abstract class OrcaRuntimeWithCollectMobileVisibleGraphChangedWorktrees extends OrcaRuntimeWithSyncWindowGraph {
|
||||
protected abstract getAuthoritativeSessionTabsInventoryEpoch(
|
||||
...args: Parameters<
|
||||
SessionTabsInventoryPublicationMethods['getAuthoritativeSessionTabsInventoryEpoch']
|
||||
>
|
||||
): ReturnType<SessionTabsInventoryPublicationMethods['getAuthoritativeSessionTabsInventoryEpoch']>
|
||||
|
||||
protected abstract getMobileSessionTabsForWorktree(
|
||||
...args: Parameters<ScheduleMobileSessionTabsChangedMethods['getMobileSessionTabsForWorktree']>
|
||||
): ReturnType<ScheduleMobileSessionTabsChangedMethods['getMobileSessionTabsForWorktree']>
|
||||
|
||||
protected abstract getValidatedExplicitWorktreeIdSelector(
|
||||
...args: Parameters<
|
||||
ResolveBrowserNetworkExecutionHostForWorktreeMethods['getValidatedExplicitWorktreeIdSelector']
|
||||
>
|
||||
): ReturnType<
|
||||
ResolveBrowserNetworkExecutionHostForWorktreeMethods['getValidatedExplicitWorktreeIdSelector']
|
||||
>
|
||||
|
||||
protected abstract hydrateHeadlessMobileSessionTabsFromWorkspaceSession(
|
||||
...args: Parameters<
|
||||
HydrateHeadlessMobileSessionTabsFromWorkspaceSessionMethods['hydrateHeadlessMobileSessionTabsFromWorkspaceSession']
|
||||
>
|
||||
): ReturnType<
|
||||
HydrateHeadlessMobileSessionTabsFromWorkspaceSessionMethods['hydrateHeadlessMobileSessionTabsFromWorkspaceSession']
|
||||
>
|
||||
|
||||
protected abstract projectMobileSessionTabsForClient(
|
||||
...args: Parameters<
|
||||
BuildHeadlessMobileSessionBrowserTabsMethods['projectMobileSessionTabsForClient']
|
||||
>
|
||||
): ReturnType<BuildHeadlessMobileSessionBrowserTabsMethods['projectMobileSessionTabsForClient']>
|
||||
|
||||
protected abstract refreshMobileSessionPtyInventory(
|
||||
...args: Parameters<
|
||||
BuildHeadlessMobileSessionBrowserTabsMethods['refreshMobileSessionPtyInventory']
|
||||
>
|
||||
): ReturnType<BuildHeadlessMobileSessionBrowserTabsMethods['refreshMobileSessionPtyInventory']>
|
||||
|
||||
protected abstract refreshMobileSessionPtyRecords(
|
||||
...args: Parameters<
|
||||
BuildHeadlessMobileSessionBrowserTabsMethods['refreshMobileSessionPtyRecords']
|
||||
>
|
||||
): ReturnType<BuildHeadlessMobileSessionBrowserTabsMethods['refreshMobileSessionPtyRecords']>
|
||||
|
||||
protected abstract restoreLivePairedRendererSessionOwnedMobileTerminals(
|
||||
...args: Parameters<
|
||||
RestoreLivePairedRendererSessionOwnedMobileTerminalsMethods['restoreLivePairedRendererSessionOwnedMobileTerminals']
|
||||
>
|
||||
): ReturnType<
|
||||
RestoreLivePairedRendererSessionOwnedMobileTerminalsMethods['restoreLivePairedRendererSessionOwnedMobileTerminals']
|
||||
>
|
||||
|
||||
protected abstract toMobileSessionTabsResult(
|
||||
...args: Parameters<PruneMobileSessionTabGroupLayoutMethods['toMobileSessionTabsResult']>
|
||||
): ReturnType<PruneMobileSessionTabGroupLayoutMethods['toMobileSessionTabsResult']>
|
||||
|
||||
protected abstract waitForSessionTabsInventoryPublication(
|
||||
...args: Parameters<
|
||||
SessionTabsInventoryPublicationMethods['waitForSessionTabsInventoryPublication']
|
||||
>
|
||||
): ReturnType<SessionTabsInventoryPublicationMethods['waitForSessionTabsInventoryPublication']>
|
||||
|
||||
export class OrcaRuntimeWithCollectMobileVisibleGraphChangedWorktrees extends OrcaRuntimeWithSyncWindowGraph {
|
||||
// Why: toMobileSessionTabsResult resolves handles/titles from this.tabs and
|
||||
// this.leaves, so any tab/leaf delta a graph sync installs can flip the
|
||||
// client payload (pending-handle → ready, tab title) with zero change to the
|
||||
+30
-22
@@ -1,34 +1,42 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { agentSessionRefusalError } from '../../shared/agent-session-wire-refusals'
|
||||
import { OrcaRuntimeWithGetWorktreePs } from './orca-runtime-get-worktree-ps'
|
||||
import { getStructuredAgentSessionHost } from '../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
import type { OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce as RestoreStructuredAgentSessionTabsOnceMethods } from './structured-session-tab-restoration'
|
||||
import { agentSessionRefusalError } from '../../../shared/agent-session-wire-refusals'
|
||||
import { OrcaRuntimeWithGetWorktreePs } from '../orca-runtime-get-worktree-ps'
|
||||
import { getStructuredAgentSessionHost } from '../../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
import {
|
||||
resolveCommittedStructuredAgentSessionAdoptionIntent,
|
||||
resolveStructuredAgentSessionAdoptionForCreate
|
||||
} from './structured-agent-session-create-adoption'
|
||||
import { isNativeLocalLocation, LOCAL_EXECUTION_HOST_ID } from '../../shared/execution-host'
|
||||
import { getLocalProjectWorktreeGitOptions } from '../project-runtime-git-options'
|
||||
import type { AgentSessionAttachParams } from '../native-chat/agent-session-wire/structured-agent-session-attach'
|
||||
} from '../structured-agent-session-create-adoption'
|
||||
import { isNativeLocalLocation, LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host'
|
||||
import { getLocalProjectWorktreeGitOptions } from '../../project-runtime-git-options'
|
||||
import type { AgentSessionAttachParams } from '../../native-chat/agent-session-wire/structured-agent-session-attach'
|
||||
import {
|
||||
resolveHostStructuredAgentCreateSupport,
|
||||
resolveHostStructuredAgentLaunchEnvironment
|
||||
} from './structured-agent-launch-support'
|
||||
import { structuredAgentRuntimeRegistration } from './structured-agent-runtime-registrations'
|
||||
import { structuredLaunchSeedOptions } from '../../shared/native-chat-session-option-defaults'
|
||||
import { hasPersistedStructuredAgentSessionStore as hasPersistedStructuredAgentSessionStoreOnDisk } from './structured-agent-session-runtime'
|
||||
import { ensureStructuredAgentSessionHostUnlessRefused } from './structured-agent-session-host-refusal'
|
||||
import { getProfileUserDataPath } from '../orca-profiles/profile-storage-paths'
|
||||
import { parseWslUncPath } from '../../shared/wsl-paths'
|
||||
} from '../structured-agent-launch-support'
|
||||
import { structuredAgentRuntimeRegistration } from '../structured-agent-runtime-registrations'
|
||||
import { structuredLaunchSeedOptions } from '../../../shared/native-chat-session-option-defaults'
|
||||
import { hasPersistedStructuredAgentSessionStore as hasPersistedStructuredAgentSessionStoreOnDisk } from '../structured-agent-session-runtime'
|
||||
import { ensureStructuredAgentSessionHostUnlessRefused } from '../structured-agent-session-host-refusal'
|
||||
import { getProfileUserDataPath } from '../../orca-profiles/profile-storage-paths'
|
||||
import { parseWslUncPath } from '../../../shared/wsl-paths'
|
||||
import {
|
||||
isFloatingWorkspaceId,
|
||||
isFloatingWorkspaceSelector
|
||||
} from '../../shared/floating-workspace-worktree'
|
||||
import { parseWorkspaceKey } from '../../shared/workspace-scope'
|
||||
import type { AgentSessionAccountHome } from '../../shared/agent-session-account-home'
|
||||
import type { StructuredAgentId } from '../../shared/agent-session-provider-handle'
|
||||
import { readPiSessionHeader, samePiDirectory } from '../pi/rpc-launch-resolution'
|
||||
} from '../../../shared/floating-workspace-worktree'
|
||||
import { parseWorkspaceKey } from '../../../shared/workspace-scope'
|
||||
import type { AgentSessionAccountHome } from '../../../shared/agent-session-account-home'
|
||||
import type { StructuredAgentId } from '../../../shared/agent-session-provider-handle'
|
||||
import { readPiSessionHeader, samePiDirectory } from '../../pi/rpc-launch-resolution'
|
||||
|
||||
export abstract class OrcaRuntimeWithGetStructuredAgentSessionCreateSupport extends OrcaRuntimeWithGetWorktreePs {
|
||||
protected abstract restoreStructuredAgentSessionTabsOnce(
|
||||
...args: Parameters<
|
||||
RestoreStructuredAgentSessionTabsOnceMethods['restoreStructuredAgentSessionTabsOnce']
|
||||
>
|
||||
): ReturnType<
|
||||
RestoreStructuredAgentSessionTabsOnceMethods['restoreStructuredAgentSessionTabsOnce']
|
||||
>
|
||||
|
||||
export class OrcaRuntimeWithGetStructuredAgentSessionCreateSupport extends OrcaRuntimeWithGetWorktreePs {
|
||||
async getStructuredAgentSessionCreateSupport(
|
||||
worktreeSelector: string,
|
||||
agent: StructuredAgentId
|
||||
@@ -270,7 +278,7 @@ export class OrcaRuntimeWithGetStructuredAgentSessionCreateSupport extends OrcaR
|
||||
providerHandle: {
|
||||
transport: definition.handleTransport,
|
||||
agent: definition.agent,
|
||||
nativeId: transcriptImport.handleNamesTranscript
|
||||
nativeId: transcriptImport!.handleNamesTranscript
|
||||
? adoption.transcriptPath
|
||||
: input.resumeFrom.providerSessionId
|
||||
},
|
||||
+36
-17
@@ -1,27 +1,46 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithCloseMobileSessionTab } from './orca-runtime-close-mobile-session-tab'
|
||||
import type { OrcaRuntimeWithPruneMobileSessionTabGroupLayout as PruneMobileSessionTabGroupLayoutMethods } from '../orca-runtime-prune-mobile-session-tab-group-layout'
|
||||
import type { RuntimeHeadlessTabGroups as HeadlessTabGroupsMethods } from './headless-tab-group-moves'
|
||||
import { OrcaRuntimeWithCloseMobileSessionTab } from '../orca-runtime-close-mobile-session-tab'
|
||||
import type {
|
||||
BrowserTabInfo,
|
||||
RuntimeMobileSessionAgentTab,
|
||||
RuntimeMobileSessionBrowserTab,
|
||||
RuntimeMobileSessionRetiredTerminalSurface,
|
||||
RuntimeMobileSessionTabsSnapshot,
|
||||
RuntimeMobileSessionTerminalTab
|
||||
} from '../../shared/runtime-types'
|
||||
import type { RuntimePtyWorktreeRecord } from './runtime-terminal-state-records'
|
||||
import { getMobileSessionSnapshotTabIdentityKeys } from './mobile-session-tab-merge'
|
||||
import type { BrowserSessionTabSelectionOptions } from './browser-tab-create-publication'
|
||||
import { getRuntimeBrowserPageRegistry } from './runtime-browser-page-registry'
|
||||
import { applyBrowserSessionTabSelection } from './browser-session-tab-selection-snapshot'
|
||||
import { getStructuredAgentSessionHost } from '../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
import type { StructuredAgentSessionCloseCause } from '../native-chat/agent-session-wire/structured-agent-session-host-lifetime'
|
||||
import { retireStructuredAgentSessionTabFrom } from './structured-agent-session-tab-retirement'
|
||||
import { chatTabId, withChatTabChanges, type ChatTabChange } from './agent-session-tab-layout'
|
||||
import { savedSessionId } from './saved-structured-agent-session-restoration'
|
||||
import { LOCAL_EXECUTION_HOST_ID } from '../../shared/execution-host'
|
||||
import { structuredSessionTabRetired } from './structured-worker-custody'
|
||||
import type { StructuredAgentId } from '../../shared/agent-session-provider-handle'
|
||||
} from '../../../shared/runtime-types'
|
||||
import type { RuntimePtyWorktreeRecord } from '../runtime-terminal-state-records'
|
||||
import { getMobileSessionSnapshotTabIdentityKeys } from '../mobile-session-tab-merge'
|
||||
import type { BrowserSessionTabSelectionOptions } from '../browser-tab-create-publication'
|
||||
import { getRuntimeBrowserPageRegistry } from '../runtime-browser-page-registry'
|
||||
import { applyBrowserSessionTabSelection } from '../browser-session-tab-selection-snapshot'
|
||||
import { getStructuredAgentSessionHost } from '../../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
import type { StructuredAgentSessionCloseCause } from '../../native-chat/agent-session-wire/structured-agent-session-host-lifetime'
|
||||
import { retireStructuredAgentSessionTabFrom } from '../structured-agent-session-tab-retirement'
|
||||
import { chatTabId, withChatTabChanges, type ChatTabChange } from '../agent-session-tab-layout'
|
||||
import { savedSessionId } from '../saved-structured-agent-session-restoration'
|
||||
import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host'
|
||||
import { structuredSessionTabRetired } from '../structured-worker-custody'
|
||||
import type { StructuredAgentId } from '../../../shared/agent-session-provider-handle'
|
||||
|
||||
export abstract class OrcaRuntimeWithCloseStructuredAgentSessionTab extends OrcaRuntimeWithCloseMobileSessionTab {
|
||||
protected abstract getListedBrowserTabsByPageId(worktreeId: string): Map<string, BrowserTabInfo>
|
||||
protected abstract findPtyForMobileTerminalTab(
|
||||
...args: Parameters<PruneMobileSessionTabGroupLayoutMethods['findPtyForMobileTerminalTab']>
|
||||
): ReturnType<PruneMobileSessionTabGroupLayoutMethods['findPtyForMobileTerminalTab']>
|
||||
|
||||
protected abstract getMobileTerminalLeafPtyIds(
|
||||
...args: Parameters<PruneMobileSessionTabGroupLayoutMethods['getMobileTerminalLeafPtyIds']>
|
||||
): ReturnType<PruneMobileSessionTabGroupLayoutMethods['getMobileTerminalLeafPtyIds']>
|
||||
|
||||
protected abstract getMobileTerminalPaneKey(
|
||||
...args: Parameters<PruneMobileSessionTabGroupLayoutMethods['getMobileTerminalPaneKey']>
|
||||
): ReturnType<PruneMobileSessionTabGroupLayoutMethods['getMobileTerminalPaneKey']>
|
||||
|
||||
protected abstract persistHeadlessTabGroups(
|
||||
...args: Parameters<HeadlessTabGroupsMethods['persistHeadlessTabGroups']>
|
||||
): ReturnType<HeadlessTabGroupsMethods['persistHeadlessTabGroups']>
|
||||
|
||||
export class OrcaRuntimeWithCloseStructuredAgentSessionTab extends OrcaRuntimeWithCloseMobileSessionTab {
|
||||
protected async closeStructuredAgentSessionTab(
|
||||
tab: RuntimeMobileSessionAgentTab,
|
||||
cause: StructuredAgentSessionCloseCause
|
||||
+36
-41
@@ -1,46 +1,46 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { defaultAgentChatLabel } from '../../shared/agent-session-chat-label'
|
||||
import { OrcaRuntimeWithGetStructuredAgentSessionCreateSupport } from './orca-runtime-get-structured-agent-session-create-support'
|
||||
import { getStructuredAgentSessionHost } from '../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
import { collectSavedStructuredAgentSessionIds } from './saved-structured-agent-session-restoration'
|
||||
import {
|
||||
chatTabChangesMatchingIndex,
|
||||
seedStructuredAgentSessionTabIndex
|
||||
} from './structured-agent-session-tab-index-seed'
|
||||
import { chatTabId } from './agent-session-tab-layout'
|
||||
import { structuredSessionTabRetired } from './structured-worker-custody'
|
||||
import { LOCAL_EXECUTION_HOST_ID } from '../../shared/execution-host'
|
||||
import type { OrcaRuntimeWithScheduleMobileSessionTabsChanged as ScheduleMobileSessionTabsChangedMethods } from '../orca-runtime-schedule-mobile-session-tabs-changed'
|
||||
import { defaultAgentChatLabel } from '../../../shared/agent-session-chat-label'
|
||||
import { OrcaRuntimeWithGetStructuredAgentSessionCreateSupport } from './structured-session-create-support'
|
||||
import { getStructuredAgentSessionHost } from '../../native-chat/agent-session-wire/structured-agent-session-registry'
|
||||
import { collectSavedStructuredAgentSessionIds } from '../saved-structured-agent-session-restoration'
|
||||
import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host'
|
||||
import { seedStructuredAgentSessionTabIndex } from '../structured-agent-session-tab-index-seed'
|
||||
import { restoredChatTabChanges } from './restored-chat-tab-changes'
|
||||
import type {
|
||||
RuntimeMobileSessionAgentTab,
|
||||
RuntimeMobileSessionTabsSnapshot,
|
||||
RuntimeRepoSearchRefs
|
||||
} from '../../shared/runtime-types'
|
||||
import { getHeadlessMobileSessionGroupId } from './mobile-session-layout-projection'
|
||||
import { DEFAULT_REPO_SEARCH_REFS_LIMIT } from './orca-runtime-postlude'
|
||||
import type { Repo } from '../../shared/repo-types'
|
||||
import type { GitAdmissionTier } from '../git/command-runner/git-exec-options'
|
||||
} from '../../../shared/runtime-types'
|
||||
import { getHeadlessMobileSessionGroupId } from '../mobile-session-layout-projection'
|
||||
import { DEFAULT_REPO_SEARCH_REFS_LIMIT } from '../orca-runtime-postlude'
|
||||
import type { Repo } from '../../../shared/repo-types'
|
||||
import type { GitAdmissionTier } from '../../git/command-runner/git-exec-options'
|
||||
import {
|
||||
getLocalProjectGhExecOptions,
|
||||
type LocalProjectGhExecOptions
|
||||
} from '../project-runtime-git-options'
|
||||
} from '../../project-runtime-git-options'
|
||||
import {
|
||||
agentLaunchPlatformForScope,
|
||||
newWorktreeLaunchScope,
|
||||
resolveAgentLaunchRuntime,
|
||||
resolveStartupAgentLaunchRuntime
|
||||
} from './agent-launch-scope-runtime'
|
||||
import type { TuiAgent } from '../../shared/tui-agent'
|
||||
import type { AgentLaunchRuntime } from '../../shared/agent-launch-runtime'
|
||||
import type { TerminalWorkspaceLaunchScope } from './runtime-legacy-worker-terminal-recovery-types'
|
||||
import { parseAppSshPtyId } from '../../shared/ssh-pty-id'
|
||||
import type { PtyProcessInspection } from '../providers/pty-process-inspection'
|
||||
import type { StructuredAgentId } from '../../shared/agent-session-provider-handle'
|
||||
} from '../agent-launch-scope-runtime'
|
||||
import type { TuiAgent } from '../../../shared/tui-agent'
|
||||
import type { AgentLaunchRuntime } from '../../../shared/agent-launch-runtime'
|
||||
import type { TerminalWorkspaceLaunchScope } from '../runtime-legacy-worker-terminal-recovery-types'
|
||||
import { parseAppSshPtyId } from '../../../shared/ssh-pty-id'
|
||||
import type { PtyProcessInspection } from '../../providers/pty-process-inspection'
|
||||
import type { StructuredAgentId } from '../../../shared/agent-session-provider-handle'
|
||||
|
||||
export type AgentLaunchScope = Parameters<
|
||||
OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce['getAgentLaunchPlatformForWorkspace']
|
||||
>[0]
|
||||
|
||||
export class OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce extends OrcaRuntimeWithGetStructuredAgentSessionCreateSupport {
|
||||
export abstract class OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce extends OrcaRuntimeWithGetStructuredAgentSessionCreateSupport {
|
||||
protected abstract notifyMobileSessionTabSnapshots(
|
||||
...args: Parameters<ScheduleMobileSessionTabsChangedMethods['notifyMobileSessionTabSnapshots']>
|
||||
): ReturnType<ScheduleMobileSessionTabsChangedMethods['notifyMobileSessionTabSnapshots']>
|
||||
|
||||
protected async restoreStructuredAgentSessionTabsOnce(): Promise<void> {
|
||||
await this.prepareStructuredAgentSessionStartupRestoration()
|
||||
const host = getStructuredAgentSessionHost()
|
||||
@@ -73,21 +73,10 @@ export class OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce extends OrcaRu
|
||||
targets,
|
||||
restored.map((session) => session.sessionId)
|
||||
)
|
||||
const changes = chatTabChangesMatchingIndex(
|
||||
const changes = restoredChatTabChanges(
|
||||
this.store?.getWorkspaceSession?.(LOCAL_EXECUTION_HOST_ID)?.unifiedTabs ?? {},
|
||||
restored.map((session) => ({
|
||||
worktreeId: session.workspaceId,
|
||||
open: {
|
||||
sessionId: session.sessionId,
|
||||
agent: session.agent,
|
||||
tabId: chatTabId(session.sessionId)
|
||||
}
|
||||
})),
|
||||
// A chat a newer Orca wrote is only unreadable here, so it keeps its tab.
|
||||
(sessionId) =>
|
||||
!!host &&
|
||||
structuredSessionTabRetired(host, sessionId) &&
|
||||
!host.deps?.store?.isSessionUnreadable?.(sessionId)
|
||||
host,
|
||||
restored
|
||||
)
|
||||
for (const [worktreeId, worktreeChanges] of changes) {
|
||||
this.changeWindowlessChatTabs(worktreeId, worktreeChanges)
|
||||
@@ -301,7 +290,13 @@ export class OrcaRuntimeWithRestoreStructuredAgentSessionTabsOnce extends OrcaRu
|
||||
connectionId?: string | null
|
||||
}
|
||||
): NodeJS.Platform {
|
||||
return agentLaunchPlatformForScope(this.requireStore(), scope)
|
||||
// Orchestration passes a repo-only scope; the platform never reads its id or folder.
|
||||
return agentLaunchPlatformForScope(this.requireStore(), {
|
||||
id: '',
|
||||
folderWorkspace: null,
|
||||
...scope,
|
||||
connectionId: scope.connectionId ?? null
|
||||
})
|
||||
}
|
||||
|
||||
protected resolveAgentLaunchRuntime(
|
||||
+16
-11
@@ -1,14 +1,18 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithTouchMobileSessionTabsForWorktree } from './orca-runtime-touch-mobile-session-tabs-for-worktree'
|
||||
import type { RetiredTerminalSurface } from './mobile-session-terminal-retirement'
|
||||
import type { RuntimeMobileSessionRetiredTerminalSurface } from '../../shared/runtime-types'
|
||||
import { LOCAL_EXECUTION_HOST_ID } from '../../shared/execution-host'
|
||||
import { retireTerminalSurfaceFromPersistence } from './mobile-session-terminal-persistence-retirement'
|
||||
import { retireTerminalSurfacesFromSnapshot } from './mobile-session-terminal-retirement'
|
||||
import { attachRetirementProofsToSnapshot } from './mobile-session-terminal-retirement-proof'
|
||||
import { getRepoIdFromWorktreeId } from '../../shared/worktree/id'
|
||||
import type { OrcaRuntimeWithBindPtyIncarnationHandle as BindPtyIncarnationHandleMethods } from '../terminal/identity/terminal-handle-bindings'
|
||||
import { OrcaRuntimeWithTouchMobileSessionTabsForWorktree } from '../orca-runtime-touch-mobile-session-tabs-for-worktree'
|
||||
import type { RetiredTerminalSurface } from '../mobile-session-terminal-retirement'
|
||||
import type { RuntimeMobileSessionRetiredTerminalSurface } from '../../../shared/runtime-types'
|
||||
import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host'
|
||||
import { retireTerminalSurfaceFromPersistence } from '../mobile-session-terminal-persistence-retirement'
|
||||
import { retireTerminalSurfacesFromSnapshot } from '../mobile-session-terminal-retirement'
|
||||
import { attachRetirementProofsToSnapshot } from '../mobile-session-terminal-retirement-proof'
|
||||
import { getRepoIdFromWorktreeId } from '../../../shared/worktree/id'
|
||||
|
||||
export abstract class OrcaRuntimeWithPersistTerminalSurfaceRetirements extends OrcaRuntimeWithTouchMobileSessionTabsForWorktree {
|
||||
protected abstract findHandleForPtyRecord(
|
||||
...args: Parameters<BindPtyIncarnationHandleMethods['findHandleForPtyRecord']>
|
||||
): ReturnType<BindPtyIncarnationHandleMethods['findHandleForPtyRecord']>
|
||||
|
||||
export class OrcaRuntimeWithPersistTerminalSurfaceRetirements extends OrcaRuntimeWithTouchMobileSessionTabsForWorktree {
|
||||
/**
|
||||
* Retires each surface in the in-memory session partition of the host that owns its worktree.
|
||||
* Why: an SSH pane's durable surface lives in that connection's partition; retiring it
|
||||
@@ -34,7 +38,8 @@ export class OrcaRuntimeWithPersistTerminalSurfaceRetirements extends OrcaRuntim
|
||||
continue
|
||||
}
|
||||
try {
|
||||
this.store.setWorkspaceSession(next, hostId)
|
||||
// The existing catch handles a missing store setter.
|
||||
this.store!.setWorkspaceSession!(next, hostId)
|
||||
accepted.push(surface)
|
||||
} catch (error) {
|
||||
// Why: the process is gone whether or not the profile admits the write (quit, maintenance).
|
||||
+9
-7
@@ -1,11 +1,13 @@
|
||||
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
|
||||
import { OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory } from './orca-runtime-refresh-pty-worktree-records-with-controller-inventory'
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../shared/constants'
|
||||
import { indexFloatingSnapshotPtyBindings } from './floating-snapshot-pty-bindings'
|
||||
import type { RuntimeLeafRecord, RuntimePtyWorktreeRecord } from './runtime-terminal-state-records'
|
||||
import { DISCONNECTED_PTY_RECORD_MAX } from './orca-runtime-postlude'
|
||||
import { OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory } from '../../orca-runtime-refresh-pty-worktree-records-with-controller-inventory'
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../../shared/constants'
|
||||
import { indexFloatingSnapshotPtyBindings } from '../../floating-snapshot-pty-bindings'
|
||||
import type {
|
||||
RuntimeLeafRecord,
|
||||
RuntimePtyWorktreeRecord
|
||||
} from '../../runtime-terminal-state-records'
|
||||
import { DISCONNECTED_PTY_RECORD_MAX } from '../../orca-runtime-postlude'
|
||||
|
||||
export class OrcaRuntimeWithRefreshFloatingWorkspacePtyLiveness extends OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory {
|
||||
export abstract class OrcaRuntimeWithRefreshFloatingWorkspacePtyLiveness extends OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory {
|
||||
protected refreshFloatingWorkspacePtyLiveness(): Set<string> | null {
|
||||
const controller = this.ptyController
|
||||
if (!controller?.hasPty) {
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
TerminalWaitStatusEvidence
|
||||
} from './terminal-wait-permission'
|
||||
|
||||
import type { AgentLaunchScope } from '../../orca-runtime-restore-structured-agent-session-tabs-once'
|
||||
import type { AgentLaunchScope } from '../../session-tabs/structured-session-tab-restoration'
|
||||
import { withTimeout } from '../../runtime-async-boundaries'
|
||||
import { TERMINAL_INTERACTIVE_WAIT_PROBE_TIMEOUT_MS } from '../../orca-runtime-core'
|
||||
import { parsePaneKey } from '../../../../shared/stable-pane-id'
|
||||
|
||||
@@ -186,7 +186,7 @@ export abstract class RuntimeWorkspaceSelectors extends OrcaRuntimeWithResolveBr
|
||||
throw new Error('repo_not_found')
|
||||
}
|
||||
|
||||
protected requireStore(): RuntimeStore {
|
||||
requireStore(): RuntimeStore {
|
||||
if (!this.store) {
|
||||
throw new Error('runtime_unavailable')
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const UNSUPPORTED_TUI_AGENT_ARGS: Partial<Record<TuiAgent, readonly string[]>> =
|
||||
|
||||
export const DEFAULT_TUI_AGENT_ARGS: Partial<Record<TuiAgent, string>> = YOLO_TUI_AGENT_ARGS
|
||||
|
||||
export const DEFAULT_TUI_AGENT_ENV: Partial<Record<TuiAgent, Record<string, string>>> =
|
||||
export const DEFAULT_TUI_AGENT_ENV: Partial<Record<string, Record<string, string>>> =
|
||||
YOLO_TUI_AGENT_ENV
|
||||
|
||||
function argPattern(arg: string): RegExp {
|
||||
@@ -111,7 +111,7 @@ export function getTuiAgentDefaultArgs(agent: TuiAgent): string {
|
||||
return DEFAULT_TUI_AGENT_ARGS[agent] ?? ''
|
||||
}
|
||||
|
||||
export function getTuiAgentDefaultEnv(agent: TuiAgent): Record<string, string> {
|
||||
export function getTuiAgentDefaultEnv(agent: string): Record<string, string> {
|
||||
return { ...DEFAULT_TUI_AGENT_ENV[agent] }
|
||||
}
|
||||
|
||||
@@ -160,8 +160,8 @@ export function resolvedTuiAgentArgsBypassPermissions(
|
||||
}
|
||||
|
||||
export function resolveTuiAgentLaunchEnv(
|
||||
agent: TuiAgent,
|
||||
configuredEnv: Partial<Record<TuiAgent, Record<string, string>>> | null | undefined
|
||||
agent: string,
|
||||
configuredEnv: Partial<Record<string, Record<string, string>>> | null | undefined
|
||||
): Record<string, string> {
|
||||
if (configuredEnv && Object.hasOwn(configuredEnv, agent)) {
|
||||
return { ...configuredEnv[agent] }
|
||||
|
||||
Reference in New Issue
Block a user