diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt index 235a1cd579c..882ec9afeb1 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-bash-rcfile.txt @@ -42,7 +42,7 @@ if [[ -n "${ORCA_DATA_ACCOUNT_DATA_HOME:-}" ]]; then export OPENCODE_DB="opencode.db" fi fi -[[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}" +[[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}" # Why: OMP does not auto-load Orca's managed status extension; wrap only # interactive launch invocations so subcommands such as `omp config` keep # their normal argv shape. diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt index a3fc8a9caeb..e605b40ebcd 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/daemon-zsh-zshenv.txt @@ -118,7 +118,7 @@ __orca_deferred_init() { export OPENCODE_DB="opencode.db" fi fi - [[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}" + [[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}" # Why: OMP does not auto-load Orca's managed status extension; wrap only # interactive launch invocations so subcommands such as `omp config` keep # their normal argv shape. diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt b/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt index 08c4705d1af..d8ba9ce90de 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/local-bash-rcfile.txt @@ -50,7 +50,7 @@ if [[ -n "${ORCA_DATA_ACCOUNT_DATA_HOME:-}" ]]; then export OPENCODE_DB="opencode.db" fi fi -[[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}" +[[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}" # Why: OMP does not auto-load Orca's managed status extension; wrap only # interactive launch invocations so subcommands such as `omp config` keep # their normal argv shape. diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt b/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt index 4267902cad6..63c76dcc739 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/local-zsh-zshenv.txt @@ -125,7 +125,7 @@ __orca_deferred_init() { export OPENCODE_DB="opencode.db" fi fi - [[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}" + [[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}" # Why: OMP does not auto-load Orca's managed status extension; wrap only # interactive launch invocations so subcommands such as `omp config` keep # their normal argv shape. diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt b/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt index e9cc47d8361..894f53fd4ce 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/relay-bash-rcfile.txt @@ -24,7 +24,7 @@ fi [[ $- == *i* ]] && bind 'set enable-bracketed-paste on' 2>/dev/null # Why: remote startup files can re-export user defaults after relay spawn. [[ -n "${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="${ORCA_OPENCODE_CONFIG_DIR}" -[[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}" +[[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}" [[ -n "${ORCA_REMOTE_CLI_BIN_DIR:-}" ]] && case ":$PATH:" in *:"${ORCA_REMOTE_CLI_BIN_DIR}":*) ;; *) export PATH="${ORCA_REMOTE_CLI_BIN_DIR}:$PATH" ;; esac if [ -n "${ORCA_CLI_BIN_DIR:-}" ]; then case "${PATH:-}" in diff --git a/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt b/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt index d17479e64ae..57ec4bbef5a 100644 --- a/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt +++ b/src/main/__fixtures__/shell-wrapper-snapshots/relay-zsh-zshenv.txt @@ -100,7 +100,7 @@ __orca_deferred_init() { export OPENCODE_DB="opencode.db" fi fi - [[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}" + [[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}" [[ -n "${ORCA_REMOTE_CLI_BIN_DIR:-}" ]] && case ":$PATH:" in *:"${ORCA_REMOTE_CLI_BIN_DIR}":*) ;; *) export PATH="${ORCA_REMOTE_CLI_BIN_DIR}:$PATH" ;; esac # Why: OMP does not auto-load Orca's managed status extension; wrap only # interactive launch invocations so subcommands such as `omp config` keep diff --git a/src/main/daemon/daemon-bash-shell-ready-rcfile.ts b/src/main/daemon/daemon-bash-shell-ready-rcfile.ts index f43b53d4485..e5c13faa4ff 100644 --- a/src/main/daemon/daemon-bash-shell-ready-rcfile.ts +++ b/src/main/daemon/daemon-bash-shell-ready-rcfile.ts @@ -37,7 +37,7 @@ ${ORCA_CLI_POSIX_PATH_RESTORE} # Restore the managed OpenCode config after user profiles may have replaced it. [[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}" ${MANAGED_DATA_ACCOUNT_POSIX_RESTORE} -[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}" +[[ -n "\${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="\${ORCA_MIMOCODE_CONFIG_DIR}" ${getPosixOmpShellWrapper()} # Preserve the managed CODEX_HOME after user profiles. [[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}" diff --git a/src/main/daemon/pty-subprocess-managed-agent-env.test.ts b/src/main/daemon/pty-subprocess-managed-agent-env.test.ts index 5ccfc4c35f7..d0532860263 100644 --- a/src/main/daemon/pty-subprocess-managed-agent-env.test.ts +++ b/src/main/daemon/pty-subprocess-managed-agent-env.test.ts @@ -151,8 +151,8 @@ describe('createPtySubprocess', () => { rows: 24, env: { SHELL: '/bin/zsh', - MIMOCODE_HOME: '/tmp/orca-mimocode-overlay', - ORCA_MIMOCODE_HOME: '/tmp/orca-mimocode-overlay' + MIMOCODE_CONFIG_DIR: '/tmp/orca-mimocode-overlay', + ORCA_MIMOCODE_CONFIG_DIR: '/tmp/orca-mimocode-overlay' } }) } finally { diff --git a/src/main/daemon/pty-subprocess-test-harness.ts b/src/main/daemon/pty-subprocess-test-harness.ts index 9b8b70ca1aa..c33386b86eb 100644 --- a/src/main/daemon/pty-subprocess-test-harness.ts +++ b/src/main/daemon/pty-subprocess-test-harness.ts @@ -7,7 +7,7 @@ import { join } from 'node:path' const ORCA_SHELL_WRAPPER_ENV = [ 'ORCA_OPENCODE_CONFIG_DIR', - 'ORCA_MIMOCODE_HOME', + 'ORCA_MIMOCODE_CONFIG_DIR', 'ORCA_PI_CODING_AGENT_DIR', 'ORCA_OMP_CODING_AGENT_DIR', 'ORCA_OMP_STATUS_EXTENSION', diff --git a/src/main/daemon/shell-ready.test.ts b/src/main/daemon/shell-ready.test.ts index 2c8b29e8c4a..7b026a63263 100644 --- a/src/main/daemon/shell-ready.test.ts +++ b/src/main/daemon/shell-ready.test.ts @@ -552,7 +552,7 @@ describePosix('daemon shell-ready launch config', () => { const restoreLine = '[[ -n "${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="${ORCA_OPENCODE_CONFIG_DIR}"' const mimoRestoreLine = - '[[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}"' + '[[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}"' const codexRestoreLine = '[[ -n "${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="${ORCA_CODEX_HOME}"' const agentTeamsPathRestoreLine = '[[ -n "${ORCA_AGENT_TEAMS_SHIM_DIR:-}" ]] || return 0' diff --git a/src/main/ipc/pty-ipc-mock-registry.ts b/src/main/ipc/pty-ipc-mock-registry.ts index b2dff12df7a..63e362851c3 100644 --- a/src/main/ipc/pty-ipc-mock-registry.ts +++ b/src/main/ipc/pty-ipc-mock-registry.ts @@ -123,9 +123,10 @@ export const openCodeHookServiceModuleMock = () => ({ }) export const mimoHookServiceModuleMock = (): { - mimoCodeHookService: { buildPtyEnv: Mock } + mimoCodeHookService: { carryOverLegacyAuth: Mock; buildPtyEnv: Mock } } => ({ mimoCodeHookService: { + carryOverLegacyAuth: vi.fn(), buildPtyEnv: mimoCodeBuildPtyEnvMock } }) diff --git a/src/main/ipc/pty-ipc-suite-environment.ts b/src/main/ipc/pty-ipc-suite-environment.ts index b1e32e7347f..dff8253b2c7 100644 --- a/src/main/ipc/pty-ipc-suite-environment.ts +++ b/src/main/ipc/pty-ipc-suite-environment.ts @@ -221,8 +221,10 @@ export function createPtyIpcSuiteEnvironment(): PtyIpcSuiteEnvironment { ? '/tmp/orca-opencode2-overlay' : '/tmp/orca-opencode2-config' })) - mimoCodeBuildPtyEnvMock.mockImplementation((_ptyId: string, existingHome?: string) => ({ - MIMOCODE_HOME: existingHome ? '/tmp/orca-mimocode-overlay' : '/tmp/orca-mimocode-shared' + mimoCodeBuildPtyEnvMock.mockImplementation((_ptyId: string, existingConfigDir?: string) => ({ + MIMOCODE_CONFIG_DIR: existingConfigDir + ? '/tmp/orca-mimocode-overlay' + : '/tmp/orca-mimocode-shared' })) buildAgentHookEnvMock.mockReturnValue({ ORCA_AGENT_HOOK_PORT: '5678', diff --git a/src/main/ipc/pty/host-env/assembly.ts b/src/main/ipc/pty/host-env/assembly.ts index b8c3d997d94..3db762dc17f 100644 --- a/src/main/ipc/pty/host-env/assembly.ts +++ b/src/main/ipc/pty/host-env/assembly.ts @@ -26,7 +26,7 @@ import { clearPiAgentShadowEnv, exposePiManagedExtensionEnv, isMimoLaunchCommand, - resolveMimocodeSourceHome, + resolveMimocodeSourceConfigDir, resolvePiAgentSourceDir, resolveScopedPiAgentSourceDir } from './pi-agent' @@ -100,25 +100,29 @@ export function buildPtyHostEnv( opts, launchCommandHint ) - if (opts.agentStatusHooksEnabled) { - if (isMimoLaunchCommand(launchCommandHint)) { - const preexistingMimocodeHome = resolveMimocodeSourceHome(baseEnv) - Object.assign(baseEnv, mimoCodeHookService.buildPtyEnv(id, preexistingMimocodeHome)) - if (baseEnv.MIMOCODE_HOME) { - baseEnv.ORCA_MIMOCODE_HOME = baseEnv.MIMOCODE_HOME - if (preexistingMimocodeHome) { - baseEnv.ORCA_MIMOCODE_SOURCE_HOME = preexistingMimocodeHome - } else { - delete baseEnv.ORCA_MIMOCODE_SOURCE_HOME - } + // Older builds redirected MIMOCODE_HOME; a nested pane must not inherit that overlay. + restoreOrStripOverlayEnv(baseEnv, { + primary: 'MIMOCODE_HOME', + overlay: 'ORCA_MIMOCODE_HOME', + source: 'ORCA_MIMOCODE_SOURCE_HOME' + }) + restoreOrStripOverlayEnv(baseEnv, { + primary: 'MIMOCODE_CONFIG_DIR', + overlay: 'ORCA_MIMOCODE_CONFIG_DIR', + source: 'ORCA_MIMOCODE_SOURCE_CONFIG_DIR', + preserveExplicitPrimary: true + }) + const mimoSourceConfigDir = resolveMimocodeSourceConfigDir(baseEnv) + if (opts.agentStatusHooksEnabled && isMimoLaunchCommand(launchCommandHint)) { + mimoCodeHookService.carryOverLegacyAuth({ ...process.env, ...baseEnv }) + const overlay = mimoCodeHookService.buildPtyEnv(id, mimoSourceConfigDir).MIMOCODE_CONFIG_DIR + if (overlay && overlay !== mimoSourceConfigDir) { + baseEnv.MIMOCODE_CONFIG_DIR = overlay + baseEnv.ORCA_MIMOCODE_CONFIG_DIR = overlay + if (mimoSourceConfigDir) { + baseEnv.ORCA_MIMOCODE_SOURCE_CONFIG_DIR = mimoSourceConfigDir } } - } else { - restoreOrStripOverlayEnv(baseEnv, { - primary: 'MIMOCODE_HOME', - overlay: 'ORCA_MIMOCODE_HOME', - source: 'ORCA_MIMOCODE_SOURCE_HOME' - }) } // Remove inherited hook coordinates before injecting the owning pane's receiver. diff --git a/src/main/ipc/pty/host-env/pi-agent.ts b/src/main/ipc/pty/host-env/pi-agent.ts index 917191a7822..e71e0b8f452 100644 --- a/src/main/ipc/pty/host-env/pi-agent.ts +++ b/src/main/ipc/pty/host-env/pi-agent.ts @@ -136,7 +136,9 @@ export function getInheritedAgentHookEnvKeysToDelete( 'ORCA_CLAUDE_CONFIG_DIR', 'ORCA_OPENCODE_AGENT', 'ORCA_OPENCODE_CONFIG_DIR', - 'ORCA_OPENCODE_SOURCE_CONFIG_DIR' + 'ORCA_OPENCODE_SOURCE_CONFIG_DIR', + 'ORCA_MIMOCODE_CONFIG_DIR', + 'ORCA_MIMOCODE_SOURCE_CONFIG_DIR' ].filter((key) => env[key] === undefined) } @@ -155,17 +157,19 @@ export function isMimoLaunchCommand(launchCommand: string | undefined): boolean return getAgentLaunchExecutableName(launchCommand) === 'mimo' } -export function resolveMimocodeSourceHome(baseEnv: Record): string | undefined { - const sourceHome = baseEnv.ORCA_MIMOCODE_SOURCE_HOME ?? process.env.ORCA_MIMOCODE_SOURCE_HOME - if (sourceHome) { - return sourceHome +/** Call after the overlay env is restored: an explicit pane value wins over inherited markers. */ +export function resolveMimocodeSourceConfigDir( + baseEnv: Record, + inheritedEnv: NodeJS.ProcessEnv = process.env +): string | undefined { + if (baseEnv.MIMOCODE_CONFIG_DIR) { + return baseEnv.MIMOCODE_CONFIG_DIR } - const configHome = baseEnv.MIMOCODE_HOME ?? process.env.MIMOCODE_HOME - const orcaHome = baseEnv.ORCA_MIMOCODE_HOME ?? process.env.ORCA_MIMOCODE_HOME - if (configHome && orcaHome && configHome === orcaHome) { - return undefined + if (inheritedEnv.ORCA_MIMOCODE_SOURCE_CONFIG_DIR) { + return inheritedEnv.ORCA_MIMOCODE_SOURCE_CONFIG_DIR } - return configHome + const configDir = inheritedEnv.MIMOCODE_CONFIG_DIR + return configDir && configDir === inheritedEnv.ORCA_MIMOCODE_CONFIG_DIR ? undefined : configDir } export function resolveOpenCodeSourceConfigDir( diff --git a/src/main/ipc/pty/pty-spawn-env-agent-overlays.test.ts b/src/main/ipc/pty/pty-spawn-env-agent-overlays.test.ts index a81fb90fe14..e8039daaca0 100644 --- a/src/main/ipc/pty/pty-spawn-env-agent-overlays.test.ts +++ b/src/main/ipc/pty/pty-spawn-env-agent-overlays.test.ts @@ -264,9 +264,9 @@ describe('registerPtyHandlers', () => { const env = await spawnAndGetEnv(undefined, undefined, undefined, undefined, 'mimo') expect(mimoCodeBuildPtyEnvMock).toHaveBeenCalledTimes(1) - expect(env.MIMOCODE_HOME).toBe('/tmp/orca-mimocode-shared') - expect(env.ORCA_MIMOCODE_HOME).toBe('/tmp/orca-mimocode-shared') - expect(env.ORCA_MIMOCODE_SOURCE_HOME).toBeUndefined() + expect(env.MIMOCODE_CONFIG_DIR).toBe('/tmp/orca-mimocode-shared') + expect(env.ORCA_MIMOCODE_CONFIG_DIR).toBe('/tmp/orca-mimocode-shared') + expect(env.ORCA_MIMOCODE_SOURCE_CONFIG_DIR).toBeUndefined() }) it.each([ '/usr/local/bin/mimo --prompt hi', @@ -276,8 +276,8 @@ describe('registerPtyHandlers', () => { const env = await spawnAndGetEnv(undefined, undefined, undefined, undefined, launchCommand) expect(mimoCodeBuildPtyEnvMock).toHaveBeenCalledTimes(1) - expect(env.MIMOCODE_HOME).toBe('/tmp/orca-mimocode-shared') - expect(env.ORCA_MIMOCODE_HOME).toBe('/tmp/orca-mimocode-shared') + expect(env.MIMOCODE_CONFIG_DIR).toBe('/tmp/orca-mimocode-shared') + expect(env.ORCA_MIMOCODE_CONFIG_DIR).toBe('/tmp/orca-mimocode-shared') }) it('uses sequenced startup env as the MiMo launch hint when command is a wrapper', async () => { const env = await spawnAndGetEnv( @@ -289,20 +289,20 @@ describe('registerPtyHandlers', () => { ) expect(mimoCodeBuildPtyEnvMock).toHaveBeenCalledTimes(1) - expect(env.MIMOCODE_HOME).toBe('/tmp/orca-mimocode-shared') - expect(env.ORCA_MIMOCODE_HOME).toBe('/tmp/orca-mimocode-shared') + expect(env.MIMOCODE_CONFIG_DIR).toBe('/tmp/orca-mimocode-shared') + expect(env.ORCA_MIMOCODE_CONFIG_DIR).toBe('/tmp/orca-mimocode-shared') }) it('does not inject MiMo overlay for non-mimo launches', async () => { await spawnAndGetEnv() expect(mimoCodeBuildPtyEnvMock).not.toHaveBeenCalled() }) - it('restores user MiMo home when agent status hooks are disabled in a nested Orca shell', async () => { + it('restores user MiMo config dir when agent status hooks are disabled in a nested Orca shell', async () => { const env = await spawnAndGetEnv( { - MIMOCODE_HOME: '/tmp/parent-orca-mimocode-overlay', - ORCA_MIMOCODE_HOME: '/tmp/parent-orca-mimocode-overlay', - ORCA_MIMOCODE_SOURCE_HOME: '/tmp/user-mimocode-home' + MIMOCODE_CONFIG_DIR: '/tmp/parent-orca-mimocode-overlay', + ORCA_MIMOCODE_CONFIG_DIR: '/tmp/parent-orca-mimocode-overlay', + ORCA_MIMOCODE_SOURCE_CONFIG_DIR: '/tmp/user-mimocode-config' }, undefined, undefined, @@ -311,9 +311,27 @@ describe('registerPtyHandlers', () => { ) expect(mimoCodeBuildPtyEnvMock).not.toHaveBeenCalled() + expect(env.MIMOCODE_CONFIG_DIR).toBe('/tmp/user-mimocode-config') + expect(env.ORCA_MIMOCODE_CONFIG_DIR).toBeUndefined() + expect(env.ORCA_MIMOCODE_SOURCE_CONFIG_DIR).toBeUndefined() + }) + it("leaves MiMo's home alone and drops an older build's MIMOCODE_HOME overlay", async () => { + const env = await spawnAndGetEnv( + { + MIMOCODE_HOME: '/tmp/parent-orca-mimocode-home', + ORCA_MIMOCODE_HOME: '/tmp/parent-orca-mimocode-home', + ORCA_MIMOCODE_SOURCE_HOME: '/tmp/user-mimocode-home' + }, + undefined, + undefined, + undefined, + 'mimo' + ) + expect(env.MIMOCODE_HOME).toBe('/tmp/user-mimocode-home') expect(env.ORCA_MIMOCODE_HOME).toBeUndefined() expect(env.ORCA_MIMOCODE_SOURCE_HOME).toBeUndefined() + expect(env.MIMOCODE_CONFIG_DIR).toBe('/tmp/orca-mimocode-shared') }) posixOnlyIt( 'reproduces issue #1534: GUI-launched Orca mirrors zshrc-only OpenCode config', diff --git a/src/main/mimo/hook-service.test.ts b/src/main/mimo/hook-service.test.ts index f1ef11e3949..82003455e1f 100644 --- a/src/main/mimo/hook-service.test.ts +++ b/src/main/mimo/hook-service.test.ts @@ -1,5 +1,15 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + statSync, + symlinkSync, + writeFileSync +} from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { setAppEnvironment } from '../../shared/app-environment' @@ -12,7 +22,7 @@ import { MimoCodeHookService } from './hook-service' describe('MimoCodeHookService buildPtyEnv', () => { let userDataDir: string - let mimocodeHome: string + let userConfigDir: string beforeEach(() => { userDataDir = mkdtempSync(join(tmpdir(), 'orca-mimocode-userdata-')) @@ -32,53 +42,109 @@ describe('MimoCodeHookService buildPtyEnv', () => { getAppMetrics: () => [] }) - mimocodeHome = mkdtempSync(join(tmpdir(), 'orca-mimocode-home-')) - const configDir = join(mimocodeHome, 'config') - mkdirSync(join(configDir, 'plugins'), { recursive: true }) - writeFileSync(join(configDir, 'mimocode.json'), '{"theme":"dark"}') - writeFileSync(join(configDir, 'plugins', 'user-plugin.js'), 'export default () => {}') - writeFileSync(join(configDir, 'plugins', 'orca-mimocode-status.js'), 'USER PLUGIN') + userConfigDir = mkdtempSync(join(tmpdir(), 'orca-mimocode-config-')) + mkdirSync(join(userConfigDir, 'plugins'), { recursive: true }) + writeFileSync(join(userConfigDir, 'mimocode.json'), '{"theme":"dark"}') + writeFileSync(join(userConfigDir, 'plugins', 'user-plugin.js'), 'export default () => {}') + writeFileSync(join(userConfigDir, 'plugins', 'orca-mimocode-status.js'), 'USER PLUGIN') }) afterEach(() => { rmSync(userDataDir, { recursive: true, force: true }) - rmSync(mimocodeHome, { recursive: true, force: true }) + rmSync(userConfigDir, { recursive: true, force: true }) }) - it('mirrors user config into shared overlay and installs Orca status plugin', () => { - const service = new MimoCodeHookService() - const env = service.buildPtyEnv('pty-1', mimocodeHome) + // MIMOCODE_HOME also moves auth.json, sessions and state (#9132); only add a config layer. + it('sets only MIMOCODE_CONFIG_DIR to a directory holding just the Orca plugin', () => { + const env = new MimoCodeHookService().buildPtyEnv('pty-1') - const overlayHome = join(userDataDir, 'mimocode-hooks', 'shared') - expect(env.MIMOCODE_HOME).toBe(overlayHome) - expect(readFileSync(join(overlayHome, 'config', 'mimocode.json'), 'utf8')).toBe( - '{"theme":"dark"}' - ) - expect(readFileSync(join(overlayHome, 'config', 'plugins', 'user-plugin.js'), 'utf8')).toBe( - 'export default () => {}' - ) - - const orcaPlugin = join(overlayHome, 'config', 'plugins', 'orca-mimocode-status.js') - expect(existsSync(orcaPlugin)).toBe(true) - const pluginSource = readFileSync(orcaPlugin, 'utf8') + const overlay = join(userDataDir, 'mimocode-hooks', 'config') + expect(env).toEqual({ MIMOCODE_CONFIG_DIR: overlay }) + expect(readdirSync(overlay)).toEqual(['plugins']) + const pluginSource = readFileSync(join(overlay, 'plugins', 'orca-mimocode-status.js'), 'utf8') expect(pluginSource).toContain('/hook/mimo-code') expect(pluginSource).not.toContain('post("SessionStart"') - - expect( - readFileSync(join(mimocodeHome, 'config', 'plugins', 'orca-mimocode-status.js'), 'utf8') - ).toBe('USER PLUGIN') }) - it('reuses the overlay home on a second buildPtyEnv call', () => { - const service = new MimoCodeHookService() - const first = service.buildPtyEnv('pty-1', mimocodeHome) - const second = service.buildPtyEnv('pty-2', mimocodeHome) + it("layers the user's own MIMOCODE_CONFIG_DIR into the overlay without touching it", () => { + const env = new MimoCodeHookService().buildPtyEnv('pty-1', userConfigDir) - const overlayHome = join(userDataDir, 'mimocode-hooks', 'shared') - expect(first.MIMOCODE_HOME).toBe(overlayHome) - expect(second.MIMOCODE_HOME).toBe(overlayHome) - expect( - readFileSync(join(overlayHome, 'config', 'plugins', 'orca-mimocode-status.js'), 'utf8') - ).toContain('/hook/mimo-code') + const overlay = env.MIMOCODE_CONFIG_DIR ?? '' + expect(overlay).toContain(join(userDataDir, 'mimocode-hooks', 'config-overlays')) + expect(readFileSync(join(overlay, 'mimocode.json'), 'utf8')).toBe('{"theme":"dark"}') + expect(readFileSync(join(overlay, 'plugins', 'user-plugin.js'), 'utf8')).toBe( + 'export default () => {}' + ) + expect(readFileSync(join(overlay, 'plugins', 'orca-mimocode-status.js'), 'utf8')).toContain( + '/hook/mimo-code' + ) + expect(readFileSync(join(userConfigDir, 'plugins', 'orca-mimocode-status.js'), 'utf8')).toBe( + 'USER PLUGIN' + ) + }) + + it.skipIf(process.platform === 'win32')( + "never writes the Orca plugin through a user's linked plugins folder", + () => { + const linkedPlugins = mkdtempSync(join(tmpdir(), 'orca-mimocode-linked-plugins-')) + writeFileSync(join(linkedPlugins, 'user-plugin.js'), 'export default () => {}') + rmSync(join(userConfigDir, 'plugins'), { recursive: true }) + symlinkSync(linkedPlugins, join(userConfigDir, 'plugins')) + try { + const env = new MimoCodeHookService().buildPtyEnv('pty-1', userConfigDir) + + expect(existsSync(join(env.MIMOCODE_CONFIG_DIR ?? '', 'plugins', 'user-plugin.js'))).toBe( + true + ) + expect(readdirSync(linkedPlugins)).toEqual(['user-plugin.js']) + } finally { + rmSync(linkedPlugins, { recursive: true, force: true }) + } + } + ) + + it('carries a login made under the old Orca MIMOCODE_HOME over once, owner-only', () => { + const legacyData = join(userDataDir, 'mimocode-hooks', 'shared', 'data') + mkdirSync(legacyData, { recursive: true }) + writeFileSync(join(legacyData, 'auth.json'), '{"legacy":true}') + const xdgData = join(userDataDir, 'xdg-data') + const service = new MimoCodeHookService() + + service.carryOverLegacyAuth({ XDG_DATA_HOME: xdgData }) + const auth = join(xdgData, 'mimocode', 'auth.json') + expect(readFileSync(auth, 'utf8')).toBe('{"legacy":true}') + if (process.platform !== 'win32') { + expect(statSync(auth).mode & 0o777).toBe(0o600) + } + + expect(existsSync(join(legacyData, 'auth.json'))).toBe(false) + expect(existsSync(join(legacyData, 'auth.json.migrated'))).toBe(true) + + rmSync(auth) + service.carryOverLegacyAuth({ XDG_DATA_HOME: xdgData }) + expect(existsSync(auth)).toBe(false) + }) + + it('never overwrites an existing login or follows a relative MIMOCODE_HOME', () => { + const legacyData = join(userDataDir, 'mimocode-hooks', 'shared', 'data') + mkdirSync(legacyData, { recursive: true }) + writeFileSync(join(legacyData, 'auth.json'), '{"legacy":true}') + const xdgData = join(userDataDir, 'xdg-data') + mkdirSync(join(xdgData, 'mimocode'), { recursive: true }) + const auth = join(xdgData, 'mimocode', 'auth.json') + writeFileSync(auth, '{"canonical":true}') + const service = new MimoCodeHookService() + + service.carryOverLegacyAuth({ MIMOCODE_HOME: 'relative-mimo-home' }) + expect(existsSync(join(process.cwd(), 'relative-mimo-home'))).toBe(false) + expect(existsSync(join(legacyData, 'auth.json'))).toBe(true) + + service.carryOverLegacyAuth({ XDG_DATA_HOME: xdgData }) + expect(readFileSync(auth, 'utf8')).toBe('{"canonical":true}') + expect(existsSync(join(legacyData, 'auth.json.migrated'))).toBe(true) + + rmSync(auth) + service.carryOverLegacyAuth({ XDG_DATA_HOME: xdgData }) + expect(existsSync(auth)).toBe(false) }) }) diff --git a/src/main/mimo/hook-service.ts b/src/main/mimo/hook-service.ts index 52fcc4e836f..5db7e31015f 100644 --- a/src/main/mimo/hook-service.ts +++ b/src/main/mimo/hook-service.ts @@ -1,81 +1,150 @@ import { getAppEnvironment } from '../../shared/app-environment' -import { join } from 'node:path' -import { existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs' +import { isAbsolute, join } from 'node:path' import { homedir } from 'node:os' +import { + chmodSync, + constants, + copyFileSync, + existsSync, + lstatSync, + mkdirSync, + readdirSync, + renameSync, + statSync, + writeFileSync +} from 'node:fs' import { getOpenCodeFamilyPluginSource } from '../opencode/hook-service' -import { mirrorEntry, safeRemoveTree } from '../pty/overlay-mirror' +import { sourceOverlayDirName } from '../opencode/overlay-dir-names' +import { + clearOpenCodeOverlayManifestEntries, + readOpenCodeOverlayManifest, + writeOpenCodeOverlayManifest, + type OpenCodeOverlayManifest +} from '../opencode/opencode-overlay-manifest' +import { isSafeDescendCandidate, mirrorEntry, safeRemoveOverlay } from '../pty/overlay-mirror' const ORCA_MIMOCODE_PLUGIN_FILE = 'orca-mimocode-status.js' const MIMOCODE_HOOKS_DIR = 'mimocode-hooks' -const MIMOCODE_SHARED_HOME = 'shared' +const PLUGIN_ONLY_CONFIG_DIR = 'config' +const SOURCE_CONFIG_OVERLAYS_DIR = 'config-overlays' +const LEGACY_SHARED_HOME = 'shared' -function defaultMimocodeConfigDir(): string { - return join(homedir(), '.config', 'mimocode') -} - -function resolveSourceConfigDir(existingHome: string | undefined): string | undefined { - if (existingHome) { - const fromHome = join(existingHome, 'config') - if (existsSync(fromHome)) { - return fromHome - } +function isDirectoryFollowingLinks(path: string): boolean { + try { + return statSync(path).isDirectory() + } catch { + return false } - const xdg = defaultMimocodeConfigDir() - return existsSync(xdg) ? xdg : undefined } +function mirrorInto(sourcePath: string, targetDir: string, name: string): void { + // MiMo may have created a same-named file in the overlay since the last launch. + safeRemoveOverlay(join(targetDir, name), targetDir) + mirrorEntry(sourcePath, join(targetDir, name)) +} + +// Keep MiMo-written overlay files (installed plugin deps); replace only what was mirrored last time. function mirrorConfigDir(sourceConfigDir: string, targetConfigDir: string): void { - mkdirSync(targetConfigDir, { recursive: true }) + clearOpenCodeOverlayManifestEntries( + targetConfigDir, + readOpenCodeOverlayManifest(targetConfigDir), + ORCA_MIMOCODE_PLUGIN_FILE + ) + const manifest: OpenCodeOverlayManifest = { + topLevelEntries: [], + pluginEntries: [], + sourceConfigDir + } for (const entry of readdirSync(sourceConfigDir, { withFileTypes: true })) { - if (entry.name === 'plugins' && entry.isDirectory()) { + const sourcePath = join(sourceConfigDir, entry.name) + // A linked plugins dir must not be linked through, or Orca's plugin lands in the user's folder. + if (entry.name === 'plugins' && isDirectoryFollowingLinks(sourcePath)) { const overlayPlugins = join(targetConfigDir, 'plugins') - mkdirSync(overlayPlugins, { recursive: true }) - for (const pluginEntry of readdirSync(join(sourceConfigDir, 'plugins'), { - withFileTypes: true - })) { - if (pluginEntry.name === ORCA_MIMOCODE_PLUGIN_FILE) { - continue + if (!ensureRealDirectory(overlayPlugins)) { + throw new Error('MiMo overlay plugins folder is not a real directory') + } + for (const pluginName of readdirSync(sourcePath)) { + if (pluginName !== ORCA_MIMOCODE_PLUGIN_FILE) { + mirrorInto(join(sourcePath, pluginName), overlayPlugins, pluginName) + manifest.pluginEntries.push(pluginName) } - mirrorEntry( - join(sourceConfigDir, 'plugins', pluginEntry.name), - join(overlayPlugins, pluginEntry.name) - ) } continue } - mirrorEntry(join(sourceConfigDir, entry.name), join(targetConfigDir, entry.name)) + mirrorInto(sourcePath, targetConfigDir, entry.name) + manifest.topLevelEntries.push(entry.name) } + writeOpenCodeOverlayManifest(targetConfigDir, manifest) +} + +function ensureRealDirectory(path: string): boolean { + mkdirSync(path, { recursive: true }) + return isSafeDescendCandidate(lstatSync(path)) } export class MimoCodeHookService { clearPty(_ptyId: string): void {} - buildPtyEnv(_ptyId: string, existingMimocodeHome?: string): Record { - const home = join( - getAppEnvironment().getPath('userData'), - MIMOCODE_HOOKS_DIR, - MIMOCODE_SHARED_HOME - ) + /** MIMOCODE_CONFIG_DIR adds a config layer; MIMOCODE_HOME would also move auth and session data. */ + buildPtyEnv(_ptyId: string, existingConfigDir?: string): { MIMOCODE_CONFIG_DIR?: string } { + const fallback = { MIMOCODE_CONFIG_DIR: existingConfigDir } + const root = join(getAppEnvironment().getPath('userData'), MIMOCODE_HOOKS_DIR) + const overlay = existingConfigDir + ? join(root, SOURCE_CONFIG_OVERLAYS_DIR, sourceOverlayDirName(existingConfigDir)) + : join(root, PLUGIN_ONLY_CONFIG_DIR) try { - for (const sub of ['config', 'data', 'cache', 'state'] as const) { - mkdirSync(join(home, sub), { recursive: true }) + if (!ensureRealDirectory(root) || !ensureRealDirectory(overlay)) { + return fallback } - const overlayConfig = join(home, 'config') - const sourceConfig = resolveSourceConfigDir(existingMimocodeHome) - if (sourceConfig) { - safeRemoveTree(overlayConfig) - mirrorConfigDir(sourceConfig, overlayConfig) + if (existingConfigDir && existsSync(existingConfigDir)) { + mirrorConfigDir(existingConfigDir, overlay) + } + const pluginsDir = join(overlay, 'plugins') + if (!ensureRealDirectory(pluginsDir)) { + return fallback } - const pluginsDir = join(home, 'config', 'plugins') - mkdirSync(pluginsDir, { recursive: true }) writeFileSync( join(pluginsDir, ORCA_MIMOCODE_PLUGIN_FILE), getOpenCodeFamilyPluginSource('/hook/mimo-code', { emitSessionStart: false }) ) } catch { - return existingMimocodeHome ? { MIMOCODE_HOME: existingMimocodeHome } : {} + return fallback + } + return { MIMOCODE_CONFIG_DIR: overlay } + } + + /** Older builds kept MiMo data under Orca's MIMOCODE_HOME; move a login made there over once, then mark it migrated. */ + carryOverLegacyAuth(env: Record): void { + const legacyAuth = join( + getAppEnvironment().getPath('userData'), + MIMOCODE_HOOKS_DIR, + LEGACY_SHARED_HOME, + 'data', + 'auth.json' + ) + // MiMo rejects a relative MIMOCODE_HOME; Orca would otherwise write relative to its own cwd. + if (env.MIMOCODE_HOME && !isAbsolute(env.MIMOCODE_HOME)) { + return + } + // Mirrors MiMo's Global.Path.data resolution (xdg-basedir, or MIMOCODE_HOME/data). + const dataDir = env.MIMOCODE_HOME + ? join(env.MIMOCODE_HOME, 'data') + : join(env.XDG_DATA_HOME || join(homedir(), '.local', 'share'), 'mimocode') + const auth = join(dataDir, 'auth.json') + try { + if (!existsSync(legacyAuth)) { + return + } + if (!existsSync(auth)) { + mkdirSync(dataDir, { recursive: true }) + copyFileSync(legacyAuth, auth, constants.COPYFILE_EXCL) + chmodSync(auth, 0o600) + } + // Never restore the Orca-only login later, e.g. after the user deletes the canonical one. + renameSync(legacyAuth, `${legacyAuth}.migrated`) + } catch { + // A failed carry-over leaves MiMo logged out, as before; never block the launch. } - return { MIMOCODE_HOME: home } } } diff --git a/src/main/powershell-osc133-bootstrap.test.ts b/src/main/powershell-osc133-bootstrap.test.ts index 1cea5b57ccf..87f82d20917 100644 --- a/src/main/powershell-osc133-bootstrap.test.ts +++ b/src/main/powershell-osc133-bootstrap.test.ts @@ -27,7 +27,7 @@ describe('PowerShell OSC 133 bootstrap', () => { expect(script).toContain('[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()') expect(script).toContain('ORCA_OPENCODE_CONFIG_DIR') - expect(script).toContain('ORCA_MIMOCODE_HOME') + expect(script).toContain('ORCA_MIMOCODE_CONFIG_DIR') expect(script).not.toContain('ORCA_PI_CODING_AGENT_DIR') expect(script).not.toContain('ORCA_OMP_CODING_AGENT_DIR') expect(script).toContain('ORCA_OMP_STATUS_EXTENSION') diff --git a/src/main/powershell-osc133-bootstrap.ts b/src/main/powershell-osc133-bootstrap.ts index d90d448fff0..3acd91916af 100644 --- a/src/main/powershell-osc133-bootstrap.ts +++ b/src/main/powershell-osc133-bootstrap.ts @@ -10,7 +10,7 @@ const POWERSHELL_OSC133_BOOTSTRAP = `# Orca OSC 133 shell integration for PowerS # Restore managed ownership before the shell-integration compatibility guard. if ($env:ORCA_OPENCODE_CONFIG_DIR) { $env:OPENCODE_CONFIG_DIR = $env:ORCA_OPENCODE_CONFIG_DIR } ${MANAGED_DATA_ACCOUNT_POWERSHELL_RESTORE} -if ($env:ORCA_MIMOCODE_HOME) { $env:MIMOCODE_HOME = $env:ORCA_MIMOCODE_HOME } +if ($env:ORCA_MIMOCODE_CONFIG_DIR) { $env:MIMOCODE_CONFIG_DIR = $env:ORCA_MIMOCODE_CONFIG_DIR } if ($env:ORCA_CODEX_HOME) { $env:CODEX_HOME = $env:ORCA_CODEX_HOME } if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage" -and diff --git a/src/main/providers/local-pty-provider-spawn-env.test.ts b/src/main/providers/local-pty-provider-spawn-env.test.ts index 816b0292b23..999c37fa2e6 100644 --- a/src/main/providers/local-pty-provider-spawn-env.test.ts +++ b/src/main/providers/local-pty-provider-spawn-env.test.ts @@ -522,8 +522,8 @@ describe('LocalPtyProvider', () => { it('uses shell wrapper when MiMo home must survive shell startup', async () => { provider.configure({ buildSpawnEnv: (_id, env) => { - env.MIMOCODE_HOME = '/tmp/orca-mimocode-overlay' - env.ORCA_MIMOCODE_HOME = '/tmp/orca-mimocode-overlay' + env.MIMOCODE_CONFIG_DIR = '/tmp/orca-mimocode-overlay' + env.ORCA_MIMOCODE_CONFIG_DIR = '/tmp/orca-mimocode-overlay' return env } }) diff --git a/src/main/providers/local-pty-shell-ready-bash-rcfile.ts b/src/main/providers/local-pty-shell-ready-bash-rcfile.ts index 54c0803af7d..e9c1e101f62 100644 --- a/src/main/providers/local-pty-shell-ready-bash-rcfile.ts +++ b/src/main/providers/local-pty-shell-ready-bash-rcfile.ts @@ -43,7 +43,7 @@ ${WSL_MANAGED_CLI_PATH_RESTORE} # Restore Orca-managed config after user startup files may override it. [[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}" ${MANAGED_DATA_ACCOUNT_POSIX_RESTORE} -[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}" +[[ -n "\${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="\${ORCA_MIMOCODE_CONFIG_DIR}" ${getPosixOmpShellWrapper()} # Profile scripts must not replace Orca's runtime CODEX_HOME. [[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}" diff --git a/src/main/providers/local-pty-shell-ready-wrapper-generation.test.ts b/src/main/providers/local-pty-shell-ready-wrapper-generation.test.ts index ca7c7da5b6a..ab25abe0815 100644 --- a/src/main/providers/local-pty-shell-ready-wrapper-generation.test.ts +++ b/src/main/providers/local-pty-shell-ready-wrapper-generation.test.ts @@ -299,7 +299,7 @@ describePosix('local PTY shell-ready launch config', () => { const restoreLine = '[[ -n "${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="${ORCA_OPENCODE_CONFIG_DIR}"' const mimoRestoreLine = - '[[ -n "${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="${ORCA_MIMOCODE_HOME}"' + '[[ -n "${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="${ORCA_MIMOCODE_CONFIG_DIR}"' const codexRestoreLine = '[[ -n "${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="${ORCA_CODEX_HOME}"' const agentTeamsPathRestoreLine = '[[ -n "${ORCA_AGENT_TEAMS_SHIM_DIR:-}" ]] || return 0' diff --git a/src/main/providers/windows-shell-args.test.ts b/src/main/providers/windows-shell-args.test.ts index ec94959601e..d69abee50e6 100644 --- a/src/main/providers/windows-shell-args.test.ts +++ b/src/main/providers/windows-shell-args.test.ts @@ -125,7 +125,9 @@ describe('resolveWindowsShellLaunchArgs', () => { const opencodeRestoreIndex = command.indexOf( '$env:OPENCODE_CONFIG_DIR = $env:ORCA_OPENCODE_CONFIG_DIR' ) - const mimocodeRestoreIndex = command.indexOf('$env:MIMOCODE_HOME = $env:ORCA_MIMOCODE_HOME') + const mimocodeRestoreIndex = command.indexOf( + '$env:MIMOCODE_CONFIG_DIR = $env:ORCA_MIMOCODE_CONFIG_DIR' + ) const duplicateStateGuardIndex = command.indexOf('Test-Path variable:global:__OrcaOsc133State') const languageModeGuardIndex = command.indexOf('LanguageMode -eq "FullLanguage"') const ompWrapperIndex = command.indexOf('function Global:omp') diff --git a/src/main/shell-startup-features.ts b/src/main/shell-startup-features.ts index 90654c8e12a..64040f1d662 100644 --- a/src/main/shell-startup-features.ts +++ b/src/main/shell-startup-features.ts @@ -16,7 +16,7 @@ export type ShellStartupFeature = (typeof SHELL_STARTUP_FEATURES)[number] const OVERLAY_ENV_KEYS = [ 'ORCA_DATA_ACCOUNT_DATA_HOME', 'ORCA_OPENCODE_CONFIG_DIR', - 'ORCA_MIMOCODE_HOME', + 'ORCA_MIMOCODE_CONFIG_DIR', 'ORCA_OMP_STATUS_EXTENSION', 'ORCA_CODEX_HOME', 'ORCA_AGENT_TEAMS_SHIM_DIR', diff --git a/src/main/shell-wrapper-generated-file-snapshot.test.ts b/src/main/shell-wrapper-generated-file-snapshot.test.ts index c82f71c383d..5ef32a08f39 100644 --- a/src/main/shell-wrapper-generated-file-snapshot.test.ts +++ b/src/main/shell-wrapper-generated-file-snapshot.test.ts @@ -50,7 +50,7 @@ const CONTRACT_GLOBALS = new Set([ // Exported only in the claude function's subshell. 'CLAUDE_CONFIG_DIR', 'HISTFILE', - 'MIMOCODE_HOME', + 'MIMOCODE_CONFIG_DIR', 'OPENCODE_CONFIG_DIR', 'OPENCODE_AUTH_CONTENT', 'OPENCODE_DB', diff --git a/src/main/zsh-startup-wrapper-builder.ts b/src/main/zsh-startup-wrapper-builder.ts index a3b59e638ae..3de62806309 100644 --- a/src/main/zsh-startup-wrapper-builder.ts +++ b/src/main/zsh-startup-wrapper-builder.ts @@ -49,7 +49,7 @@ const AGENT_TEAMS_PATH_RESTORE_BLOCK = `__orca_restore_agent_teams_path() { __orca_restore_agent_teams_path` const OPENCODE_CONFIG_DIR_RESTORE = `[[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}"` -const MIMOCODE_HOME_RESTORE = `[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}"` +const MIMOCODE_CONFIG_DIR_RESTORE = `[[ -n "\${ORCA_MIMOCODE_CONFIG_DIR:-}" ]] && export MIMOCODE_CONFIG_DIR="\${ORCA_MIMOCODE_CONFIG_DIR}"` const REMOTE_CLI_BIN_DIR_RESTORE = `[[ -n "\${ORCA_REMOTE_CLI_BIN_DIR:-}" ]] && case ":$PATH:" in *:"\${ORCA_REMOTE_CLI_BIN_DIR}":*) ;; *) export PATH="\${ORCA_REMOTE_CLI_BIN_DIR}:$PATH" ;; esac` const CODEX_HOME_RESTORE = `# Restore the runtime CODEX_HOME after user rc files. [[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}"` @@ -93,7 +93,7 @@ function getOverlayRestoreBlocks(spec: ZshStartupHookSpec): (string | null)[] { spec.restores.agentTeamsPath ? AGENT_TEAMS_PATH_RESTORE_BLOCK : null, OPENCODE_CONFIG_DIR_RESTORE, MANAGED_DATA_ACCOUNT_POSIX_RESTORE, - MIMOCODE_HOME_RESTORE, + MIMOCODE_CONFIG_DIR_RESTORE, spec.restores.remoteCliBinDir ? REMOTE_CLI_BIN_DIR_RESTORE : null, getPosixOmpShellWrapper(), spec.restores.codexHome ? CODEX_HOME_RESTORE : null