mirror of
https://github.com/stablyai/orca.git
synced 2026-10-02 08:02:02 +00:00
* fix(codex): safely re-land WSL direct homes * fix(codex): finish WSL direct-home cutover * fix(codex): coalesce WSL launch hook installs * perf(codex): avoid duplicate retired WSL session scan * fix(codex): retain canonical WSL retired-home path * fix(codex): fail closed before retiring WSL auth * fix(codex): reopen WSL drain after rollback * fix(codex): preserve WSL source on unknown panes * fix(codex): harden repeated WSL runtime drains * perf(codex): bound pending WSL session scans * fix(codex): recover invalid WSL session watermarks * fix(codex): validate retained WSL scan state * fix(codex): accept durable WSL scan state * test(codex): cover the drain's inode-identity guard against destination replacement Removing the four `target_auth -ef temporary_destination_auth` assertions left all 33 apply-script tests passing, so a regression deleting them would have shipped silently. Reproduced before writing this. A hash check cannot catch the case. The pinned hard link keeps the original inode, so it still hashes correctly after another writer atomically renames a different file over the destination path; only inode identity sees it. Without the guard the script exits 0 and retires the source, leaving the user holding bytes nothing validated. The new case asserts the source survives. The harness is split by responsibility so no file exceeds its max-lines budget: fixtures, the coreutils interference shims, the run types, the apply runner, and the recovery/absent runners. The atomic-rename hook is deliberately separate from the in-place rewrite shim because different guards catch them. * fix(codex): keep the split drain harness inside the child-process boundaries Extracting the harness into non-test modules moved it out of the exemptions the single test file had: three new files import child_process, and two spawned without windowsHide. Adds the three to the import allowlist, and sets windowsHide on the spawns rather than exempting them - the flag is correct for these calls regardless of the ratchet, and they are skipped on win32 anyway. --------- Co-authored-by: Merge Sim <sim@local>
166 lines
6.0 KiB
TypeScript
166 lines
6.0 KiB
TypeScript
import type { GlobalSettings } from '../../shared/global-settings-types'
|
|
import { normalizeRuntimePathForComparison } from '../../shared/cross-platform-path'
|
|
import { parseWslUncPath } from '../../shared/wsl-paths'
|
|
import {
|
|
getCodexSelectionLaneKey,
|
|
getCodexSelectionTargetForAccount,
|
|
getSelectedCodexAccountIdForTarget,
|
|
type CodexAccountSelectionTarget
|
|
} from '../codex-accounts/runtime-selection'
|
|
import type { CodexPaneAccountRecord, CodexPaneHomeRoute } from './codex-pane-account-registry'
|
|
import type {
|
|
CodexEnvironmentHomeOverride,
|
|
CodexShellStartupHomeOverride
|
|
} from './codex-real-home-path'
|
|
|
|
type CodexPaneLaunchAccountSettings = Pick<
|
|
GlobalSettings,
|
|
'activeCodexManagedAccountId' | 'activeCodexManagedAccountIdsByRuntime' | 'codexManagedAccounts'
|
|
>
|
|
|
|
/**
|
|
* Resolves which Codex account a PTY is actually launching under.
|
|
*
|
|
* Why: an automatic session resume deliberately pins CODEX_HOME to the home
|
|
* that owns the session rather than to the current selection, so a cold-restored
|
|
* pane can come back on an account the user already switched away from. Naming
|
|
* that real account — instead of the selection Orca ignored — is what lets the
|
|
* restart prompt tell the user which account the pane is stuck on.
|
|
*
|
|
* Returns null when the launch cannot be attributed, which keeps the pane out of
|
|
* the stale-pane report entirely.
|
|
*/
|
|
export function resolveCodexPaneLaunchAccount(args: {
|
|
pinnedByResume: boolean
|
|
launchCodexHomePath: string | null
|
|
recordComparableHomeRoute?: boolean
|
|
shellStartupHomeOverride?: CodexShellStartupHomeOverride
|
|
environmentHomeOverride?: CodexEnvironmentHomeOverride
|
|
systemCodexHomePath: string
|
|
settings: CodexPaneLaunchAccountSettings
|
|
target: CodexAccountSelectionTarget
|
|
}): CodexPaneAccountRecord | null {
|
|
const selectionKey = getCodexSelectionLaneKey(args.target)
|
|
const resolvedHomeRoute = resolveCodexPaneHomeRoute(args)
|
|
const homeRoute =
|
|
args.recordComparableHomeRoute === false && resolvedHomeRoute === 'shared-home'
|
|
? 'custom-home'
|
|
: resolvedHomeRoute
|
|
if (!args.pinnedByResume) {
|
|
return {
|
|
selectionKey,
|
|
accountId: getSelectedCodexAccountIdForTarget(args.settings, args.target),
|
|
...(homeRoute ? { homeRoute } : {}),
|
|
...(args.shellStartupHomeOverride
|
|
? { shellStartupHomeOverride: args.shellStartupHomeOverride }
|
|
: {}),
|
|
...(args.environmentHomeOverride
|
|
? { environmentHomeOverride: args.environmentHomeOverride }
|
|
: {})
|
|
}
|
|
}
|
|
const accountId = resolveCodexHomeOwnerAccountId(args)
|
|
return accountId === undefined
|
|
? null
|
|
: {
|
|
selectionKey,
|
|
accountId,
|
|
...(homeRoute ? { homeRoute } : {}),
|
|
...(args.shellStartupHomeOverride
|
|
? { shellStartupHomeOverride: args.shellStartupHomeOverride }
|
|
: {}),
|
|
...(args.environmentHomeOverride
|
|
? { environmentHomeOverride: args.environmentHomeOverride }
|
|
: {})
|
|
}
|
|
}
|
|
|
|
function resolveCodexPaneHomeRoute(args: {
|
|
launchCodexHomePath: string | null
|
|
systemCodexHomePath: string
|
|
settings: CodexPaneLaunchAccountSettings
|
|
target: CodexAccountSelectionTarget
|
|
}): CodexPaneHomeRoute {
|
|
if (
|
|
!args.launchCodexHomePath ||
|
|
normalizeRuntimePathForComparison(args.launchCodexHomePath) ===
|
|
normalizeRuntimePathForComparison(args.systemCodexHomePath)
|
|
) {
|
|
return 'real-home'
|
|
}
|
|
const launchHomePath = args.launchCodexHomePath
|
|
const accountOwnsHome = args.settings.codexManagedAccounts?.some((account) =>
|
|
accountOwnsCodexHome(account, args.target, launchHomePath)
|
|
)
|
|
if (accountOwnsHome) {
|
|
return 'account-home'
|
|
}
|
|
if (args.target.runtime === 'wsl') {
|
|
return parseWslUncPath(args.launchCodexHomePath)?.linuxPath.endsWith('/.codex')
|
|
? 'real-home'
|
|
: 'wsl-home'
|
|
}
|
|
return 'shared-home'
|
|
}
|
|
|
|
/** undefined when no account owns the home; null means the system-default account. */
|
|
function resolveCodexHomeOwnerAccountId(args: {
|
|
launchCodexHomePath: string | null
|
|
systemCodexHomePath: string
|
|
settings: CodexPaneLaunchAccountSettings
|
|
target: CodexAccountSelectionTarget
|
|
}): string | null | undefined {
|
|
// Why: no injected CODEX_HOME means Codex reads the user's own home.
|
|
if (!args.launchCodexHomePath) {
|
|
return null
|
|
}
|
|
if (
|
|
normalizeRuntimePathForComparison(args.launchCodexHomePath) ===
|
|
normalizeRuntimePathForComparison(args.systemCodexHomePath)
|
|
) {
|
|
return null
|
|
}
|
|
const launchHomePath = args.launchCodexHomePath
|
|
const owner = args.settings.codexManagedAccounts?.find((account) =>
|
|
accountOwnsCodexHome(account, args.target, launchHomePath)
|
|
)
|
|
// Why: an unowned home cannot be named, and naming the account a pane is stuck
|
|
// on is the prompt's whole job — so decline rather than guess. A wrong notice
|
|
// silently drops every keystroke in that terminal. Note the shared runtime
|
|
// mirror only hot-swaps to the current selection on the legacy flag-OFF lane;
|
|
// a pane resumed into it after the per-account rollout is genuinely stale but
|
|
// still unnameable, so that cohort stays unreported.
|
|
return owner ? owner.id : undefined
|
|
}
|
|
|
|
function accountOwnsCodexHome(
|
|
account: NonNullable<CodexPaneLaunchAccountSettings['codexManagedAccounts']>[number],
|
|
target: CodexAccountSelectionTarget,
|
|
launchHomePath: string
|
|
): boolean {
|
|
// Why: a WSL pane resolves its account from its own per-distro lane, so a
|
|
// host account's home must never answer for it (and vice versa).
|
|
if (
|
|
getCodexSelectionLaneKey(getCodexSelectionTargetForAccount(account)) !==
|
|
getCodexSelectionLaneKey(target)
|
|
) {
|
|
return false
|
|
}
|
|
if (
|
|
normalizeRuntimePathForComparison(account.managedHomePath) ===
|
|
normalizeRuntimePathForComparison(launchHomePath)
|
|
) {
|
|
return true
|
|
}
|
|
const launchWslHome = target.runtime === 'wsl' ? parseWslUncPath(launchHomePath) : null
|
|
const accountDistro = account.wslDistro?.trim()
|
|
const accountLinuxHome = account.wslLinuxHomePath?.trim()
|
|
return Boolean(
|
|
launchWslHome &&
|
|
accountDistro &&
|
|
accountLinuxHome &&
|
|
launchWslHome.distro.toLowerCase() === accountDistro.toLowerCase() &&
|
|
launchWslHome.linuxPath === accountLinuxHome
|
|
)
|
|
}
|