diff --git a/src/renderer/src/components/native-chat/native-chat-image-runtime-context.test.ts b/src/renderer/src/components/native-chat/native-chat-image-runtime-context.test.ts index 9f1eecd143b..cfda20998fa 100644 --- a/src/renderer/src/components/native-chat/native-chat-image-runtime-context.test.ts +++ b/src/renderer/src/components/native-chat/native-chat-image-runtime-context.test.ts @@ -66,4 +66,31 @@ describe('resolveNativeChatImageRuntimeContext', () => { expect(second?.settings).toBe(first?.settings) expect(shallow(second, first)).toBe(true) }) + + it('derives a runtime host from an owner-only route during paired hydration', () => { + const storeState = state() + const ownerOnlyWorktree = { + id: 'wt-1', + repoId: 'repo', + path: '/repo/worktree', + runtimeOwnerEnvironmentId: 'owner-a' + } + const ownerState = { + ...storeState, + activeWorktreeId: null, + activeWorkspaceExecutionHostId: null, + getKnownWorktreeById: () => ownerOnlyWorktree, + worktreesByRepo: { repo: [ownerOnlyWorktree] }, + runtimeEnvironments: [{ id: 'owner-a' }] + } as unknown as AppState + + const context = resolveNativeChatImageRuntimeContext(ownerState, 'tab-1') + + expect(context).toMatchObject({ + worktreeId: 'wt-1', + worktreePath: '/repo/worktree', + expectedExecutionHostId: 'local', + settings: { activeRuntimeEnvironmentId: 'owner-a' } + }) + }) }) diff --git a/src/renderer/src/components/native-chat/native-chat-image-runtime-context.ts b/src/renderer/src/components/native-chat/native-chat-image-runtime-context.ts index 933f903b072..600c5b63c1d 100644 --- a/src/renderer/src/components/native-chat/native-chat-image-runtime-context.ts +++ b/src/renderer/src/components/native-chat/native-chat-image-runtime-context.ts @@ -7,7 +7,11 @@ import { } from '@/lib/worktree-operation-route' import { resolveNativeChatFileLinkContext } from './native-chat-file-link' import { captureDirectSshMutationExpectation } from '@/lib/ssh-mutation-expectation' -import { parseExecutionHostId, type ExecutionHostId } from '../../../../shared/execution-host' +import { + parseExecutionHostId, + toRuntimeExecutionHostId, + type ExecutionHostId +} from '../../../../shared/execution-host' import { parseWorkspaceKey } from '../../../../shared/workspace-scope' import { useMemo } from 'react' import { useShallow } from 'zustand/react/shallow' @@ -130,15 +134,21 @@ export function resolveNativeChatImageRuntimeContext( return null } const routeResolution = resolveWorktreeOperationRouteResult(state, linkContext.worktreeId) - if (routeResolution.kind !== 'resolved' || !routeResolution.route.executionHostId) { + if (routeResolution.kind !== 'resolved') { return null } const route = routeResolution.route - const worktreePath = resolvePath(state, linkContext.worktreeId, route.executionHostId) + const executionHostId = + route.executionHostId ?? + (route.runtimeEnvironmentId ? toRuntimeExecutionHostId(route.runtimeEnvironmentId) : null) + if (!executionHostId) { + return null + } + const worktreePath = resolvePath(state, linkContext.worktreeId, executionHostId) if (!worktreePath) { return null } - const host = parseExecutionHostId(route.executionHostId) + const host = parseExecutionHostId(executionHostId) if (!host) { return null }