/** * approval-updates.ts, watching approval records over the push channel instead * of asking again every few seconds. * * ── What this replaces ───────────────────────────────────────────────────── * * Two consumers polled `approvals.list`: the client raise seam (approval-raiser * .ts, every 750ms while a prompt was open) and every surface's approvals panel * (a 15s refresh). The 15s one is the worse of the two, an ask raised on a * phone took up to fifteen seconds to appear on the terminal that could answer * it, and a decision made elsewhere left a stale prompt on screen for the same * window. * * `control.approval_update` already carries every transition of every record, * raised, claimed, approved, denied, cancelled, expired, the moment the broker * records it, with the whole record in the payload so nothing needs a follow-up * read. This is the subscription over it. * * ── Why it degrades rather than insists ──────────────────────────────────── * * A stream can be refused (no daemon, a 401, a proxy that will not hold a * connection). A permission ask blocks a tool call, so a consumer that cannot * open a stream must still work, {@link watchApprovalUpdates} reports failure * to the caller instead of throwing, and the caller keeps whatever fallback it * had. Push is the fast path, not a new dependency. * * ── Ownership is unchanged ───────────────────────────────────────────────── * * The record on the wire is the daemon's. A subscriber renders what the record * says, not what it locally believes it asked for, the same parity contract * the decide verbs have always documented. */ /** The wire event name the broker publishes approval transitions on. */ export declare const APPROVAL_UPDATE_WIRE_EVENT = "approval-update"; /** The event domain a subscriber must include when it narrows with `?domains=`. */ export declare const APPROVAL_UPDATE_DOMAIN = "permissions"; /** * An approval record as a subscriber needs to read it. Deliberately narrow: * the id to match, the status to act on, and the decision when there is one. * The full record is on the event for rendering. */ export interface ApprovalUpdateRecord { readonly id: string; readonly status?: string | undefined; readonly decision?: { readonly approved?: boolean | undefined; readonly remember?: boolean | undefined; readonly note?: string | undefined; } | undefined; readonly [key: string]: unknown; } /** One `control.approval_update` frame. */ export interface ApprovalUpdateNotice { readonly approval: ApprovalUpdateRecord; readonly createdAt: number; } export interface WatchApprovalUpdatesOptions { /** The daemon's base URL, e.g. `http://127.0.0.1:3421`. */ readonly baseUrl: string; /** Bearer token for the control plane. Resolved per connection attempt. */ readonly getAuthToken?: (() => string | null | Promise) | undefined; /** Called for every approval transition the daemon publishes. */ readonly onUpdate: (notice: ApprovalUpdateNotice) => void; /** Called when the stream drops for good. The caller decides what to do about it. */ readonly onTerminate?: ((error: unknown) => void) | undefined; /** Injectable fetch (tests, or a relay-tunnelled fetch). */ readonly fetchImpl?: typeof fetch | undefined; readonly signal?: AbortSignal | undefined; } /** A live subscription. `close()` is idempotent. */ export interface ApprovalUpdateSubscription { close(): void; } /** Whether a frame is an approval notice we can act on. */ export declare function readApprovalUpdateNotice(payload: unknown): ApprovalUpdateNotice | null; /** * The control-plane events URL narrowed to the permissions domain. * * Narrowing matters: an unnarrowed subscriber receives every domain the daemon * publishes, which for a client that only wants approvals is a lot of traffic * it will discard. */ export declare function approvalUpdateStreamUrl(baseUrl: string): string; /** * Open a subscription to approval transitions. * * Resolves to null when the stream could not be opened, the caller keeps * whatever it was doing before, and the reason is logged once rather than * thrown into a keystroke path. */ export declare function watchApprovalUpdates(options: WatchApprovalUpdatesOptions): Promise; /** * A one-shot wait for a specific approval id to be decided, over the push * channel. * * Returns the decided record, or null when `stop()` says the caller no longer * cares (its own prompt was answered) or the stream ended without a decision. * The seam every raise path wants: raise, then watch the id you were handed. */ export declare function awaitApprovalDecision(input: { readonly subscribe: (onUpdate: (notice: ApprovalUpdateNotice) => void) => Promise; readonly approvalId: string; readonly isDecided: (record: ApprovalUpdateRecord) => boolean; readonly stop: () => boolean; }): Promise; //# sourceMappingURL=approval-updates.d.ts.map