From ff1285a9361a22cdf6fc6fdf6d95d18f76a6a2de Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Wed, 14 Oct 2026 11:22:35 -0700 Subject: [PATCH] fix(terminal): judge an agent's --shell against the runtime it runs in (#28234) * fix(terminal): judge an agent's --shell against the runtime it runs in `orca terminal create --shell` for an agent is now judged only against the runtime that agent runs in, not also against the project's saved runtime. So --shell wsl.exe for an agent in a \\wsl$ repo (saved as Windows host, or with no setting) runs instead of being refused. * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main --- .../runtime-agent-terminal-startup.test.ts | 10 +++--- .../runtime/runtime-agent-terminal-startup.ts | 32 ++++++++----------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/main/runtime/runtime-agent-terminal-startup.test.ts b/src/main/runtime/runtime-agent-terminal-startup.test.ts index 95267d597f8..31e3284beff 100644 --- a/src/main/runtime/runtime-agent-terminal-startup.test.ts +++ b/src/main/runtime/runtime-agent-terminal-startup.test.ts @@ -79,8 +79,8 @@ describe('host agent planner', () => { }) }) - // TEMPORARY parity: main's project runtime still refuses this, though the agent runs in WSL. - it('refuses --shell wsl.exe for an agent in a WSL-share repo set to Windows host', async () => { + // A `\\wsl$` cwd runs in WSL whatever the project says, so a WSL shell is what this agent gets. + it('applies --shell wsl.exe for an agent in a WSL-share repo set to Windows host', async () => { const repo = { id: 'r', path: '\\\\wsl$\\Ubuntu\\r' } const preference = { kind: 'windows-host' } const store = { @@ -95,9 +95,7 @@ describe('host agent planner', () => { const opts = { startupAgent: 'claude', shellOverride: 'wsl.exe' } as const // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: as above. const planHost = { ...host, store: store as never } - const plan = resolveAgentTerminalCreateOptions(share, opts, planHost) - await expect(plan).rejects.toThrow( - "This workspace's project runs its terminals on the Windows host" - ) + const launch = await resolveAgentTerminalCreateOptions(share, opts, planHost) + expect(launch.launchRuntime?.pty.shellOverride).toBe('wsl.exe') }) }) diff --git a/src/main/runtime/runtime-agent-terminal-startup.ts b/src/main/runtime/runtime-agent-terminal-startup.ts index 615236f3ec2..8c1ae331464 100644 --- a/src/main/runtime/runtime-agent-terminal-startup.ts +++ b/src/main/runtime/runtime-agent-terminal-startup.ts @@ -1,5 +1,4 @@ import type { SessionOptionValue } from '../../shared/native-chat-session-options' -import type { ProjectExecutionRuntimeResolution } from '../../shared/project-execution-runtime' import type { TuiAgent } from '../../shared/tui-agent' import type { AgentLaunchPreferences } from '../../shared/agent-session-host-authority' import { @@ -76,24 +75,19 @@ export async function resolveAgentTerminalCreateOptions( const launchAgent = plannedAgent ?? opts.launchAgent // Before any early return: a host that cannot apply the requested shell must refuse rather than // spawn another one. Judged against the runtime this PTY's shell will come from. - const refuseShell = (projectRuntime: ProjectExecutionRuntimeResolution | undefined) => - terminalShellOverrideRefusal({ - shellOverride: opts.shellOverride, - connectionId: workspace.connectionId, - platform: process.platform, - projectRuntime, - cwd: resolveTerminalStartupCwd(workspace.path, opts.cwd) ?? workspace.path, - workspacePath: workspace.path - }) - const judgedStore = opts.shellOverride ? store : undefined - // TEMPORARY parity: main's project-only runtime still refuses an agent, then the agent's own. - const shellRefusal = - refuseShell(resolveLocalProjectRuntimeForWorktreeId(judgedStore, workspace.id)) ?? - (judgedStore && (plannedAgent || opts.launchRuntime) - ? refuseShell( - agentLaunchProjectRuntime(judgedStore, workspace, plannedAgent ?? opts.launchAgent) - ) - : null) + const shellRefusal = terminalShellOverrideRefusal({ + shellOverride: opts.shellOverride, + connectionId: workspace.connectionId, + platform: process.platform, + projectRuntime: + opts.shellOverride && store + ? plannedAgent || opts.launchRuntime + ? agentLaunchProjectRuntime(store, workspace, plannedAgent ?? opts.launchAgent) + : resolveLocalProjectRuntimeForWorktreeId(store, workspace.id) + : undefined, + cwd: resolveTerminalStartupCwd(workspace.path, opts.cwd) ?? workspace.path, + workspacePath: workspace.path + }) if (shellRefusal) { throw shellRefusal }