mirror of
https://github.com/stablyai/orca.git
synced 2026-10-25 16:03:53 +00:00
refactor(shell): build every zsh startup wrapper from one shared builder
Local PTY, daemon/SSH, and relay each had their own copy of the zsh ZDOTDIR wrapper templates, and the copies had drifted. buildZshStartupWrapperFiles now produces .zshenv/.zprofile/.zshrc/.zlogin for all three, with every real difference expressed as a field on ZshStartupWrapperSpec. No behavior change: the generated text is byte-for-byte identical for every configuration, pinned by the snapshots committed in the previous commit (captured from the pre-refactor generators).
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
import { getPosixOmpShellWrapper } from '../pty/omp-shell-wrapper'
|
||||
import { getPosixCodexShellLaunchPreflight } from '../pty/codex-shell-launch-preflight'
|
||||
import {
|
||||
getZshFinalZdotdirRestoreBlock,
|
||||
getZshStartupFileSourceBlock,
|
||||
ZSH_HISTFILE_RESTORE_BLOCK
|
||||
} from '../shell-templates'
|
||||
|
||||
export function getDaemonZshShellReadyRcfileContent(): string {
|
||||
return `# Orca daemon zsh shell-ready wrapper
|
||||
${getZshStartupFileSourceBlock({
|
||||
fileName: '.zshrc',
|
||||
interactiveOnly: true,
|
||||
skipWhenHomeIsCurrentZdotdir: true
|
||||
})}
|
||||
__orca_restore_agent_teams_path() {
|
||||
[[ -n "\${ORCA_AGENT_TEAMS_SHIM_DIR:-}" ]] || return 0
|
||||
case "$PATH" in
|
||||
"\${ORCA_AGENT_TEAMS_SHIM_DIR}"|"\${ORCA_AGENT_TEAMS_SHIM_DIR}:"*) return 0 ;;
|
||||
esac
|
||||
export PATH="\${ORCA_AGENT_TEAMS_SHIM_DIR}:$PATH"
|
||||
}
|
||||
[[ ! -o login ]] && __orca_restore_agent_teams_path
|
||||
if [[ ! -o login ]]; then
|
||||
# Why: ~/.zshrc can export the user's default OpenCode config after spawn.
|
||||
[[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}"
|
||||
[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}"
|
||||
${getPosixOmpShellWrapper()}
|
||||
[[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}"
|
||||
${ZSH_HISTFILE_RESTORE_BLOCK}
|
||||
${getPosixCodexShellLaunchPreflight()}
|
||||
fi
|
||||
__orca_osc133_precmd() {
|
||||
local exit_code=$?
|
||||
if [[ -n "\${__orca_in_command:-}" ]]; then
|
||||
printf "\\033]133;D;%s\\007" "$exit_code"
|
||||
unset __orca_in_command
|
||||
fi
|
||||
printf "\\033]133;A\\007"
|
||||
}
|
||||
__orca_osc133_preexec() {
|
||||
printf "\\033]133;C\\007"
|
||||
__orca_in_command=1
|
||||
}
|
||||
# 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
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { ZshStartupWrapperSpec } from '../zsh-startup-wrapper-builder'
|
||||
import { SHELL_READY_MARKER } from './daemon-shell-ready-marker'
|
||||
|
||||
/** The zsh wrapper the daemon (local fork and SSH host) launches shells with. */
|
||||
export function getDaemonZshWrapperSpec(zshDir: string): ZshStartupWrapperSpec {
|
||||
return {
|
||||
headerLabel: 'Orca daemon zsh shell-ready wrapper',
|
||||
zshDir,
|
||||
zshenvStrategy: 'discover-user-zdotdir',
|
||||
readyMarkerEscaped: SHELL_READY_MARKER,
|
||||
osc133CommandMarkers: true,
|
||||
skipUserZshrcWhenHomeIsWrapperDir: true,
|
||||
interactiveRestoreComment:
|
||||
"# Why: ~/.zshrc can export the user's default OpenCode config after spawn.",
|
||||
loginRestoreComment:
|
||||
'# Why: .zlogin is the final login startup file before the prompt is shown.',
|
||||
restores: {
|
||||
agentTeamsPath: true,
|
||||
remoteCliBinDir: false,
|
||||
codexHome: true,
|
||||
codexLaunchPreflight: true
|
||||
},
|
||||
readyMarkerOrder: 'before-zdotdir-restore'
|
||||
}
|
||||
}
|
||||
@@ -6,22 +6,12 @@ import {
|
||||
getPowerShellOsc133Bootstrap,
|
||||
isPowerShellExecutableName
|
||||
} from '../powershell-osc133-bootstrap'
|
||||
import { getPosixOmpShellWrapper } from '../pty/omp-shell-wrapper'
|
||||
import {
|
||||
getFishCodexShellLaunchPreflight,
|
||||
getPosixCodexShellLaunchPreflight
|
||||
} from '../pty/codex-shell-launch-preflight'
|
||||
import {
|
||||
getFishShellReadyInitCommand,
|
||||
getZshEnvTemplate,
|
||||
getZshFinalZdotdirRestoreBlock,
|
||||
getZshShellReadyMarkerRegistrationBlock,
|
||||
getZshStartupFileSourceBlock,
|
||||
ZSH_HISTFILE_RESTORE_BLOCK
|
||||
} from '../shell-templates'
|
||||
import { getFishCodexShellLaunchPreflight } from '../pty/codex-shell-launch-preflight'
|
||||
import { getFishShellReadyInitCommand } from '../shell-templates'
|
||||
import { buildZshStartupWrapperFiles } from '../zsh-startup-wrapper-builder'
|
||||
import { SHELL_READY_MARKER } from './daemon-shell-ready-marker'
|
||||
import { getDaemonBashShellReadyRcfileContent } from './daemon-bash-shell-ready-rcfile'
|
||||
import { getDaemonZshShellReadyRcfileContent } from './daemon-zsh-shell-ready-rcfile'
|
||||
import { getDaemonZshWrapperSpec } from './daemon-zsh-shell-ready-wrapper-spec'
|
||||
|
||||
const ORCA_USER_DATA_PATH_ENV = 'ORCA_USER_DATA_PATH'
|
||||
|
||||
@@ -102,38 +92,14 @@ function ensureShellReadyWrappers(): void {
|
||||
const zshDir = join(root, 'zsh')
|
||||
const bashDir = join(root, 'bash')
|
||||
|
||||
const zshEnv = getZshEnvTemplate(zshDir, 'daemon')
|
||||
const zshProfile = `# Orca daemon zsh shell-ready wrapper
|
||||
${getZshStartupFileSourceBlock({ fileName: '.zprofile' })}
|
||||
`
|
||||
const zshRc = getDaemonZshShellReadyRcfileContent()
|
||||
const zshLogin = `# Orca daemon zsh shell-ready wrapper
|
||||
${getZshStartupFileSourceBlock({ fileName: '.zlogin', interactiveOnly: true })}
|
||||
__orca_restore_agent_teams_path() {
|
||||
[[ -n "\${ORCA_AGENT_TEAMS_SHIM_DIR:-}" ]] || return 0
|
||||
case "$PATH" in
|
||||
"\${ORCA_AGENT_TEAMS_SHIM_DIR}"|"\${ORCA_AGENT_TEAMS_SHIM_DIR}:"*) return 0 ;;
|
||||
esac
|
||||
export PATH="\${ORCA_AGENT_TEAMS_SHIM_DIR}:$PATH"
|
||||
}
|
||||
__orca_restore_agent_teams_path
|
||||
# Why: .zlogin is the final login startup file before the prompt is shown.
|
||||
[[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}"
|
||||
[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}"
|
||||
${getPosixOmpShellWrapper()}
|
||||
[[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}"
|
||||
${ZSH_HISTFILE_RESTORE_BLOCK}
|
||||
${getPosixCodexShellLaunchPreflight()}
|
||||
${getZshShellReadyMarkerRegistrationBlock(SHELL_READY_MARKER)}
|
||||
${getZshFinalZdotdirRestoreBlock()}
|
||||
`
|
||||
const zsh = buildZshStartupWrapperFiles(getDaemonZshWrapperSpec(zshDir))
|
||||
const bashRc = getDaemonBashShellReadyRcfileContent()
|
||||
|
||||
const files = [
|
||||
[join(zshDir, '.zshenv'), zshEnv],
|
||||
[join(zshDir, '.zprofile'), zshProfile],
|
||||
[join(zshDir, '.zshrc'), zshRc],
|
||||
[join(zshDir, '.zlogin'), zshLogin],
|
||||
[join(zshDir, '.zshenv'), zsh.zshenv],
|
||||
[join(zshDir, '.zprofile'), zsh.zprofile],
|
||||
[join(zshDir, '.zshrc'), zsh.zshrc],
|
||||
[join(zshDir, '.zlogin'), zsh.zlogin],
|
||||
[join(bashDir, 'rcfile'), bashRc]
|
||||
] as const
|
||||
|
||||
|
||||
@@ -5,15 +5,10 @@
|
||||
* readiness scanner watches for before a startup command is written.
|
||||
*/
|
||||
import { mkdirSync, writeFileSync, chmodSync } from 'node:fs'
|
||||
import { getPosixOmpShellWrapper } from '../pty/omp-shell-wrapper'
|
||||
import { getPosixCodexShellLaunchPreflight } from '../pty/codex-shell-launch-preflight'
|
||||
import {
|
||||
getZshEnvTemplate,
|
||||
getZshFinalZdotdirRestoreBlock,
|
||||
getZshShellReadyMarkerRegistrationBlock,
|
||||
getZshStartupFileSourceBlock,
|
||||
ZSH_HISTFILE_RESTORE_BLOCK
|
||||
} from '../shell-templates'
|
||||
buildZshStartupWrapperFiles,
|
||||
type ZshStartupWrapperSpec
|
||||
} from '../zsh-startup-wrapper-builder'
|
||||
import { getBashShellReadyRcfileContent } from './local-pty-shell-ready-bash-rcfile'
|
||||
import {
|
||||
getShellReadyWrapperRoot,
|
||||
@@ -23,50 +18,36 @@ import {
|
||||
|
||||
let didEnsureShellReadyWrappers = false
|
||||
|
||||
function getLocalZshWrapperSpec(zshDir: string): ZshStartupWrapperSpec {
|
||||
return {
|
||||
headerLabel: 'Orca zsh shell-ready wrapper',
|
||||
zshDir,
|
||||
zshenvStrategy: 'discover-user-zdotdir',
|
||||
readyMarkerEscaped: SHELL_READY_MARKER_ESCAPED,
|
||||
osc133CommandMarkers: true,
|
||||
skipUserZshrcWhenHomeIsWrapperDir: true,
|
||||
interactiveRestoreComment:
|
||||
"# Why: ~/.zshrc can export the user's default OpenCode config after spawn.",
|
||||
loginRestoreComment:
|
||||
'# Why: .zlogin is the final login startup file before the prompt is shown.',
|
||||
restores: {
|
||||
agentTeamsPath: true,
|
||||
remoteCliBinDir: false,
|
||||
codexHome: true,
|
||||
codexLaunchPreflight: true
|
||||
},
|
||||
readyMarkerOrder: 'before-zdotdir-restore',
|
||||
legacyFormatting: {
|
||||
unindentedMimocodeRestore: true,
|
||||
codexHomeRestoreComment:
|
||||
"# Why: Codex must keep using Orca's runtime CODEX_HOME after rc files."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getZshShellReadyRcfileContent(): string {
|
||||
return `# Orca zsh shell-ready wrapper
|
||||
${getZshStartupFileSourceBlock({
|
||||
fileName: '.zshrc',
|
||||
interactiveOnly: true,
|
||||
skipWhenHomeIsCurrentZdotdir: true
|
||||
})}
|
||||
__orca_restore_agent_teams_path() {
|
||||
[[ -n "\${ORCA_AGENT_TEAMS_SHIM_DIR:-}" ]] || return 0
|
||||
case "$PATH" in
|
||||
"\${ORCA_AGENT_TEAMS_SHIM_DIR}"|"\${ORCA_AGENT_TEAMS_SHIM_DIR}:"*) return 0 ;;
|
||||
esac
|
||||
export PATH="\${ORCA_AGENT_TEAMS_SHIM_DIR}:$PATH"
|
||||
}
|
||||
[[ ! -o login ]] && __orca_restore_agent_teams_path
|
||||
if [[ ! -o login ]]; then
|
||||
# Why: ~/.zshrc can export the user's default OpenCode config after spawn.
|
||||
[[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}"
|
||||
[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}"
|
||||
${getPosixOmpShellWrapper()}
|
||||
# Why: Codex must keep using Orca's runtime CODEX_HOME after rc files.
|
||||
[[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}"
|
||||
${ZSH_HISTFILE_RESTORE_BLOCK}
|
||||
${getPosixCodexShellLaunchPreflight()}
|
||||
fi
|
||||
__orca_osc133_precmd() {
|
||||
local exit_code=$?
|
||||
if [[ -n "\${__orca_in_command:-}" ]]; then
|
||||
printf "\\033]133;D;%s\\007" "$exit_code"
|
||||
unset __orca_in_command
|
||||
fi
|
||||
printf "\\033]133;A\\007"
|
||||
}
|
||||
__orca_osc133_preexec() {
|
||||
printf "\\033]133;C\\007"
|
||||
__orca_in_command=1
|
||||
}
|
||||
# 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
|
||||
`
|
||||
return buildZshStartupWrapperFiles(getLocalZshWrapperSpec(`${getShellReadyWrapperRoot()}/zsh`))
|
||||
.zshrc
|
||||
}
|
||||
|
||||
export function ensureShellReadyWrappersAt(root = getShellReadyWrapperRoot()): void {
|
||||
@@ -78,38 +59,14 @@ export function ensureShellReadyWrappersAt(root = getShellReadyWrapperRoot()): v
|
||||
const zshDir = `${root}/zsh`
|
||||
const bashDir = `${root}/bash`
|
||||
|
||||
const zshEnv = getZshEnvTemplate(zshDir)
|
||||
const zshProfile = `# Orca zsh shell-ready wrapper
|
||||
${getZshStartupFileSourceBlock({ fileName: '.zprofile' })}
|
||||
`
|
||||
const zshRc = getZshShellReadyRcfileContent()
|
||||
const zshLogin = `# Orca zsh shell-ready wrapper
|
||||
${getZshStartupFileSourceBlock({ fileName: '.zlogin', interactiveOnly: true })}
|
||||
__orca_restore_agent_teams_path() {
|
||||
[[ -n "\${ORCA_AGENT_TEAMS_SHIM_DIR:-}" ]] || return 0
|
||||
case "$PATH" in
|
||||
"\${ORCA_AGENT_TEAMS_SHIM_DIR}"|"\${ORCA_AGENT_TEAMS_SHIM_DIR}:"*) return 0 ;;
|
||||
esac
|
||||
export PATH="\${ORCA_AGENT_TEAMS_SHIM_DIR}:$PATH"
|
||||
}
|
||||
__orca_restore_agent_teams_path
|
||||
# Why: .zlogin is the final login startup file before the prompt is shown.
|
||||
[[ -n "\${ORCA_OPENCODE_CONFIG_DIR:-}" ]] && export OPENCODE_CONFIG_DIR="\${ORCA_OPENCODE_CONFIG_DIR}"
|
||||
[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}"
|
||||
${getPosixOmpShellWrapper()}
|
||||
[[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}"
|
||||
${ZSH_HISTFILE_RESTORE_BLOCK}
|
||||
${getPosixCodexShellLaunchPreflight()}
|
||||
${getZshShellReadyMarkerRegistrationBlock(SHELL_READY_MARKER_ESCAPED)}
|
||||
${getZshFinalZdotdirRestoreBlock()}
|
||||
`
|
||||
const zsh = buildZshStartupWrapperFiles(getLocalZshWrapperSpec(zshDir))
|
||||
const bashRc = getBashShellReadyRcfileContent()
|
||||
|
||||
const files = [
|
||||
[`${zshDir}/.zshenv`, zshEnv],
|
||||
[`${zshDir}/.zprofile`, zshProfile],
|
||||
[`${zshDir}/.zshrc`, zshRc],
|
||||
[`${zshDir}/.zlogin`, zshLogin],
|
||||
[`${zshDir}/.zshenv`, zsh.zshenv],
|
||||
[`${zshDir}/.zprofile`, zsh.zprofile],
|
||||
[`${zshDir}/.zshrc`, zsh.zshrc],
|
||||
[`${zshDir}/.zlogin`, zsh.zlogin],
|
||||
[`${bashDir}/rcfile`, bashRc]
|
||||
] as const
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ fi`
|
||||
|
||||
// Why: daemon, local, and relay wrappers must preserve one Bash prompt-hook contract.
|
||||
export { BASH_PROMPT_COMMAND_COMPOSITION_BLOCK } from './bash-prompt-command-composition'
|
||||
export function getZshEnvTemplate(zshDir: string, headerPrefix = ''): string {
|
||||
const header = headerPrefix
|
||||
? `Orca ${headerPrefix} zsh shell-ready wrapper`
|
||||
: 'Orca zsh shell-ready wrapper'
|
||||
return `# ${header}
|
||||
export function getZshEnvTemplate(
|
||||
zshDir: string,
|
||||
headerLabel = 'Orca zsh shell-ready wrapper'
|
||||
): string {
|
||||
return `# ${headerLabel}
|
||||
${SHELL_STARTUP_IDENTITY_MARKER_BLOCK}
|
||||
# Why: capture the runtime wrapper dir before it is unset below. On WSL this
|
||||
# file is generated with a Windows path but sourced via /mnt/c, so the baked
|
||||
@@ -103,6 +103,30 @@ unset _orca_spawn_orig_zdotdir _orca_user_zdotdir _orca_zshenv_source_dir _orca_
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* The relay variant of the .zshenv above: it trusts the ZDOTDIR the remote
|
||||
* shell already inherited instead of re-deriving one, and republishes it as
|
||||
* ORCA_USER_ZDOTDIR for the later wrapper files.
|
||||
*
|
||||
* Why separate: this diverged from the discovery template before unification
|
||||
* and is preserved verbatim here — reconciling the two is a follow-up.
|
||||
*/
|
||||
export function getZshOverlayEnvTemplate(zshDir: string, headerLabel: string): string {
|
||||
return `# ${headerLabel}
|
||||
${SHELL_STARTUP_IDENTITY_MARKER_BLOCK}
|
||||
export ORCA_ORIG_ZDOTDIR="\${ORCA_ORIG_ZDOTDIR:-$HOME}"
|
||||
case "\${ORCA_ORIG_ZDOTDIR%/}" in
|
||||
*/shell-ready/zsh) export ORCA_ORIG_ZDOTDIR="$HOME" ;;
|
||||
esac
|
||||
[[ -f "$ORCA_ORIG_ZDOTDIR/.zshenv" ]] && source "$ORCA_ORIG_ZDOTDIR/.zshenv"
|
||||
export ORCA_USER_ZDOTDIR="\${ZDOTDIR:-\${ORCA_ORIG_ZDOTDIR:-$HOME}}"
|
||||
case "\${ORCA_USER_ZDOTDIR%/}" in
|
||||
*/shell-ready/zsh) export ORCA_USER_ZDOTDIR="$HOME" ;;
|
||||
esac
|
||||
export ZDOTDIR=${quotePosixSingle(zshDir)}
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the worktree-scoped HISTFILE that macOS `/etc/zshrc` destroys.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* The single source of the zsh startup wrapper files (.zshenv/.zprofile/.zshrc/
|
||||
* .zlogin) Orca writes for every transport: local PTY, daemon/SSH, and relay.
|
||||
*
|
||||
* Why: the three generators were copies that drifted apart, so a fix landed in
|
||||
* one transport and silently missed the other two. Everything they genuinely
|
||||
* disagree on is a field on ZshStartupWrapperSpec, so the disagreements are
|
||||
* visible in one place instead of spread across three template literals.
|
||||
*/
|
||||
import { getPosixOmpShellWrapper } from './pty/omp-shell-wrapper'
|
||||
import { getPosixCodexShellLaunchPreflight } from './pty/codex-shell-launch-preflight'
|
||||
import {
|
||||
getZshEnvTemplate,
|
||||
getZshFinalZdotdirRestoreBlock,
|
||||
getZshOverlayEnvTemplate,
|
||||
getZshShellReadyMarkerRegistrationBlock,
|
||||
getZshStartupFileSourceBlock,
|
||||
ZSH_HISTFILE_RESTORE_BLOCK
|
||||
} from './shell-templates'
|
||||
|
||||
/** Runtime values the wrapper re-exports after the user's own startup files ran. */
|
||||
export type ZshWrapperRestoreSpec = {
|
||||
/** Orca's agent-teams shim dir back onto PATH. */
|
||||
agentTeamsPath: boolean
|
||||
/** Remote CLI bin dir onto PATH — relay hosts only. */
|
||||
remoteCliBinDir: boolean
|
||||
/** Orca's runtime CODEX_HOME. */
|
||||
codexHome: boolean
|
||||
/** The `codex()` wrapper that runs Orca's launch preflight. */
|
||||
codexLaunchPreflight: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-existing cosmetic drift in the .zshrc restore block. Carried as explicit
|
||||
* fields so unifying the generators stays byte-identical; normalizing these
|
||||
* away is a follow-up, not part of the unification.
|
||||
*/
|
||||
export type ZshWrapperLegacyFormatting = {
|
||||
/** Local .zshrc lost the two-space indent on the MIMOCODE_HOME restore. */
|
||||
unindentedMimocodeRestore?: boolean
|
||||
/** Only local .zshrc carries a comment above the CODEX_HOME restore. */
|
||||
codexHomeRestoreComment?: string
|
||||
}
|
||||
|
||||
export type ZshStartupWrapperSpec = {
|
||||
/** First line of every generated file, e.g. `# Orca zsh shell-ready wrapper`. */
|
||||
headerLabel: string
|
||||
/** Wrapper ZDOTDIR baked into .zshenv as the fallback literal. */
|
||||
zshDir: string
|
||||
/**
|
||||
* How .zshenv finds the user's real ZDOTDIR. `discover-user-zdotdir` sources
|
||||
* the user .zshenv and reads what it exported; `overlay-user-zdotdir` trusts
|
||||
* the inherited ZDOTDIR and republishes it as ORCA_USER_ZDOTDIR.
|
||||
*/
|
||||
zshenvStrategy: 'discover-user-zdotdir' | 'overlay-user-zdotdir'
|
||||
/** zsh expression the wrapper resolves the user's startup-file dir from. */
|
||||
homeExpression?: string
|
||||
readyMarkerEscaped: string
|
||||
/** OSC 133 command-lifecycle hooks in .zshrc. */
|
||||
osc133CommandMarkers: boolean
|
||||
/** Skip the user .zshrc when its dir is already the wrapper ZDOTDIR. */
|
||||
skipUserZshrcWhenHomeIsWrapperDir: boolean
|
||||
/** Comment heading the non-login restore block in .zshrc. */
|
||||
interactiveRestoreComment: string
|
||||
/** Comment heading the restore block in .zlogin. */
|
||||
loginRestoreComment: string
|
||||
restores: ZshWrapperRestoreSpec
|
||||
/** Where the ready-marker widget lands relative to the final ZDOTDIR restore. */
|
||||
readyMarkerOrder: 'before-zdotdir-restore' | 'after-zdotdir-restore'
|
||||
legacyFormatting?: ZshWrapperLegacyFormatting
|
||||
}
|
||||
|
||||
export type ZshStartupWrapperFiles = {
|
||||
zshenv: string
|
||||
zprofile: string
|
||||
zshrc: string
|
||||
zlogin: string
|
||||
}
|
||||
|
||||
const AGENT_TEAMS_PATH_RESTORE_FUNCTION = `__orca_restore_agent_teams_path() {
|
||||
[[ -n "\${ORCA_AGENT_TEAMS_SHIM_DIR:-}" ]] || return 0
|
||||
case "$PATH" in
|
||||
"\${ORCA_AGENT_TEAMS_SHIM_DIR}"|"\${ORCA_AGENT_TEAMS_SHIM_DIR}:"*) return 0 ;;
|
||||
esac
|
||||
export PATH="\${ORCA_AGENT_TEAMS_SHIM_DIR}:$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 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 = `[[ -n "\${ORCA_CODEX_HOME:-}" ]] && export CODEX_HOME="\${ORCA_CODEX_HOME}"`
|
||||
|
||||
const ZSH_OSC133_COMMAND_MARKER_BLOCK = `__orca_osc133_precmd() {
|
||||
local exit_code=$?
|
||||
if [[ -n "\${__orca_in_command:-}" ]]; then
|
||||
printf "\\033]133;D;%s\\007" "$exit_code"
|
||||
unset __orca_in_command
|
||||
fi
|
||||
printf "\\033]133;A\\007"
|
||||
}
|
||||
__orca_osc133_preexec() {
|
||||
printf "\\033]133;C\\007"
|
||||
__orca_in_command=1
|
||||
}
|
||||
# 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[@]})`
|
||||
|
||||
/**
|
||||
* Blocks already carrying a trailing newline (the omp wrapper, the codex
|
||||
* preflight, the shared source/restore templates) keep it, so joining on a
|
||||
* single newline reproduces the blank-line spacing of the originals.
|
||||
*/
|
||||
function joinBlocks(blocks: (string | null)[]): string {
|
||||
return blocks.filter((block): block is string => block !== null).join('\n')
|
||||
}
|
||||
|
||||
/** The env/PATH restores that must outlast the user's own startup files. */
|
||||
function getRestoreLines(
|
||||
spec: ZshStartupWrapperSpec,
|
||||
indent: string,
|
||||
legacyFormatting?: ZshWrapperLegacyFormatting
|
||||
): (string | null)[] {
|
||||
const mimocodeIndent = legacyFormatting?.unindentedMimocodeRestore ? '' : indent
|
||||
const codexHomeComment = legacyFormatting?.codexHomeRestoreComment
|
||||
return [
|
||||
`${indent}${OPENCODE_CONFIG_DIR_RESTORE}`,
|
||||
`${mimocodeIndent}${MIMOCODE_HOME_RESTORE}`,
|
||||
spec.restores.remoteCliBinDir ? `${indent}${REMOTE_CLI_BIN_DIR_RESTORE}` : null,
|
||||
`${indent}${getPosixOmpShellWrapper()}`,
|
||||
spec.restores.codexHome && codexHomeComment ? `${indent}${codexHomeComment}` : null,
|
||||
spec.restores.codexHome ? `${indent}${CODEX_HOME_RESTORE}` : null,
|
||||
ZSH_HISTFILE_RESTORE_BLOCK,
|
||||
spec.restores.codexLaunchPreflight ? `${indent}${getPosixCodexShellLaunchPreflight()}` : null
|
||||
]
|
||||
}
|
||||
|
||||
function buildZshrc(spec: ZshStartupWrapperSpec): string {
|
||||
return `${joinBlocks([
|
||||
`# ${spec.headerLabel}`,
|
||||
getZshStartupFileSourceBlock({
|
||||
fileName: '.zshrc',
|
||||
homeExpression: spec.homeExpression,
|
||||
interactiveOnly: true,
|
||||
skipWhenHomeIsCurrentZdotdir: spec.skipUserZshrcWhenHomeIsWrapperDir
|
||||
}),
|
||||
spec.restores.agentTeamsPath
|
||||
? `${AGENT_TEAMS_PATH_RESTORE_FUNCTION}\n[[ ! -o login ]] && __orca_restore_agent_teams_path`
|
||||
: null,
|
||||
joinBlocks([
|
||||
'if [[ ! -o login ]]; then',
|
||||
` ${spec.interactiveRestoreComment}`,
|
||||
...getRestoreLines(spec, ' ', spec.legacyFormatting),
|
||||
'fi'
|
||||
]),
|
||||
spec.osc133CommandMarkers ? ZSH_OSC133_COMMAND_MARKER_BLOCK : null,
|
||||
`if [[ ! -o login ]]; then\n${getZshFinalZdotdirRestoreBlock(spec.homeExpression)}\nfi`
|
||||
])}\n`
|
||||
}
|
||||
|
||||
function buildZlogin(spec: ZshStartupWrapperSpec): string {
|
||||
const finalZdotdirRestore = getZshFinalZdotdirRestoreBlock(spec.homeExpression)
|
||||
const readyMarker = getZshShellReadyMarkerRegistrationBlock(spec.readyMarkerEscaped)
|
||||
const tail =
|
||||
spec.readyMarkerOrder === 'before-zdotdir-restore'
|
||||
? [readyMarker, finalZdotdirRestore]
|
||||
: [finalZdotdirRestore, readyMarker]
|
||||
|
||||
return `${joinBlocks([
|
||||
`# ${spec.headerLabel}`,
|
||||
getZshStartupFileSourceBlock({
|
||||
fileName: '.zlogin',
|
||||
homeExpression: spec.homeExpression,
|
||||
interactiveOnly: true
|
||||
}),
|
||||
spec.restores.agentTeamsPath
|
||||
? `${AGENT_TEAMS_PATH_RESTORE_FUNCTION}\n__orca_restore_agent_teams_path`
|
||||
: null,
|
||||
joinBlocks([spec.loginRestoreComment, ...getRestoreLines(spec, '')]),
|
||||
...tail
|
||||
])}\n`
|
||||
}
|
||||
|
||||
export function buildZshStartupWrapperFiles(spec: ZshStartupWrapperSpec): ZshStartupWrapperFiles {
|
||||
return {
|
||||
zshenv:
|
||||
spec.zshenvStrategy === 'discover-user-zdotdir'
|
||||
? getZshEnvTemplate(spec.zshDir, spec.headerLabel)
|
||||
: getZshOverlayEnvTemplate(spec.zshDir, spec.headerLabel),
|
||||
zprofile: `${joinBlocks([
|
||||
`# ${spec.headerLabel}`,
|
||||
getZshStartupFileSourceBlock({
|
||||
fileName: '.zprofile',
|
||||
homeExpression: spec.homeExpression
|
||||
})
|
||||
])}\n`,
|
||||
zshrc: buildZshrc(spec),
|
||||
zlogin: buildZlogin(spec)
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,13 @@ import { dirname, join } from 'node:path'
|
||||
import { getPosixOmpShellWrapper } from '../main/pty/omp-shell-wrapper'
|
||||
import {
|
||||
BASH_PROMPT_COMMAND_COMPOSITION_BLOCK,
|
||||
getZshFinalZdotdirRestoreBlock,
|
||||
getZshShellReadyMarkerRegistrationBlock,
|
||||
SHELL_STARTUP_IDENTITY_MARKER_BLOCK,
|
||||
ZSH_HISTFILE_RESTORE_BLOCK,
|
||||
getZshStartupFileSourceBlock
|
||||
ZSH_HISTFILE_RESTORE_BLOCK
|
||||
} from '../main/shell-templates'
|
||||
import {
|
||||
buildZshStartupWrapperFiles,
|
||||
type ZshStartupWrapperSpec
|
||||
} from '../main/zsh-startup-wrapper-builder'
|
||||
|
||||
/** Writes the zsh/bash overlay wrapper files a relay-spawned shell sources.
|
||||
* Split from pty-shell-launch.ts so the launch-config decisions stay readable
|
||||
@@ -16,66 +17,37 @@ import {
|
||||
|
||||
const SHELL_READY_MARKER_ESCAPED = '\\033]777;orca-shell-ready\\007'
|
||||
|
||||
function quotePosixSingle(value: string): string {
|
||||
return `'${value.replace(/'/g, `'\\''`)}'`
|
||||
// Why: the relay .zshenv republishes the inherited ZDOTDIR as ORCA_USER_ZDOTDIR,
|
||||
// so later wrapper files prefer it over the spawn-time ORCA_ORIG_ZDOTDIR.
|
||||
const RELAY_HOME_EXPRESSION = '"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"'
|
||||
|
||||
function getRelayZshWrapperSpec(zshDir: string): ZshStartupWrapperSpec {
|
||||
return {
|
||||
headerLabel: 'Orca relay zsh overlay wrapper',
|
||||
zshDir,
|
||||
zshenvStrategy: 'overlay-user-zdotdir',
|
||||
homeExpression: RELAY_HOME_EXPRESSION,
|
||||
readyMarkerEscaped: SHELL_READY_MARKER_ESCAPED,
|
||||
osc133CommandMarkers: false,
|
||||
skipUserZshrcWhenHomeIsWrapperDir: false,
|
||||
interactiveRestoreComment:
|
||||
'# Why: remote startup files can re-export user defaults after relay spawn.',
|
||||
loginRestoreComment: '# Why: .zlogin is the final zsh login startup file before the prompt.',
|
||||
restores: {
|
||||
agentTeamsPath: false,
|
||||
remoteCliBinDir: true,
|
||||
codexHome: false,
|
||||
codexLaunchPreflight: false
|
||||
},
|
||||
readyMarkerOrder: 'after-zdotdir-restore'
|
||||
}
|
||||
}
|
||||
|
||||
export function ensureOverlayRestoreWrappers(root: string): void {
|
||||
const zshDir = join(root, 'zsh')
|
||||
const bashDir = join(root, 'bash')
|
||||
|
||||
const zshEnv = `# Orca relay zsh overlay wrapper
|
||||
${SHELL_STARTUP_IDENTITY_MARKER_BLOCK}
|
||||
export ORCA_ORIG_ZDOTDIR="\${ORCA_ORIG_ZDOTDIR:-$HOME}"
|
||||
case "\${ORCA_ORIG_ZDOTDIR%/}" in
|
||||
*/shell-ready/zsh) export ORCA_ORIG_ZDOTDIR="$HOME" ;;
|
||||
esac
|
||||
[[ -f "$ORCA_ORIG_ZDOTDIR/.zshenv" ]] && source "$ORCA_ORIG_ZDOTDIR/.zshenv"
|
||||
export ORCA_USER_ZDOTDIR="\${ZDOTDIR:-\${ORCA_ORIG_ZDOTDIR:-$HOME}}"
|
||||
case "\${ORCA_USER_ZDOTDIR%/}" in
|
||||
*/shell-ready/zsh) export ORCA_USER_ZDOTDIR="$HOME" ;;
|
||||
esac
|
||||
export ZDOTDIR=${quotePosixSingle(zshDir)}
|
||||
`
|
||||
const zshProfile = `# Orca relay zsh overlay wrapper
|
||||
${getZshStartupFileSourceBlock({
|
||||
fileName: '.zprofile',
|
||||
homeExpression: '"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"'
|
||||
})}
|
||||
`
|
||||
const zshRc = `# Orca relay zsh overlay wrapper
|
||||
${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}"
|
||||
[[ -n "\${ORCA_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}"
|
||||
[[ -n "\${ORCA_REMOTE_CLI_BIN_DIR:-}" ]] && case ":$PATH:" in *:"\${ORCA_REMOTE_CLI_BIN_DIR}":*) ;; *) export PATH="\${ORCA_REMOTE_CLI_BIN_DIR}:$PATH" ;; esac
|
||||
${getPosixOmpShellWrapper()}
|
||||
${ZSH_HISTFILE_RESTORE_BLOCK}
|
||||
fi
|
||||
if [[ ! -o login ]]; then
|
||||
${getZshFinalZdotdirRestoreBlock('"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"')}
|
||||
fi
|
||||
`
|
||||
const zshLogin = `# Orca relay zsh overlay wrapper
|
||||
${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_MIMOCODE_HOME:-}" ]] && export MIMOCODE_HOME="\${ORCA_MIMOCODE_HOME}"
|
||||
[[ -n "\${ORCA_REMOTE_CLI_BIN_DIR:-}" ]] && case ":$PATH:" in *:"\${ORCA_REMOTE_CLI_BIN_DIR}":*) ;; *) export PATH="\${ORCA_REMOTE_CLI_BIN_DIR}:$PATH" ;; esac
|
||||
${getPosixOmpShellWrapper()}
|
||||
${ZSH_HISTFILE_RESTORE_BLOCK}
|
||||
${getZshFinalZdotdirRestoreBlock('"${ORCA_USER_ZDOTDIR:-${ORCA_ORIG_ZDOTDIR:-$HOME}}"')}
|
||||
${getZshShellReadyMarkerRegistrationBlock(SHELL_READY_MARKER_ESCAPED)}
|
||||
`
|
||||
const zsh = buildZshStartupWrapperFiles(getRelayZshWrapperSpec(zshDir))
|
||||
const bashRc = `# Orca relay bash overlay wrapper
|
||||
${SHELL_STARTUP_IDENTITY_MARKER_BLOCK}
|
||||
[[ -f /etc/profile ]] && source /etc/profile
|
||||
@@ -181,10 +153,10 @@ unset __orca_initializing_wrapper
|
||||
`
|
||||
|
||||
const files = [
|
||||
[join(zshDir, '.zshenv'), zshEnv],
|
||||
[join(zshDir, '.zprofile'), zshProfile],
|
||||
[join(zshDir, '.zshrc'), zshRc],
|
||||
[join(zshDir, '.zlogin'), zshLogin],
|
||||
[join(zshDir, '.zshenv'), zsh.zshenv],
|
||||
[join(zshDir, '.zprofile'), zsh.zprofile],
|
||||
[join(zshDir, '.zshrc'), zsh.zshrc],
|
||||
[join(zshDir, '.zlogin'), zsh.zlogin],
|
||||
[join(bashDir, 'rcfile'), bashRc]
|
||||
] as const
|
||||
|
||||
|
||||
Reference in New Issue
Block a user