diff --git a/src/main/daemon/pty-subprocess-windows-shell-launch.test.ts b/src/main/daemon/pty-subprocess-windows-shell-launch.test.ts index bb0516a9584..1ea6850bffe 100644 --- a/src/main/daemon/pty-subprocess-windows-shell-launch.test.ts +++ b/src/main/daemon/pty-subprocess-windows-shell-launch.test.ts @@ -1,4 +1,6 @@ // Native Windows shell launch: PowerShell implementations, cmd.exe and Git Bash. +import { writeFileSync, mkdirSync } from 'node:fs' +import { join } from 'node:path' import { describe, expect, it, vi } from 'vitest' import type * as LocalPtyUtils from '../providers/local-pty-utils' @@ -348,6 +350,34 @@ describe('createPtySubprocess', () => { ) }) + it('abandons the default-home marker when Git Bash wrapper materialization fails', async () => { + const proc = mockPtyProcess() + spawnMock.mockReturnValue(proc) + const platform = Object.getOwnPropertyDescriptor(process, 'platform')! + const userDataPath = process.env.ORCA_USER_DATA_PATH! + // A file occupying the wrapper directory deterministically prevents materialization. + mkdirSync(userDataPath, { recursive: true }) + writeFileSync(join(userDataPath, 'shell-wrappers'), 'occupied') + Object.defineProperty(process, 'platform', { value: 'win32' }) + try { + await createPtySubprocess({ + sessionId: 'test', + cols: 80, + rows: 24, + cwd: 'C:\\Users\\jin\\repo', + shellOverride: 'C:\\PortableGit\\bin\\bash.exe', + env: { [ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]: '1' } + }) + } finally { + Object.defineProperty(process, 'platform', platform) + } + expect(spawnMock).toHaveBeenCalledTimes(1) + const [shell, args, options] = spawnMock.mock.calls[0] + expect(shell).toBe('C:\\PortableGit\\bin\\bash.exe') + expect(args).toEqual(['-c', 'chcp.com 65001 >/dev/null 2>&1; exec "$BASH" --login -i']) + expect(options.env[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]).toBeUndefined() + }) + it('keeps the Git Bash wrapper without a managed Codex preflight', async () => { const proc = mockPtyProcess() spawnMock.mockReturnValue(proc) diff --git a/src/main/daemon/pty-subprocess/native-pty-spawn.ts b/src/main/daemon/pty-subprocess/native-pty-spawn.ts index 507ad3ff445..dc8973803b8 100644 --- a/src/main/daemon/pty-subprocess/native-pty-spawn.ts +++ b/src/main/daemon/pty-subprocess/native-pty-spawn.ts @@ -5,7 +5,7 @@ import { } from '../../providers/macos-tcc-login-shell' import type { WindowsShellSpawnAttempt } from '../../providers/windows-shell-fallback-chain' import { assignHostProcessToKillOnCloseJob } from '../../windows/windows-pty-job' -import { scrubCodexDefaultHomeMarkerForWindowsShell } from '../../pty/codex-default-home-shell-startup' +import { scrubCodexDefaultHomeMarkerForLaunch } from '../../pty/codex-default-home-shell-startup' export type SpawnedDaemonPty = { process: pty.IPty @@ -62,7 +62,7 @@ export function spawnNativeDaemonPty(args: { } for (const attempt of args.windowsFallbackAttempts.slice(1)) { try { - scrubCodexDefaultHomeMarkerForWindowsShell(args.env, attempt.shellPath) + scrubCodexDefaultHomeMarkerForLaunch(args.env, attempt.supportsCodexDefaultHomeAfterProfile) const process = spawnAt(attempt.shellPath, attempt.shellArgs, attempt.effectiveCwd) const message = primaryErr instanceof Error ? primaryErr.message : String(primaryErr) console.warn( diff --git a/src/main/daemon/pty-subprocess/shell-launch-plan.ts b/src/main/daemon/pty-subprocess/shell-launch-plan.ts index d4feda2418d..3b28bbbbcf8 100644 --- a/src/main/daemon/pty-subprocess/shell-launch-plan.ts +++ b/src/main/daemon/pty-subprocess/shell-launch-plan.ts @@ -36,7 +36,7 @@ import { import { ORCA_HERMES_STARTUP_QUERY_ENV } from '../../../shared/hermes-startup-query' import { ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV, - scrubCodexDefaultHomeMarkerForWindowsShell + scrubCodexDefaultHomeMarkerForLaunch } from '../../pty/codex-default-home-shell-startup' import { WINDOWS_GIT_BASH_SHELL } from '../../../shared/windows-terminal-shell' import { getShellLaunchConfig, resolvePtyShellPath } from '../shell-ready' @@ -72,8 +72,6 @@ export function createPtyShellLaunchPlan( let validationCwd = spawnCwd if (process.platform === 'win32') { - // Why: execution-host reconciliation may preserve a daemon-only custom home - // by dropping the reset, but that must not also disable shell integration. const useGitBashShellReadyWrapper = opts.env?.[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV] !== undefined const normalizedShellFamily = pathWin32.basename(shellPath).toLowerCase() @@ -117,8 +115,11 @@ export function createPtyShellLaunchPlan( wslContext: resolvedWslContext, startupCommand: opts.command }) + let supportsCodexDefaultHomeAfterProfile = false const primaryAttempt = windowsFallbackAttempts[0] if (primaryAttempt) { + supportsCodexDefaultHomeAfterProfile = + primaryAttempt.supportsCodexDefaultHomeAfterProfile === true shellPath = primaryAttempt.shellPath shellArgs = primaryAttempt.shellArgs spawnCwd = primaryAttempt.effectiveCwd @@ -134,6 +135,7 @@ export function createPtyShellLaunchPlan( env.ORCA_CODEX_LAUNCH_PREFLIGHT, useGitBashShellReadyWrapper ) + supportsCodexDefaultHomeAfterProfile = resolved.supportsCodexDefaultHomeAfterProfile === true shellArgs = resolved.shellArgs spawnCwd = resolved.effectiveCwd validationCwd = resolved.validationCwd @@ -163,6 +165,8 @@ export function createPtyShellLaunchPlan( env.ORCA_CODEX_LAUNCH_PREFLIGHT, useGitBashShellReadyWrapper ) + supportsCodexDefaultHomeAfterProfile = + resolved.supportsCodexDefaultHomeAfterProfile === true shellArgs = resolved.shellArgs spawnCwd = resolved.effectiveCwd validationCwd = resolved.validationCwd @@ -189,7 +193,7 @@ export function createPtyShellLaunchPlan( if (pathWin32.basename(shellPath).toLowerCase() === 'wsl.exe') { addOrcaWslInteropEnv(env) } - scrubCodexDefaultHomeMarkerForWindowsShell(env, shellPath) + scrubCodexDefaultHomeMarkerForLaunch(env, supportsCodexDefaultHomeAfterProfile) } else { rescrubDaemonPtyEnvironment(env, opts) const preferredShellPath = shellPath diff --git a/src/main/providers/local-pty-launch-plan.ts b/src/main/providers/local-pty-launch-plan.ts index 199459dc0b8..98a196e0fa7 100644 --- a/src/main/providers/local-pty-launch-plan.ts +++ b/src/main/providers/local-pty-launch-plan.ts @@ -45,6 +45,7 @@ export type LocalPtyLaunchPlan = { shellArgs: string[] effectiveCwd: string validationCwd: string + supportsCodexDefaultHomeAfterProfile?: boolean startupCommandDeliveredInShellArgs: boolean windowsFallbackAttempts: ReturnType shellReadyLaunch: ReturnType | null @@ -72,6 +73,7 @@ function finalizeLocalPtyLaunchPlan( shellArgs: string[] effectiveCwd: string validationCwd: string + supportsCodexDefaultHomeAfterProfile?: boolean startupCommandDeliveredInShellArgs?: boolean windowsFallbackAttempts?: ReturnType } @@ -91,6 +93,7 @@ function finalizeLocalPtyLaunchPlan( preferredWslContext: seed.preferredWslContext, launchWslContext: seed.launchWslContext, shellPath: shell.shellPath, + supportsCodexDefaultHomeAfterProfile: shell.supportsCodexDefaultHomeAfterProfile, shellArgs: shell.shellArgs, effectiveCwd: shell.effectiveCwd, validationCwd: shell.validationCwd, @@ -162,6 +165,7 @@ function createWindowsLocalPtyLaunchPlan( if (primaryAttempt) { return finalizeLocalPtyLaunchPlan(seed, { shellPath: primaryAttempt.shellPath, + supportsCodexDefaultHomeAfterProfile: primaryAttempt.supportsCodexDefaultHomeAfterProfile, shellArgs: primaryAttempt.shellArgs, effectiveCwd: primaryAttempt.effectiveCwd, validationCwd: primaryAttempt.validationCwd, @@ -178,6 +182,7 @@ function createWindowsLocalPtyLaunchPlan( ) return finalizeLocalPtyLaunchPlan(seed, { shellPath, + supportsCodexDefaultHomeAfterProfile: resolved.supportsCodexDefaultHomeAfterProfile, shellArgs: resolved.shellArgs, effectiveCwd: resolved.effectiveCwd, validationCwd: resolved.validationCwd, @@ -229,6 +234,7 @@ export function createLocalPtyLaunchPlan( const resolved = resolveWindowsShellLaunchArgs(shellPath, cwd, defaultCwd) return finalizeLocalPtyLaunchPlan(seed, { shellPath, + supportsCodexDefaultHomeAfterProfile: resolved.supportsCodexDefaultHomeAfterProfile, shellArgs: resolved.shellArgs, effectiveCwd: resolved.effectiveCwd, validationCwd: resolved.validationCwd diff --git a/src/main/providers/local-pty-provider-windows-shell-launch.test.ts b/src/main/providers/local-pty-provider-windows-shell-launch.test.ts index de9d799f159..8d69f19ca55 100644 --- a/src/main/providers/local-pty-provider-windows-shell-launch.test.ts +++ b/src/main/providers/local-pty-provider-windows-shell-launch.test.ts @@ -632,6 +632,40 @@ describe('LocalPtyProvider', () => { ) }) + it('abandons the default-home marker when Git Bash wrapper writing fails', async () => { + spawnMock.mockClear() + Object.defineProperty(process, 'platform', { configurable: true, value: 'win32' }) + statSyncMock.mockImplementation((path: string) => { + if (String(path).includes('shell-wrappers')) { + throw new Error('ENOENT') + } + return { isDirectory: () => true, mode: 0o755, size: 1 } + }) + writeFileSyncMock.mockImplementation(() => { + throw new Error('ENOSPC') + }) + provider.configure({ + buildSpawnEnv: (_id, env) => ({ + ...env, + [ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]: '1' + }) + }) + + await provider.spawn({ + cols: 80, + rows: 24, + cwd: 'C:\\Users\\jin\\repo', + shellOverride: 'C:\\PortableGit\\bin\\bash.exe' + }) + + expect(writeFileSyncMock).toHaveBeenCalledTimes(1) + expect(spawnMock).toHaveBeenCalledTimes(1) + const [shell, args, options] = spawnMock.mock.calls[0] + expect(shell).toBe('C:\\PortableGit\\bin\\bash.exe') + expect(args).toEqual(['-c', 'chcp.com 65001 >/dev/null 2>&1; exec "$BASH" --login -i']) + expect(options.env[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]).toBeUndefined() + }) + it('keeps the Git Bash wrapper without a managed Codex preflight', async () => { const platform = Object.getOwnPropertyDescriptor(process, 'platform') const originalProgramFiles = process.env.ProgramFiles diff --git a/src/main/providers/local-pty-utils.ts b/src/main/providers/local-pty-utils.ts index 4fbff4f72ad..a7c6289d6c3 100644 --- a/src/main/providers/local-pty-utils.ts +++ b/src/main/providers/local-pty-utils.ts @@ -1,3 +1,5 @@ +import type { WindowsShellSpawnAttempt } from './windows-shell-fallback-chain' +export type { WindowsShellSpawnAttempt } from './windows-shell-fallback-chain' import { basename, isAbsolute, join } from 'node:path' import { existsSync, accessSync, statSync, chmodSync, constants as fsConstants } from 'node:fs' import type * as pty from 'node-pty' @@ -7,7 +9,7 @@ import { wrapShellSpawnForMacosTccAttribution } from './macos-tcc-login-shell' import { formatLocalPtyEnvironmentDiag } from './working-directory-validation' -import { scrubCodexDefaultHomeMarkerForWindowsShell } from '../pty/codex-default-home-shell-startup' +import { scrubCodexDefaultHomeMarkerForLaunch } from '../pty/codex-default-home-shell-startup' export { formatLocalPtyEnvironmentDiag, @@ -111,17 +113,6 @@ export function ensureNodePtySpawnHelperExecutable(): void { } } -/** A pre-resolved Windows shell attempt: an absolute executable plus the launch - * args + cwd computed for it. Used to walk the PowerShell -> Windows PowerShell - * -> cmd.exe fallback chain when ConPTY rejects the primary shell. */ -export type WindowsShellSpawnAttempt = { - shellPath: string - shellArgs: string[] - effectiveCwd: string - validationCwd: string - startupCommandDeliveredInShellArgs: boolean -} - export type ShellSpawnParams = { shellPath: string shellArgs: string[] @@ -185,7 +176,7 @@ function spawnWindowsFallbackChain( // Skip the first entry: it is the primary that already failed above. for (const attempt of attempts.slice(1)) { try { - scrubCodexDefaultHomeMarkerForWindowsShell(env, attempt.shellPath) + scrubCodexDefaultHomeMarkerForLaunch(env, attempt.supportsCodexDefaultHomeAfterProfile) const proc = ptySpawn(attempt.shellPath, attempt.shellArgs, { name: termName, cols, diff --git a/src/main/providers/local-pty-windows-spawn-environment.ts b/src/main/providers/local-pty-windows-spawn-environment.ts index 9f02e101708..0c2477a5329 100644 --- a/src/main/providers/local-pty-windows-spawn-environment.ts +++ b/src/main/providers/local-pty-windows-spawn-environment.ts @@ -6,7 +6,7 @@ import { parseWslPath } from '../wsl' import { isWindowsGitBashShellPath } from '../git-bash' import { ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV, - scrubCodexDefaultHomeMarkerForWindowsShell + scrubCodexDefaultHomeMarkerForLaunch } from '../pty/codex-default-home-shell-startup' import type { LocalPtyLaunchPlan } from './local-pty-launch-plan' import { @@ -41,6 +41,7 @@ export function finalizeWindowsLocalPtySpawnEnvironment(args: { distro: codexHomeWslInfo.distro } ) + plan.supportsCodexDefaultHomeAfterProfile = resolved.supportsCodexDefaultHomeAfterProfile plan.shellArgs = resolved.shellArgs plan.effectiveCwd = resolved.effectiveCwd plan.validationCwd = resolved.validationCwd @@ -72,7 +73,6 @@ export function finalizeWindowsLocalPtySpawnEnvironment(args: { const shellBasename = pathWin32.basename(plan.shellPath).toLowerCase() const codexLaunchPreflightCommand = env.ORCA_CODEX_LAUNCH_PREFLIGHT const useGitBashShellReadyWrapper = env[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV] !== undefined - scrubCodexDefaultHomeMarkerForWindowsShell(env, plan.shellPath) if ( (codexLaunchPreflightCommand || useGitBashShellReadyWrapper) && ((shellBasename === 'cmd.exe' && Boolean(codexLaunchPreflightCommand)) || @@ -91,9 +91,11 @@ export function finalizeWindowsLocalPtySpawnEnvironment(args: { codexLaunchPreflightCommand, useGitBashShellReadyWrapper ) + plan.supportsCodexDefaultHomeAfterProfile = resolved.supportsCodexDefaultHomeAfterProfile plan.shellArgs = resolved.shellArgs plan.effectiveCwd = resolved.effectiveCwd plan.validationCwd = resolved.validationCwd plan.startupCommandDeliveredInShellArgs = resolved.startupCommandDeliveredInShellArgs === true } + scrubCodexDefaultHomeMarkerForLaunch(env, plan.supportsCodexDefaultHomeAfterProfile) } diff --git a/src/main/providers/windows-shell-args.ts b/src/main/providers/windows-shell-args.ts index 51215f18e86..9f941d3c64b 100644 --- a/src/main/providers/windows-shell-args.ts +++ b/src/main/providers/windows-shell-args.ts @@ -32,20 +32,23 @@ const GIT_BASH_UTF8_LOGIN_COMMAND = 'chcp.com 65001 >/dev/null 2>&1; exec "$BASH function getGitBashLaunchCommand( codexLaunchPreflightCommand?: string, useGitBashShellReadyWrapper = false -): string { +): { command: string; supportsCodexDefaultHomeAfterProfile: boolean } { if (!codexLaunchPreflightCommand && !useGitBashShellReadyWrapper) { - return GIT_BASH_UTF8_LOGIN_COMMAND + return { command: GIT_BASH_UTF8_LOGIN_COMMAND, supportsCodexDefaultHomeAfterProfile: false } } ensureShellReadyWrappersAt() const wrapperArgs = getBashWrapperLaunchArgs() if (!wrapperArgs) { - return GIT_BASH_UTF8_LOGIN_COMMAND + return { command: GIT_BASH_UTF8_LOGIN_COMMAND, supportsCodexDefaultHomeAfterProfile: false } } const bashArgs = [...wrapperArgs, '-i'] .map((arg) => (arg.startsWith('-') ? arg : quotePosixShell(arg.replace(/\\/g, '/')))) .join(' ') - return `chcp.com 65001 >/dev/null 2>&1; exec "$BASH" ${bashArgs}` + return { + command: `chcp.com 65001 >/dev/null 2>&1; exec "$BASH" ${bashArgs}`, + supportsCodexDefaultHomeAfterProfile: true + } } /** Result of resolving a Windows shell to its launch args + effective cwd. @@ -57,6 +60,8 @@ function getGitBashLaunchCommand( * shellOverride never reached the daemon's shell-args branches. Sharing the * decision here keeps both paths honest. */ export type WindowsShellLaunchArgs = { + /** Set only when the resolved launch actually installs the post-profile consumer. */ + supportsCodexDefaultHomeAfterProfile?: boolean shellArgs: string[] /** True when the startup command was embedded in shellArgs and must not be * written again through stdin. */ @@ -210,6 +215,7 @@ export function resolveWindowsShellLaunchArgs( // Why base64 and not -Command: see powershell-osc133-bootstrap.ts (MDE review). return { shellArgs: ['-NoLogo', '-NoExit', '-EncodedCommand', powerShellCommand.encodedCommand], + supportsCodexDefaultHomeAfterProfile: true, ...(powerShellCommand.startupCommandDeliveredInShellArgs ? { startupCommandDeliveredInShellArgs: true } : {}), @@ -219,11 +225,10 @@ export function resolveWindowsShellLaunchArgs( } if (isWindowsGitBashShellPath(shellPath)) { + const launch = getGitBashLaunchCommand(codexLaunchPreflightCommand, useGitBashShellReadyWrapper) return { - shellArgs: [ - '-c', - getGitBashLaunchCommand(codexLaunchPreflightCommand, useGitBashShellReadyWrapper) - ], + shellArgs: ['-c', launch.command], + supportsCodexDefaultHomeAfterProfile: launch.supportsCodexDefaultHomeAfterProfile, effectiveCwd: nativeCwd, validationCwd: nativeCwd } diff --git a/src/main/providers/windows-shell-fallback-chain.ts b/src/main/providers/windows-shell-fallback-chain.ts index 867d19eb549..d0e9873efc3 100644 --- a/src/main/providers/windows-shell-fallback-chain.ts +++ b/src/main/providers/windows-shell-fallback-chain.ts @@ -9,6 +9,7 @@ import { /** A single attempt in the Windows shell-spawn fallback chain: the absolute * executable plus the launch args + cwd computed for it. */ export type WindowsShellSpawnAttempt = { + supportsCodexDefaultHomeAfterProfile?: boolean shellPath: string shellArgs: string[] effectiveCwd: string @@ -32,6 +33,7 @@ function toAttempt( ) return { shellPath, + supportsCodexDefaultHomeAfterProfile: resolved.supportsCodexDefaultHomeAfterProfile, shellArgs: resolved.shellArgs, effectiveCwd: resolved.effectiveCwd, validationCwd: resolved.validationCwd, diff --git a/src/main/pty/codex-default-home-shell-startup.test.ts b/src/main/pty/codex-default-home-shell-startup.test.ts index 806254290f3..ee7491f2dec 100644 --- a/src/main/pty/codex-default-home-shell-startup.test.ts +++ b/src/main/pty/codex-default-home-shell-startup.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import { ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV, reconcileDaemonCodexDefaultHomeMarker, - scrubCodexDefaultHomeMarkerForWindowsShell + scrubCodexDefaultHomeMarkerForLaunch } from './codex-default-home-shell-startup' describe('reconcileDaemonCodexDefaultHomeMarker', () => { @@ -63,29 +63,15 @@ describe('reconcileDaemonCodexDefaultHomeMarker', () => { }) }) -describe('scrubCodexDefaultHomeMarkerForWindowsShell', () => { - it.each([ - 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', - 'C:\\Program Files\\PowerShell\\7\\pwsh.exe', - 'C:\\Program Files\\Git\\bin\\bash.exe' - ])('keeps the one-shot marker for a consuming shell: %s', (shellPath) => { - const env = { [ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]: '1' } - - scrubCodexDefaultHomeMarkerForWindowsShell(env, shellPath) - - expect(env[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]).toBe('1') - }) - - it.each(['cmd.exe', 'wsl.exe', 'C:\\msys64\\usr\\bin\\bash.exe'])( - 'removes the marker before an unwrapped shell: %s', - (shellPath) => { - const env: Record = { - [ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]: '1' - } - - scrubCodexDefaultHomeMarkerForWindowsShell(env, shellPath) - - expect(env[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]).toBeUndefined() +describe('scrubCodexDefaultHomeMarkerForLaunch', () => { + it.each([true, false, undefined])( + 'retains the marker only with a consumer: %s', + (supportsConsumer) => { + const env = { [ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]: '1' } + scrubCodexDefaultHomeMarkerForLaunch(env, supportsConsumer) + expect(env[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV]).toBe( + supportsConsumer ? '1' : undefined + ) } ) }) diff --git a/src/main/pty/codex-default-home-shell-startup.ts b/src/main/pty/codex-default-home-shell-startup.ts index abe0c2abdfd..664c978c21a 100644 --- a/src/main/pty/codex-default-home-shell-startup.ts +++ b/src/main/pty/codex-default-home-shell-startup.ts @@ -1,6 +1,3 @@ -import { win32 as pathWin32 } from 'node:path' -import { isWindowsGitBashShellPath } from '../git-bash' - export const ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV = 'ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE' export const ORCA_CODEX_DEFAULT_HOME_UNSET_AFTER_PROFILE = '1' @@ -24,16 +21,11 @@ export function reconcileDaemonCodexDefaultHomeMarker( } /** Drops the one-shot marker from shells whose startup path cannot consume it. */ -export function scrubCodexDefaultHomeMarkerForWindowsShell( +export function scrubCodexDefaultHomeMarkerForLaunch( env: Record, - shellPath: string + supportsCodexDefaultHomeAfterProfile: boolean | undefined ): void { - const shellName = pathWin32.basename(shellPath).toLowerCase() - if ( - shellName !== 'powershell.exe' && - shellName !== 'pwsh.exe' && - !isWindowsGitBashShellPath(shellPath) - ) { + if (!supportsCodexDefaultHomeAfterProfile) { delete env[ORCA_CODEX_DEFAULT_HOME_AFTER_PROFILE_ENV] } }