mirror of
https://github.com/stablyai/orca.git
synced 2026-10-02 00:02:05 +00:00
202 lines
6.5 KiB
TypeScript
202 lines
6.5 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import type { AppState } from '@/store/types'
|
|
import type * as localPreflightContext from '@/lib/local-preflight-context'
|
|
import type { ProjectExecutionRuntimeResolution } from '../../../shared/project-execution-runtime'
|
|
import { canUseStructuredNativeChat } from './structured-native-chat-availability'
|
|
|
|
const { mockGetRendererAppPlatform } = vi.hoisted(() => ({
|
|
mockGetRendererAppPlatform: vi.fn<() => NodeJS.Platform>(() => 'darwin')
|
|
}))
|
|
|
|
vi.mock('@/lib/renderer-app-platform', () => ({
|
|
getRendererAppPlatform: mockGetRendererAppPlatform
|
|
}))
|
|
|
|
type GetLocalProjectExecutionRuntimeContext =
|
|
typeof localPreflightContext.getLocalProjectExecutionRuntimeContext
|
|
|
|
const projectRuntimeMock = vi.hoisted(() => ({
|
|
fn: vi.fn<GetLocalProjectExecutionRuntimeContext>(),
|
|
actual: undefined as GetLocalProjectExecutionRuntimeContext | undefined
|
|
}))
|
|
|
|
vi.mock('@/lib/local-preflight-context', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof localPreflightContext>()
|
|
projectRuntimeMock.actual = actual.getLocalProjectExecutionRuntimeContext
|
|
return { ...actual, getLocalProjectExecutionRuntimeContext: projectRuntimeMock.fn }
|
|
})
|
|
|
|
const wslRuntimeResolution: ProjectExecutionRuntimeResolution = {
|
|
status: 'resolved',
|
|
runtime: {
|
|
kind: 'wsl',
|
|
hostPlatform: 'wsl',
|
|
projectId: 'repo-1',
|
|
distro: 'Ubuntu',
|
|
reason: 'project-override',
|
|
cacheKey: 'repo-1|wsl|Ubuntu'
|
|
}
|
|
}
|
|
|
|
const repairRequiredResolution: ProjectExecutionRuntimeResolution = {
|
|
status: 'repair-required',
|
|
repair: {
|
|
projectId: 'repo-1',
|
|
preferredRuntime: { kind: 'wsl', distro: null },
|
|
reason: 'wsl-distro-required',
|
|
source: 'project-override',
|
|
cacheKey: 'repo-1|wsl|repair'
|
|
}
|
|
}
|
|
|
|
function stateFor(input: {
|
|
connectionId?: string | null
|
|
windowsRuntime?: 'windows-host' | 'wsl'
|
|
worktreePath?: string
|
|
}): AppState {
|
|
return {
|
|
activeRepoId: 'repo-1',
|
|
activeWorktreeId: 'wt-1',
|
|
projects: [
|
|
{
|
|
id: 'repo-1',
|
|
localWindowsRuntimePreference:
|
|
input.windowsRuntime === 'wsl'
|
|
? { kind: 'wsl', distro: 'Ubuntu' }
|
|
: { kind: 'windows-host' }
|
|
}
|
|
],
|
|
repos: [{ id: 'repo-1', connectionId: input.connectionId ?? null, path: 'C:\\repo' }],
|
|
settings: { experimentalStructuredNativeChat: true, openAgentTabsInChatByDefault: true },
|
|
worktreesByRepo: {
|
|
'repo-1': [
|
|
{
|
|
id: 'wt-1',
|
|
repoId: 'repo-1',
|
|
projectId: 'repo-1',
|
|
path: input.worktreePath ?? 'C:\\repo\\worktree'
|
|
}
|
|
]
|
|
},
|
|
detectedWorktreesByRepo: {}
|
|
} as unknown as AppState
|
|
}
|
|
|
|
describe('canUseStructuredNativeChat', () => {
|
|
beforeEach(() => {
|
|
mockGetRendererAppPlatform.mockReturnValue('darwin')
|
|
projectRuntimeMock.fn.mockReset()
|
|
projectRuntimeMock.fn.mockImplementation((...args) => {
|
|
if (!projectRuntimeMock.actual) {
|
|
throw new Error('real getLocalProjectExecutionRuntimeContext was never captured')
|
|
}
|
|
return projectRuntimeMock.actual(...args)
|
|
})
|
|
})
|
|
|
|
it('allows the structured stack on a local worktree', () => {
|
|
expect(canUseStructuredNativeChat(stateFor({}), 'wt-1')).toBe(true)
|
|
})
|
|
|
|
it('keeps the legacy bridge when the updated runtime is opted out', () => {
|
|
expect(
|
|
canUseStructuredNativeChat(
|
|
{
|
|
...stateFor({}),
|
|
settings: {
|
|
experimentalStructuredNativeChat: false,
|
|
openAgentTabsInChatByDefault: true
|
|
}
|
|
} as AppState,
|
|
'wt-1'
|
|
)
|
|
).toBe(false)
|
|
})
|
|
|
|
it('refuses a stale structured opt-in while the default view is Terminal chat', () => {
|
|
expect(
|
|
canUseStructuredNativeChat(
|
|
{
|
|
...stateFor({}),
|
|
settings: {
|
|
experimentalStructuredNativeChat: true,
|
|
openAgentTabsInChatByDefault: false
|
|
}
|
|
} as AppState,
|
|
'wt-1'
|
|
)
|
|
).toBe(false)
|
|
})
|
|
|
|
it('refuses a structured opt-in when the default view was never chosen', () => {
|
|
expect(
|
|
canUseStructuredNativeChat(
|
|
{ ...stateFor({}), settings: { experimentalStructuredNativeChat: true } } as AppState,
|
|
'wt-1'
|
|
)
|
|
).toBe(false)
|
|
})
|
|
|
|
it('refuses an SSH worktree so the pane stays on the bridge', () => {
|
|
expect(canUseStructuredNativeChat(stateFor({ connectionId: 'ssh-a' }), 'wt-1')).toBe(false)
|
|
})
|
|
|
|
it('refuses a runtime-paired worktree so the pane stays on the bridge', () => {
|
|
expect(canUseStructuredNativeChat(stateFor({ connectionId: 'runtime-ssh-a' }), 'wt-1')).toBe(
|
|
false
|
|
)
|
|
})
|
|
|
|
it('refuses a WSL project on Windows so the pane stays on the bridge', () => {
|
|
mockGetRendererAppPlatform.mockReturnValue('win32')
|
|
expect(canUseStructuredNativeChat(stateFor({ windowsRuntime: 'wsl' }), 'wt-1')).toBe(false)
|
|
})
|
|
|
|
it('allows Windows-host projects when structured chat is enabled', () => {
|
|
mockGetRendererAppPlatform.mockReturnValue('win32')
|
|
expect(canUseStructuredNativeChat(stateFor({ windowsRuntime: 'windows-host' }), 'wt-1')).toBe(true)
|
|
})
|
|
|
|
it('refuses a Windows folder workspace even though its key resolves no project runtime', () => {
|
|
mockGetRendererAppPlatform.mockReturnValue('win32')
|
|
const state = {
|
|
...stateFor({}),
|
|
activeRepoId: null,
|
|
activeWorktreeId: null
|
|
} as unknown as AppState
|
|
expect(canUseStructuredNativeChat(state, 'folder:folder-1')).toBe(true)
|
|
})
|
|
|
|
it('allows a folder workspace on a non-Windows platform', () => {
|
|
const state = {
|
|
...stateFor({}),
|
|
activeRepoId: null,
|
|
activeWorktreeId: null
|
|
} as unknown as AppState
|
|
expect(canUseStructuredNativeChat(state, 'folder:folder-1')).toBe(true)
|
|
})
|
|
|
|
it.each(['darwin', 'linux'] as const)('allows a supported local worktree on %s', (platform) => {
|
|
mockGetRendererAppPlatform.mockReturnValue(platform)
|
|
expect(canUseStructuredNativeChat(stateFor({}), 'wt-1')).toBe(true)
|
|
})
|
|
|
|
it.each(['darwin', 'linux'] as const)(
|
|
'refuses a WSL project runtime even when the renderer reports %s',
|
|
(platform) => {
|
|
mockGetRendererAppPlatform.mockReturnValue(platform)
|
|
projectRuntimeMock.fn.mockReturnValue(wslRuntimeResolution)
|
|
expect(canUseStructuredNativeChat(stateFor({}), 'wt-1')).toBe(false)
|
|
}
|
|
)
|
|
|
|
it.each(['darwin', 'linux'] as const)(
|
|
'refuses a repair-required runtime even when the renderer reports %s',
|
|
(platform) => {
|
|
mockGetRendererAppPlatform.mockReturnValue(platform)
|
|
projectRuntimeMock.fn.mockReturnValue(repairRequiredResolution)
|
|
expect(canUseStructuredNativeChat(stateFor({}), 'wt-1')).toBe(false)
|
|
}
|
|
)
|
|
})
|