/** * Local HTTP listener that resolves OOB-confirm clicks. One per sigil-mcp * process, bound to 127.0.0.1 on a random port assigned by the kernel. * * Wire shape (intentionally trivial — every transport hands the human these * two URLs, and tapping either resolves the gate): * * POST /approve?t= → 200 if token matches a pending request * POST /deny?t= → 200 if token matches a pending request * GET variants are accepted too, so a stock email/SMS link that's * followed by a phone browser also works (some clients refuse to POST * from a tap). * * Token semantics: * - 32-byte cryptographically random, base64url-encoded, kept in process * memory only. * - Bound to one pending request — a token issued for sign-request A * cannot approve sign-request B. * - Single-use: cleared the moment we resolve. A replayed approval click * after timeout gets a 410 Gone, not a silent re-approve. * * No TLS: the listener is on 127.0.0.1. A local attacker who can already * make HTTP requests from this machine could also read the process's * memory, so TLS here would be theatre. */ /** Outcome the ack server hands back to the gate. */ export type AckOutcome = 'approve' | 'deny'; export interface AckServer { /** Hostname-and-port base, e.g. "http://127.0.0.1:42424". No trailing slash. */ readonly baseUrl: string; /** * Mint a single-use token bound to a pending request, and return the * approve/deny URLs the human will click. The returned Promise resolves * when the human clicks (or the caller calls `cancel(token)` — e.g. on * timeout). */ pending(): { token: string; approveUrl: string; denyUrl: string; settled: Promise; }; /** Drop a pending token without resolving (e.g. the gate timed out). * Subsequent clicks for that token get 410 Gone. */ cancel(token: string): void; close(): Promise; } /** * Start a local ack server on 127.0.0.1 and resolve when it's listening. * The chosen port is observable via `baseUrl`. */ export declare function startAckServer(): Promise; //# sourceMappingURL=ack-server.d.ts.map