/** * Long-lived Codex gateway: one `codex app-server --stdio` child, one durable * thread, and the message verbs the dsh agent layer will forward through. * * The gateway is runtime-agnostic (no dsh imports): it exposes raw * notifications and a running/idle projection so the dsh-facing adapter can * decide how to render and route them. * * @module dsh-subagent-codex-plus/gateway/gateway */ import { EventEmitter } from 'node:events'; import { type ActiveTool } from './tool-tracker.ts'; import { type CodexGatewayNotification, type GatewayUserInput, type QueuedSubmissionView } from './wire.ts'; /** Process/thread lifecycle phase of one gateway. */ export type CodexGatewayPhase = 'stopped' | 'starting' | 'ready' | 'failed'; /** Whether the server currently has an active turn on this thread. */ export type CodexGatewayTurnState = 'idle' | 'running'; export interface CodexGatewayOptions { /** Working directory for the app-server child and the thread. */ readonly cwd: string; /** * App-server argv; defaults to `codex app-server --stdio` resolved through * PATH. The dsh profile supplies the package-local bin instead. */ readonly argv?: readonly string[]; /** Optional per-thread model override (left to Codex settings when absent). */ readonly model?: string; /** Optional approval policy passed to `thread/start`. */ readonly approvalPolicy?: string; /** Extra environment layered over the inherited environment. */ readonly env?: Record; /** Diagnostic sink for child stderr lines. */ readonly onStderr?: (line: string) => void; } export interface SubmitOutcome { readonly kind: 'turn' | 'queued'; readonly id: string; } interface GatewayEvents { notification: [notification: CodexGatewayNotification]; phase: [phase: CodexGatewayPhase]; turn: [state: CodexGatewayTurnState]; error: [error: Error]; } export interface CodexGateway { on(event: K, listener: (...args: GatewayEvents[K]) => void): this; emit(event: K, ...args: GatewayEvents[K]): boolean; } /** One durable Codex thread driven by a dedicated app-server child. */ export declare class CodexGateway extends EventEmitter { private readonly cwd; private readonly argv; private readonly model?; private readonly approvalPolicy?; private readonly env?; private readonly onStderr?; private child; private wire; private phaseValue; private turnStateValue; private threadIdValue; private turnIdValue; private readonly tools; private exitPromise; constructor(options: CodexGatewayOptions); /** Current lifecycle phase. */ get phase(): CodexGatewayPhase; /** Active-turn projection, kept in sync with server notifications. */ get turnState(): CodexGatewayTurnState; /** Durable thread id once started. */ get threadId(): string | undefined; /** Active turn id, present between `turn/started` and `turn/completed`. */ get turnId(): string | undefined; /** Tool call currently executing inside the active turn, if any. */ get currentTool(): ActiveTool | undefined; /** * Start the app-server child and either create a fresh durable thread or * resume an existing one (C3 restart recovery). * @param resumeThreadId - durable thread id to reconnect to; absent creates a new thread. * @returns the thread id. */ start(resumeThreadId?: string): Promise; /** * Submit user input: starts a turn when idle, enqueues behind an active * turn (auto-drain on completion). * @param input - text/image input blocks. * @param clientUserMessageId - stable caller-supplied identity for the submission. */ submit(input: readonly GatewayUserInput[], clientUserMessageId?: string): Promise; /** Redirect the active turn; when idle, starts a new turn instead. */ steer(input: readonly GatewayUserInput[], expectedTurnId?: string): Promise; /** Best-effort cancel of the active turn (keeps the thread/process alive). */ cancel(): void; /** Pending queue contents. */ queue(): Promise; /** Remove one queued submission. */ dequeue(queuedSubmissionId: string): Promise; /** Reorder queued submissions (array order = new FIFO order). */ requeue(queuedSubmissionIds: readonly string[]): Promise; /** Replace the input text of one queued submission. */ updateQueue(queuedSubmissionId: string, text: string): Promise; /** * Close the wire and terminate the child process tree. Idempotent; safe to * call from any phase. */ dispose(): Promise; private handleNotification; private fail; private setPhase; private setTurnState; private requireThread; private wireAsReady; } export {};