mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 00:03:15 +00:00
fix: resolve terminal surface host from the runtime owner when no physical host is published
hasRenderableTerminalWorktreeSurface returned false whenever the route had no executionHostId, which is the normal shape for a paired-HUB row that only carries runtimeOwnerEnvironmentId. Focused creates and reveals on such rows would fail closed with worktree_hidden even though the sidebar row exists. Share one catalog-host resolver between the surface check and the import path.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { hasRenderableTerminalWorktreeSurface as hasTerminalWorktreeRow } from '@/lib/terminal-worktree-route'
|
||||
import {
|
||||
hasRenderableTerminalWorktreeSurface as hasTerminalWorktreeRow,
|
||||
resolveTerminalWorktreeCatalogHostId
|
||||
} from '@/lib/terminal-worktree-route'
|
||||
import { importNewExternalWorktreeInboxPaths } from '@/components/sidebar/new-external-worktrees-inbox-actions'
|
||||
import { resolveWorktreeOperationRoute } from '@/lib/worktree-operation-route'
|
||||
import { findRepoForHost, getRepoHostIdentity } from '@/store/slices/repo-host-identity'
|
||||
import { getRepoIdFromWorktreeId } from '@/store/slices/worktree-helpers'
|
||||
import {
|
||||
@@ -22,10 +24,7 @@ export async function ensureTerminalWorktreeVisible(worktreeId: string): Promise
|
||||
if (hasTerminalWorktreeRow(state, worktreeId)) {
|
||||
return
|
||||
}
|
||||
const route = resolveWorktreeOperationRoute(state, worktreeId)
|
||||
const hostId = route?.runtimeEnvironmentId
|
||||
? (`runtime:${encodeURIComponent(route.runtimeEnvironmentId)}` as const)
|
||||
: route?.executionHostId
|
||||
const hostId = resolveTerminalWorktreeCatalogHostId(state, worktreeId)
|
||||
if (!hostId) {
|
||||
throw hiddenTerminalWorktreeError()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../shared/constants'
|
||||
import { isEphemeralSetupTerminalWorktreeId } from '../../../shared/ephemeral-setup-terminal-worktree-id'
|
||||
import { parseExecutionHostId } from '../../../shared/execution-host'
|
||||
import {
|
||||
parseExecutionHostId,
|
||||
toRuntimeExecutionHostId,
|
||||
type ExecutionHostId
|
||||
} from '../../../shared/execution-host'
|
||||
import { parseWorkspaceKey } from '../../../shared/workspace-scope'
|
||||
import type { AppState } from '@/store/types'
|
||||
import { getIndexedWorktreesById } from '@/store/worktree-repo-index'
|
||||
@@ -24,6 +28,21 @@ export type TerminalWorktreeRoute = {
|
||||
runtimeEnvironmentId: string | null
|
||||
}
|
||||
|
||||
/** The catalog host whose rows can render this worktree, or null when ownership is unresolved. */
|
||||
export function resolveTerminalWorktreeCatalogHostId(
|
||||
state: AppState,
|
||||
worktreeId: string
|
||||
): ExecutionHostId | null {
|
||||
const route = resolveWorktreeOperationRoute(state, worktreeId)
|
||||
if (!route) {
|
||||
return null
|
||||
}
|
||||
// Why: a paired-HUB row can publish only its environment owner, leaving the physical host null.
|
||||
return route.runtimeEnvironmentId
|
||||
? toRuntimeExecutionHostId(route.runtimeEnvironmentId)
|
||||
: route.executionHostId
|
||||
}
|
||||
|
||||
export function hasRenderableTerminalWorktreeSurface(
|
||||
state: AppState,
|
||||
worktreeId: string | null | undefined
|
||||
@@ -41,15 +60,11 @@ export function hasRenderableTerminalWorktreeSurface(
|
||||
)
|
||||
}
|
||||
// Only the workbench's row index can host new tabs; detected rows and inline setup ids cannot.
|
||||
const route = resolveWorktreeOperationRoute(state, worktreeId)
|
||||
const hostId = route?.executionHostId
|
||||
if (!hostId) {
|
||||
const catalogHostId = resolveTerminalWorktreeCatalogHostId(state, worktreeId)
|
||||
if (!catalogHostId) {
|
||||
return false
|
||||
}
|
||||
const repoId = getRepoIdFromWorktreeId(worktreeId)
|
||||
const catalogHostId = route.runtimeEnvironmentId
|
||||
? (`runtime:${encodeURIComponent(route.runtimeEnvironmentId)}` as const)
|
||||
: hostId
|
||||
const matchOptions = worktreeHostMatchOptions(state, repoId, catalogHostId)
|
||||
return state.worktreesByRepo
|
||||
? getIndexedWorktreesById(state.worktreesByRepo, worktreeId).some((row) =>
|
||||
|
||||
@@ -28,6 +28,16 @@ describe('hasRenderableTerminalWorktreeSurface', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('accepts a paired-runtime row that carries only its environment owner', () => {
|
||||
const store = state({
|
||||
repos: [{ id: 'repo-1', executionHostId: 'runtime:hub' }],
|
||||
worktreesByRepo: {
|
||||
'repo-1': [{ id: 'repo-1::/workspace', repoId: 'repo-1', runtimeOwnerEnvironmentId: 'hub' }]
|
||||
}
|
||||
} as unknown as Partial<AppState>)
|
||||
expect(hasRenderableTerminalWorktreeSurface(store, 'repo-1::/workspace')).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects a hidden detected worktree even when its repo is registered', () => {
|
||||
const store = state({
|
||||
detectedWorktreesByRepo: {
|
||||
|
||||
Reference in New Issue
Block a user