diff --git a/src/main/codex-accounts/runtime-home-service.test.ts b/src/main/codex-accounts/runtime-home-service.test.ts index f4349930751..b3f9fa4f41f 100644 --- a/src/main/codex-accounts/runtime-home-service.test.ts +++ b/src/main/codex-accounts/runtime-home-service.test.ts @@ -361,6 +361,48 @@ describe('CodexRuntimeHomeService', () => { ) }) + it('uses the canonical Electron userData for legacy active host migration', async () => { + const staleUserDataDir = mkdtempSync(join(tmpdir(), 'orca-stale-runtime-home-')) + const staleRuntimeHomePath = join(staleUserDataDir, 'codex-runtime-home', 'home') + try { + mkdirSync(staleRuntimeHomePath, { recursive: true }) + process.env.ORCA_USER_DATA_PATH = staleUserDataDir + const legacyLaunchHomePath = join( + testState.userDataDir, + 'codex-runtime-home', + 'launch', + 'host', + 'account-old', + 'home' + ) + const legacyActiveHomePath = getLegacyActiveHostCodexHomePath() + mkdirSync(legacyLaunchHomePath, { recursive: true }) + mkdirSync(join(legacyActiveHomePath, '..'), { recursive: true }) + symlinkSync( + legacyLaunchHomePath, + legacyActiveHomePath, + process.platform === 'win32' ? 'junction' : undefined + ) + writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') + const store = createStore(createSettings()) + + const { configureOrcaUserDataPathEnv } = await import('../startup/configure-process') + configureOrcaUserDataPathEnv() + const { CodexRuntimeHomeService } = await import('./runtime-home-service') + new CodexRuntimeHomeService(store as never) + + expect(process.env.ORCA_USER_DATA_PATH).toBe(testState.userDataDir) + expect(normalizeLinkTarget(readlinkSync(legacyActiveHomePath))).toBe( + normalizeLinkTarget(getRuntimeCodexHomePath()) + ) + expect(normalizeLinkTarget(readlinkSync(legacyActiveHomePath))).not.toBe( + normalizeLinkTarget(staleRuntimeHomePath) + ) + } finally { + rmSync(staleUserDataDir, { recursive: true, force: true }) + } + }) + it('does not create a legacy active host pointer for fresh shared-home users', async () => { writeFileSync(getSystemCodexAuthPath(), '{"account":"system"}\n', 'utf-8') const store = createStore(createSettings()) diff --git a/src/main/index.ts b/src/main/index.ts index fa90ae9fb10..71e9fc3c09d 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -45,6 +45,7 @@ import { import { checkForUpdatesFromMenu, isQuittingForUpdate } from './updater' import { configureDevUserDataPath, + configureOrcaUserDataPathEnv, enableMainProcessGpuFeatures, installDevParentDisconnectQuit, installDevParentSignalQuit, @@ -233,9 +234,7 @@ if (app.isPackaged && process.platform !== 'win32') { }) } configureDevUserDataPath(is.dev) -// Why: CLI-shared Codex helpers cannot import Electron. Seed the resolved -// app userData path once Electron has applied dev/e2e overrides. -process.env.ORCA_USER_DATA_PATH ??= app.getPath('userData') +configureOrcaUserDataPathEnv() const startupDiagnosticsEnabled = isStartupDiagnosticsEnabled() if (startupDiagnosticsEnabled) { logStartupDiagnostic('before-single-instance-lock', { diff --git a/src/main/startup/configure-process.test.ts b/src/main/startup/configure-process.test.ts index 4f33ea01809..370b1d3bdb8 100644 --- a/src/main/startup/configure-process.test.ts +++ b/src/main/startup/configure-process.test.ts @@ -151,6 +151,30 @@ describe('configureDevUserDataPath', () => { }) }) +describe('configureOrcaUserDataPathEnv', () => { + it('overwrites stale inherited ORCA_USER_DATA_PATH with Electron userData', async () => { + const { app } = await import('electron') + const { configureOrcaUserDataPathEnv } = await import('./configure-process') + const originalUserDataPath = process.env.ORCA_USER_DATA_PATH + process.env.ORCA_USER_DATA_PATH = '/tmp/stale-orca-user-data' + app.setPath('userData', '/tmp/current-orca-user-data') + let configuredUserDataPath: string | undefined + + try { + configureOrcaUserDataPathEnv() + configuredUserDataPath = process.env.ORCA_USER_DATA_PATH + } finally { + if (originalUserDataPath === undefined) { + delete process.env.ORCA_USER_DATA_PATH + } else { + process.env.ORCA_USER_DATA_PATH = originalUserDataPath + } + } + + expect(configuredUserDataPath).toBe('/tmp/current-orca-user-data') + }) +}) + describe('shouldInstallManagedHooks', () => { it('keeps managed hook auto-install enabled for default dev runs', async () => { const { shouldInstallManagedHooks } = await import('./configure-process') diff --git a/src/main/startup/configure-process.ts b/src/main/startup/configure-process.ts index 175cfab544e..4a859d64597 100644 --- a/src/main/startup/configure-process.ts +++ b/src/main/startup/configure-process.ts @@ -145,6 +145,13 @@ export function configureDevUserDataPath(isDev: boolean): void { app.setPath('userData', join(app.getPath('appData'), 'orca-dev')) } +export function configureOrcaUserDataPathEnv(): void { + // Why: app relaunches can inherit an ORCA_USER_DATA_PATH from an older CLI or + // updater process. Main must canonicalize it before CLI-shared modules build + // runtime-home paths, or migrations can bridge two Orca app-data directories. + process.env.ORCA_USER_DATA_PATH = app.getPath('userData') +} + export function shouldInstallManagedHooks(isDev: boolean): boolean { void isDev // Why: managed hook installation now targets Orca-owned, environment-scoped