mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 00:03:52 +00:00
Returning a Codex session from structured chat to its terminal always failed with "did not prove the expected Codex rollout". Adoption stops the pane's Codex, so `launchAdoptedStructuredTui` typed a resume command into a bare shell and went straight to the proof, which pasted `/status` and scraped the tail for 15s. The probe landed before Codex was up, and it read kittyKeyboardFlags from the mode tracker before the new process negotiated, submitting a bare CR. A `tui-idle` wait would not fix it: that resolves on a shell prompt preview and on the pre-adoption `lastAgentStatus`. Nothing on screen separates a ready shell from a ready Codex. The resumed CLI can answer for itself. Orca already installs Codex SessionStart hooks, and the payload carries session_id, transcript_path and source=resume. The hook now also echoes back a one-shot nonce Orca stamps into the single resume invocation it types, so a stale SessionStart from an earlier process in the same pane cannot pass for the new one. The nonce is a new env var rather than `launchToken`, which is pane-lifetime identity that authority attestation matches against. Nothing is pasted at the pane any more, so the submit-key question disappears with the probe. An installed hook script predating this omits the nonce; pane + thread still bind, so that degrades instead of stranding the path. With agent status hooks off there is no proof to wait for, and the launch says so up front.
47 lines
2.0 KiB
TypeScript
47 lines
2.0 KiB
TypeScript
// Env assignments for a command Orca TYPES into a shell it already owns, rather
|
|
// than one it spawns with an env map. The adopted-Codex return path has no spawn
|
|
// to attach env to: the pane is a live shell and the resume command is keystrokes.
|
|
import {
|
|
quoteStartupArg,
|
|
resolveStartupShell,
|
|
type AgentStartupShell
|
|
} from './tui-agent-startup-shell'
|
|
|
|
export function buildInlineEnvCommandPrefix(args: {
|
|
env: Record<string, string>
|
|
platform: NodeJS.Platform
|
|
shell?: AgentStartupShell
|
|
}): string {
|
|
const entries = Object.entries(args.env)
|
|
if (entries.length === 0) {
|
|
return ''
|
|
}
|
|
const shell = resolveStartupShell(args.platform, args.shell)
|
|
const quote = (value: string): string => quoteStartupArg(value, shell)
|
|
if (shell === 'powershell') {
|
|
return `${entries.map(([name, value]) => `$env:${name}=${quote(value)}`).join('; ')}; `
|
|
}
|
|
if (shell === 'cmd') {
|
|
// Why: `set` here outlives the command, unlike the POSIX one-shot form. Safe
|
|
// because every caller overwrites the same names on its next invocation, so a
|
|
// leftover value can only ever fail a match — never satisfy a fresh one.
|
|
return `${entries.map(([name, value]) => `set ${quote(`${name}=${value}`)}`).join(' && ')} && `
|
|
}
|
|
// Why `env` rather than the bare `NAME=value cmd` prefix: fish rejects that form
|
|
// outright ("Unsupported use of '='"), and the pane's POSIX dialect is not
|
|
// recorded anywhere Orca can read at write time. `env` parses in sh, bash, zsh
|
|
// and fish alike, and matches how every other Orca launch path reaches the agent
|
|
// binary — through the executable, not a shell alias.
|
|
return `env ${entries.map(([name, value]) => `${name}=${quote(value)}`).join(' ')} `
|
|
}
|
|
|
|
/** Prefixes a typed command so the assignments apply to that invocation. */
|
|
export function withInlineEnvAssignments(args: {
|
|
command: string
|
|
env: Record<string, string>
|
|
platform: NodeJS.Platform
|
|
shell?: AgentStartupShell
|
|
}): string {
|
|
return `${buildInlineEnvCommandPrefix(args)}${args.command}`
|
|
}
|