@guilz-dev/belay 0.4.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +27 -2
  2. package/dist/adapters/claude/runtime-entry.js +54 -25
  3. package/dist/adapters/layouts/scope.js +3 -2
  4. package/dist/adapters/shared/gate-runtime.d.ts +8 -2
  5. package/dist/adapters/shared/gate-runtime.js +579 -181
  6. package/dist/bundle/claude-runtime.mjs +13574 -6334
  7. package/dist/bundle/codex-runtime.mjs +13108 -5903
  8. package/dist/bundle/cursor-runtime.mjs +12676 -5476
  9. package/dist/cli.js +80 -2
  10. package/dist/commands/approve.js +34 -10
  11. package/dist/commands/classify-for-report.js +1 -1
  12. package/dist/commands/config.d.ts +8 -0
  13. package/dist/commands/config.js +134 -11
  14. package/dist/commands/doctor.js +87 -1
  15. package/dist/commands/explain.js +11 -1
  16. package/dist/commands/judge.js +3 -2
  17. package/dist/commands/recovery-checkpoints.d.ts +164 -0
  18. package/dist/commands/recovery-checkpoints.js +347 -0
  19. package/dist/commands/revoke.js +19 -7
  20. package/dist/commands/session.d.ts +20 -0
  21. package/dist/commands/session.js +51 -0
  22. package/dist/commands/status.js +7 -0
  23. package/dist/config-io.js +91 -23
  24. package/dist/conformance/guarantee-posture.d.ts +21 -0
  25. package/dist/conformance/guarantee-posture.js +46 -0
  26. package/dist/conformance/guarantee-table.d.ts +1 -0
  27. package/dist/conformance/guarantee-table.js +20 -9
  28. package/dist/conformance/types.d.ts +1 -0
  29. package/dist/core/approval-replay.d.ts +1 -1
  30. package/dist/core/approval-replay.js +4 -1
  31. package/dist/core/approval-service.d.ts +6 -1
  32. package/dist/core/approval-service.js +87 -24
  33. package/dist/core/approval.d.ts +4 -0
  34. package/dist/core/approval.js +19 -5
  35. package/dist/core/audit-types.d.ts +13 -0
  36. package/dist/core/capability/approval-state-mutation.d.ts +32 -0
  37. package/dist/core/capability/approval-state-mutation.js +165 -0
  38. package/dist/core/capability/approval-v3.d.ts +32 -0
  39. package/dist/core/capability/approval-v3.js +114 -0
  40. package/dist/core/capability/attestation.d.ts +16 -0
  41. package/dist/core/capability/attestation.js +62 -0
  42. package/dist/core/capability/boundary-attestation-sign.d.ts +21 -0
  43. package/dist/core/capability/boundary-attestation-sign.js +84 -0
  44. package/dist/core/capability/boundary-driver-container.d.ts +19 -0
  45. package/dist/core/capability/boundary-driver-container.js +189 -0
  46. package/dist/core/capability/boundary-driver.d.ts +29 -0
  47. package/dist/core/capability/boundary-driver.js +44 -0
  48. package/dist/core/capability/boundary-egress.d.ts +21 -0
  49. package/dist/core/capability/boundary-egress.js +109 -0
  50. package/dist/core/capability/boundary-grant-materialize.d.ts +14 -0
  51. package/dist/core/capability/boundary-grant-materialize.js +93 -0
  52. package/dist/core/capability/boundary-profile.d.ts +15 -0
  53. package/dist/core/capability/boundary-profile.js +25 -0
  54. package/dist/core/capability/boundary-run.d.ts +48 -0
  55. package/dist/core/capability/boundary-run.js +51 -0
  56. package/dist/core/capability/boundary-session.d.ts +61 -0
  57. package/dist/core/capability/boundary-session.js +138 -0
  58. package/dist/core/capability/boundary-workspace-mount.d.ts +5 -0
  59. package/dist/core/capability/boundary-workspace-mount.js +68 -0
  60. package/dist/core/capability/capability-request-hash.d.ts +2 -0
  61. package/dist/core/capability/capability-request-hash.js +8 -0
  62. package/dist/core/capability/gate-latency-ratchet.d.ts +7 -0
  63. package/dist/core/capability/gate-latency-ratchet.js +18 -0
  64. package/dist/core/capability/gate-policy-shadow.d.ts +25 -0
  65. package/dist/core/capability/gate-policy-shadow.js +130 -0
  66. package/dist/core/capability/gate-shadow-audit.d.ts +1 -0
  67. package/dist/core/capability/gate-shadow-audit.js +1 -0
  68. package/dist/core/capability/gate-shadow-ratchet.d.ts +14 -0
  69. package/dist/core/capability/gate-shadow-ratchet.js +81 -0
  70. package/dist/core/capability/grant-consumption.d.ts +4 -0
  71. package/dist/core/capability/grant-consumption.js +11 -0
  72. package/dist/core/capability/grant-lease.d.ts +44 -0
  73. package/dist/core/capability/grant-lease.js +243 -0
  74. package/dist/core/capability/grant-loader.d.ts +12 -0
  75. package/dist/core/capability/grant-loader.js +23 -0
  76. package/dist/core/capability/grant-match.d.ts +6 -0
  77. package/dist/core/capability/grant-match.js +96 -0
  78. package/dist/core/capability/grant.d.ts +16 -0
  79. package/dist/core/capability/grant.js +16 -0
  80. package/dist/core/capability/index.d.ts +8 -0
  81. package/dist/core/capability/index.js +7 -0
  82. package/dist/core/capability/limits.d.ts +7 -0
  83. package/dist/core/capability/limits.js +55 -0
  84. package/dist/core/capability/policy-bridge.d.ts +18 -0
  85. package/dist/core/capability/policy-bridge.js +51 -0
  86. package/dist/core/capability/policy-engine.d.ts +77 -0
  87. package/dist/core/capability/policy-engine.js +663 -0
  88. package/dist/core/capability/policy-types.d.ts +20 -0
  89. package/dist/core/capability/policy-types.js +1 -0
  90. package/dist/core/capability/request.d.ts +48 -0
  91. package/dist/core/capability/request.js +1 -0
  92. package/dist/core/capability/resolver.d.ts +4 -0
  93. package/dist/core/capability/resolver.js +4 -0
  94. package/dist/core/classify-subagent.d.ts +2 -1
  95. package/dist/core/classify-subagent.js +38 -2
  96. package/dist/core/classify-tool.js +126 -62
  97. package/dist/core/config.d.ts +34 -3
  98. package/dist/core/config.js +118 -3
  99. package/dist/core/effect-ir/audit.d.ts +9 -0
  100. package/dist/core/effect-ir/audit.js +86 -0
  101. package/dist/core/effect-ir/build.d.ts +31 -0
  102. package/dist/core/effect-ir/build.js +277 -0
  103. package/dist/core/effect-ir/index.d.ts +8 -0
  104. package/dist/core/effect-ir/index.js +7 -0
  105. package/dist/core/effect-ir/normalize.d.ts +4 -0
  106. package/dist/core/effect-ir/normalize.js +104 -0
  107. package/dist/core/effect-ir/package-exec-eval.d.ts +8 -0
  108. package/dist/core/effect-ir/package-exec-eval.js +152 -0
  109. package/dist/core/effect-ir/package-exec.d.ts +29 -0
  110. package/dist/core/effect-ir/package-exec.js +292 -0
  111. package/dist/core/effect-ir/policy.d.ts +13 -0
  112. package/dist/core/effect-ir/policy.js +77 -0
  113. package/dist/core/effect-ir/types.d.ts +55 -0
  114. package/dist/core/effect-ir/types.js +1 -0
  115. package/dist/core/egress/allowlist.d.ts +1 -0
  116. package/dist/core/egress/allowlist.js +8 -0
  117. package/dist/core/egress-approval.js +45 -51
  118. package/dist/core/gate-contract.d.ts +5 -0
  119. package/dist/core/gate-contract.js +5 -0
  120. package/dist/core/gate-engine.js +30 -8
  121. package/dist/core/index.d.ts +3 -1
  122. package/dist/core/index.js +2 -1
  123. package/dist/core/judge-cloud-consent.js +29 -15
  124. package/dist/core/judge-doctor.js +39 -14
  125. package/dist/core/judge-fallback-hints.d.ts +13 -0
  126. package/dist/core/judge-fallback-hints.js +108 -0
  127. package/dist/core/network-endpoint.d.ts +10 -0
  128. package/dist/core/network-endpoint.js +51 -0
  129. package/dist/core/path-utils.d.ts +1 -0
  130. package/dist/core/path-utils.js +5 -2
  131. package/dist/core/process-runner.d.ts +10 -0
  132. package/dist/core/process-runner.js +124 -0
  133. package/dist/core/recover-advice.js +2 -1
  134. package/dist/core/recovery/artifact-store.d.ts +29 -0
  135. package/dist/core/recovery/artifact-store.js +336 -0
  136. package/dist/core/recovery/capability.d.ts +3 -0
  137. package/dist/core/recovery/capability.js +22 -0
  138. package/dist/core/recovery/checkpoint.d.ts +25 -0
  139. package/dist/core/recovery/checkpoint.js +260 -0
  140. package/dist/core/recovery/fail-closed.d.ts +6 -0
  141. package/dist/core/recovery/fail-closed.js +25 -0
  142. package/dist/core/recovery/index.d.ts +5 -0
  143. package/dist/core/recovery/index.js +4 -0
  144. package/dist/core/recovery/operator-guidance.d.ts +7 -0
  145. package/dist/core/recovery/operator-guidance.js +39 -0
  146. package/dist/core/recovery/reconcile.d.ts +3 -0
  147. package/dist/core/recovery/reconcile.js +48 -0
  148. package/dist/core/recovery/resource-identity.d.ts +4 -0
  149. package/dist/core/recovery/resource-identity.js +34 -0
  150. package/dist/core/recovery/restore.d.ts +13 -0
  151. package/dist/core/recovery/restore.js +114 -0
  152. package/dist/core/recovery/snapshot-node.d.ts +27 -0
  153. package/dist/core/recovery/snapshot-node.js +261 -0
  154. package/dist/core/recovery/types.d.ts +104 -0
  155. package/dist/core/recovery/types.js +1 -0
  156. package/dist/core/standing-allow.js +3 -0
  157. package/dist/core/transactional/apply-observed-changes.d.ts +13 -0
  158. package/dist/core/transactional/apply-observed-changes.js +275 -0
  159. package/dist/core/transactional/backend-selector.d.ts +8 -0
  160. package/dist/core/transactional/backend-selector.js +118 -0
  161. package/dist/core/transactional/backend.d.ts +55 -0
  162. package/dist/core/transactional/backend.js +1 -0
  163. package/dist/core/transactional/diff-evaluator.js +4 -1
  164. package/dist/core/transactional/eligibility.js +4 -0
  165. package/dist/core/transactional/file-checkpoint-backend.d.ts +3 -0
  166. package/dist/core/transactional/file-checkpoint-backend.js +278 -0
  167. package/dist/core/transactional/file-checkpoint-git.d.ts +11 -0
  168. package/dist/core/transactional/file-checkpoint-git.js +217 -0
  169. package/dist/core/transactional/file-checkpoint-staging.d.ts +13 -0
  170. package/dist/core/transactional/file-checkpoint-staging.js +54 -0
  171. package/dist/core/transactional/file-clone.d.ts +15 -0
  172. package/dist/core/transactional/file-clone.js +139 -0
  173. package/dist/core/transactional/file-tree-path.d.ts +7 -0
  174. package/dist/core/transactional/file-tree-path.js +50 -0
  175. package/dist/core/transactional/file-tree.d.ts +41 -0
  176. package/dist/core/transactional/file-tree.js +186 -0
  177. package/dist/core/transactional/git-worktree-backend.d.ts +2 -0
  178. package/dist/core/transactional/git-worktree-backend.js +50 -0
  179. package/dist/core/transactional/git-worktree.d.ts +14 -9
  180. package/dist/core/transactional/git-worktree.js +62 -87
  181. package/dist/core/transactional/index.d.ts +11 -0
  182. package/dist/core/transactional/index.js +10 -0
  183. package/dist/core/transactional/reasons.d.ts +1 -0
  184. package/dist/core/transactional/reasons.js +5 -0
  185. package/dist/core/transactional/runner.js +171 -23
  186. package/dist/core/transactional/snapshot-node.d.ts +26 -0
  187. package/dist/core/transactional/snapshot-node.js +87 -0
  188. package/dist/core/transactional/types.d.ts +21 -1
  189. package/dist/core/types.d.ts +30 -3
  190. package/dist/core/verdict/adapter.d.ts +3 -4
  191. package/dist/core/verdict/adapter.js +24 -12
  192. package/dist/core/verdict/cursor-acp-client.d.ts +67 -0
  193. package/dist/core/verdict/cursor-acp-client.js +345 -0
  194. package/dist/core/verdict/egress-classify.d.ts +2 -2
  195. package/dist/core/verdict/egress-classify.js +2 -2
  196. package/dist/core/verdict/git-classifier.d.ts +26 -0
  197. package/dist/core/verdict/git-classifier.js +533 -0
  198. package/dist/core/verdict/judge-audit.js +1 -0
  199. package/dist/core/verdict/judge-baseline.d.ts +1 -1
  200. package/dist/core/verdict/judge-baseline.js +1 -0
  201. package/dist/core/verdict/judge-broker-service.js +12 -0
  202. package/dist/core/verdict/judge-catalog.js +1 -0
  203. package/dist/core/verdict/judge-cli-fingerprint.d.ts +1 -0
  204. package/dist/core/verdict/judge-cli-fingerprint.js +6 -0
  205. package/dist/core/verdict/judge-cli.js +5 -3
  206. package/dist/core/verdict/judge-provider-matrix.js +1 -1
  207. package/dist/core/verdict/judge-runtime-config.d.ts +2 -0
  208. package/dist/core/verdict/judge-runtime-config.js +10 -6
  209. package/dist/core/verdict/judge-session-broker.d.ts +1 -1
  210. package/dist/core/verdict/judge-session-broker.js +10 -5
  211. package/dist/core/verdict/judge-transport.d.ts +5 -1
  212. package/dist/core/verdict/judge-transport.js +24 -14
  213. package/dist/core/verdict/judge.d.ts +2 -15
  214. package/dist/core/verdict/judge.js +5 -68
  215. package/dist/core/verdict/launcher-resolve.d.ts +2 -0
  216. package/dist/core/verdict/launcher-resolve.js +14 -16
  217. package/dist/core/verdict/prescan.d.ts +15 -0
  218. package/dist/core/verdict/prescan.js +68 -0
  219. package/dist/core/verdict/shell-policy.d.ts +26 -0
  220. package/dist/core/verdict/shell-policy.js +40 -0
  221. package/dist/core/verdict/shell-semantics.d.ts +24 -0
  222. package/dist/core/verdict/shell-semantics.js +225 -0
  223. package/dist/core/verdict/types.d.ts +18 -1
  224. package/dist/core/verdict/verdict.js +313 -178
  225. package/dist/corpus/evaluate.js +3 -7
  226. package/dist/corpus/gate-latency-budget.d.ts +39 -0
  227. package/dist/corpus/gate-latency-budget.js +33 -0
  228. package/dist/corpus/mutators.d.ts +1 -1
  229. package/dist/corpus/mutators.js +11 -0
  230. package/dist/corpus/runtime-match.js +1 -3
  231. package/dist/corpus/standing-allow-catalog.generated.js +29 -9
  232. package/dist/judge-broker-daemon.js +15 -1
  233. package/dist/services/sandbox-service.d.ts +4 -0
  234. package/dist/services/sandbox-service.js +28 -2
  235. package/dist/types.d.ts +13 -2
  236. package/dist/version.d.ts +1 -1
  237. package/dist/version.js +1 -1
  238. package/package.json +1 -1
  239. package/skills/belay/SKILL.md +8 -3
  240. package/skills/belay/belay-approve.md +10 -7
@@ -0,0 +1,243 @@
1
+ import { canonicalStringify } from '../fingerprint.js';
2
+ import { isGrantScopeTooBroad } from './grant.js';
3
+ import { grantMatchesRequest } from './grant-match.js';
4
+ function isActiveGrant(grant, now) {
5
+ if (isGrantScopeTooBroad(grant)) {
6
+ return false;
7
+ }
8
+ const expires = Date.parse(grant.expiresAt);
9
+ return Number.isFinite(expires) && expires > now && grant.usesRemaining > 0;
10
+ }
11
+ export function grantsFromApproval(approval) {
12
+ if (approval.grants?.length) {
13
+ return approval.grants;
14
+ }
15
+ if (approval.grant) {
16
+ return [approval.grant];
17
+ }
18
+ return [];
19
+ }
20
+ export function approvalGrantBundleExhausted(approval) {
21
+ const bundle = grantsFromApproval(approval);
22
+ if (!bundle.length) {
23
+ return false;
24
+ }
25
+ return bundle.every((grant) => grant.usesRemaining <= 0);
26
+ }
27
+ export function consumeApprovalGrantBundle(approval, requests) {
28
+ const bundle = grantsFromApproval(approval);
29
+ if (!bundle.length || !requests.length) {
30
+ return { approval, consumed: false };
31
+ }
32
+ const grants = [...bundle];
33
+ const now = Date.now();
34
+ for (const request of requests) {
35
+ const index = grants.findIndex((grant) => {
36
+ return isActiveGrant(grant, now) && grantMatchesRequest(grant, request);
37
+ });
38
+ if (index === -1) {
39
+ return { approval, consumed: false };
40
+ }
41
+ const grant = grants[index];
42
+ if (!grant) {
43
+ return { approval, consumed: false };
44
+ }
45
+ grants[index] = decrementGrant(grant);
46
+ }
47
+ return {
48
+ approval: {
49
+ ...approval,
50
+ grants,
51
+ grant: grants[0],
52
+ },
53
+ consumed: true,
54
+ };
55
+ }
56
+ function exactGrantMatchesRequest(grant, request) {
57
+ return (persistedCanonicalStringify(grant.principal) ===
58
+ persistedCanonicalStringify(request.principal) &&
59
+ grant.action === request.action &&
60
+ persistedCanonicalStringify(grant.resource) === persistedCanonicalStringify(request.resource) &&
61
+ grant.inputFingerprint === request.context.inputFingerprint);
62
+ }
63
+ function validateExactGrantBundle(approval, requests, now, usage) {
64
+ if (approval.grantBundleVersion !== 1) {
65
+ return { ok: false, reason: 'legacy_record' };
66
+ }
67
+ if (!requests.length) {
68
+ return { ok: false, reason: 'empty_requests' };
69
+ }
70
+ const bundle = grantsFromApproval(approval);
71
+ if (bundle.length !== requests.length) {
72
+ return { ok: false, reason: 'cardinality_mismatch' };
73
+ }
74
+ if (bundle.some((grant) => isGrantScopeTooBroad(grant))) {
75
+ return { ok: false, reason: 'grant_scope_too_broad' };
76
+ }
77
+ const usageIsValid = bundle.every((grant) => {
78
+ const expires = Date.parse(grant.expiresAt);
79
+ if (!Number.isFinite(expires) || expires <= now) {
80
+ return false;
81
+ }
82
+ return usage === 'available'
83
+ ? grant.usesRemaining > 0
84
+ : grant.usesRemaining >= 0 && grant.usesRemaining < grant.maxUses;
85
+ });
86
+ if (!usageIsValid) {
87
+ return { ok: false, reason: 'grant_inactive' };
88
+ }
89
+ const unmatched = [...bundle];
90
+ for (const request of requests) {
91
+ const index = unmatched.findIndex((grant) => exactGrantMatchesRequest(grant, request));
92
+ if (index === -1) {
93
+ return { ok: false, reason: 'grant_mismatch' };
94
+ }
95
+ unmatched.splice(index, 1);
96
+ }
97
+ if (unmatched.length > 0) {
98
+ return { ok: false, reason: 'grant_mismatch' };
99
+ }
100
+ return { ok: true, approval };
101
+ }
102
+ function persistedCanonicalStringify(value) {
103
+ return canonicalStringify(omitUndefined(value));
104
+ }
105
+ function omitUndefined(value) {
106
+ if (Array.isArray(value)) {
107
+ return value.map((entry) => omitUndefined(entry));
108
+ }
109
+ if (!value || typeof value !== 'object') {
110
+ return value;
111
+ }
112
+ return Object.fromEntries(Object.entries(value)
113
+ .filter(([, entry]) => entry !== undefined)
114
+ .map(([key, entry]) => [key, omitUndefined(entry)]));
115
+ }
116
+ /** Validate and consume a marked exact bundle without mutating on any failure. */
117
+ export function validateAndConsumeGrantBundle(approval, requests, now = Date.now()) {
118
+ const validated = validateExactGrantBundle(approval, requests, now, 'available');
119
+ if (!validated.ok) {
120
+ return validated;
121
+ }
122
+ const grants = grantsFromApproval(approval).map((grant) => decrementGrant(grant));
123
+ return {
124
+ ok: true,
125
+ approval: {
126
+ ...approval,
127
+ grants,
128
+ grant: grants[0],
129
+ },
130
+ };
131
+ }
132
+ /** Revalidate a marked bundle during an active replay lease without consuming it twice. */
133
+ export function validateGrantBundleForLeaseReuse(approval, requests, now = Date.now()) {
134
+ return validateExactGrantBundle(approval, requests, now, 'previously_consumed');
135
+ }
136
+ /** Consume every grant in an approved record after fingerprint/hash replay validation. */
137
+ export function consumeApprovedRecordGrantBundle(approval) {
138
+ const bundle = grantsFromApproval(approval);
139
+ const now = Date.now();
140
+ if (!bundle.length ||
141
+ bundle.some((grant) => {
142
+ const expires = Date.parse(grant.expiresAt);
143
+ return !Number.isFinite(expires) || expires <= now || grant.usesRemaining <= 0;
144
+ })) {
145
+ return { approval, consumed: false };
146
+ }
147
+ const grants = bundle.map((grant) => decrementGrant(grant));
148
+ return {
149
+ approval: {
150
+ ...approval,
151
+ grants,
152
+ grant: grants[0],
153
+ },
154
+ consumed: true,
155
+ };
156
+ }
157
+ export function decrementApprovalLegacyGrant(approval) {
158
+ const bundle = grantsFromApproval(approval);
159
+ if (!bundle.length) {
160
+ return approval;
161
+ }
162
+ const grants = bundle.map((grant, index) => (index === 0 ? decrementGrant(grant) : grant));
163
+ return {
164
+ ...approval,
165
+ grants,
166
+ grant: grants[0],
167
+ };
168
+ }
169
+ export function grantsFromApprovedState(state, repoRoot) {
170
+ const now = Date.now();
171
+ const collected = [];
172
+ for (const approval of state.approvals) {
173
+ if (approval.repoRoot !== repoRoot) {
174
+ continue;
175
+ }
176
+ for (const grant of grantsFromApproval(approval)) {
177
+ if (isActiveGrant(grant, now)) {
178
+ collected.push(grant);
179
+ }
180
+ }
181
+ }
182
+ return collected;
183
+ }
184
+ function decrementGrant(grant) {
185
+ return {
186
+ ...grant,
187
+ usesRemaining: grant.usesRemaining - 1,
188
+ };
189
+ }
190
+ export function consumeGrantLease(state, grantId) {
191
+ let consumed = false;
192
+ const approvals = state.approvals.map((approval) => {
193
+ const bundle = grantsFromApproval(approval);
194
+ const index = bundle.findIndex((g) => g.grantId === grantId);
195
+ if (index === -1) {
196
+ return approval;
197
+ }
198
+ const grant = bundle[index];
199
+ if (!grant || grant.usesRemaining <= 0) {
200
+ return approval;
201
+ }
202
+ consumed = true;
203
+ const updated = decrementGrant(grant);
204
+ const grants = [...bundle];
205
+ grants[index] = updated;
206
+ return {
207
+ ...approval,
208
+ grants,
209
+ grant: grants[0],
210
+ };
211
+ });
212
+ return {
213
+ state: { ...state, approvals },
214
+ consumed,
215
+ };
216
+ }
217
+ /** Consume one lease for each request; all must succeed (atomic bundle consumption). */
218
+ export function consumeGrantLeasesForRequests(state, requests) {
219
+ const repoRoot = requests[0]?.principal.repoRoot;
220
+ if (!repoRoot || requests.some((request) => request.principal.repoRoot !== repoRoot)) {
221
+ return { state, consumed: false };
222
+ }
223
+ for (let index = 0; index < state.approvals.length; index += 1) {
224
+ const approval = state.approvals[index];
225
+ if (!approval || approval.repoRoot !== repoRoot) {
226
+ continue;
227
+ }
228
+ const consumed = consumeApprovalGrantBundle(approval, requests);
229
+ if (!consumed.consumed) {
230
+ continue;
231
+ }
232
+ const approvals = [...state.approvals];
233
+ approvals[index] = consumed.approval;
234
+ return { state: { ...state, approvals }, consumed: true };
235
+ }
236
+ return { state, consumed: false };
237
+ }
238
+ export function findMatchingGrant(grants, request) {
239
+ if (!grants?.length) {
240
+ return undefined;
241
+ }
242
+ return grants.find((grant) => grantMatchesRequest(grant, request));
243
+ }
@@ -0,0 +1,12 @@
1
+ import type { BelayConfigV4 } from '../config.js';
2
+ import type { ApprovalStateFile, ClassifierOptions } from '../types.js';
3
+ import type { BoundaryAttestation } from './attestation.js';
4
+ import type { CapabilityGrantV1 } from './grant.js';
5
+ export declare function capabilityGrantsEnabled(config: BelayConfigV4): boolean;
6
+ export declare function grantsFromApprovalState(state: ApprovalStateFile, repoRoot: string, config: BelayConfigV4): CapabilityGrantV1[] | undefined;
7
+ export declare function loadClassifierAuthorization(params: {
8
+ repoRoot: string;
9
+ config: BelayConfigV4;
10
+ approvedState: ApprovalStateFile;
11
+ }): Promise<Pick<ClassifierOptions, 'grants' | 'attestation' | 'boundaryProfile'>>;
12
+ export type { BoundaryAttestation, CapabilityGrantV1 };
@@ -0,0 +1,23 @@
1
+ import { configuredControlPlaneDir } from '../config.js';
2
+ import { resolveBoundaryProfile } from './boundary-profile.js';
3
+ import { boundaryAttestationPath, loadBoundaryAttestation } from './boundary-session.js';
4
+ import { grantsFromApprovedState } from './grant-lease.js';
5
+ export function capabilityGrantsEnabled(config) {
6
+ return config.capability?.grantsEnabled !== false;
7
+ }
8
+ export function grantsFromApprovalState(state, repoRoot, config) {
9
+ if (!capabilityGrantsEnabled(config)) {
10
+ return undefined;
11
+ }
12
+ const grants = grantsFromApprovedState(state, repoRoot);
13
+ return grants.length > 0 ? grants : undefined;
14
+ }
15
+ export async function loadClassifierAuthorization(params) {
16
+ const grants = grantsFromApprovalState(params.approvedState, params.repoRoot, params.config);
17
+ const attestation = await loadBoundaryAttestation(boundaryAttestationPath(params.repoRoot, params.config), params.repoRoot, configuredControlPlaneDir(params.config));
18
+ const boundaryProfile = resolveBoundaryProfile({
19
+ config: params.config,
20
+ attestation,
21
+ });
22
+ return { grants, attestation, boundaryProfile };
23
+ }
@@ -0,0 +1,6 @@
1
+ import type { CapabilityGrantV1 } from './grant.js';
2
+ import type { CapabilityRequestV1 } from './request.js';
3
+ export declare function grantTargetsRequest(grant: CapabilityGrantV1, request: CapabilityRequestV1): boolean;
4
+ /** Repo-scoped target match for forged broad-grant detection (principal may be incomplete). */
5
+ export declare function broadGrantTargetsRequest(grant: CapabilityGrantV1, request: CapabilityRequestV1): boolean;
6
+ export declare function grantMatchesRequest(grant: CapabilityGrantV1, request: CapabilityRequestV1): boolean;
@@ -0,0 +1,96 @@
1
+ import { canonicalPath } from '../path-utils.js';
2
+ import { isGrantScopeTooBroad } from './grant.js';
3
+ function principalMatches(grant, request) {
4
+ if (grant.repoRoot !== request.repoRoot) {
5
+ return false;
6
+ }
7
+ if (request.adapter !== undefined && grant.adapter !== request.adapter) {
8
+ return false;
9
+ }
10
+ if (request.sessionHash !== undefined && grant.sessionHash !== request.sessionHash) {
11
+ return false;
12
+ }
13
+ if (grant.adapter !== undefined && grant.adapter !== request.adapter) {
14
+ return false;
15
+ }
16
+ if (grant.sessionHash !== undefined && grant.sessionHash !== request.sessionHash) {
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ function networkResourceMatches(grant, request) {
22
+ if (grant.host !== request.host) {
23
+ return false;
24
+ }
25
+ if (grant.port !== undefined && grant.port !== request.port) {
26
+ return false;
27
+ }
28
+ if (grant.protocol !== undefined &&
29
+ grant.protocol !== 'unknown' &&
30
+ request.protocol !== undefined &&
31
+ request.protocol !== 'unknown' &&
32
+ grant.protocol !== request.protocol) {
33
+ return false;
34
+ }
35
+ return true;
36
+ }
37
+ function grantTargetsResource(grant, request) {
38
+ if (grant.action !== request.action) {
39
+ if (grant.action === 'indeterminate') {
40
+ return request.action === 'indeterminate';
41
+ }
42
+ return false;
43
+ }
44
+ if (grant.inputFingerprint && grant.inputFingerprint !== request.context.inputFingerprint) {
45
+ return false;
46
+ }
47
+ if (grant.resource.kind === 'path' && request.resource.kind === 'path') {
48
+ return canonicalPath(grant.resource.path) === canonicalPath(request.resource.path);
49
+ }
50
+ if (grant.resource.kind === 'network' && request.resource.kind === 'network') {
51
+ return networkResourceMatches(grant.resource, request.resource);
52
+ }
53
+ if (grant.resource.kind === 'executable' && request.resource.kind === 'executable') {
54
+ return grant.resource.command === request.resource.command;
55
+ }
56
+ if (grant.resource.kind === 'package-cache' && request.resource.kind === 'package-cache') {
57
+ return grant.resource.manager === request.resource.manager;
58
+ }
59
+ if (grant.resource.kind === 'git-ref' && request.resource.kind === 'git-ref') {
60
+ return grant.resource.ref === request.resource.ref;
61
+ }
62
+ if (grant.resource.kind === 'unknown') {
63
+ if (grant.action === 'network.connect' && request.resource.kind === 'network') {
64
+ return true;
65
+ }
66
+ if (grant.action === 'fs.write' && request.resource.kind === 'path') {
67
+ return true;
68
+ }
69
+ if (grant.action === 'indeterminate') {
70
+ return request.action === 'indeterminate';
71
+ }
72
+ }
73
+ return grant.resource.kind === request.resource.kind;
74
+ }
75
+ export function grantTargetsRequest(grant, request) {
76
+ if (grant.usesRemaining <= 0) {
77
+ return false;
78
+ }
79
+ if (!principalMatches(grant.principal, request.principal)) {
80
+ return false;
81
+ }
82
+ return grantTargetsResource(grant, request);
83
+ }
84
+ /** Repo-scoped target match for forged broad-grant detection (principal may be incomplete). */
85
+ export function broadGrantTargetsRequest(grant, request) {
86
+ if (grant.principal.repoRoot !== request.principal.repoRoot) {
87
+ return false;
88
+ }
89
+ return grantTargetsResource(grant, request);
90
+ }
91
+ export function grantMatchesRequest(grant, request) {
92
+ if (isGrantScopeTooBroad(grant)) {
93
+ return false;
94
+ }
95
+ return grantTargetsRequest(grant, request);
96
+ }
@@ -0,0 +1,16 @@
1
+ import type { CapabilityAction, CapabilityPrincipal, CapabilityResource } from './request.js';
2
+ export declare const CAPABILITY_GRANT_VERSION: 1;
3
+ export interface CapabilityGrantV1 {
4
+ version: typeof CAPABILITY_GRANT_VERSION;
5
+ grantId: string;
6
+ principal: CapabilityPrincipal;
7
+ action: CapabilityAction;
8
+ resource: CapabilityResource;
9
+ inputFingerprint?: string;
10
+ issuedAt: string;
11
+ expiresAt: string;
12
+ maxUses: number;
13
+ usesRemaining: number;
14
+ issuer: string;
15
+ }
16
+ export declare function isGrantScopeTooBroad(grant: CapabilityGrantV1): boolean;
@@ -0,0 +1,16 @@
1
+ export const CAPABILITY_GRANT_VERSION = 1;
2
+ export function isGrantScopeTooBroad(grant) {
3
+ if (grant.action === 'network.connect' && grant.resource.kind === 'unknown') {
4
+ return true;
5
+ }
6
+ if (grant.resource.kind === 'network' && grant.resource.host === '*') {
7
+ return true;
8
+ }
9
+ if (grant.action === 'fs.write' && grant.resource.kind === 'unknown') {
10
+ return true;
11
+ }
12
+ if (grant.action === 'indeterminate') {
13
+ return true;
14
+ }
15
+ return false;
16
+ }
@@ -1,6 +1,14 @@
1
1
  export { addPathToAllowlist, allPathsAllowlisted, fsScopeAllowlistPath, isPathAllowlisted, loadFsScopeAllowlist, loadFsScopeAllowlistSync, saveFsScopeAllowlist, } from './allowlist.js';
2
+ export { attestsWorkspaceMountIsolation, BOUNDARY_ATTESTATION_VERSION, type BoundaryAttestation, type BoundaryDriverId, isAttestationFresh, } from './attestation.js';
3
+ export { BOUNDARY_PROFILE_L1_ATTESTED, BOUNDARY_PROFILE_L3_L4_ONLY, BOUNDARY_PROFILE_L3_POLICY, boundaryVerifiedAllowEnabled, isAttestedBoundary, resolveBoundaryProfile, } from './boundary-profile.js';
2
4
  export { evaluateL1FullStatus, hasSandboxRuntime, isCapabilityBrokerDemotionActive, isSandboxBrokerEnabled, } from './broker.js';
5
+ export { CAPABILITY_GRANT_VERSION, type CapabilityGrantV1, isGrantScopeTooBroad, } from './grant.js';
6
+ export { checkGatedActionLimits, MAX_SHELL_COMMAND_BYTES, MAX_TOOL_PAYLOAD_BYTES, } from './limits.js';
3
7
  export { collectOutsideRepoPaths, collectOutsideRepoPathsFromToolPayload } from './paths.js';
8
+ export { type CapabilityAuthorizationMetadata, type PolicyLegacyReasonHints, policyDecisionToLegacyReason, policyReasonToLegacyReason, singleCapabilityMetadata, } from './policy-bridge.js';
9
+ export { buildFileMutationCapabilityRequest, buildShellCapabilityRequest, createTypeScriptPolicyEngine, evaluateFileMutationPolicy, evaluateShellPolicy, evaluateSubagentPolicy, type FileMutationCapabilityAnalysis, getDefaultPolicyEngine, policyDecisionRequiresAsk, type ShellCapabilityAnalysis, type SubagentCapabilityAnalysis, } from './policy-engine.js';
10
+ export type { AuthorizationContext, PolicyDecision, PolicyEngine, PolicyOutcome, } from './policy-types.js';
4
11
  export { FS_SCOPE_REASONS, shouldSkipBrokerApprovedOnce, shouldSkipBrokerApprovedRecord, } from './reasons.js';
12
+ export { CAPABILITY_REQUEST_VERSION, type CapabilityAction, type CapabilityEvidence, type CapabilityEvidenceLevel, type CapabilityHookKind, type CapabilityPrincipal, type CapabilityRequestContext, type CapabilityRequestV1, type CapabilityResource, } from './request.js';
5
13
  export { addTrustedWorkspaceRoot, isBroadTrustedWorkspaceRoot, isHighStakesTrustedWorkspaceRoot, isPathWithinTrustedWorkspaceRoots, loadTrustedWorkspaceRoots, loadTrustedWorkspaceRootsSync, normalizeTrustedWorkspaceRootPath, saveTrustedWorkspaceRoots, trustedWorkspaceRootsPath, validateTrustedWorkspaceRootCandidate, } from './trusted-workspace-roots.js';
6
14
  export type { CapabilityApprovalScope, FsScopeAllowlistEntry, FsScopeAllowlistFile, TrustedWorkspaceRootEntry, TrustedWorkspaceRootsFile, } from './types.js';
@@ -1,5 +1,12 @@
1
1
  export { addPathToAllowlist, allPathsAllowlisted, fsScopeAllowlistPath, isPathAllowlisted, loadFsScopeAllowlist, loadFsScopeAllowlistSync, saveFsScopeAllowlist, } from './allowlist.js';
2
+ export { attestsWorkspaceMountIsolation, BOUNDARY_ATTESTATION_VERSION, isAttestationFresh, } from './attestation.js';
3
+ export { BOUNDARY_PROFILE_L1_ATTESTED, BOUNDARY_PROFILE_L3_L4_ONLY, BOUNDARY_PROFILE_L3_POLICY, boundaryVerifiedAllowEnabled, isAttestedBoundary, resolveBoundaryProfile, } from './boundary-profile.js';
2
4
  export { evaluateL1FullStatus, hasSandboxRuntime, isCapabilityBrokerDemotionActive, isSandboxBrokerEnabled, } from './broker.js';
5
+ export { CAPABILITY_GRANT_VERSION, isGrantScopeTooBroad, } from './grant.js';
6
+ export { checkGatedActionLimits, MAX_SHELL_COMMAND_BYTES, MAX_TOOL_PAYLOAD_BYTES, } from './limits.js';
3
7
  export { collectOutsideRepoPaths, collectOutsideRepoPathsFromToolPayload } from './paths.js';
8
+ export { policyDecisionToLegacyReason, policyReasonToLegacyReason, singleCapabilityMetadata, } from './policy-bridge.js';
9
+ export { buildFileMutationCapabilityRequest, buildShellCapabilityRequest, createTypeScriptPolicyEngine, evaluateFileMutationPolicy, evaluateShellPolicy, evaluateSubagentPolicy, getDefaultPolicyEngine, policyDecisionRequiresAsk, } from './policy-engine.js';
4
10
  export { FS_SCOPE_REASONS, shouldSkipBrokerApprovedOnce, shouldSkipBrokerApprovedRecord, } from './reasons.js';
11
+ export { CAPABILITY_REQUEST_VERSION, } from './request.js';
5
12
  export { addTrustedWorkspaceRoot, isBroadTrustedWorkspaceRoot, isHighStakesTrustedWorkspaceRoot, isPathWithinTrustedWorkspaceRoots, loadTrustedWorkspaceRoots, loadTrustedWorkspaceRootsSync, normalizeTrustedWorkspaceRootPath, saveTrustedWorkspaceRoots, trustedWorkspaceRootsPath, validateTrustedWorkspaceRootCandidate, } from './trusted-workspace-roots.js';
@@ -0,0 +1,7 @@
1
+ import type { GatedAction } from '../gate-contract.js';
2
+ import type { ClassifyResult } from '../types.js';
3
+ import { BOUNDARY_PROFILE_L3_POLICY } from './boundary-profile.js';
4
+ export { BOUNDARY_PROFILE_L3_POLICY };
5
+ export declare const MAX_SHELL_COMMAND_BYTES: number;
6
+ export declare const MAX_TOOL_PAYLOAD_BYTES: number;
7
+ export declare function checkGatedActionLimits(action: GatedAction): ClassifyResult | null;
@@ -0,0 +1,55 @@
1
+ import { BOUNDARY_PROFILE_L3_POLICY } from './boundary-profile.js';
2
+ export { BOUNDARY_PROFILE_L3_POLICY };
3
+ export const MAX_SHELL_COMMAND_BYTES = 64 * 1024;
4
+ export const MAX_TOOL_PAYLOAD_BYTES = 1024 * 1024;
5
+ function limitExceededResult(reason, summary) {
6
+ return {
7
+ verdict: 'deny_pending_approval',
8
+ reason,
9
+ fingerprint: `limit:${reason}`,
10
+ summary,
11
+ assessment: {
12
+ reversibility: 'irreversible',
13
+ external: false,
14
+ blastRadius: 'gate input budget',
15
+ confidence: 1,
16
+ signals: [reason, 'analysis_budget_exceeded'],
17
+ },
18
+ boundaryProfile: BOUNDARY_PROFILE_L3_POLICY,
19
+ };
20
+ }
21
+ function shellCommandFromAction(action) {
22
+ if (action.command?.trim()) {
23
+ return action.command.trim();
24
+ }
25
+ const payload = action.payload;
26
+ if (!payload) {
27
+ return '';
28
+ }
29
+ const direct = payload.command;
30
+ if (typeof direct === 'string' && direct.trim()) {
31
+ return direct.trim();
32
+ }
33
+ const toolInput = payload.tool_input;
34
+ if (toolInput && typeof toolInput === 'object') {
35
+ const command = toolInput.command;
36
+ if (typeof command === 'string' && command.trim()) {
37
+ return command.trim();
38
+ }
39
+ }
40
+ return '';
41
+ }
42
+ export function checkGatedActionLimits(action) {
43
+ if (action.kind === 'shell') {
44
+ const command = shellCommandFromAction(action);
45
+ if (Buffer.byteLength(command, 'utf8') > MAX_SHELL_COMMAND_BYTES) {
46
+ return limitExceededResult('input_too_large', command.slice(0, 120));
47
+ }
48
+ return null;
49
+ }
50
+ const payloadBytes = Buffer.byteLength(JSON.stringify(action.payload ?? {}), 'utf8');
51
+ if (payloadBytes > MAX_TOOL_PAYLOAD_BYTES) {
52
+ return limitExceededResult('input_too_large', action.toolName ?? action.kind);
53
+ }
54
+ return null;
55
+ }
@@ -0,0 +1,18 @@
1
+ import type { PolicyDecision } from './policy-types.js';
2
+ import type { CapabilityRequestV1 } from './request.js';
3
+ export interface CapabilityAuthorizationMetadata {
4
+ capabilityRequests: CapabilityRequestV1[];
5
+ authorizationDecision: PolicyDecision;
6
+ }
7
+ export interface PolicyLegacyReasonHints {
8
+ outsideMutation?: boolean;
9
+ effect?: 'read_only' | 'local_mutation' | 'remote_mutation' | 'unknown';
10
+ }
11
+ export declare function singleCapabilityMetadata(request: CapabilityRequestV1, decision: PolicyDecision): CapabilityAuthorizationMetadata;
12
+ /**
13
+ * Maps a PolicyDecision to hook-facing legacy reason strings.
14
+ * Pass hints when the shell segment context is known (outside-repo mutation, etc.).
15
+ */
16
+ export declare function policyDecisionToLegacyReason(decision: PolicyDecision, hints?: PolicyLegacyReasonHints): string;
17
+ /** @deprecated Use policyDecisionToLegacyReason for shell segments that need outside-repo hints. */
18
+ export declare function policyReasonToLegacyReason(decision: PolicyDecision): string;
@@ -0,0 +1,51 @@
1
+ export function singleCapabilityMetadata(request, decision) {
2
+ return {
3
+ capabilityRequests: [request],
4
+ authorizationDecision: decision,
5
+ };
6
+ }
7
+ /**
8
+ * Maps a PolicyDecision to hook-facing legacy reason strings.
9
+ * Pass hints when the shell segment context is known (outside-repo mutation, etc.).
10
+ */
11
+ export function policyDecisionToLegacyReason(decision, hints = {}) {
12
+ if (decision.reason === 'outside_repo_mutation') {
13
+ return 'outside_repo_mutation';
14
+ }
15
+ if (decision.reason === 'external_effect' || decision.reason === 'network_connect') {
16
+ return 'external_effect';
17
+ }
18
+ if (decision.reason === 'high_stakes_path' || decision.reason === 'secret_path') {
19
+ return 'tier1_catastrophic';
20
+ }
21
+ if (decision.reason === 'indeterminate_effect') {
22
+ return 'unknown_local_effect';
23
+ }
24
+ if (decision.reason === 'opaque_execution') {
25
+ return 'opaque_execution';
26
+ }
27
+ if (decision.reason === 'control_plane_mutation') {
28
+ return 'control_plane_mutation';
29
+ }
30
+ if (decision.reason === 'policy_default') {
31
+ if (decision.signals.includes('outside_repo_path') ||
32
+ decision.signals.includes('outside_repo_mutation')) {
33
+ return 'outside_repo_mutation';
34
+ }
35
+ if (hints.outsideMutation && hints.effect !== 'read_only') {
36
+ return 'outside_repo_mutation';
37
+ }
38
+ return 'unknown_local_effect';
39
+ }
40
+ if (decision.reason === 'subagent_review') {
41
+ return 'subagent_review';
42
+ }
43
+ if (decision.outcome === 'deny') {
44
+ return decision.reason;
45
+ }
46
+ return decision.reason;
47
+ }
48
+ /** @deprecated Use policyDecisionToLegacyReason for shell segments that need outside-repo hints. */
49
+ export function policyReasonToLegacyReason(decision) {
50
+ return policyDecisionToLegacyReason(decision);
51
+ }
@@ -0,0 +1,77 @@
1
+ import type { BelayConfigV4 } from '../config.js';
2
+ import type { VerdictEffect, VerdictLocation, VerdictOpacity } from '../verdict/types.js';
3
+ import type { AuthorizationContext, PolicyDecision, PolicyEngine } from './policy-types.js';
4
+ import { type CapabilityHookKind, type CapabilityRequestV1 } from './request.js';
5
+ export type PolicyAuthExtras = Pick<AuthorizationContext, 'grants' | 'attestation'> & {
6
+ egressProxyActive?: boolean;
7
+ sensitivePaths?: string[];
8
+ };
9
+ export interface ShellCapabilityAnalysis {
10
+ command: string;
11
+ hookKind: CapabilityHookKind;
12
+ segmentHead: string;
13
+ effect: VerdictEffect;
14
+ location: VerdictLocation;
15
+ opacity: VerdictOpacity;
16
+ egressClass?: 'read' | 'destructive' | 'ambiguous';
17
+ pathArgs: string[];
18
+ /** Verdict-resolved canonical paths aligned with pathArgs (preferred for policy resource selection). */
19
+ resolvedPathTargets?: string[];
20
+ signals: string[];
21
+ cwd: string;
22
+ repoRoot: string;
23
+ inputFingerprint: string;
24
+ adapter?: string;
25
+ trustedWorkspaceRoots?: string[];
26
+ sensitivePaths?: string[];
27
+ protectedArtifactRoots?: string[];
28
+ }
29
+ export interface FileMutationCapabilityAnalysis {
30
+ hookKind: CapabilityHookKind;
31
+ toolKind: string;
32
+ filePath: string;
33
+ resolvedPath: string;
34
+ repoRoot: string;
35
+ cwd: string;
36
+ inputFingerprint: string;
37
+ signals: string[];
38
+ isDelete: boolean;
39
+ locationLabel: 'repo_local' | 'outside_repo' | 'sensitive_path' | 'control_plane';
40
+ trustedWorkspaceRoots?: string[];
41
+ sensitivePaths?: string[];
42
+ adapter?: string;
43
+ }
44
+ export interface SubagentCapabilityAnalysis {
45
+ subagentType: string;
46
+ summary: string;
47
+ repoRoot: string;
48
+ cwd: string;
49
+ inputFingerprint: string;
50
+ signals: string[];
51
+ adapter?: string;
52
+ }
53
+ export declare function buildSubagentCapabilityRequest(analysis: SubagentCapabilityAnalysis): CapabilityRequestV1;
54
+ export declare function evaluateSubagentPolicy(analysis: SubagentCapabilityAnalysis, config: BelayConfigV4, auth?: PolicyAuthExtras): {
55
+ request: CapabilityRequestV1;
56
+ decision: PolicyDecision;
57
+ };
58
+ export declare function buildShellCapabilityRequest(analysis: ShellCapabilityAnalysis): CapabilityRequestV1;
59
+ export declare function buildShellCapabilityRequests(analysis: ShellCapabilityAnalysis): CapabilityRequestV1[];
60
+ export declare function buildFileMutationCapabilityRequest(analysis: FileMutationCapabilityAnalysis): CapabilityRequestV1;
61
+ export declare function createTypeScriptPolicyEngine(): PolicyEngine;
62
+ export declare function getDefaultPolicyEngine(): PolicyEngine;
63
+ export declare function policyDecisionRequiresAsk(decision: PolicyDecision): boolean;
64
+ export declare function combinePolicyDecisions(decisions: readonly PolicyDecision[]): PolicyDecision;
65
+ export declare function evaluateCapabilityRequestsPolicy(requests: readonly CapabilityRequestV1[], config: BelayConfigV4, auth?: PolicyAuthExtras, trustedWorkspaceRoots?: string[]): {
66
+ decisions: PolicyDecision[];
67
+ decision: PolicyDecision;
68
+ };
69
+ export declare function evaluateShellPolicy(analysis: ShellCapabilityAnalysis, config: BelayConfigV4, auth?: PolicyAuthExtras): {
70
+ request: CapabilityRequestV1;
71
+ requests: CapabilityRequestV1[];
72
+ decision: PolicyDecision;
73
+ };
74
+ export declare function evaluateFileMutationPolicy(analysis: FileMutationCapabilityAnalysis, config: BelayConfigV4, auth?: PolicyAuthExtras): {
75
+ request: CapabilityRequestV1;
76
+ decision: PolicyDecision;
77
+ };