diff --git a/src/main/daemon/shell-ready.test.ts b/src/main/daemon/shell-ready.test.ts index b4fc60669..47ad5adc5 100644 --- a/src/main/daemon/shell-ready.test.ts +++ b/src/main/daemon/shell-ready.test.ts @@ -57,6 +57,17 @@ function expectBashOsc133Lifecycle(output: string): void { expect(output.split(oscD)).toHaveLength(3) } +function expectZdotdirSourceContext(content: string, fileName: '.zprofile' | '.zshrc' | '.zlogin') { + expect(content).toContain('export ZDOTDIR="$_orca_home"') + expect(content).toContain(`source "$_orca_home/${fileName}"`) + expect(content).toContain('export ZDOTDIR="$_orca_wrapper_zdotdir"') +} + +function expectFinalZdotdirRestoreContext(content: string) { + expect(content).toContain("after Orca's last wrapper file has loaded") + expect(content).toContain('export ZDOTDIR="$_orca_home"') +} + describePosix('daemon shell-ready launch config', () => { let previousUserDataPath: string | undefined let previousOrcaOrigZdotdir: string | undefined @@ -213,9 +224,17 @@ describePosix('daemon shell-ready launch config', () => { getShellReadyLaunchConfig('/bin/zsh') const zshenv = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zshenv'), 'utf8') + const zprofile = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zprofile'), 'utf8') + const zshrc = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zshrc'), 'utf8') + const zlogin = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zlogin'), 'utf8') expect(zshenv).toContain('_orca_user_zdotdir="${_orca_spawn_orig_zdotdir:-$HOME}"') expect(zshenv).toContain('*/shell-ready/zsh) _orca_user_zdotdir="$HOME" ;;') expect(zshenv).toContain('""|*/shell-ready/zsh) export ORCA_ORIG_ZDOTDIR="$HOME" ;;') + expectZdotdirSourceContext(zprofile, '.zprofile') + expectZdotdirSourceContext(zshrc, '.zshrc') + expectZdotdirSourceContext(zlogin, '.zlogin') + expectFinalZdotdirRestoreContext(zshrc) + expectFinalZdotdirRestoreContext(zlogin) }) it('writes wrappers that restore OpenCode and Pi config after user startup files', async () => { diff --git a/src/main/daemon/shell-ready.ts b/src/main/daemon/shell-ready.ts index 81f7834ae..cf850c9cf 100644 --- a/src/main/daemon/shell-ready.ts +++ b/src/main/daemon/shell-ready.ts @@ -11,7 +11,11 @@ import { isPowerShellExecutableName } from '../powershell-osc133-bootstrap' import { getPosixOmpShellWrapper } from '../pty/omp-shell-wrapper' -import { getZshEnvTemplate } from '../shell-templates' +import { + getZshEnvTemplate, + getZshFinalZdotdirRestoreBlock, + getZshStartupFileSourceBlock +} from '../shell-templates' const ORCA_USER_DATA_PATH_ENV = 'ORCA_USER_DATA_PATH' const SHELL_READY_MARKER = '\\033]777;orca-shell-ready\\007' @@ -195,10 +199,11 @@ trap '__orca_osc133_preexec' DEBUG export function getDaemonZshShellReadyRcfileContent(): string { return `# Orca daemon zsh shell-ready wrapper -_orca_home="\${ORCA_ORIG_ZDOTDIR:-$HOME}" -if [[ "$_orca_home" != "$ZDOTDIR" && -o interactive && -f "$_orca_home/.zshrc" ]]; then - source "$_orca_home/.zshrc" -fi +${getZshStartupFileSourceBlock({ + fileName: '.zshrc', + interactiveOnly: true, + skipWhenHomeIsCurrentZdotdir: true +})} __orca_restore_attribution_path() { [[ -n "\${ORCA_ATTRIBUTION_SHIM_DIR:-}" ]] || return 0 case "$PATH" in @@ -234,6 +239,9 @@ __orca_osc133_preexec() { # Why: prepend so Orca captures $? before user prompt hooks can overwrite it. precmd_functions=(__orca_osc133_precmd \${precmd_functions[@]}) preexec_functions=(__orca_osc133_preexec \${preexec_functions[@]}) +if [[ ! -o login ]]; then +${getZshFinalZdotdirRestoreBlock()} +fi ` } @@ -252,21 +260,11 @@ function ensureShellReadyWrappers(): void { const zshEnv = getZshEnvTemplate(zshDir, 'daemon') const zshProfile = `# Orca daemon zsh shell-ready wrapper -_orca_home="\${ORCA_ORIG_ZDOTDIR:-$HOME}" -case "\${_orca_home%/}" in - */shell-ready/zsh) _orca_home="$HOME" ;; -esac -[[ -f "$_orca_home/.zprofile" ]] && source "$_orca_home/.zprofile" +${getZshStartupFileSourceBlock({ fileName: '.zprofile' })} ` const zshRc = getDaemonZshShellReadyRcfileContent() const zshLogin = `# Orca daemon zsh shell-ready wrapper -_orca_home="\${ORCA_ORIG_ZDOTDIR:-$HOME}" -case "\${_orca_home%/}" in - */shell-ready/zsh) _orca_home="$HOME" ;; -esac -if [[ -o interactive && -f "$_orca_home/.zlogin" ]]; then - source "$_orca_home/.zlogin" -fi +${getZshStartupFileSourceBlock({ fileName: '.zlogin', interactiveOnly: true })} __orca_restore_attribution_path() { [[ -n "\${ORCA_ATTRIBUTION_SHIM_DIR:-}" ]] || return 0 case "$PATH" in @@ -293,6 +291,7 @@ if [[ "\${ORCA_SHELL_READY_MARKER:-0}" == "1" ]]; then zle -N __orca_prompt_mark add-zle-hook-widget line-init __orca_prompt_mark fi +${getZshFinalZdotdirRestoreBlock()} ` const bashRc = getDaemonBashShellReadyRcfileContent() diff --git a/src/main/providers/__tests__/shell-ready-framework-example.test.ts b/src/main/providers/__tests__/shell-ready-framework-example.test.ts index 4d4640330..3d4866c29 100644 --- a/src/main/providers/__tests__/shell-ready-framework-example.test.ts +++ b/src/main/providers/__tests__/shell-ready-framework-example.test.ts @@ -61,7 +61,7 @@ EOF expect(stdout).toMatchInlineSnapshot(` "HOME= - ZDOTDIR= + ZDOTDIR=/.config/zsh " `) }) @@ -85,8 +85,8 @@ EOF ) expect(stdout).toMatchInlineSnapshot(` - "ORCA_ORIG_ZDOTDIR=/.config/zsh-remote - ZDOTDIR= + "ORCA_ORIG_ZDOTDIR= + ZDOTDIR=/.config/zsh-remote " `) }) diff --git a/src/main/providers/__tests__/shell-ready-framework/README.md b/src/main/providers/__tests__/shell-ready-framework/README.md index f3122326e..19f4ac96c 100644 --- a/src/main/providers/__tests__/shell-ready-framework/README.md +++ b/src/main/providers/__tests__/shell-ready-framework/README.md @@ -25,8 +25,7 @@ EOF expect(stdout).toMatchInlineSnapshot(` "HOME= - ORCA_ORIG_ZDOTDIR=/.config/zsh - ZDOTDIR= + ZDOTDIR=/.config/zsh " `) }) @@ -93,8 +92,7 @@ Use `toMatchInlineSnapshot()` to keep expected output visible in the test file: ```typescript expect(stdout).toMatchInlineSnapshot(` "HOME= - ORCA_ORIG_ZDOTDIR=/.config/zsh - ZDOTDIR= + ZDOTDIR=/.config/zsh " `) ``` diff --git a/src/main/providers/__tests__/shell-ready-framework/shell-script-test.ts b/src/main/providers/__tests__/shell-ready-framework/shell-script-test.ts index d3921cebd..755132c40 100644 --- a/src/main/providers/__tests__/shell-ready-framework/shell-script-test.ts +++ b/src/main/providers/__tests__/shell-ready-framework/shell-script-test.ts @@ -62,7 +62,11 @@ export async function shellScriptTest( const env: Record = { ...config.env, - HOME: testHome + // Why: the framework creates user startup files under testHome after + // computing the wrapper config; route wrapper discovery to that fixture. + HOME: testHome, + ORCA_ORIG_ZDOTDIR: testHome, + ORCA_ZSHENV_SOURCE_DIR: testHome } const spawnOptions = { diff --git a/src/main/providers/local-pty-shell-ready.test.ts b/src/main/providers/local-pty-shell-ready.test.ts index 80612f6e0..f42aff7b8 100644 --- a/src/main/providers/local-pty-shell-ready.test.ts +++ b/src/main/providers/local-pty-shell-ready.test.ts @@ -172,6 +172,17 @@ function expectBashOsc133Lifecycle(output: string): void { expect(output.split(oscD)).toHaveLength(3) } +function expectZdotdirSourceContext(content: string, fileName: '.zprofile' | '.zshrc' | '.zlogin') { + expect(content).toContain('export ZDOTDIR="$_orca_home"') + expect(content).toContain(`source "$_orca_home/${fileName}"`) + expect(content).toContain('export ZDOTDIR="$_orca_wrapper_zdotdir"') +} + +function expectFinalZdotdirRestoreContext(content: string) { + expect(content).toContain("after Orca's last wrapper file has loaded") + expect(content).toContain('export ZDOTDIR="$_orca_home"') +} + describePosix('local PTY shell-ready launch config', () => { let userDataPath: string let previousOrcaOrigZdotdir: string | undefined @@ -288,9 +299,17 @@ describePosix('local PTY shell-ready launch config', () => { getShellReadyLaunchConfig('/bin/zsh') const zshenv = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zshenv'), 'utf8') + const zprofile = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zprofile'), 'utf8') + const zshrc = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zshrc'), 'utf8') + const zlogin = readFileSync(join(userDataPath, 'shell-ready', 'zsh', '.zlogin'), 'utf8') expect(zshenv).toContain('_orca_user_zdotdir="${_orca_spawn_orig_zdotdir:-$HOME}"') expect(zshenv).toContain('*/shell-ready/zsh) _orca_user_zdotdir="$HOME" ;;') expect(zshenv).toContain('""|*/shell-ready/zsh) export ORCA_ORIG_ZDOTDIR="$HOME" ;;') + expectZdotdirSourceContext(zprofile, '.zprofile') + expectZdotdirSourceContext(zshrc, '.zshrc') + expectZdotdirSourceContext(zlogin, '.zlogin') + expectFinalZdotdirRestoreContext(zshrc) + expectFinalZdotdirRestoreContext(zlogin) }) it('writes wrappers that restore agent config homes after user startup files', async () => { @@ -644,6 +663,56 @@ export ZDOTDIR="$HOME/.config/zsh" expect(result.stdout).toContain('from-zshenv-function') }) + it('sources user startup files with their own ZDOTDIR in scope', async () => { + // Why: plugin managers such as Antidote resolve files from $ZDOTDIR + // while .zprofile/.zshrc/.zlogin are sourced. + const xdgZshDir = join(testHome, '.config', 'zsh') + const zdotdirLog = join(testHome, 'zdotdir.log') + mkdirSync(xdgZshDir, { recursive: true }) + writeFileSync(join(testHome, '.zshenv'), 'export ZDOTDIR="$HOME/.config/zsh"\n') + writeFileSync( + join(xdgZshDir, '.zprofile'), + 'printf "zprofile=%s\\n" "$ZDOTDIR" >> "$HOME/zdotdir.log"\n' + ) + writeFileSync( + join(xdgZshDir, '.zshrc'), + 'printf "zshrc=%s\\n" "$ZDOTDIR" >> "$HOME/zdotdir.log"\n' + ) + writeFileSync( + join(xdgZshDir, '.zlogin'), + 'printf "zlogin=%s\\n" "$ZDOTDIR" >> "$HOME/zdotdir.log"\n' + ) + + const { getShellReadyLaunchConfig } = await importFreshLocalPtyShellReady() + const config = getShellReadyLaunchConfig('/bin/zsh') + + const cleanEnv: Record = { ...process.env, HOME: testHome } + delete cleanEnv.ZDOTDIR + delete cleanEnv.ORCA_ORIG_ZDOTDIR + cleanEnv.ZDOTDIR = config.env.ZDOTDIR + + const result = spawnSync( + 'zsh', + ['-l', '-i', '-c', 'printf "command=%s\\n" "$ZDOTDIR" >> "$HOME/zdotdir.log"'], + { + env: cleanEnv as NodeJS.ProcessEnv, + encoding: 'utf8', + timeout: 5000 + } + ) + + expect(result.status).toBe(0) + expect(readFileSync(zdotdirLog, 'utf8')).toBe( + [ + `zprofile=${xdgZshDir}`, + `zshrc=${xdgZshDir}`, + `zlogin=${xdgZshDir}`, + `command=${xdgZshDir}`, + '' + ].join('\n') + ) + }) + it('survives early return in user .zshenv without crashing', async () => { // Why: common pattern to skip non-interactive sourcing. A direct source // at zsh top level must keep the wrapper running, matching normal zsh. diff --git a/src/main/providers/local-pty-shell-ready.ts b/src/main/providers/local-pty-shell-ready.ts index 53f46f96e..e6f504169 100644 --- a/src/main/providers/local-pty-shell-ready.ts +++ b/src/main/providers/local-pty-shell-ready.ts @@ -21,7 +21,11 @@ import { isPowerShellExecutableName } from '../powershell-osc133-bootstrap' import { getPosixOmpShellWrapper } from '../pty/omp-shell-wrapper' -import { getZshEnvTemplate } from '../shell-templates' +import { + getZshEnvTemplate, + getZshFinalZdotdirRestoreBlock, + getZshStartupFileSourceBlock +} from '../shell-templates' let didEnsureShellReadyWrappers = false @@ -259,10 +263,11 @@ trap '__orca_osc133_preexec' DEBUG export function getZshShellReadyRcfileContent(): string { return `# Orca zsh shell-ready wrapper -_orca_home="\${ORCA_ORIG_ZDOTDIR:-$HOME}" -if [[ "$_orca_home" != "$ZDOTDIR" && -o interactive && -f "$_orca_home/.zshrc" ]]; then - source "$_orca_home/.zshrc" -fi +${getZshStartupFileSourceBlock({ + fileName: '.zshrc', + interactiveOnly: true, + skipWhenHomeIsCurrentZdotdir: true +})} __orca_restore_attribution_path() { [[ -n "\${ORCA_ATTRIBUTION_SHIM_DIR:-}" ]] || return 0 case "$PATH" in @@ -299,6 +304,9 @@ __orca_osc133_preexec() { # Why: prepend so Orca captures $? before user prompt hooks can overwrite it. precmd_functions=(__orca_osc133_precmd \${precmd_functions[@]}) preexec_functions=(__orca_osc133_preexec \${preexec_functions[@]}) +if [[ ! -o login ]]; then +${getZshFinalZdotdirRestoreBlock()} +fi ` } @@ -317,21 +325,11 @@ function ensureShellReadyWrappers(): void { const zshEnv = getZshEnvTemplate(zshDir) const zshProfile = `# Orca zsh shell-ready wrapper -_orca_home="\${ORCA_ORIG_ZDOTDIR:-$HOME}" -case "\${_orca_home%/}" in - */shell-ready/zsh) _orca_home="$HOME" ;; -esac -[[ -f "$_orca_home/.zprofile" ]] && source "$_orca_home/.zprofile" +${getZshStartupFileSourceBlock({ fileName: '.zprofile' })} ` const zshRc = getZshShellReadyRcfileContent() const zshLogin = `# Orca zsh shell-ready wrapper -_orca_home="\${ORCA_ORIG_ZDOTDIR:-$HOME}" -case "\${_orca_home%/}" in - */shell-ready/zsh) _orca_home="$HOME" ;; -esac -if [[ -o interactive && -f "$_orca_home/.zlogin" ]]; then - source "$_orca_home/.zlogin" -fi +${getZshStartupFileSourceBlock({ fileName: '.zlogin', interactiveOnly: true })} __orca_restore_attribution_path() { [[ -n "\${ORCA_ATTRIBUTION_SHIM_DIR:-}" ]] || return 0 case "$PATH" in @@ -358,6 +356,7 @@ if [[ "\${ORCA_SHELL_READY_MARKER:-0}" == "1" ]]; then zle -N __orca_prompt_mark add-zle-hook-widget line-init __orca_prompt_mark fi +${getZshFinalZdotdirRestoreBlock()} ` const bashRc = getBashShellReadyRcfileContent() diff --git a/src/main/shell-templates.ts b/src/main/shell-templates.ts index 30a8820bf..96c37179d 100644 --- a/src/main/shell-templates.ts +++ b/src/main/shell-templates.ts @@ -71,3 +71,44 @@ export ZDOTDIR=${quotePosixSingle(zshDir)} unset _orca_spawn_orig_zdotdir _orca_user_zdotdir _orca_zshenv_source_dir _orca_zshenv_path _orca_discovered_zdotdir ` } + +export function getZshStartupFileSourceBlock(options: { + fileName: '.zprofile' | '.zshrc' | '.zlogin' + homeExpression?: string + interactiveOnly?: boolean + skipWhenHomeIsCurrentZdotdir?: boolean +}): string { + const homeExpression = options.homeExpression ?? '"${ORCA_ORIG_ZDOTDIR:-$HOME}"' + const checks = [ + options.skipWhenHomeIsCurrentZdotdir ? '"$_orca_home" != "$ZDOTDIR"' : null, + options.interactiveOnly ? '-o interactive' : null, + `-f "$_orca_home/${options.fileName}"` + ].filter(Boolean) + + return `_orca_home=${homeExpression} +case "\${_orca_home%/}" in + */shell-ready/zsh) _orca_home="$HOME" ;; +esac +if [[ ${checks.join(' && ')} ]]; then + _orca_wrapper_zdotdir="$ZDOTDIR" + # Why: user startup files resolve plugin/config paths from their own ZDOTDIR; + # Orca restores its wrapper dir afterward so zsh still loads wrapper files. + export ZDOTDIR="$_orca_home" + source "$_orca_home/${options.fileName}" + export ZDOTDIR="$_orca_wrapper_zdotdir" + unset _orca_wrapper_zdotdir +fi +` +} + +export function getZshFinalZdotdirRestoreBlock(homeExpression = '"${ORCA_ORIG_ZDOTDIR:-$HOME}"') { + return `_orca_home=${homeExpression} +case "\${_orca_home%/}" in + */shell-ready/zsh) _orca_home="$HOME" ;; +esac +# Why: after Orca's last wrapper file has loaded, the interactive shell should +# expose the same ZDOTDIR a normal zsh startup would expose. +export ZDOTDIR="$_orca_home" +unset _orca_home +` +} diff --git a/src/relay/pty-shell-launch.test.ts b/src/relay/pty-shell-launch.test.ts index 3993dbf08..d6a942210 100644 --- a/src/relay/pty-shell-launch.test.ts +++ b/src/relay/pty-shell-launch.test.ts @@ -44,6 +44,17 @@ function expectBashOsc133Lifecycle(output: string): void { expect(output.split(oscD)).toHaveLength(3) } +function expectZdotdirSourceContext(content: string, fileName: '.zprofile' | '.zshrc' | '.zlogin') { + expect(content).toContain('export ZDOTDIR="$_orca_home"') + expect(content).toContain(`source "$_orca_home/${fileName}"`) + expect(content).toContain('export ZDOTDIR="$_orca_wrapper_zdotdir"') +} + +function expectFinalZdotdirRestoreContext(content: string) { + expect(content).toContain("after Orca's last wrapper file has loaded") + expect(content).toContain('export ZDOTDIR="$_orca_home"') +} + describe('getRelayShellLaunchConfig', () => { let homeDir: string @@ -72,12 +83,16 @@ describe('getRelayShellLaunchConfig', () => { expect(readFileSync(join(zshRoot, '.zprofile'), 'utf8')).toContain( '_orca_home="${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"' ) - expect(readFileSync(join(zshRoot, '.zshrc'), 'utf8')).toContain( - '_orca_home="${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"' - ) - expect(readFileSync(join(zshRoot, '.zlogin'), 'utf8')).toContain( - '_orca_home="${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"' - ) + const zprofile = readFileSync(join(zshRoot, '.zprofile'), 'utf8') + const zshrc = readFileSync(join(zshRoot, '.zshrc'), 'utf8') + const zlogin = readFileSync(join(zshRoot, '.zlogin'), 'utf8') + expect(zshrc).toContain('_orca_home="${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"') + expect(zlogin).toContain('_orca_home="${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"') + expectZdotdirSourceContext(zprofile, '.zprofile') + expectZdotdirSourceContext(zshrc, '.zshrc') + expectZdotdirSourceContext(zlogin, '.zlogin') + expectFinalZdotdirRestoreContext(zshrc) + expectFinalZdotdirRestoreContext(zlogin) } ) diff --git a/src/relay/pty-shell-launch.ts b/src/relay/pty-shell-launch.ts index 8de35b5f5..90d85e99d 100644 --- a/src/relay/pty-shell-launch.ts +++ b/src/relay/pty-shell-launch.ts @@ -2,6 +2,10 @@ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'fs' import { homedir } from 'os' import { basename, dirname, join } from 'path' import { getPosixOmpShellWrapper } from '../main/pty/omp-shell-wrapper' +import { + getZshFinalZdotdirRestoreBlock, + getZshStartupFileSourceBlock +} from '../main/shell-templates' const RELAY_SHELL_READY_DIR = '.orca-relay/shell-ready' const POSIX_LOGIN_ARGS = ['-l'] @@ -66,20 +70,17 @@ esac export ZDOTDIR=${quotePosixSingle(zshDir)} ` const zshProfile = `# Orca relay zsh overlay wrapper -_orca_home="\${ORCA_USER_ZDOTDIR:-\${ORCA_ORIG_ZDOTDIR:-$HOME}}" -case "\${_orca_home%/}" in - */shell-ready/zsh) _orca_home="$HOME" ;; -esac -[[ -f "$_orca_home/.zprofile" ]] && source "$_orca_home/.zprofile" +${getZshStartupFileSourceBlock({ + fileName: '.zprofile', + homeExpression: '"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"' +})} ` const zshRc = `# Orca relay zsh overlay wrapper -_orca_home="\${ORCA_USER_ZDOTDIR:-\${ORCA_ORIG_ZDOTDIR:-$HOME}}" -case "\${_orca_home%/}" in - */shell-ready/zsh) _orca_home="$HOME" ;; -esac -if [[ -o interactive && -f "$_orca_home/.zshrc" ]]; then - source "$_orca_home/.zshrc" -fi +${getZshStartupFileSourceBlock({ + fileName: '.zshrc', + homeExpression: '"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"', + interactiveOnly: true +})} if [[ ! -o login ]]; then # 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}" @@ -90,15 +91,16 @@ if [[ ! -o login ]]; then [[ -n "\${ORCA_REMOTE_CLI_BIN_DIR:-}" ]] && case ":$PATH:" in *:"\${ORCA_REMOTE_CLI_BIN_DIR}":*) ;; *) export PATH="\${ORCA_REMOTE_CLI_BIN_DIR}:$PATH" ;; esac ${getPosixOmpShellWrapper()} fi +if [[ ! -o login ]]; then +${getZshFinalZdotdirRestoreBlock('"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"')} +fi ` const zshLogin = `# Orca relay zsh overlay wrapper -_orca_home="\${ORCA_USER_ZDOTDIR:-\${ORCA_ORIG_ZDOTDIR:-$HOME}}" -case "\${_orca_home%/}" in - */shell-ready/zsh) _orca_home="$HOME" ;; -esac -if [[ -o interactive && -f "$_orca_home/.zlogin" ]]; then - source "$_orca_home/.zlogin" -fi +${getZshStartupFileSourceBlock({ + fileName: '.zlogin', + homeExpression: '"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"', + interactiveOnly: true +})} # Why: .zlogin is the final zsh login startup file before the prompt. [[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}" [[ -n "\${ORCA_PI_CODING_AGENT_DIR:-}" ]] && export PI_CODING_AGENT_DIR="\${ORCA_PI_CODING_AGENT_DIR}" @@ -107,6 +109,7 @@ if [[ -z "\${ORCA_PI_CODING_AGENT_DIR:-}" && -n "\${ORCA_OMP_CODING_AGENT_DIR:-} fi [[ -n "\${ORCA_REMOTE_CLI_BIN_DIR:-}" ]] && case ":$PATH:" in *:"\${ORCA_REMOTE_CLI_BIN_DIR}":*) ;; *) export PATH="\${ORCA_REMOTE_CLI_BIN_DIR}:$PATH" ;; esac ${getPosixOmpShellWrapper()} +${getZshFinalZdotdirRestoreBlock('"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"')} ` const bashRc = `# Orca relay bash overlay wrapper [[ -f /etc/profile ]] && source /etc/profile