import type { ForwardedSessionApproval } from "#src/authority/permission-forwarding"; /** * Value object for a session-scoped approval: one surface, one-or-more patterns. * * Owned by gate descriptors and passed to the session store — the runner never * needs to know whether there is one pattern or many. */ export class SessionApproval { private constructor( readonly surface: string, readonly patterns: readonly string[], ) {} /** Create an approval for a single pattern (the common case). */ static single(surface: string, pattern: string): SessionApproval { return new SessionApproval(surface, [pattern]); } /** * Create an approval for multiple patterns (e.g. bash external-directory * gates that cover several uncovered paths in one prompt). */ static multiple( surface: string, patterns: readonly string[], ): SessionApproval { return new SessionApproval(surface, [...patterns]); } /** Representative pattern for the interactive prompt — the first, if any. */ get representativePattern(): string | undefined { return this.patterns[0]; } /** * Single-pattern shape `applyPermissionGate` echoes back to the caller. * Returns `undefined` when patterns is empty (degenerate case). */ toGateApproval(): { surface: string; pattern: string } | undefined { const pattern = this.representativePattern; if (pattern === undefined) return undefined; return { surface: this.surface, pattern }; } /** * Plain data shape for relaying this approval on a forwarded request, so the * serving node can record the same pattern(s) as a whole-session grant. * Returns a defensive copy of the patterns. */ toForwardedData(): ForwardedSessionApproval { return { surface: this.surface, patterns: [...this.patterns] }; } }