Files
orca/src/main/codex/codex-server-request-disposition.ts
T
Brennan Benson 290b4b3b4a feat(native-chat): port structured Codex sessions from restructure-recovery
Rebuilds the desktop structured native-chat implementation from
brennanb2025/native-chat-restructure-recovery (tip 4e31c08db3) on top of
current main as a single commit, scoped to the local Codex path.

Ported:
- Structured agent-session core: durable record store + single-writer lease,
  canonical journal, agent-session wire host/attach/eviction/subscribers,
  `agentSession.*` RPC surface (registered via ALL_RPC_METHODS; host-side
  mobile allowlist included for wire compat), pty write gate, transcript
  additions, and the Codex app-server adapter/launch resolution.
- Renderer: NativeChatStructuredSession view/composer stack, structured
  launch path with the single-flight guard, local structured session tabs
  sync, activation gate + structured inventory (read-only
  `agentSession.handoffStatus` probe), agent-session tabs in the tab strip,
  AI-vault structured session activation, and the settings pane with the
  parent Experimental Chat UI toggle plus the nested "Use updated structured
  native chat" toggle. New sessions require both flags, agent codex, no
  prompt, and a local non-WSL, non-Windows-host execution host
  (structured-native-chat-availability).
- Fixes 72c013cea6 (verified Codex launch recovery), 8ddbaf5e3d (defer
  native terminal view switching affordances), and 4e31c08db3 (release the
  launch gate after a visibility retry) with their regression tests,
  including the third-launch-after-retry guard case.
- Cross-version agent-session wire test + CI lane, packaging entries
  (proper-lockfile, agent-tooling asar excludes), and the wire-compat doc
  section.

Deliberately not ported: mobile/ changes, the Claude structured runtime
(only the claude-transcript-branch-proof and claude-structured-owner-identity
leaf modules remain, backing the kept TUI-recovery arms), the terminal↔chat
adoption/handoff flow (`agentSession.adoptTerminal`/`requestHandoff`, the
handoff request engine, TUI adoption machinery, orca-runtime adoption
methods), renderer switching affordances and their dead leftovers, the
hook/subagent-status refactor cluster, and unrelated branch changes. The
crash-during-acquisition recovery path (restart handoff adjudication,
restore/reverse re-acquire, lease schema handoff keys) is kept because every
plain direct launch depends on it; a trimmed handoff coordinator exposes
only status/restore/close.

Branch edits that targeted files main has since split (ipc/pty.ts,
worktrees.ts, rpc/methods/terminal.ts, useIpcEvents, pty-connection,
store/slices/terminals.ts, runtime-types, web preload) were re-applied to
the split modules, preserving main's newer logic (Windows CIM fallback,
browser tab close rework, cold-restore resume flow, dispatcher threading).

Known seam: the mobile clipboard image-provenance CONSUMER gate ships
(agentSession.send refuses unproven mobile image refs with
agent_session_image_untrusted) but the producer hunk in
rpc/methods/clipboard.ts stays with the unported mobile cluster, so mobile
image sends into structured chat fail closed until that side ports.
2026-08-26 10:47:56 -07:00

87 lines
3.2 KiB
TypeScript

import type {
CodexAppServerConnection,
CodexAppServerServerRequest
} from './codex-app-server-connection'
import {
CODEX_COMMAND_APPROVAL_METHOD,
CODEX_FILE_CHANGE_APPROVAL_METHOD,
CODEX_USER_INPUT_METHOD,
type CodexPromptRegistry,
type CodexPendingPrompt
} from './codex-structured-prompt-replies'
export const CODEX_MCP_ELICITATION_METHOD = 'mcpServer/elicitation/request'
export const CODEX_PERMISSIONS_APPROVAL_METHOD = 'item/permissions/requestApproval'
export const CODEX_DYNAMIC_TOOL_CALL_METHOD = 'item/tool/call'
export const CODEX_AUTH_TOKEN_REFRESH_METHOD = 'account/chatgptAuthTokens/refresh'
export const CODEX_ATTESTATION_METHOD = 'attestation/generate'
export const CODEX_LEGACY_APPLY_PATCH_APPROVAL_METHOD = 'applyPatchApproval'
export const CODEX_LEGACY_EXEC_APPROVAL_METHOD = 'execCommandApproval'
export const CODEX_BLOCKING_SERVER_REQUEST_METHODS = [
CODEX_COMMAND_APPROVAL_METHOD,
CODEX_FILE_CHANGE_APPROVAL_METHOD,
CODEX_USER_INPUT_METHOD,
CODEX_MCP_ELICITATION_METHOD,
CODEX_PERMISSIONS_APPROVAL_METHOD,
CODEX_DYNAMIC_TOOL_CALL_METHOD,
CODEX_AUTH_TOKEN_REFRESH_METHOD,
CODEX_ATTESTATION_METHOD,
CODEX_LEGACY_APPLY_PATCH_APPROVAL_METHOD,
CODEX_LEGACY_EXEC_APPROVAL_METHOD
] as const
export type CodexServerRequestDisposition =
| { kind: 'prompt'; prompt: CodexPendingPrompt }
| { kind: 'responded'; method: string }
type ResponseConnection = Pick<CodexAppServerConnection, 'respond' | 'respondWithError'>
/** Every app-server request either becomes a durable prompt or receives a safe reply. */
export function disposeCodexServerRequest(
registry: CodexPromptRegistry,
connection: ResponseConnection,
request: CodexAppServerServerRequest
): CodexServerRequestDisposition {
const prompt = registry.register(request)
if (prompt) {
return { kind: 'prompt', prompt }
}
switch (request.method) {
case CODEX_COMMAND_APPROVAL_METHOD:
case CODEX_FILE_CHANGE_APPROVAL_METHOD:
connection.respond(request.id, { decision: 'cancel' })
break
case CODEX_USER_INPUT_METHOD:
connection.respond(request.id, { answers: {} })
break
case CODEX_MCP_ELICITATION_METHOD:
connection.respond(request.id, { action: 'decline', content: null, _meta: null })
break
case CODEX_PERMISSIONS_APPROVAL_METHOD:
connection.respond(request.id, { permissions: {}, scope: 'turn', strictAutoReview: true })
break
case CODEX_DYNAMIC_TOOL_CALL_METHOD:
connection.respond(request.id, { contentItems: [], success: false })
break
case CODEX_LEGACY_APPLY_PATCH_APPROVAL_METHOD:
case CODEX_LEGACY_EXEC_APPROVAL_METHOD:
connection.respond(request.id, { decision: 'abort' })
break
case CODEX_AUTH_TOKEN_REFRESH_METHOD:
connection.respondWithError(request.id, -32001, 'Orca cannot refresh app-server auth tokens')
break
case CODEX_ATTESTATION_METHOD:
connection.respondWithError(request.id, -32001, 'Orca did not negotiate attestation')
break
default:
connection.respondWithError(
request.id,
-32000,
`Orca rejected unrecognized blocking request ${request.method}`
)
}
return { kind: 'responded', method: request.method }
}