/** * Gateway protocol adapter for `codex app-server --stdio`. Owns the product * methods only: framing and correlation live in the shared line transport. * * Unlike the one-shot wire (`src/wire.ts`), this adapter keeps a persistent * thread, enables the experimental API surface (queue/steer), and streams * every server notification to the gateway layer for replay and forwarding. * * @module dsh-subagent-codex-plus/gateway/wire */ import type { Readable, Writable } from 'node:stream'; type JsonObject = Record; /** Text input accepted by every Codex turn/queue verb. */ export interface GatewayTextInput { readonly type: 'text'; readonly text: string; readonly text_elements: readonly unknown[]; } /** Local-path image input (verified against the real app-server). */ export interface GatewayLocalImageInput { readonly type: 'localImage'; readonly path: string; } /** Remote-URL image input. */ export interface GatewayImageInput { readonly type: 'image'; readonly url: string; } export type GatewayUserInput = GatewayTextInput | GatewayLocalImageInput | GatewayImageInput; /** One queued submission projected from `thread/queue/list`. */ export interface QueuedSubmissionView { readonly id: string; readonly input: readonly GatewayUserInput[]; readonly clientUserMessageId: string; } /** A server-initiated notification observed on the wire. */ export interface CodexGatewayNotification { readonly method: string; readonly params: JsonObject; } /** * One long-lived app-server connection. Request methods return narrow, * validated projections; every notification is captured for replay and * forwarded through {@link onNotification}. */ export declare class CodexGatewayWire { private readonly clientName; private readonly clientVersion; private readonly transport; private readonly captured; private notificationHandler; constructor(input: Readable, output: Writable, clientName?: string, clientVersion?: string); /** Begin reading app-server frames. */ start(): void; /** Subscribe to forwarded notifications; only one listener at a time. */ onNotification(handler: (notification: CodexGatewayNotification) => void): void; /** Replay every notification observed so far, oldest first. */ replayNotifications(): readonly CodexGatewayNotification[]; /** Drop the replay buffer. */ clearReplay(): void; /** * Complete the initialize/initialized handshake with the experimental API * enabled (required for `thread/queue/*` and `turn/steer`). */ initialize(signal?: AbortSignal): Promise; /** Create a new thread; `ephemeral: false` keeps it durable on disk. */ startThread(cwd: string, options?: { ephemeral?: boolean; model?: string; approvalPolicy?: string; }, signal?: AbortSignal): Promise; /** Reconnect to a durable thread by id (restart recovery). */ resumeThread(threadId: string, signal?: AbortSignal): Promise; /** Start one turn immediately; returns the new turn id. */ startTurn(threadId: string, input: readonly GatewayUserInput[], options?: { clientUserMessageId?: string; model?: string; }, signal?: AbortSignal): Promise; /** Enqueue one submission behind the active turn; returns its queue id. */ queueAdd(threadId: string, input: readonly GatewayUserInput[], clientUserMessageId: string, signal?: AbortSignal): Promise; /** List pending queued submissions, oldest first. */ queueList(threadId: string, signal?: AbortSignal): Promise; /** Replace the input of one queued submission. */ queueUpdate(threadId: string, queuedSubmissionId: string, input: readonly GatewayUserInput[], signal?: AbortSignal): Promise; /** Remove one queued submission. */ queueDelete(threadId: string, queuedSubmissionId: string, signal?: AbortSignal): Promise; /** Reorder queued submissions; the array order is the new FIFO order. */ queueReorder(threadId: string, queuedSubmissionIds: readonly string[], signal?: AbortSignal): Promise; /** Manually start the next queued submission; returns the new turn id. */ queueStart(threadId: string, queuedSubmissionId?: string, signal?: AbortSignal): Promise; /** * Redirect the active turn to new input. Returns the new turn id when the * server reports one; steer is side-effectful, so `undefined` still means * the redirect was accepted. */ steer(threadId: string, expectedTurnId: string, input: readonly GatewayUserInput[], signal?: AbortSignal): Promise; /** Best-effort cancellation of the active turn. */ interrupt(threadId: string, turnId: string): void; /** Detach listeners and reject outstanding requests. Idempotent. */ close(): void; } export {};