mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
* test(chat): snapshot every native-chat agent's spawned child as a parity oracle Captures the exact child each native-chat agent spawns (Claude, Codex, Grok, OpenCode, OMP, Pi), worktree and floating, fresh and resumed, plus a registered worker with visuals off, at the real spawn boundary (the process host's spawn) and through production's own host dependency wiring. The inherited environment holds every pane, hook, caller, terminal-handle and visuals key a parent Orca pane could hand down, so the snapshot records today's per-agent differences as they are. Each case also records the launch's permission posture, which for Codex (thread policy) and the ACP agents (full access) acts only after spawn. Each agent also runs fresh and resumed with every launch setting moved off its default: a Command setting naming another binary, the permission posture flipped, an environment overlay over inherited and shell keys, and only named login-shell variables inherited (the fake login shell carries its own PATH and a variable no case names). A second test fails when a registered agent has no snapshot, since the oracle lists its agents by hand. Test only: the launch-path refactor that follows must leave both tests and the snapshot file unchanged. * refactor(chat): one composed launch for every native-chat agent Every native-chat agent (Claude, Codex, Grok, OpenCode, OMP, Pi) now builds its child through one composer instead of six hand-written resolvers. Each agent contributes only its own part (command, args, agent env, keys it must strip); the shared composer admits the session record, reads the launch directory, base environment, launch overrides and visuals once each (memoized, in the agent's original order), sets cwd, and seals the child. The seal (sealStructuredSessionChild) is the one place that names a child: session id, structured marker, worker terminal handle, the Orca CLI env, the spawn token under one shared constant, and the per-launch list of inherited keys to delete, minus any key the seal itself sets. Claude's delete list now reaches its SDK spawn after buildClaudeChildProcessEnv's merge. Behaviour is unchanged: the parity snapshot from the previous commit passes byte for byte, including each agent's existing differences (Claude and Codex keep inherited pane and hook env, Pi has no visuals and always full access, the ACP history read stays unsealed). Admission refusals keep their reasons; only log-only wording moved to the shared check. Drops launch dependencies no production caller wires (resolveLaunchEnv, resolveCodexOverrides) and folds the per-agent env overlay hooks into the existing resolveAgentLaunchEnv. * refactor(chat): only the seal names a native-chat child Follow-ups from review of the composed launch: - The spawn token is required on every resolveLaunch. The one read that starts no child, ACP's restart-recovery history read, now has its own path (composeStructuredLaunchRead, deps.readLaunch) that returns the agent's own env unsealed, as before. Agent parts receive the session identity only, never the token. - structuredSessionChildIdentityEnv is gone; the seal is the only way to build a child's identity env, and tests go through it. - A launch's environment is the runtime's resolveAgentEnvironment, so the base-plus-overlay rule exists once. - Claude's connection test now covers a non-empty envToDelete applied after the inherited env is merged. No change to any spawned child: the parity snapshot is unchanged. * ci: run the login-shell contract job for the renamed child-env seal The seal moved from structured-session-child-identity-env to structured-session-child-env, but the PR job classifier still listed the old path, so a change to only the seal would skip the live login-shell contract job. The prefix now covers the seal, its test and its test support (which the login-shell harness imports).
43 lines
1.8 KiB
TypeScript
43 lines
1.8 KiB
TypeScript
/**
|
|
* The Orca-minted agent session id, injected into a structured session's own child processes. When
|
|
* it is present it IS the orchestration caller: the CLI sends it in the orchestration envelope and
|
|
* the host resolves the session it names, so no terminal is resolved or guessed on its behalf.
|
|
*
|
|
* Identity by session id assumes one machine and one user. A host boundary (SSH, a paired peer,
|
|
* WSL) re-opens that decision: the host refuses a claim that arrives across one, and the SSH
|
|
* passthrough never carries the id.
|
|
*/
|
|
import { ORCA_SESSION_ADDRESS_PREFIX } from './orca-session-address-prefix'
|
|
import { isStructuredWorkerHandle } from './structured-worker-handle'
|
|
|
|
export const ORCA_AGENT_SESSION_ID_ENV = 'ORCA_AGENT_SESSION_ID'
|
|
|
|
/** The spawn token a structured session's child echoes, so the owner probe can tell a live child
|
|
* of that reservation from a same-pid stranger. */
|
|
export const ORCA_AGENT_SESSION_SPAWN_TOKEN_ENV = 'ORCA_AGENT_SESSION_SPAWN_TOKEN'
|
|
|
|
export function readInjectedAgentSessionId(
|
|
env: Readonly<Record<string, string | undefined>> = process.env
|
|
): string | undefined {
|
|
const value = env[ORCA_AGENT_SESSION_ID_ENV]?.trim()
|
|
return value ? value : undefined
|
|
}
|
|
|
|
/**
|
|
* The address the host gives this session (`mailboxAddressOf` on its resolved party): a structured
|
|
* worker keeps the handle it was minted, any other session is `orca_session_id:<id>`. Only for text that
|
|
* must match what the host writes; the CLI spells it without the host resolver.
|
|
*/
|
|
export function injectedSessionAddress(
|
|
env: Readonly<Record<string, string | undefined>> = process.env
|
|
): string | undefined {
|
|
const sessionId = readInjectedAgentSessionId(env)
|
|
if (!sessionId) {
|
|
return undefined
|
|
}
|
|
const ownHandle = env.ORCA_TERMINAL_HANDLE
|
|
return isStructuredWorkerHandle(ownHandle)
|
|
? ownHandle
|
|
: `${ORCA_SESSION_ADDRESS_PREFIX}${sessionId}`
|
|
}
|