import type { Socket } from 'node:net'; import type { Decision } from './types.js'; export interface PendingApproval { runId: string; reqId: string; toolName: string; threadId: string; /** `platform:channelId:threadId` — used as the Map key for pendingByThread * and autoAllowByThread so different platforms/channels don't collide. */ compositeKey: string; /** Cached at registration so cancelPending can fire ResolutionListener with * a valid platform even when the underlying runContext has already been * cleared (e.g. unregisterRun deletes the context BEFORE cancelling). */ platform: string; /** Only this user may resolve an explicit-decision request. */ approverUserId: string; /** Truncated input fingerprint used for auto-allow lookups + revocation. */ fingerprint: string; /** Original tool input — kept verbatim so dashboard / `listPending` can * surface a useful preview to operators. Never sent over the wire by * the bus itself; sidecar already has the original. */ input: Record; /** Wall-clock ms when the pending was registered. Used by listPending * to compute age; zero in pre-existing rehydrated state (impossible * in practice — bus is process-local). */ registeredAt: number; /** Set when the pending was created from a unix-socket sidecar (Claude * path). cancelPending writes the decision back over this socket. Either * `socket` or `dispatch` must be set, never both. */ socket?: Socket; /** Set when the pending was created via {@link ApprovalBus.registerSyntheticPending} * (opencode HTTP path, P2). cancelPending invokes this callback instead * of writing to a socket — the caller is responsible for delivering the * decision to its own backend (e.g. POST /permission/:id/reply). Errors * thrown from dispatch are logged, never propagated. */ dispatch?: (decision: Decision) => void; timer: ReturnType; resolved: boolean; /** When true, this pending was created in auto-allow mode: timer expiry * resolves to allow rather than deny, and an explicit deny revokes the * matching auto-allow rule. */ autoAllow: boolean; /** True for approval-only state transitions that must be decided by a * human for this exact request. */ requiresExplicitDecision: boolean; /** See {@link ApprovalNotification.allowSessionPin}. */ allowSessionPin: boolean; } /** Remove a resolved pending from both index maps. */ export declare function removePending(p: PendingApproval, pendingById: Map, pendingByThread: Map): void; /** Register a new auto-allow rule for the given composite key. */ export declare function addAutoAllowRule(autoAllowByThread: Map>, compositeKey: string, toolName: string, fingerprint: string): void; /** Remove an auto-allow rule; deletes the thread entry when the set empties. */ export declare function removeAutoAllowRule(autoAllowByThread: Map>, compositeKey: string, toolName: string, fingerprint: string): void; /** * v1.3.7 (F8) — deny + drop the oldest unresolved pending approval so the * maps stay under `cap`. Insertion order of a Map is iteration order, and * pendingById is inserted in registration order, so the first unresolved * entry is the oldest. * * `onEvict` is called once with the pending that should be cancelled. The * caller (ApprovalBus.cancelPending) owns the actual resolution side-effects. */ export declare function evictOldestPending(pendingById: Map, cap: number, onEvict: (p: PendingApproval) => void): void; //# sourceMappingURL=pending.d.ts.map