refactor(execution-host): one connection-to-host helper (#26929)

Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
This commit is contained in:
OrcaWin
2026-10-09 11:45:37 -07:00
committed by GitHub
co-authored by m4air
parent cbc6f54e1c
commit 54b623b6a3
26 changed files with 72 additions and 125 deletions
@@ -1,7 +1,6 @@
import {
LOCAL_EXECUTION_HOST_ID,
getConnectionExecutionHostId,
parseExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../shared/execution-host'
import type { FolderWorkspace } from '../../shared/folder-workspace-types'
@@ -96,8 +95,7 @@ function resolveDeclaredExecutionHost(owner: ExecutionHostOwner): ExecutionHostI
if (owner.executionHostId?.trim()) {
return parseExecutionHostId(owner.executionHostId)?.id ?? null
}
const connectionId = owner.connectionId?.trim()
return connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
return getConnectionExecutionHostId(owner.connectionId?.trim())
}
/** Resolve persisted workspace ownership; unknown provenance is not local authority. */
@@ -1,8 +1,7 @@
import { ptyOwnership } from '../provider/ownership-state'
import { getProvider, localProvider, registeredPtyProviders } from '../provider/registry'
import {
LOCAL_EXECUTION_HOST_ID,
toSshExecutionHostId,
getConnectionExecutionHostId,
type ExecutionHostId
} from '../../../../shared/execution-host'
import type { PtyProcessInfo } from '../../../providers/pty-process-info'
@@ -27,9 +26,7 @@ export async function listProcessesWithHostScopeFromRuntimeController(
): Promise<{ processes: PtyProcessInfo[]; hostIds: ExecutionHostId[] }> {
const providerSessions = await Promise.all(
registeredPtyProviders().map(async ({ provider, connectionId }) => {
const hostId: ExecutionHostId = connectionId
? toSshExecutionHostId(connectionId)
: LOCAL_EXECUTION_HOST_ID
const hostId = getConnectionExecutionHostId(connectionId)
try {
return {
processes: await (connectionId ? provider.listProcesses(opts) : provider.listProcesses()),
@@ -14,7 +14,7 @@ import {
} from '../../project-groups/nested-repo-import'
import { createNestedRepoImportTargetResolver } from '../../project-groups/nested-repo-import-target'
import { getSshGitProvider } from '../../providers/ssh-git-dispatch'
import { LOCAL_EXECUTION_HOST_ID, toSshExecutionHostId } from '../../../shared/execution-host'
import { getConnectionExecutionHostId } from '../../../shared/execution-host'
import { detectRepoIconAndUpstream } from '../../repo-icon-autodetect'
import { prepareLocalWorktreeRootForRepo } from '../../worktree-root-preparation'
import { getActiveMultiplexer } from '../ssh'
@@ -123,9 +123,7 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store
const detected = await detectRepoIconAndUpstream({
repoPath: importRepoPath,
kind: 'git',
executionHostId: args.connectionId
? toSshExecutionHostId(args.connectionId)
: LOCAL_EXECUTION_HOST_ID
executionHostId: getConnectionExecutionHostId(args.connectionId)
})
const repo: Repo = {
id: randomUUID(),
@@ -3,9 +3,8 @@ import { awaitRuntimeFileWatcherUnsubscribes, RuntimeFileCommands } from './orca
import { resetSshConnectionGenerations } from '../ssh/ssh-connection-generation'
import { resetRuntimeFileMocks } from './orca-runtime-files-mock-registry'
import {
LOCAL_EXECUTION_HOST_ID,
getConnectionExecutionHostId,
normalizeExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../shared/execution-host'
@@ -61,10 +60,7 @@ export function createRuntimeFileCommands(options?: {
// Mirrors the real resolver: the worktree's own host outranks the repo row.
const runtimeFileTargetExecutionHostId = (): ExecutionHostId => {
const connectionId = store.getRepo(worktree.repoId)?.connectionId
return (
normalizeExecutionHostId(options?.hostId) ??
(connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID)
)
return normalizeExecutionHostId(options?.hostId) ?? getConnectionExecutionHostId(connectionId)
}
const commands = new RuntimeFileCommands({
getRuntimeId: () => 'runtime-1',
@@ -2,11 +2,7 @@
import { OrcaRuntimeWithResolveKnownWorkspaceFileTarget } from './orca-runtime-resolve-known-workspace-file-target'
import type { PtyIncarnationId } from '../../shared/pty-incarnation'
import { getPtyExecutionHost } from '../../shared/terminal-execution-host'
import {
LOCAL_EXECUTION_HOST_ID,
parseExecutionHostId,
toSshExecutionHostId
} from '../../shared/execution-host'
import { getConnectionExecutionHostId, parseExecutionHostId } from '../../shared/execution-host'
export class OrcaRuntimeWithInvalidateAllHandlesForPty extends OrcaRuntimeWithResolveKnownWorkspaceFileTarget {
protected invalidateAllHandlesForPty(ptyId: string, preserveHandle?: string): Set<string> {
@@ -128,8 +124,7 @@ export class OrcaRuntimeWithInvalidateAllHandlesForPty extends OrcaRuntimeWithRe
}
const connection =
connectionId === undefined ? this.ptysById.get(ptyId)?.connectionId : connectionId
const providerKey =
hostId ?? (connection ? toSshExecutionHostId(connection) : LOCAL_EXECUTION_HOST_ID)
const providerKey = hostId ?? getConnectionExecutionHostId(connection)
// A pending census predates this admission or exit, including legacy IDs without an incarnation.
this.ptyControllerInventoryGenerationByProvider.set(providerKey, generation)
}
@@ -9,8 +9,8 @@ import type {
import type { ResolvedWorktree } from './runtime-worktree-path-identity'
import type { Repo } from '../../shared/repo-types'
import {
getConnectionExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
toSshExecutionHostId,
type ExecutionHostId
} from '../../shared/execution-host'
import { getLocalProjectWorktreeGitOptions } from '../project-runtime-git-options'
@@ -214,9 +214,7 @@ export class OrcaRuntimeWithPersistHeadlessTerminalTitle extends OrcaRuntimeWith
// ambiguous one, and it is never hosted by a runtime environment.
return {
worktree: this.folderWorkspaceToResolvedWorktree(folderScope.folderWorkspace),
executionHostId: folderScope.connectionId
? toSshExecutionHostId(folderScope.connectionId)
: LOCAL_EXECUTION_HOST_ID
executionHostId: getConnectionExecutionHostId(folderScope.connectionId)
}
}
@@ -4,6 +4,7 @@ import type { ResolvedWorktree } from './runtime-worktree-path-identity'
import type * as PtyControllerContract from './runtime-pty-controller-contract'
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../shared/constants'
import {
getConnectionExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
parseExecutionHostId,
toSshExecutionHostId
@@ -55,7 +56,7 @@ export class OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory ext
return null
}
const inventoryGeneration = ++this.ptyControllerInventorySequence
const providerKey = connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
const providerKey = getConnectionExecutionHostId(connectionId)
const livenessObservationAtStart = this.ptyLivenessObservationSequence
if (connectionId === undefined) {
this.ptyControllerAggregateInventoryGeneration = inventoryGeneration
@@ -150,7 +151,7 @@ export class OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory ext
parseAppSshPtyId(session.id)?.connectionId ??
(typeof connectionId === 'string' ? connectionId : null)
const persistedIndexes = getPersistedIndexes(
sessionConnectionId ? toSshExecutionHostId(sessionConnectionId) : LOCAL_EXECUTION_HOST_ID
getConnectionExecutionHostId(sessionConnectionId)
)
const controllerIdentity = controllerIdentityByPtyId.get(session.id)
const persistedWorktreeId = persistedIndexes.worktreeIdByPtyId.get(session.id)
@@ -243,8 +244,7 @@ export class OrcaRuntimeWithRefreshPtyWorktreeRecordsWithControllerInventory ext
const ptyHostId =
encodedHostId === 'foreign'
? null
: (encodedHostId ??
(pty.connectionId ? toSshExecutionHostId(pty.connectionId) : LOCAL_EXECUTION_HOST_ID))
: (encodedHostId ?? getConnectionExecutionHostId(pty.connectionId))
if (!ptyHostId) {
continue
}
@@ -1,8 +1,8 @@
// @ts-nocheck -- mechanically split from OrcaRuntimeService; behavior is covered by AST equivalence and characterization tests.
import { OrcaRuntimeWithPersistHeadlessTerminalTitle } from './orca-runtime-persist-headless-terminal-title'
import {
getConnectionExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
toSshExecutionHostId,
type ExecutionHostId
} from '../../shared/execution-host'
import type { ResolvedWorktree } from './runtime-worktree-path-identity'
@@ -57,9 +57,7 @@ export class OrcaRuntimeWithResolveKnownWorkspaceFileTarget extends OrcaRuntimeW
const worktree = this.folderWorkspaceToResolvedWorktree(folderWorkspace)
const target = {
worktree,
executionHostId: candidateConnectionId
? toSshExecutionHostId(candidateConnectionId)
: LOCAL_EXECUTION_HOST_ID
executionHostId: getConnectionExecutionHostId(candidateConnectionId)
}
targets.set(`${target.executionHostId}\0${worktree.id}`, target)
} catch {
@@ -1,5 +1,5 @@
import { parseAppSshPtyId } from '../../shared/ssh-pty-id'
import { LOCAL_EXECUTION_HOST_ID, toSshExecutionHostId } from '../../shared/execution-host'
import { getConnectionExecutionHostId } from '../../shared/execution-host'
import { getPtyExecutionHost } from '../../shared/terminal-execution-host'
import type { RuntimeLegacyWorkerTerminalRecoveryController } from './runtime-legacy-worker-terminal-recovery-controller'
import {
@@ -104,9 +104,7 @@ export async function runLegacyWorkerTerminalRecovery(
).values()
]
const inventory = await ports.refreshInventory(resolvedWorktrees, provider.connectionId)
const hostId = provider.connectionId
? toSshExecutionHostId(provider.connectionId)
: LOCAL_EXECUTION_HOST_ID
const hostId = getConnectionExecutionHostId(provider.connectionId)
if (!inventory || !inventory.queriedHostIds.has(hostId)) {
provider.entries.forEach(({ candidate }) => deferredDispatchIds.add(candidate.dispatchId))
continue
@@ -2,12 +2,12 @@ import { homedir } from 'node:os'
import { getWslHome } from '../wsl'
import { parseWslUncPath } from '../../shared/wsl-paths'
import {
type ExecutionHostId,
getConnectionExecutionHostId,
getRepoExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
normalizeExecutionHostId,
parseExecutionHostId,
toSshExecutionHostId
type ExecutionHostId
} from '../../shared/execution-host'
import { getRepoIdFromWorktreeId } from '../../shared/worktree/id'
import type { IPtyProvider } from '../providers/types'
@@ -124,7 +124,7 @@ export function folderExecutionHostId(folder: {
}): ExecutionHostId {
return (
normalizeExecutionHostId(folder.executionHostId) ??
(folder.connectionId ? toSshExecutionHostId(folder.connectionId) : LOCAL_EXECUTION_HOST_ID)
getConnectionExecutionHostId(folder.connectionId)
)
}
@@ -1,8 +1,8 @@
import {
LOCAL_EXECUTION_HOST_ID,
getConnectionExecutionHostId,
getRepoExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
parseExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../shared/execution-host'
import type { FolderWorkspace } from '../../shared/folder-workspace-types'
@@ -43,8 +43,7 @@ export class RuntimeWorkspaceSessionController {
}
return parsedHostId
}
const connectionId = this.deps.resolveFolderConnectionId(workspace)
return connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
return getConnectionExecutionHostId(this.deps.resolveFolderConnectionId(workspace))
}
const resolvedWorktreeId = scope?.type === 'worktree' ? scope.worktreeId : worktreeId
const repo = store?.getRepo?.(getRepoIdFromWorktreeId(resolvedWorktreeId))
@@ -156,11 +155,7 @@ export class RuntimeWorkspaceSessionController {
? (parseExecutionHostId(workspace.executionHostId)?.id ?? null)
: null
const connectionId = explicitHostId ? null : this.deps.resolveFolderConnectionId(workspace)
return [
workspace.id,
explicitHostId ??
(connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID)
] as const
return [workspace.id, explicitHostId ?? getConnectionExecutionHostId(connectionId)] as const
})
)
const hostIds = new Set<ExecutionHostId>(['local'])
+2 -2
View File
@@ -1,5 +1,5 @@
import { randomBytes } from 'node:crypto'
import { toSshExecutionHostId } from '../../shared/execution-host'
import { getConnectionExecutionHostId } from '../../shared/execution-host'
const SESSION_COUNTER_BITS = 13
const SESSION_COUNTER_STRIDE = 2 ** SESSION_COUNTER_BITS
@@ -105,7 +105,7 @@ export function assertSshMutationExpectation(
expectedGeneration: number | undefined,
expectedExecutionHostId?: string
): void {
const actualExecutionHostId = connectionId ? toSshExecutionHostId(connectionId) : 'local'
const actualExecutionHostId = getConnectionExecutionHostId(connectionId)
if (expectedExecutionHostId !== undefined && expectedExecutionHostId !== actualExecutionHostId) {
throw new Error('Workspace host changed; refresh and try again')
}
@@ -2,7 +2,7 @@ import { findIndexedRepoOwnerForHost } from '@/lib/worktree-runtime-owner-index'
import { getRemoteRuntimePtyEnvironmentId } from '@/runtime/runtime-terminal-stream'
import type { AgentStatusEntry } from '../../../../shared/agent-status-types'
import {
LOCAL_EXECUTION_HOST_ID,
getConnectionExecutionHostId,
toRuntimeExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
@@ -126,7 +126,7 @@ function resolveActivityExecutionHostId(
return toRuntimeExecutionHostId(runtimeEnvironmentId)
}
if (entry.connectionId !== undefined) {
return entry.connectionId ? toSshExecutionHostId(entry.connectionId) : LOCAL_EXECUTION_HOST_ID
return getConnectionExecutionHostId(entry.connectionId)
}
const connectionId = parseAppSshPtyId(terminalPtyId ?? '')?.connectionId
return connectionId ? toSshExecutionHostId(connectionId) : undefined
@@ -9,9 +9,9 @@ import { translate } from '@/i18n/i18n'
import { extractIpcErrorMessage } from '@/lib/ipc-error'
import { findKnownWorktreeById } from '@/store/slices/worktrees/listing/detected-worktree-meta'
import {
getConnectionExecutionHostId,
parseExecutionHostId,
toRuntimeExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../../../shared/execution-host'
import { getConnectionIdFromState } from '@/lib/connection-context'
@@ -106,9 +106,7 @@ export function resolveNativeChatAttachmentHost(
}
const hostId = runtimeId
? toRuntimeExecutionHostId(runtimeId)
: connectionId
? toSshExecutionHostId(connectionId)
: 'local'
: getConnectionExecutionHostId(connectionId)
return findKnownWorktreeById(state, worktreeId, hostId) ? hostId : null
}
@@ -9,10 +9,9 @@ import {
} from '../../../../shared/new-workspace/workspace-source'
import { isPathInsideOrEqual } from '../../../../shared/cross-platform-path'
import {
getConnectionExecutionHostId,
getRepoExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
normalizeExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../../../shared/execution-host'
import { getProjectGroupSubtreeIds } from '../../../../shared/project-groups'
@@ -33,9 +32,7 @@ function getProjectGroupExecutionHostId(projectGroup: ProjectGroup): ExecutionHo
if (executionHostId) {
return executionHostId
}
return projectGroup.connectionId
? toSshExecutionHostId(projectGroup.connectionId)
: LOCAL_EXECUTION_HOST_ID
return getConnectionExecutionHostId(projectGroup.connectionId)
}
export function getFolderSourceRepos(
@@ -1,5 +1,6 @@
import {
ALL_EXECUTION_HOSTS_SCOPE,
getConnectionExecutionHostId,
normalizeExecutionHostId,
parseExecutionHostId,
toSshExecutionHostId,
@@ -110,7 +111,7 @@ function getProjectGroupExecutionHostIdForFolderPathStatus(
if (executionHostId) {
return executionHostId
}
return group.connectionId ? toSshExecutionHostId(group.connectionId) : 'local'
return getConnectionExecutionHostId(group.connectionId)
}
export function getFolderPathStatusRouteOptionsForRows({
@@ -1,4 +1,4 @@
import { toSshExecutionHostId } from '../../../../shared/execution-host'
import { getConnectionExecutionHostId } from '../../../../shared/execution-host'
import { attachIpcPty } from './ipc-pty-attach'
import { connectIpcPty } from './ipc-pty-connect'
import { createIpcPtySessionHandlers } from './ipc-pty-session-handlers'
@@ -296,7 +296,7 @@ export function createIpcPtyTransport(opts: IpcPtyTransportOptions = {}): PtyTra
isConnected: () => connected,
getPtyId: () => ptyId,
getConnectionId: () => connectionId ?? null,
getExecutionHostId: () => (connectionId ? toSshExecutionHostId(connectionId) : 'local'),
getExecutionHostId: () => getConnectionExecutionHostId(connectionId),
getRuntimeEnvironmentId: () => null,
getLocalSessionMetadata: () =>
connectionId
@@ -16,9 +16,8 @@ import {
type TerminalFileContext
} from './terminal-file-path-mapping'
import {
LOCAL_EXECUTION_HOST_ID,
getConnectionExecutionHostId,
toRuntimeExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../../../shared/execution-host'
import { statUserOpenedPath } from '@/lib/user-opened-local-path'
@@ -231,9 +230,7 @@ export function openDetectedFilePath(
const runtimeOwnerId = fileContext.settings?.activeRuntimeEnvironmentId?.trim()
const executionHostId = runtimeOwnerId
? toRuntimeExecutionHostId(runtimeOwnerId)
: fileContext.connectionId
? toSshExecutionHostId(fileContext.connectionId)
: LOCAL_EXECUTION_HOST_ID
: getConnectionExecutionHostId(fileContext.connectionId)
const siblingRoute = findWorkspaceFileRoute(store, executionHostId, mappedFilePath)
if (siblingRoute) {
targetWorktreeId = siblingRoute.worktreeId
+2 -4
View File
@@ -1,8 +1,8 @@
import {
getConnectionExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
normalizeExecutionHostId,
parseExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../../shared/execution-host'
@@ -13,9 +13,7 @@ export function resolveJiraSourceHostId(args: {
}): ExecutionHostId {
const groupHostId =
normalizeExecutionHostId(args.groupExecutionHostId) ??
(args.groupConnectionId
? toSshExecutionHostId(args.groupConnectionId)
: LOCAL_EXECUTION_HOST_ID)
getConnectionExecutionHostId(args.groupConnectionId)
const hostId = normalizeExecutionHostId(args.workspaceHostId) ?? groupHostId
return parseExecutionHostId(hostId)?.kind === 'ssh' ? LOCAL_EXECUTION_HOST_ID : hostId
}
@@ -4,12 +4,7 @@ import type { Project, ProjectHostSetup } from '../../../shared/project-types'
import type { Repo } from '../../../shared/repo-types'
import { isClipboardTextByteLengthOverLimit } from '../../../shared/clipboard-text'
import type { ExecutionHostRegistryEntry } from '../../../shared/execution-host-registry'
import {
LOCAL_EXECUTION_HOST_ID,
parseExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../../shared/execution-host'
import { getRepoExecutionHostId, type ExecutionHostId } from '../../../shared/execution-host'
import {
getDuplicateProjectDetailsById,
type ProjectSetupDirectory
@@ -154,12 +149,7 @@ function getProjectGroupDetail(group: ProjectGroup): string {
}
export function getNewWorkspaceProjectGroupHostId(group: ProjectGroup): ExecutionHostId {
const executionHost = parseExecutionHostId(group.executionHostId)
if (executionHost) {
return executionHost.id
}
const connectionId = group.connectionId?.trim()
return connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
return getRepoExecutionHostId(group)
}
/**
@@ -6,7 +6,6 @@ import {
getRepoExecutionHostId,
parseExecutionHostId,
toRuntimeExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../../shared/execution-host'
@@ -58,12 +57,7 @@ export function getCatalogOwnerHostId(owner: {
connectionId?: string | null
executionHostId?: string | null
}): ExecutionHostId {
const explicitHost = parseExecutionHostId(owner.executionHostId)
if (explicitHost) {
return explicitHost.id
}
const connectionId = owner.connectionId?.trim()
return connectionId ? toSshExecutionHostId(connectionId) : 'local'
return getRepoExecutionHostId(owner)
}
function buildCatalogOwnerIndex<
@@ -1,10 +1,9 @@
import type { GlobalSettings } from '../../../../shared/global-settings-types'
import type { ProjectGroup } from '../../../../shared/project-group-types'
import {
getRepoExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
normalizeExecutionHostId,
parseExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../../../../shared/execution-host'
import { findIndexedProjectGroupOwner } from '@/lib/worktree-runtime-owner-index'
@@ -21,12 +20,7 @@ type ProjectGroupOwnerRoutingState = {
// Why: persisted rows predate host stamping and may carry padded/unparseable ids; normalize so
// routing and catalog identity agree on the same owner host.
export function getProjectGroupHostId(group: ProjectGroupHostParts): ExecutionHostId {
const executionHostId = normalizeExecutionHostId(group.executionHostId)
if (executionHostId) {
return executionHostId
}
const connectionId = group.connectionId?.trim()
return connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
return getRepoExecutionHostId(group)
}
export function catalogOwnsHost(catalogHostId: string, rowHostId: string): boolean {
+7
View File
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'
import {
ALL_EXECUTION_HOSTS_SCOPE,
LOCAL_EXECUTION_HOST_ID,
getConnectionExecutionHostId,
getExecutionHostLabel,
getLocalExecutionHostLabel,
getRepoExecutionHostId,
@@ -97,6 +98,12 @@ describe('execution host identity', () => {
)
})
it('maps a legacy connection id to its host without trimming it', () => {
expect(getConnectionExecutionHostId(null)).toBe('local')
expect(getConnectionExecutionHostId('')).toBe('local')
expect(getConnectionExecutionHostId('a b')).toBe('ssh:a%20b')
})
it('derives repo ownership from SSH connection ids', () => {
expect(getRepoExecutionHostId({ connectionId: null })).toBe(LOCAL_EXECUTION_HOST_ID)
expect(getRepoExecutionHostId({ connectionId: 'ssh-target-1' })).toBe('ssh:ssh-target-1')
+8 -2
View File
@@ -54,6 +54,13 @@ export function toSshExecutionHostId(targetId: string): `ssh:${string}` {
return `ssh:${encodeURIComponent(targetId)}`
}
/** Legacy `connectionId` spelling: absent means this machine, present means that SSH target. */
export function getConnectionExecutionHostId(
connectionId: string | null | undefined
): ExecutionHostId {
return connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
}
export function toRuntimeExecutionHostId(environmentId: string): `runtime:${string}` {
return `runtime:${encodeURIComponent(environmentId)}`
}
@@ -165,8 +172,7 @@ export function getRepoExecutionHostId(repo: {
if (executionHostId) {
return executionHostId
}
const connectionId = normalizeHostPart(repo.connectionId)
return connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
return getConnectionExecutionHostId(normalizeHostPart(repo.connectionId))
}
export function getSshTargetIdForExecutionHost(
+6 -5
View File
@@ -1,7 +1,11 @@
import type { FolderWorkspace } from './folder-workspace-types'
import type { Worktree } from './worktree/types'
import { folderWorkspaceKey } from './workspace-scope'
import { parseExecutionHostId, toSshExecutionHostId, type ExecutionHostId } from './execution-host'
import {
getConnectionExecutionHostId,
parseExecutionHostId,
type ExecutionHostId
} from './execution-host'
import { composeWorktreeHostIdentity } from './worktree/host-qualified-identity'
import { normalizeWorkspaceCreatorProvenance } from './workspace-creator-provenance'
import { getWorkspaceAttachments } from './workspace-attachments'
@@ -32,10 +36,7 @@ export function projectGroupIdFromRepoId(repoId: string | null | undefined): str
function getFolderWorkspaceWorktreeHostId(
workspace: Pick<FolderWorkspace, 'executionHostId' | 'connectionId'>
): ExecutionHostId {
return (
workspace.executionHostId ??
(workspace.connectionId ? toSshExecutionHostId(workspace.connectionId) : 'local')
)
return workspace.executionHostId ?? getConnectionExecutionHostId(workspace.connectionId)
}
export function getFolderWorkspaceHostIdentity(
+3 -12
View File
@@ -1,10 +1,10 @@
import {
getRepoExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
type ExecutionHostId,
normalizeExecutionHostId,
parseExecutionHostId,
toRuntimeExecutionHostId,
toSshExecutionHostId
type ExecutionHostId
} from './execution-host'
import {
areTaskProviderIdentitiesEqual,
@@ -113,7 +113,7 @@ export function buildTaskSourceContextFromRepo(args: {
return normalizeTaskSourceContext({
provider: args.provider,
projectId: args.projectId,
hostId: getRepoHostId(args.repo),
hostId: getRepoExecutionHostId(args.repo),
repoId: args.repo.id,
projectHostSetupId: args.projectHostSetupId,
providerIdentity: args.providerIdentity,
@@ -195,15 +195,6 @@ export function buildWorkspaceRunContext(args: {
}
}
function getRepoHostId(repo: Pick<Repo, 'connectionId' | 'executionHostId'>): ExecutionHostId {
const explicit = normalizeExecutionHostId(repo.executionHostId)
if (explicit) {
return explicit
}
const connectionId = normalizeNonEmptyString(repo.connectionId)
return connectionId ? toSshExecutionHostId(connectionId) : LOCAL_EXECUTION_HOST_ID
}
function normalizeTaskProvider(value: unknown): TaskProvider | null {
switch (value) {
case 'github':