/** * ClaudeBackend — adapter implementing AgentBackend over the existing * agent/src/claude.ts subprocess driver and agent/src/history.ts JSONL reader. * * Design (locked decisions, see docs/2026-05-09-pr3-claude-backend.md): * - claude.ts is unchanged; this class wraps it. * - For Claude, `backendThreadId === backendSessionId` (single-thread sessions). * - Emits NormalizedEvents only via on(listener). In PR3 the runtime * facade does NOT yet subscribe to these events or translate them back * to legacy wire frames — connection.ts still uses the re-exported * claude.ts surface directly. PR4 wires the runtime to call * getBackend().on(...) and routes outbound traffic through the * translation pipeline; the NormalizedEvents emitted here are currently * consumed only by the contract tests. * - listSessions / readSession / deleteSession / renameSession delegate * to history.ts directly. * * The class subscribes to claude.ts's outbound traffic via the multi-listener * `addSendFn` / `addOnSessionStarted` hooks (returning unsubscribe handles * stored on the instance). Because these hooks support fanout, multiple * ClaudeBackend instances can coexist with the legacy connection.ts * subscribers without clobbering each other; shutdown() detaches cleanly. */ import { type AgentBackend, type ApprovalAnswer, type BackendCapabilities, type BackendHistoryMessage, type BackendSessionInfo, type BackendSessionRef, type EnsureSessionOpts, type EventListener, type StartOpts, type UserInputAnswer, type UserTurnInput } from './types.js'; export declare class ClaudeBackend implements AgentBackend { readonly type: "claude"; readonly capabilities: BackendCapabilities; private readonly listeners; /** Map from conversationId → most-recent backendSessionId we've observed. * Lets us tag events that don't carry a session id (e.g. turn_completed). */ private readonly convToSession; /** Map from placeholder ref id (e.g. 'pending:c1') → conversationId. Used * to resolve startTurn() before session_started has populated convToSession. */ private readonly pendingRefToConv; /** Map from conversationId → workDir provided to ensureSession(). Used as a * fallback in startTurn() when claude.ts has no live ConversationState yet * (e.g. first turn before session_started). */ private readonly convToWorkDir; /** Unsubscribe handles for the multi-subscriber claude.ts hooks. */ private readonly unsubSend; private readonly unsubSessionStarted; readonly compact?: undefined; readonly fork?: undefined; readonly listModels?: undefined; readonly renameSession: (workDir: string, session: BackendSessionRef, title: string) => Promise; readonly deleteSession: (workDir: string, session: BackendSessionRef) => Promise; constructor(_opts?: StartOpts); on(listener: EventListener): () => void; private emit; start(_opts: StartOpts): Promise; shutdown(): Promise; ensureSession(opts: EnsureSessionOpts): Promise; startTurn(session: BackendSessionRef, input: UserTurnInput): Promise; interruptTurn(session: BackendSessionRef): Promise; answerUserInput(answer: UserInputAnswer): void; answerApproval(answer: ApprovalAnswer): void; listSessions(workDir: string): Promise; readSession(workDir: string, session: BackendSessionRef): Promise; /** Reverse-lookup: find the conversationId we associated with a session ref. */ private findConvId; /** * Translate a legacy outbound wire frame (as produced by claude.ts via the * SendFn closure) into a NormalizedEvent and fan out to listeners. * * In PR3 the runtime facade does NOT yet perform the reverse translation * back to legacy frames — connection.ts still uses the re-exported claude.ts * surface directly (see runtime.ts header comment). The NormalizedEvents * emitted here are currently consumed only by the contract tests; the raw * frame fanout below preserves wire fidelity for when PR4 wires the runtime * to translate. The `runtime.test.ts` suite verifies only that runtime.ts * re-exports the expected surface, not round-trip correctness. * * For frames that don't have a NormalizedEvent equivalent (or that the * runtime should pass through unchanged), we emit a `process_output`-shaped * event carrying the raw frame so the runtime can forward it verbatim. */ private onClaudeSend; /** * Special-purpose event used internally to ferry untranslated/raw frames * through to the runtime facade without losing fidelity. Encoded as a * `process_output` NormalizedEvent for now; PR4+ may add a dedicated kind. */ private emitRawFrame; }