* Persist a decision. Scopes: * - 'once' — just for this call (no-op here; caller acts) * - 'session' — until QodeX restart, for THIS exact tool:operation pair * - 'pattern' — until QodeX restart, for anything matching the command prefix * - 'tool' — until Q
(req: PermissionRequest, decision: 'allow' | 'deny', scope: 'once' | 'session' | 'pattern' | 'tool')
| 92 | /** |
| 93 | * Returns a non-asking decision based purely on policy. |
| 94 | * Returns 'ask' when policy is undecided. |
| 95 | */ |
| 96 | evaluate(req: PermissionRequest): PermissionDecision { |
| 97 | const r = this.decide(req); |
| 98 | try { this.onDecision?.(req, r.decision, r.via); } catch { /* audit must not stall */ } |
| 99 | return r.decision; |
| 100 | } |
| 101 | |
| 102 | /** Same as evaluate, plus the reason — for tests and the audit trail. */ |
| 103 | evaluateDetailed(req: PermissionRequest): { decision: PermissionDecision; via: PermissionVia } { |
| 104 | const r = this.decide(req); |
| 105 | try { this.onDecision?.(req, r.decision, r.via); } catch { /* */ } |
| 106 | return r; |
| 107 | } |
| 108 | |
| 109 | private decide(req: PermissionRequest): { decision: PermissionDecision; via: PermissionVia } { |