import { type LocalTurnAccumulator } from "./usage.js"; /** * A built-in tool Claude Code wants to run that `permissionMode` does not * auto-approve (anything that writes or shells out under `allow-reads`). */ export type LocalToolApproval = { approvalId: string; toolCallId: string; toolName: string; /** Compact one-line rendering of the tool input, for the prompt. */ summary: string; input: unknown; }; /** A tool starting or finishing, so the caller can show what is happening. */ export type LocalToolActivity = { kind: "start"; toolCallId: string; toolName: string; summary: string; } | { kind: "end"; toolCallId: string; toolName: string; isError: boolean; } /** * Announced, then never run — a tool whose input stopped mid-stream, one * that was refused, or a sibling whose approval request the harness lost. * None of them report a result, so `end` never comes: a caller tracking * what is live has to be told, or it shows that tool for the rest of the * turn. `retractAbandonedCalls` decides which calls qualify and when. */ | { kind: "dropped"; toolCallId: string; toolName: string; }; export type LocalStreamHandlers = { onTextDelta?: (delta: string) => void; /** * Decide whether the tool may run. Omitted (`--print`, non-interactive) * means deny — the turn continues and the model reports what it could not * do rather than silently running commands on the user's machine. */ onApproval?: (approval: LocalToolApproval) => Promise; /** * Present `AskUserQuestion` in this session's own picker. Used by the host * tool that replaces Claude Code's native picker, and by the approval path * if a call is still offered. Omitted (`--print`) means the model is told * to ask in its reply instead. */ onUserQuestion?: (input: unknown) => Promise | undefined>; onActivity?: (activity: LocalToolActivity) => void; /** Path of a file the turn wrote or edited, as the tool named it. */ onFileTouched?: (path: string) => void; /** Something worth saying that is not part of the reply. */ onNotice?: (message: string) => void; }; export type LocalStreamOptions = LocalStreamHandlers & { /** Aborts the turn; the harness interrupts Claude Code gracefully. */ abortSignal?: AbortSignal; /** * Fired when the stall watchdog gives up, before the turn is rejected. * Should abort `abortSignal` so Claude Code stops rather than being torn * down out from under a still-open bridge. */ onStall?: () => void; }; export type StreamLike = { fullStream: AsyncIterable; text: PromiseLike; }; export type ApprovalContinuation = { approvalResponse: { type: "tool-approval-response"; approvalId: string; approved: boolean; reason?: string; }; toolCall: { type: "tool-call"; toolCallId: string; toolName: string; input: unknown; }; }; /** The two harness calls a turn needs. Split out so tests can fake them. */ export type TurnDriver = { start: () => Promise; continueWithApprovals: (continuations: readonly ApprovalContinuation[]) => Promise; }; /** * Run one turn to completion, answering approval requests along the way. * * A turn suspends whenever Claude Code wants a tool `permissionMode` does not * cover: the stream ends with the approvals still pending, and the turn only * finishes once decisions are fed back in. Exported for tests. */ export declare function runPromptTurn(input: { driver: TurnDriver; handlers: LocalStreamHandlers | undefined; accumulator?: LocalTurnAccumulator; /** * Filled with approvals the harness asked about and drained as each is * answered, so a turn that ends mid-question leaves the unanswered ones * behind for the caller to deny. */ unanswered?: LocalToolApproval[]; /** Overridden by tests; `Infinity` waits forever. */ stallTimeoutMs?: number; /** The same, for the stream while a tool is executing. */ toolStallTimeoutMs?: number; /** * Called when the stall watchdog fires, before the turn is rejected — abort * the harness stream so Claude Code does not keep running after we give up. */ onStall?: () => void; }): Promise; /** * The previous turn could not be wound down, so this session cannot take * another prompt. Raised rather than pressed on with: the harness would either * refuse the prompt itself or run it alongside the turn we failed to finish. * * The caller's recovery is to replace the session — nothing about a wedged * runtime gets better by asking it again. */ export declare class HarnessTurnStuck extends Error { constructor(); } /** * The turn produced nothing for `TURN_STALL_TIMEOUT_MS` while no tool was in * flight. Common causes: a step that asked to run several confirmable tools at * once (the harness only surfaces one approval), or the Claude Code bridge * going silent. Recoverable — replace the session and ask again. */ export declare class HarnessTurnStalled extends Error { constructor(timeoutMs: number, whileToolRunning?: boolean); } /** * The Claude Code bridge dropped mid-turn. Same recovery as a stall: the * process behind the session is gone, so the next question needs a new one. */ export declare function isBridgeClosedError(error: unknown): boolean; /** * Wait for `work`, but give up after `timeoutMs` rather than blocking a * teardown forever. Resolves either way; the caller has already decided that * an unfinished result is better than waiting. * * Exported for tests. */ export declare function settleWithin(work: Promise, timeoutMs: number): Promise; //# sourceMappingURL=turn.d.ts.map