import { type AttachMessage, type ClientKind, type FinishedMessage, type Hello, type NoticeMessage, type PartiesMessage, type PartyKind, type RequestMessage, type StatusMessage } from "./protocol.js"; /** A number the adapter gives each connection. */ export type PartyId = number; /** The CLI's hold on the session: the visit connected now, if any, and * when the last one closed. */ export type CliHold = { visit: PartyId | null; lastVisit: number | null; }; /** An answer the session accepted, kept so a late reply to the same * request can be told what happened. */ export type Answered = { id: number; by: PartyKind; command: string; }; export type SessionState = { /** The run's `hello`, sent to every party as it joins. */ hello: Hello | null; /** When the first party joined, for the refusal a later one gets. */ attachedSince: number | null; terminal: PartyId | null; cli: CliHold | null; /** The driver's requests no party has answered, oldest first. The * driver has more than one in flight at a time: its callbacks redraw * without waiting, so two renders can be out before the first is * acknowledged. */ pending: RequestMessage[]; /** For each pending `render`, by id, the parties still to acknowledge * it. */ awaiting: Record; /** The parties sent the last render on joining and not yet done * drawing it; the requests waiting go to each once it has. */ drawing: PartyId[]; /** The last `render`, so a joining party sees the stop. A render the * driver sends without a checkpoint means "the same stop, redrawn", * so the checkpoint of the render before is carried into it. */ lastRender: RequestMessage | null; /** The notices whose latest value is the whole truth (`setMode`, * `setOverrides`, `setBusy`), by method, replayed to a joiner. */ settings: Record; /** Whether the driver's spinner is on: the program is running under * the debugger, and a joining terminal starts its own. */ spinning: boolean; /** The last activity lines, so a visit sees what happened since. */ recent: string[]; /** The last answers, newest last. */ answered: Answered[]; /** The program's end, kept for a visit that comes after it. */ finished: FinishedMessage | null; }; export declare function emptySession(): SessionState; export type SessionEvent = { type: "connect"; party: PartyId; kind: ClientKind; now: number; } | { type: "disconnect"; party: PartyId; now: number; } | { type: "fromDriver"; message: AttachMessage; } | { type: "fromParty"; party: PartyId; message: AttachMessage; } | { type: "leaseExpired"; }; export type Effect = { type: "send"; to: PartyId; message: AttachMessage; } | { type: "close"; party: PartyId; } | { type: "toDriver"; message: AttachMessage; } | { type: "startLease"; } | { type: "clearLease"; } | { type: "log"; line: string; } /** The program has ended with no party to tell: nothing waits on a * debugger now, so the session must stop keeping the process alive * while it holds the news for the next visit. */ | { type: "release"; } | { type: "end"; }; export type Stepped = { state: SessionState; effects: Effect[]; }; /** How long the CLI's hold outlives its last visit. A program must never * wait on a debugger that is not there, and an agent can crash or * forget. */ export declare const LEASE_MS: number; export declare const RECENT_LINES = 20; export declare const ANSWERED_KEPT = 10; export declare function step(state: SessionState, event: SessionEvent): Stepped; /** What a probe is told, and what the server tells one when no session * is open. */ export declare function statusOf(state: SessionState): StatusMessage; /** Who is on the run, as every party is told when that changes. */ export declare function partiesOf(state: SessionState): PartiesMessage;