mirror of
https://github.com/stablyai/orca.git
synced 2026-10-28 00:02:54 +00:00
Closes #10793. When Orca could not verify the originating Codex session file it either threw — a red per-pane toast and a failed spawn, reported as constant spam on #10757 — or returned null. Returning null did NOT start a fresh session: the renderer had already baked ['codex','resume',<id>] into the command and pty.ts never rewrote it, so CODEX_HOME simply fell through to whichever account was selected. The resume argv is now dropped so a plain `codex` launches, with a banner telling the user. The invariant — never run `codex resume <id>` under an account that does not own that rollout — is now satisfied by construction rather than by refusing to spawn. A verified resume is unchanged and still pins CODEX_HOME to the originating home. Reviewed over two adversarial rounds; seven defects found and fixed, including a HIGH where local-provider (non-daemon) spawns still carried ORCA_SEQUENCED_STARTUP_COMMAND with `resume <id>` — the wrong account behind a banner claiming it started fresh. `env` is now declared after the strip so no point in the handler can reach the pre-strip value. Live-validated in a real Orca dev build: all five cases proven on the SPAWNED PROCESS, including a real rollout under an untrusted home (the only shape that discriminates) and the local-provider path forced by stopping the daemon. An earlier CI failure on multi-client-navigation-isolation.integration.test.ts was investigated and is a PRE-EXISTING flake — a ~4ms race in the session-tabs notify coalescer that fails 5-8/24 on clean main, more often than on this branch. Fixed separately in #11022. Not verified: no Windows execution — its POSIX-only tests skip there and the #10757 reporter is on Windows. SSH is partial: no spurious banner or drop observed against a real target, but headless spawn does not deliver startup commands so the remote argv could not be read. The relay/mobile notice channel deliberately has no banner; the argv drop does happen there, so the invariant holds.
49 lines
2.0 KiB
TypeScript
49 lines
2.0 KiB
TypeScript
import {
|
|
resolveCodexSessionResumeProvenance,
|
|
type CodexSessionResumePreparation
|
|
} from './codex-session-resume-home'
|
|
|
|
export type VerifiedCodexResumeSource = { homePath: string; transcriptPath: string }
|
|
|
|
/**
|
|
* The launch decision for an automatic Codex resume: pin the verified origin home, or
|
|
* fall back to a fresh session whose resume argv the PTY layer drops (#10793). The
|
|
* caller supplies `resolveVerifiedResumeHome` because migration, project trust and hook
|
|
* repair only run once provenance is verified — a fresh outcome must skip all of them.
|
|
*
|
|
* The three rescan ranking inputs stay required through this hop (#10801): defaulting or
|
|
* nulling any of them would silently degrade the legacy rescan to pure path order.
|
|
*/
|
|
export async function prepareCodexSessionResume(args: {
|
|
sessionId: string
|
|
transcriptPath: string | undefined
|
|
trustedCodexHomes: readonly string[]
|
|
getSelectedAccountCodexHome: () => string | null
|
|
systemCodexHomePath: string | null
|
|
sharedRuntimeCodexHomePath: string | null
|
|
resolveVerifiedResumeHome: (source: VerifiedCodexResumeSource) => Promise<string>
|
|
fileIsRegular?: (filePath: string) => boolean
|
|
listSessionFiles?: (sessionsRoot: string) => AsyncIterable<string>
|
|
}): Promise<CodexSessionResumePreparation> {
|
|
const provenance = await resolveCodexSessionResumeProvenance({
|
|
sessionId: args.sessionId,
|
|
transcriptPath: args.transcriptPath,
|
|
trustedCodexHomes: args.trustedCodexHomes,
|
|
getSelectedAccountCodexHome: args.getSelectedAccountCodexHome,
|
|
systemCodexHomePath: args.systemCodexHomePath,
|
|
sharedRuntimeCodexHomePath: args.sharedRuntimeCodexHomePath,
|
|
...(args.fileIsRegular ? { fileIsRegular: args.fileIsRegular } : {}),
|
|
...(args.listSessionFiles ? { listSessionFiles: args.listSessionFiles } : {})
|
|
})
|
|
if (provenance.outcome === 'fresh') {
|
|
return provenance
|
|
}
|
|
return {
|
|
outcome: 'resume',
|
|
codexHomePath: await args.resolveVerifiedResumeHome({
|
|
homePath: provenance.homePath,
|
|
transcriptPath: provenance.transcriptPath
|
|
})
|
|
}
|
|
}
|