/** * `turn/start` submission and same-`commandId` replay (spec 14990 FR-018 / * T030 obligations (a) and (d); tdd SS3.1.1, SS3.2, SS4.13). * * Split out of `session.ts` for the same reason `approval.ts` was: this is a * wire-shaping and idempotency concern, not a fold concern, and `Session` was * already the package's largest module. * * It holds the ONE piece of state `PendingCommandSet` deliberately cannot: the * `turn/start` params per `commandId`. The set stores the COMPOSER input and is * wire-blind by design (INV-001), so a replay — which must re-send the SAME * logical command, byte for byte, to be the sanctioned retry rather than a * double execution — needs the params to live on this side of that boundary. */ import type { Connection } from "../connection/connection.js"; import type { PendingCommandSet } from "../pending/pending-command-set.js"; import type { CommandErrorResponse, PendingCommandAck, PendingRetirement, ReplayAnswer } from "../pending/pending-command-set.js"; import type { TurnStartParams } from "../msp.js"; /** * What `Session.sendUserTurn` sends, COMPOSED from the generated params rather * than restated (INV-001). * * `commandId` is excluded because `Connection` is the single minter (INV-013); * `sessionId` because the session already knows its own and a caller-supplied * one could only disagree with it. */ export type SendUserTurnOptions = Readonly> & { /** * What to hand back to the composer if this submit is ever retired — SS4.13 * restores the INPUT, not the wire parts. Optional: a consumer that renders * nothing optimistically has nothing to restore. */ readonly composerInput?: I; }; /** * An `MspError` as the pending set reads it (SS4.13's settlement test). * * `undefined` for anything that is NOT a server-authored MSP error — a * `ProtocolError`, a dead transport — because those admit nothing AND prove * nothing about the intake, so the entry must HOLD rather than be judged. */ export declare function commandErrorResponse(error: unknown): CommandErrorResponse | undefined; export declare class TurnSubmitter { #private; constructor(sessionId: string, connection: Connection | undefined, pending: PendingCommandSet); get wired(): boolean; requireConnection(verb: string): Connection; /** * Record the optimistic SS4.13 entry, then send `turn/start`. * * The ORDER is the point. An entry created only on the ack is invisible for * exactly the window it exists to cover — between the user pressing enter and * the host answering — and `anchorAfterItemId` is fixed here, at submission * time, because SS4.13's insertion point may never be relocated by events * that fold in afterwards. */ submit(options: SendUserTurnOptions, anchorAfterItemId: string | null): Promise; /** * Re-send one remembered `turn/start` under its ORIGINAL `commandId` * (SS3.1.1 — always safe, and the only re-send that is not a double * execution). * * `undefined` means "no answer this set can act on": either this session * never authored the command (a caller-seeded entry), or the failure was a * transport/protocol one, which proves nothing about the intake. */ replay(commandId: string): Promise; /** Replay one entry and feed the answer back through the live SS4.13 rules. */ driveReplay(commandId: string, into: PendingRetirement[]): Promise; /** Drop the replay memory for retired entries so it tracks the pending set. */ forgetRetired(retirements: readonly PendingRetirement[]): void; }