import type { BidirectionalPublisher, ClaudeCodeEvent, ClaudeCodeEventExtended, ClientCommandHandler, ClientCommandObserver } from "./types.js"; import { type WebSocketUpgradeResult } from "../../platform/compat/http/index.js"; /** * WebSocket publisher configuration */ export interface WebSocketPublisherConfig { /** WebSocket instance */ socket: WebSocket; /** Run ID for this connection */ runId: string; /** Enable debug logging */ debug?: boolean; /** Ping interval (ms) - 0 to disable */ pingInterval?: number; /** Maximum time for the authoritative command handler to settle. */ commandHandlerTimeout?: number; } /** Run-scoped controller policy. */ export interface AgentControllerConfig { /** Maximum time to wait for an approval decision. */ approvalTimeout?: number; /** Maximum time to wait for requested input. */ inputTimeout?: number; /** Invoked after an admitted cancellation command. */ onCancel?: (reason?: string) => void; } /** Run-scoped command surface without transport lifecycle authority. */ export interface AgentControllerHandle { /** Immutable workflow run identity. */ readonly runId: string; /** Whether an admitted cancellation command ended the run. */ readonly isCancelled: boolean; /** Request an exactly correlated tool approval. */ requestApproval(toolCallId: string, toolName: string, input: Record, reason: string): Promise; /** Request user input for this run. */ requestInput(prompt: string, defaultValue?: string): Promise; } /** Opaque ownership token for one run controller generation. */ export interface AgentControllerRunRegistration { /** Immutable workflow run identity. */ readonly runId: string; /** Unique identity for this controller generation. */ readonly generation: symbol; /** Controller retained for the lifetime of this run generation. */ readonly controller: AgentControllerHandle; } /** Opaque ownership token for one run publisher generation. */ export interface AgentControllerRegistration { /** Stable controller ownership token shared by reconnecting publishers. */ readonly run: AgentControllerRunRegistration; /** Immutable workflow run identity. */ readonly runId: string; /** Unique identity for this publisher generation. */ readonly generation: symbol; /** Publisher owned by this exact registration. */ readonly publisher: BidirectionalPublisher; /** Run controller shared by reconnecting publishers. */ readonly controller: AgentControllerHandle; } /** * WebSocket-based bidirectional publisher * * Enables two-way communication: * - Server → Client: Events (text, tool calls, results) * - Client → Server: Commands (cancel, approve, reject, input) */ export declare class WebSocketPublisher implements BidirectionalPublisher { #private; private readonly config; private commandHandler; private commandObservers; private commandLedger; private commandHandlerTimers; private closed; private pingTimer; constructor(config: WebSocketPublisherConfig); get runId(): string; private setupSocketListeners; private handleCommand; private dispatchLegacyCommand; private notifyCommandObservers; private dispatchKeyedCommand; private reserveCommand; private finishKeyedCommand; private createCommandAck; private sendCommandAck; private trySend; private reportHandlerError; private sendPong; private startPingInterval; private stopPingInterval; private stopCommandHandlerTimers; /** * Subscribe to client commands */ onCommand(handler: ClientCommandHandler): () => void; /** Subscribe to admitted commands without participating in acknowledgement. */ observeCommands(observer: ClientCommandObserver): () => void; /** * Send an event to the client */ send(event: ClaudeCodeEventExtended): void; /** * Publish an event (implements ClaudeCodeEventPublisher) */ publish(event: ClaudeCodeEvent): void; /** * Close the publisher */ close(): void; /** * Send a cancellation event */ sendCancelled(reason?: string): void; /** * Check if the connection is open */ get isOpen(): boolean; } /** * Configuration for a registry-owned WebSocket upgrade handler. */ export interface WebSocketHandlerConfig { /** Get run ID from request */ getRunId: (req: Request) => string | null; /** * Run-keyed controller ownership. * * A socket close releases its run by default. When `retainRunOnClose` is * enabled, the caller must invoke `releaseRun()` with the exact run * registration when the run itself ends. */ registry: AgentControllerRegistry; /** Called when a current connection generation is established. */ onConnection: (registration: AgentControllerRegistration) => void | Promise; /** Called only when the exact current connection generation closes. */ onClose?: (registration: AgentControllerRegistration) => void | Promise; /** WebSocket upgrade implementation. Defaults to the portable runtime adapter. */ upgradeWebSocket?: (request: Request) => WebSocketUpgradeResult; /** * Retain run-scoped state after its socket closes. * * Use this only when the application terminally calls `releaseRun()` for * every admitted run. Defaults to false so arbitrary run IDs cannot leave * persistent registry entries. */ retainRunOnClose?: boolean; /** Enable debug logging */ debug?: boolean; } /** Create a WebSocket handler for HTTP upgrade requests. */ export declare function createWebSocketHandler(config: WebSocketHandlerConfig): (req: Request) => Response; /** * Backwards-compatible single-connection controller. * * Prefer {@link AgentControllerRegistry} when a run may outlive one publisher * connection. Registry registrations deliberately expose no disposal method. */ export declare class AgentController implements AgentControllerHandle { #private; constructor(publisher: BidirectionalPublisher, config?: AgentControllerConfig); get runId(): string; get isCancelled(): boolean; requestApproval(toolCallId: string, toolName: string, input: Record, reason: string): Promise; requestInput(prompt: string, defaultValue?: string): Promise; /** Release the direct controller's subscription and pending work. */ dispose(): void; } /** * Retains one controller generation per run independently of transient * publisher connections. Replacements synchronously retire the old publisher; * only an exact publisher token can detach, and only an exact run token can * terminally release the controller. */ export declare class AgentControllerRegistry { private readonly runs; private readonly registeredPublishers; private readonly controllerConfig; private closed; constructor(controllerConfig?: AgentControllerConfig); /** Attach a new authoritative publisher generation to its run controller. */ register(publisher: BidirectionalPublisher): AgentControllerRegistration; /** Return the stable controller ownership token for a live run. */ get(runId: string): AgentControllerRunRegistration | undefined; /** Return the currently attached publisher generation, if one exists. */ getPublisher(runId: string): AgentControllerRegistration | undefined; /** * Detach one exact publisher generation while retaining run-scoped state. * Stale registrations cannot detach a replacement. */ detach(registration: AgentControllerRegistration): boolean; /** * Terminally release one exact run controller generation. * Stale run registrations cannot release a replacement run with the same ID. */ releaseRun(registration: AgentControllerRunRegistration): boolean; /** Terminally release every run and reject future registrations. */ close(): void; } //# sourceMappingURL=websocket-publisher.d.ts.map