diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json index 5852b2a95c3..16a4fe72a53 100644 --- a/config/scripts/ci-shard-timings.json +++ b/config/scripts/ci-shard-timings.json @@ -11124,7 +11124,6 @@ "src/renderer/src/lib/worktree-visit-recency.test.ts": 35, "src/renderer/src/lib/wsl-host-account-owner.test.ts": 103, "src/renderer/src/runtime/abortable-runtime-environment-call.test.ts": 121, - "src/renderer/src/runtime/agent-resume-host-authority-capability.test.ts": 225, "src/renderer/src/runtime/agent-session-keyboard-capability.test.ts": 147, "src/renderer/src/runtime/agent-session-operation-id.test.ts": 24, "src/renderer/src/runtime/antigravity-generation-compatibility.test.ts": 175, diff --git a/src/main/cli/cli-installer-command-conflicts.test.ts b/src/main/cli/cli-installer-command-conflicts.test.ts index e93565675ad..75e8b10aae9 100644 --- a/src/main/cli/cli-installer-command-conflicts.test.ts +++ b/src/main/cli/cli-installer-command-conflicts.test.ts @@ -57,37 +57,6 @@ describe('CliInstaller', () => { } ) - it.skipIf(process.platform === 'win32')( - 'replaces stale packaged Orca launcher symlinks', - async () => { - const fixture = await makeFixture() - const commandDir = join(fixture.root, 'bin') - const installPath = join(commandDir, 'orca') - const resourcesPath = join(fixture.root, 'Current.app', 'Contents', 'Resources') - const launcherPath = join(resourcesPath, 'bin', 'orca') - const oldLauncherPath = join(fixture.root, 'Old.app', 'Contents', 'Resources', 'bin', 'orca') - await mkdir(commandDir, { recursive: true }) - await mkdir(join(resourcesPath, 'bin'), { recursive: true }) - await writeFile(launcherPath, '#!/usr/bin/env bash\n', 'utf8') - await symlink(oldLauncherPath, installPath) - - const installer = new CliInstaller({ - platform: 'darwin', - isPackaged: true, - resourcesPath, - commandPathOverride: installPath, - processPathEnv: commandDir - }) - - await expect(installer.getStatus()).resolves.toMatchObject({ - state: 'stale', - currentTarget: oldLauncherPath - }) - await expect(installer.install()).resolves.toMatchObject({ state: 'installed' }) - await expect(readlink(installPath)).resolves.toBe(launcherPath) - } - ) - // Older builds wrote generated launcher files directly into /usr/local/bin/orca. it.skipIf(process.platform === 'win32')( 'replaces stale generated Unix launcher files', diff --git a/src/main/cli/cli-installer-unreadable-command.test.ts b/src/main/cli/cli-installer-unreadable-command.test.ts index d5671a13121..58314a684ae 100644 --- a/src/main/cli/cli-installer-unreadable-command.test.ts +++ b/src/main/cli/cli-installer-unreadable-command.test.ts @@ -52,45 +52,5 @@ describe.skipIf(process.platform === 'win32' || process.getuid?.() === 0)( await chmod(fixture.foreignPath, 0o600) expect(await readFile(fixture.foreignPath, 'utf8')).toBe(unreadableContents) }) - - it('keeps the installed launcher before a later unreadable executable', async () => { - const fixture = await createUnreadableCommandFixture() - const installer = new CliInstaller({ - ...fixture, - platform: 'darwin', - isPackaged: true, - execPath: join(fixture.root, 'Orca'), - homePath: join(fixture.root, 'home'), - defaultMacCommandPath: fixture.commandPath, - processPathEnv: `${fixture.defaultBin}:${fixture.foreignBin}` - }) - - await expect(installer.getStatus()).resolves.toMatchObject({ - state: 'installed', - commandPath: fixture.commandPath - }) - }) - - it.each(['darwin', 'linux'] as const)( - 'reports an unreadable explicit %s command as a conflict', - async (platform) => { - const fixture = await createUnreadableCommandFixture() - const installer = new CliInstaller({ - ...fixture, - platform, - isPackaged: true, - execPath: join(fixture.root, 'Orca'), - homePath: join(fixture.root, 'home'), - commandPathOverride: fixture.foreignPath, - processPathEnv: fixture.foreignBin - }) - - await expect(installer.getStatus()).resolves.toMatchObject({ - state: 'conflict', - commandPath: fixture.foreignPath, - currentTarget: null - }) - } - ) } ) diff --git a/src/main/cli/linux-terminal-orca-cli-shim.test.ts b/src/main/cli/linux-terminal-orca-cli-shim.test.ts index b7bbff7a56b..a70ecd54241 100644 --- a/src/main/cli/linux-terminal-orca-cli-shim.test.ts +++ b/src/main/cli/linux-terminal-orca-cli-shim.test.ts @@ -30,36 +30,6 @@ afterEach(async () => { }) describe('ensureLinuxTerminalOrcaCliShimDir', () => { - it('uses the mounted bundled launcher when only APPDIR is inherited', async () => { - const { userDataPath, resourcesPath } = await makeFixture() - vi.stubEnv('APPIMAGE', '') - vi.stubEnv('APPDIR', resourcesPath) - - const shimDir = ensureLinuxTerminalOrcaCliShimDir({ userDataPath, resourcesPath }) - - expect(shimDir).toBe(join(userDataPath, 'linux-orca-cli-shim')) - expect(readFileSync(join(shimDir!, 'orca'), 'utf8')).toContain( - `exec '${join(resourcesPath, 'bin', 'orca-ide')}' "$@"` - ) - }) - - it('writes an executable bare-orca shim that execs the bundled orca-ide launcher', async () => { - const { userDataPath, resourcesPath } = await makeFixture() - - const shimDir = ensureLinuxTerminalOrcaCliShimDir({ - userDataPath, - resourcesPath, - appImagePath: null - }) - - expect(shimDir).toBe(join(userDataPath, 'linux-orca-cli-shim')) - const content = readFileSync(join(shimDir!, 'orca'), 'utf8') - // Single-quoted so a resources path with shell metacharacters can't break out. - expect(content).toContain(`exec '${join(resourcesPath, 'bin', 'orca-ide')}' "$@"`) - const mode = statSync(join(shimDir!, 'orca')).mode & 0o777 - expect(mode & 0o111).not.toBe(0) - }) - it('reuses the shim path and re-asserts its exec bit', async () => { const { userDataPath, resourcesPath } = await makeFixture() const options = { userDataPath, resourcesPath, appImagePath: null } @@ -216,27 +186,4 @@ describe('ensureLinuxTerminalOrcaCliShimDir', () => { ).resolves.toMatchObject({ code: 1, stdout: '' }) } ) - - it('returns null (and does not memoize) when the bundled launcher is missing', async () => { - const root = await mkdtemp(join(tmpdir(), 'orca-terminal-cli-shim-missing-')) - created.push(root) - const userDataPath = join(root, 'user-data') - - const missing = ensureLinuxTerminalOrcaCliShimDir({ - userDataPath, - resourcesPath: join(root, 'resources'), - appImagePath: null - }) - expect(missing).toBeNull() - - const resourcesPath = join(root, 'resources') - mkdirSync(join(resourcesPath, 'bin'), { recursive: true }) - writeFileSync(join(resourcesPath, 'bin', 'orca-ide'), '#!/usr/bin/env bash\n', 'utf8') - const recovered = ensureLinuxTerminalOrcaCliShimDir({ - userDataPath, - resourcesPath, - appImagePath: null - }) - expect(recovered).toBe(join(userDataPath, 'linux-orca-cli-shim')) - }) }) diff --git a/src/main/cli/packaged-cli-assets.test.ts b/src/main/cli/packaged-cli-assets.test.ts index d3113a951fa..fe6943b922f 100644 --- a/src/main/cli/packaged-cli-assets.test.ts +++ b/src/main/cli/packaged-cli-assets.test.ts @@ -51,11 +51,6 @@ const unixLauncherFixtures = [ ] as const describe('packaged CLI assets', () => { - it('ships embedded skill guides with the CLI instead of source Markdown', () => { - expect(builderConfig.asarUnpack).toContain('out/cli/**') - expect(builderConfig.files).toContain('!skill-guides{,/**/*}') - }) - it('loads worktree link validation from the installed CLI', async () => { const root = await mkdtemp(join(tmpdir(), 'orca-cli-gitlab-package-')) const projectDir = fileURLToPath(new URL('../../../', import.meta.url)) @@ -137,48 +132,6 @@ describe('packaged CLI assets', () => { } }) - itRunsUnixShell('keeps the Linux launcher executable in packaged resources', async () => { - const launcherStats = await stat(linuxLauncherAsset) - expect(launcherStats.mode & 0o111).not.toBe(0) - }) - - it('retries an incomplete listener-state write', async () => { - const root = await mkdtemp(join(tmpdir(), 'orca-listener-state-')) - const statePath = join(root, 'listener-state.json') - const expectedState = { pid: 1234, port: 5678 } - await writeFile(statePath, '{"pid":', 'utf8') - const completedWrite = new Promise((resolve, reject) => { - setTimeout(() => { - writeFile(statePath, JSON.stringify(expectedState), 'utf8').then(resolve, reject) - }, 50) - }) - - try { - await expect(waitForListenerState(statePath)).resolves.toEqual(expectedState) - } finally { - await completedWrite - await rm(root, { recursive: true, force: true }) - } - }) - - it.each([ - { state: { pid: '1234', port: 5678 }, reason: 'non-numeric pid' }, - { state: { pid: 0, port: 5678 }, reason: 'non-positive pid' }, - { state: { pid: 1234, port: '5678' }, reason: 'non-numeric port' }, - { state: { pid: 1234, port: 65_536 }, reason: 'out-of-range port' } - ])('rejects $reason in listener state', async ({ state }) => { - const root = await mkdtemp(join(tmpdir(), 'orca-listener-state-')) - const statePath = join(root, 'listener-state.json') - try { - await writeFile(statePath, JSON.stringify(state), 'utf8') - await expect(waitForListenerState(statePath)).rejects.toThrow( - 'Invalid launcher listener state' - ) - } finally { - await rm(root, { recursive: true, force: true }) - } - }) - itRunsUnixShell.each(unixLauncherFixtures)( 'delivers Unix termination signals to the $name executable and releases its listener', async (launcherFixture) => { @@ -360,63 +313,6 @@ node -e 'console.log(JSON.stringify({ } } ) - - itRunsUnixShell('keeps Linux serve on the CLI entrypoint in node mode', async () => { - const root = await mkdtemp(join(tmpdir(), 'orca-linux-cli-serve-')) - try { - const appDir = join(root, 'Orca') - const resourcesDir = join(appDir, 'resources') - const launcherDir = join(resourcesDir, 'bin') - const cliDir = join(resourcesDir, 'app.asar.unpacked', 'out', 'cli') - const launcherPath = join(launcherDir, 'orca-ide') - const appRunPath = join(appDir, 'AppRun') - const electronPath = join(appDir, 'orca-ide') - const cliPath = join(cliDir, 'index.js') - const statePath = join(root, 'launch-state.json') - - await mkdir(launcherDir, { recursive: true }) - await mkdir(cliDir, { recursive: true }) - await copyFile(linuxLauncherAsset, launcherPath) - await writeFile(cliPath, '', 'utf8') - // An accidental AppRun handoff would skip CLI validation and fail this contract. - await writeFile( - appRunPath, - `#!/usr/bin/env bash -printf 'unexpected AppRun handoff\n' >&2 -exit 97 -`, - { encoding: 'utf8', mode: 0o755 } - ) - await writeFile( - electronPath, - `#!/usr/bin/env node -require('node:fs').writeFileSync(process.env.ORCA_TEST_LAUNCH_STATE, JSON.stringify({ - argv: process.argv.slice(2), - runAsNode: process.env.ELECTRON_RUN_AS_NODE ?? null -})) -`, - { encoding: 'utf8', mode: 0o755 } - ) - - await execFileAsync(launcherPath, ['serve', '--recipe-json', '--project-root', '/tmp/repo'], { - env: { ...process.env, ORCA_TEST_LAUNCH_STATE: statePath } - }) - const payload = JSON.parse(await readFile(statePath, 'utf8')) as { - argv: string[] - runAsNode: string | null - } - expect(payload.argv).toEqual([ - cliPath, - 'serve', - '--recipe-json', - '--project-root', - '/tmp/repo' - ]) - expect(payload.runAsNode).toBe('1') - } finally { - await rm(root, { recursive: true, force: true }) - } - }) }) async function waitForListenerState(path: string): Promise<{ pid: number; port: number }> { diff --git a/src/renderer/src/runtime/agent-resume-host-authority-capability.test.ts b/src/renderer/src/runtime/agent-resume-host-authority-capability.test.ts deleted file mode 100644 index c13407fba42..00000000000 --- a/src/renderer/src/runtime/agent-resume-host-authority-capability.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { RESUMABLE_TUI_AGENTS } from '../../../shared/agent-session-resume' -import { - AGENT_SESSION_QODER_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_QODER_CN_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_QWEN_CODE_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_CODEBUDDY_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_DSH_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_KIMI_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_CURSOR_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_MUSE_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_OPENCODE2_RESUME_RUNTIME_CAPABILITY, - AGENT_SESSION_OMP_RESUME_PATH_RUNTIME_CAPABILITY, - RUNTIME_CAPABILITIES -} from '../../../shared/protocol-version' -import { agentResumeHostAuthorityCapability } from './agent-resume-host-authority-capability' - -describe('agentResumeHostAuthorityCapability', () => { - it('requires Cursor support from the owning host', () => { - expect(agentResumeHostAuthorityCapability('cursor')).toBe( - AGENT_SESSION_CURSOR_RESUME_RUNTIME_CAPABILITY - ) - expect(RUNTIME_CAPABILITIES).toContain(AGENT_SESSION_CURSOR_RESUME_RUNTIME_CAPABILITY) - }) - it('gates Muse resume behind its own advertised capability', () => { - expect(agentResumeHostAuthorityCapability('muse')).toBe( - AGENT_SESSION_MUSE_RESUME_RUNTIME_CAPABILITY - ) - expect(RUNTIME_CAPABILITIES).toContain(AGENT_SESSION_MUSE_RESUME_RUNTIME_CAPABILITY) - }) - - it('gates OpenCode 2 resume behind its own advertised capability', () => { - expect(agentResumeHostAuthorityCapability('opencode2')).toBe( - AGENT_SESSION_OPENCODE2_RESUME_RUNTIME_CAPABILITY - ) - expect(RUNTIME_CAPABILITIES).toContain(AGENT_SESSION_OPENCODE2_RESUME_RUNTIME_CAPABILITY) - }) - - it('leaves agents shipped with host authority on the generic probe', () => { - expect(agentResumeHostAuthorityCapability('codex')).toBeUndefined() - expect(agentResumeHostAuthorityCapability(null)).toBeUndefined() - expect(agentResumeHostAuthorityCapability(undefined)).toBeUndefined() - }) - - it('pins the gate for every resumable agent so a new member is a deliberate decision', () => { - // New resumable agents need explicit capability review; generic-probe defaults recreate the version-skew failure. - expect( - Object.fromEntries( - RESUMABLE_TUI_AGENTS.map((agent) => [agent, agentResumeHostAuthorityCapability(agent)]) - ) - ).toEqual({ - claude: undefined, - codebuddy: AGENT_SESSION_CODEBUDDY_RESUME_RUNTIME_CAPABILITY, - codex: undefined, - cursor: AGENT_SESSION_CURSOR_RESUME_RUNTIME_CAPABILITY, - qoder: AGENT_SESSION_QODER_RESUME_RUNTIME_CAPABILITY, - 'qoder-cn': AGENT_SESSION_QODER_CN_RESUME_RUNTIME_CAPABILITY, - 'qwen-code': AGENT_SESSION_QWEN_CODE_RESUME_RUNTIME_CAPABILITY, - gemini: undefined, - antigravity: undefined, - opencode: undefined, - opencode2: AGENT_SESSION_OPENCODE2_RESUME_RUNTIME_CAPABILITY, - pi: undefined, - 'mimo-code': undefined, - droid: undefined, - grok: undefined, - devin: undefined, - 'prime-agent': undefined, - zcode: 'agent-session.zcode-resume.v1', - copilot: undefined, - muse: AGENT_SESSION_MUSE_RESUME_RUNTIME_CAPABILITY, - omp: AGENT_SESSION_OMP_RESUME_PATH_RUNTIME_CAPABILITY, - kimi: AGENT_SESSION_KIMI_RESUME_RUNTIME_CAPABILITY, - dsh: AGENT_SESSION_DSH_RESUME_RUNTIME_CAPABILITY, - kiro: 'agent-session.kiro-resume.v1', - hermes: 'agent-session.hermes-resume.v1' - }) - }) -}) diff --git a/src/renderer/src/runtime/runtime-terminal-artifact-read.test.ts b/src/renderer/src/runtime/runtime-terminal-artifact-read.test.ts index 8063665ce60..d41ca5836d7 100644 --- a/src/renderer/src/runtime/runtime-terminal-artifact-read.test.ts +++ b/src/renderer/src/runtime/runtime-terminal-artifact-read.test.ts @@ -23,29 +23,6 @@ function grantIdOf(params: unknown): string | undefined { } describe('a granted host file outside every workspace', () => { - it('reads text through its grant', async () => { - runtimeEnvironmentCall.mockResolvedValue({ - id: 'rpc-1', - ok: true, - result: { - worktree: 'wt-1', - relativePath: '/tmp/out.png', - content: 'log', - truncated: false, - byteLength: 3 - }, - _meta: { runtimeId: 'remote-runtime' } - }) - - await expect(readRuntimeFileContent(granted)).resolves.toEqual({ - content: 'log', - isBinary: false - }) - expect(runtimeEnvironmentCall).toHaveBeenCalledWith( - expect.objectContaining({ method: 'files.readTerminalArtifact', params: grantParams }) - ) - }) - it('previews a binary file through its grant', async () => { const preview = { content: 'iVBO', isBinary: true, isImage: true, mimeType: 'image/png' } runtimeEnvironmentCall.mockImplementation((args: { method: string }) => @@ -72,6 +49,7 @@ describe('a granted host file outside every workspace', () => { // Why: Reload, Compare and Keep My Edits read a file whose host change staled the tab's grant. it('renews a stale grant for the same path and reads through the new one', async () => { + const grantedText = { ...granted, filePath: '/tmp/out.txt', relativePath: '/tmp/out.txt' } const meta = { runtimeId: 'remote-runtime' } runtimeEnvironmentCall.mockImplementation( async (args: { method: string; params?: unknown }) => { @@ -82,13 +60,13 @@ describe('a granted host file outside every workspace', () => { result: { worktree: 'wt-1', relativePath: null, - absolutePath: '/tmp/out.png', + absolutePath: '/tmp/out.txt', exists: true, isDirectory: false, openTarget: { kind: 'absolute-file', provider: 'local', - absolutePath: '/tmp/out.png', + absolutePath: '/tmp/out.txt', grantId: 'g-2' } }, @@ -105,20 +83,26 @@ describe('a granted host file outside every workspace', () => { : { id: 'rpc', ok: true, - result: { content: 'new', truncated: false, byteLength: 3 }, + result: { + worktree: 'wt-1', + relativePath: '/tmp/out.txt', + content: 'new', + truncated: false, + byteLength: 3 + }, _meta: meta } } ) - await expect(readRuntimeFileContent(granted)).resolves.toEqual({ + await expect(readRuntimeFileContent(grantedText)).resolves.toEqual({ content: 'new', isBinary: false }) expect(runtimeEnvironmentCall).toHaveBeenCalledWith( expect.objectContaining({ method: 'files.readTerminalArtifact', - params: { ...grantParams, grantId: 'g-2' } + params: { ...grantParams, absolutePath: grantedText.filePath, grantId: 'g-2' } }) ) }) diff --git a/src/renderer/src/runtime/use-worktree-runtime-target.test.ts b/src/renderer/src/runtime/use-worktree-runtime-target.test.ts index 62091019497..6e59c6e035d 100644 --- a/src/renderer/src/runtime/use-worktree-runtime-target.test.ts +++ b/src/renderer/src/runtime/use-worktree-runtime-target.test.ts @@ -3,7 +3,7 @@ import { act, cleanup, renderHook } from '@testing-library/react' import { afterEach, expect, it } from 'vitest' import { useAppStore } from '@/store' -import { useActiveAccountOwner, useWorktreeRuntimeTarget } from './use-worktree-runtime-target' +import { useWorktreeRuntimeTarget } from './use-worktree-runtime-target' const initialState = useAppStore.getInitialState() @@ -32,28 +32,3 @@ it('keeps the runtime target identity stable across unrelated store writes', () expect(renders).toBe(rendersAfterMount) expect(result.current).toBe(first) }) - -it('gives a WSL host owner to this desktop, for that distro, with a stable identity', () => { - const environments = [ - { - id: 'wsl:Ubuntu', - orcadDeployment: { - kind: 'wsl', - distro: 'Ubuntu', - localPort: 41000, - remotePort: 41001 - } - } - ] - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the account owner reads only id and orcadDeployment. - useAppStore.setState({ runtimeEnvironments: environments as never }) - const fallback = { - kind: 'environment', - environmentId: 'wsl:Ubuntu' - } as const - const { result } = renderHook(() => useActiveAccountOwner(fallback)) - const first = result.current - expect(first).toEqual({ target: { kind: 'local' }, wslHostDistro: 'Ubuntu' }) - act(() => useAppStore.setState({ activeRepoId: 'repo-x' })) - expect(result.current).toBe(first) -}) diff --git a/src/renderer/src/runtime/web-runtime-plain-terminal-create-params.test.ts b/src/renderer/src/runtime/web-runtime-plain-terminal-create-params.test.ts index 29c52ec9c07..3cf1452dee7 100644 --- a/src/renderer/src/runtime/web-runtime-plain-terminal-create-params.test.ts +++ b/src/renderer/src/runtime/web-runtime-plain-terminal-create-params.test.ts @@ -6,7 +6,7 @@ vi.mock('./runtime-rpc-client', () => ({ runtimeEnvironmentSupportsCapability: supportsCapability })) -const { buildPlainCreateTerminalParams, resolveCreateTerminalShellParams } = +const { resolveCreateTerminalShellParams } = await import('./web-runtime-plain-terminal-create-params') describe('resolveCreateTerminalShellParams', () => { @@ -33,23 +33,4 @@ describe('resolveCreateTerminalShellParams', () => { command: 'cmd.exe' }) }) - - it('does not probe the host when no shell was picked', async () => { - await expect(resolveCreateTerminalShellParams('env-1', { command: 'ls' })).resolves.toEqual({ - command: 'ls' - }) - expect(supportsCapability).not.toHaveBeenCalled() - }) - - it('builds caller-selected plain terminal params with the shell pick', async () => { - supportsCapability.mockResolvedValue(true) - - const params = await buildPlainCreateTerminalParams('env-1', { - worktreeId: 'repo-1::/repo', - shell: 'cmd.exe' - }) - - expect(params).toMatchObject({ shell: 'cmd.exe', select: true, navigation: 'caller' }) - expect(params.command).toBeUndefined() - }) })