@guilz-dev/belay 0.3.0 → 0.6.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 (242) hide show
  1. package/README.md +7 -1
  2. package/dist/adapters/cursor/runtime-entry.js +1 -0
  3. package/dist/adapters/layouts/scope.js +3 -2
  4. package/dist/adapters/shared/gate-runtime.d.ts +12 -16
  5. package/dist/adapters/shared/gate-runtime.js +499 -43
  6. package/dist/bundle/claude-runtime.mjs +8004 -2676
  7. package/dist/bundle/codex-runtime.mjs +8021 -2683
  8. package/dist/bundle/cursor-runtime.mjs +7993 -2667
  9. package/dist/cli.js +180 -6
  10. package/dist/commands/approve.d.ts +1 -0
  11. package/dist/commands/approve.js +45 -26
  12. package/dist/commands/classify-for-report.js +1 -1
  13. package/dist/commands/config.d.ts +8 -0
  14. package/dist/commands/config.js +264 -58
  15. package/dist/commands/doctor.js +47 -2
  16. package/dist/commands/explain.js +17 -2
  17. package/dist/commands/harvest.d.ts +29 -0
  18. package/dist/commands/harvest.js +72 -0
  19. package/dist/commands/judge.d.ts +11 -1
  20. package/dist/commands/judge.js +24 -4
  21. package/dist/commands/metrics.js +34 -2
  22. package/dist/commands/quality.d.ts +38 -0
  23. package/dist/commands/quality.js +105 -0
  24. package/dist/commands/session.d.ts +20 -0
  25. package/dist/commands/session.js +51 -0
  26. package/dist/commands/simulate.d.ts +1 -0
  27. package/dist/commands/simulate.js +7 -2
  28. package/dist/commands/standing-allow.d.ts +10 -0
  29. package/dist/commands/standing-allow.js +26 -0
  30. package/dist/commands/tui.d.ts +48 -0
  31. package/dist/commands/tui.js +150 -0
  32. package/dist/config-io.js +59 -17
  33. package/dist/conformance/guarantee-posture.d.ts +21 -0
  34. package/dist/conformance/guarantee-posture.js +46 -0
  35. package/dist/conformance/guarantee-table.d.ts +1 -0
  36. package/dist/conformance/guarantee-table.js +14 -9
  37. package/dist/core/approval-replay-cli.d.ts +7 -0
  38. package/dist/core/approval-replay-cli.js +36 -0
  39. package/dist/core/approval-replay.d.ts +45 -0
  40. package/dist/core/approval-replay.js +141 -0
  41. package/dist/core/approval-service.d.ts +15 -0
  42. package/dist/core/approval-service.js +53 -4
  43. package/dist/core/approval.d.ts +26 -3
  44. package/dist/core/approval.js +61 -7
  45. package/dist/core/audit-analysis.d.ts +7 -1
  46. package/dist/core/audit-analysis.js +111 -0
  47. package/dist/core/audit-metrics.d.ts +7 -0
  48. package/dist/core/audit-metrics.js +24 -4
  49. package/dist/core/audit-query.d.ts +1 -0
  50. package/dist/core/audit-query.js +3 -0
  51. package/dist/core/audit-replay-context.d.ts +35 -0
  52. package/dist/core/audit-replay-context.js +88 -0
  53. package/dist/core/audit-types.d.ts +24 -1
  54. package/dist/core/audit-types.js +1 -1
  55. package/dist/core/capability/approval-state-mutation.d.ts +13 -0
  56. package/dist/core/capability/approval-state-mutation.js +92 -0
  57. package/dist/core/capability/approval-v3.d.ts +15 -0
  58. package/dist/core/capability/approval-v3.js +74 -0
  59. package/dist/core/capability/attestation.d.ts +13 -0
  60. package/dist/core/capability/attestation.js +55 -0
  61. package/dist/core/capability/boundary-attestation-sign.d.ts +21 -0
  62. package/dist/core/capability/boundary-attestation-sign.js +84 -0
  63. package/dist/core/capability/boundary-driver-container.d.ts +7 -0
  64. package/dist/core/capability/boundary-driver-container.js +122 -0
  65. package/dist/core/capability/boundary-driver.d.ts +29 -0
  66. package/dist/core/capability/boundary-driver.js +43 -0
  67. package/dist/core/capability/boundary-egress.d.ts +21 -0
  68. package/dist/core/capability/boundary-egress.js +109 -0
  69. package/dist/core/capability/boundary-grant-materialize.d.ts +13 -0
  70. package/dist/core/capability/boundary-grant-materialize.js +78 -0
  71. package/dist/core/capability/boundary-profile.d.ts +15 -0
  72. package/dist/core/capability/boundary-profile.js +25 -0
  73. package/dist/core/capability/boundary-run.d.ts +23 -0
  74. package/dist/core/capability/boundary-run.js +23 -0
  75. package/dist/core/capability/boundary-session.d.ts +57 -0
  76. package/dist/core/capability/boundary-session.js +129 -0
  77. package/dist/core/capability/capability-request-hash.d.ts +2 -0
  78. package/dist/core/capability/capability-request-hash.js +8 -0
  79. package/dist/core/capability/gate-latency-ratchet.d.ts +7 -0
  80. package/dist/core/capability/gate-latency-ratchet.js +18 -0
  81. package/dist/core/capability/gate-policy-shadow.d.ts +25 -0
  82. package/dist/core/capability/gate-policy-shadow.js +108 -0
  83. package/dist/core/capability/gate-shadow-audit.d.ts +1 -0
  84. package/dist/core/capability/gate-shadow-audit.js +1 -0
  85. package/dist/core/capability/gate-shadow-ratchet.d.ts +14 -0
  86. package/dist/core/capability/gate-shadow-ratchet.js +81 -0
  87. package/dist/core/capability/grant-lease.d.ts +9 -0
  88. package/dist/core/capability/grant-lease.js +46 -0
  89. package/dist/core/capability/grant-loader.d.ts +12 -0
  90. package/dist/core/capability/grant-loader.js +23 -0
  91. package/dist/core/capability/grant-match.d.ts +6 -0
  92. package/dist/core/capability/grant-match.js +93 -0
  93. package/dist/core/capability/grant.d.ts +16 -0
  94. package/dist/core/capability/grant.js +16 -0
  95. package/dist/core/capability/index.d.ts +10 -1
  96. package/dist/core/capability/index.js +8 -0
  97. package/dist/core/capability/limits.d.ts +7 -0
  98. package/dist/core/capability/limits.js +55 -0
  99. package/dist/core/capability/paths.d.ts +2 -2
  100. package/dist/core/capability/paths.js +9 -9
  101. package/dist/core/capability/policy-bridge.d.ts +18 -0
  102. package/dist/core/capability/policy-bridge.js +51 -0
  103. package/dist/core/capability/policy-engine.d.ts +70 -0
  104. package/dist/core/capability/policy-engine.js +476 -0
  105. package/dist/core/capability/policy-types.d.ts +20 -0
  106. package/dist/core/capability/policy-types.js +1 -0
  107. package/dist/core/capability/request.d.ts +45 -0
  108. package/dist/core/capability/request.js +1 -0
  109. package/dist/core/capability/resolver.d.ts +4 -0
  110. package/dist/core/capability/resolver.js +4 -0
  111. package/dist/core/capability/trusted-workspace-roots.d.ts +25 -0
  112. package/dist/core/capability/trusted-workspace-roots.js +149 -0
  113. package/dist/core/capability/types.d.ts +11 -1
  114. package/dist/core/capability-approval.d.ts +2 -1
  115. package/dist/core/capability-approval.js +100 -2
  116. package/dist/core/classify-subagent.d.ts +2 -1
  117. package/dist/core/classify-subagent.js +40 -22
  118. package/dist/core/classify-tool.js +157 -64
  119. package/dist/core/config.d.ts +32 -3
  120. package/dist/core/config.js +105 -3
  121. package/dist/core/gate-contract.d.ts +3 -0
  122. package/dist/core/gate-contract.js +3 -0
  123. package/dist/core/gate-engine.js +12 -7
  124. package/dist/core/harvest.d.ts +53 -0
  125. package/dist/core/harvest.js +276 -0
  126. package/dist/core/index.d.ts +9 -3
  127. package/dist/core/index.js +6 -2
  128. package/dist/core/judge-doctor.d.ts +3 -0
  129. package/dist/core/judge-doctor.js +90 -11
  130. package/dist/core/judge-fallback-hints.d.ts +13 -0
  131. package/dist/core/judge-fallback-hints.js +108 -0
  132. package/dist/core/path-utils.d.ts +12 -0
  133. package/dist/core/path-utils.js +60 -7
  134. package/dist/core/reclassify.d.ts +3 -0
  135. package/dist/core/reclassify.js +44 -14
  136. package/dist/core/recovery/capability.d.ts +3 -0
  137. package/dist/core/recovery/capability.js +22 -0
  138. package/dist/core/recovery/fail-closed.d.ts +6 -0
  139. package/dist/core/recovery/fail-closed.js +25 -0
  140. package/dist/core/recovery/index.d.ts +3 -0
  141. package/dist/core/recovery/index.js +2 -0
  142. package/dist/core/recovery/types.d.ts +20 -0
  143. package/dist/core/recovery/types.js +1 -0
  144. package/dist/core/replay-scrub.d.ts +9 -0
  145. package/dist/core/replay-scrub.js +43 -0
  146. package/dist/core/shell-tokenizer.d.ts +2 -0
  147. package/dist/core/shell-tokenizer.js +82 -23
  148. package/dist/core/standing-allow.d.ts +50 -0
  149. package/dist/core/standing-allow.js +178 -0
  150. package/dist/core/transactional/diff-evaluator.js +4 -1
  151. package/dist/core/transactional/eligibility.js +4 -0
  152. package/dist/core/transactional/git-worktree.d.ts +10 -3
  153. package/dist/core/transactional/git-worktree.js +81 -11
  154. package/dist/core/transactional/reasons.d.ts +1 -0
  155. package/dist/core/transactional/reasons.js +4 -0
  156. package/dist/core/transactional/runner.js +22 -6
  157. package/dist/core/transactional/types.d.ts +4 -0
  158. package/dist/core/types.d.ts +36 -3
  159. package/dist/core/verdict/adapter.d.ts +3 -4
  160. package/dist/core/verdict/adapter.js +19 -6
  161. package/dist/core/verdict/containment.d.ts +4 -3
  162. package/dist/core/verdict/containment.js +17 -12
  163. package/dist/core/verdict/cursor-acp-client.d.ts +67 -0
  164. package/dist/core/verdict/cursor-acp-client.js +345 -0
  165. package/dist/core/verdict/egress-classify.d.ts +2 -2
  166. package/dist/core/verdict/egress-classify.js +2 -2
  167. package/dist/core/verdict/git-classifier.d.ts +26 -0
  168. package/dist/core/verdict/git-classifier.js +533 -0
  169. package/dist/core/verdict/judge-audit.d.ts +1 -0
  170. package/dist/core/verdict/judge-audit.js +33 -1
  171. package/dist/core/verdict/judge-baseline.d.ts +20 -0
  172. package/dist/core/verdict/judge-baseline.js +49 -0
  173. package/dist/core/verdict/judge-broker-service.d.ts +42 -0
  174. package/dist/core/verdict/judge-broker-service.js +291 -0
  175. package/dist/core/verdict/judge-catalog.js +1 -0
  176. package/dist/core/verdict/judge-cli-fingerprint.d.ts +6 -0
  177. package/dist/core/verdict/judge-cli-fingerprint.js +67 -0
  178. package/dist/core/verdict/judge-cli.d.ts +23 -0
  179. package/dist/core/verdict/judge-cli.js +139 -16
  180. package/dist/core/verdict/judge-factory.js +13 -4
  181. package/dist/core/verdict/judge-provider-matrix.d.ts +20 -0
  182. package/dist/core/verdict/judge-provider-matrix.js +66 -0
  183. package/dist/core/verdict/judge-runtime-config.d.ts +44 -0
  184. package/dist/core/verdict/judge-runtime-config.js +96 -0
  185. package/dist/core/verdict/judge-session-broker.d.ts +48 -0
  186. package/dist/core/verdict/judge-session-broker.js +200 -0
  187. package/dist/core/verdict/judge-session-guard.d.ts +27 -0
  188. package/dist/core/verdict/judge-session-guard.js +91 -0
  189. package/dist/core/verdict/judge-session-kill-switch.d.ts +11 -0
  190. package/dist/core/verdict/judge-session-kill-switch.js +43 -0
  191. package/dist/core/verdict/judge-session-mutex.d.ts +9 -0
  192. package/dist/core/verdict/judge-session-mutex.js +23 -0
  193. package/dist/core/verdict/judge-shadow.d.ts +24 -0
  194. package/dist/core/verdict/judge-shadow.js +116 -0
  195. package/dist/core/verdict/judge-transport.d.ts +44 -0
  196. package/dist/core/verdict/judge-transport.js +268 -0
  197. package/dist/core/verdict/judge.d.ts +14 -14
  198. package/dist/core/verdict/judge.js +5 -67
  199. package/dist/core/verdict/launcher-resolve.d.ts +2 -0
  200. package/dist/core/verdict/launcher-resolve.js +16 -0
  201. package/dist/core/verdict/parser.js +6 -1
  202. package/dist/core/verdict/prescan.d.ts +15 -0
  203. package/dist/core/verdict/prescan.js +68 -0
  204. package/dist/core/verdict/shell-policy.d.ts +25 -0
  205. package/dist/core/verdict/shell-policy.js +40 -0
  206. package/dist/core/verdict/shell-semantics.d.ts +24 -0
  207. package/dist/core/verdict/shell-semantics.js +225 -0
  208. package/dist/core/verdict/types.d.ts +26 -1
  209. package/dist/core/verdict/verdict.js +300 -179
  210. package/dist/corpus/adversarial-probe.d.ts +86 -0
  211. package/dist/corpus/adversarial-probe.js +220 -0
  212. package/dist/corpus/evaluate.d.ts +45 -12
  213. package/dist/corpus/evaluate.js +61 -8
  214. package/dist/corpus/gate-latency-budget.d.ts +39 -0
  215. package/dist/corpus/gate-latency-budget.js +33 -0
  216. package/dist/corpus/gates.d.ts +35 -0
  217. package/dist/corpus/gates.js +81 -0
  218. package/dist/corpus/judge-accuracy.d.ts +8 -0
  219. package/dist/corpus/judge-accuracy.js +39 -0
  220. package/dist/corpus/must-allow-commands.d.ts +5 -0
  221. package/dist/corpus/must-allow-commands.js +13 -0
  222. package/dist/corpus/mutators.d.ts +28 -0
  223. package/dist/corpus/mutators.js +162 -0
  224. package/dist/corpus/ratchet.d.ts +42 -0
  225. package/dist/corpus/ratchet.js +116 -0
  226. package/dist/corpus/runtime-match.d.ts +19 -0
  227. package/dist/corpus/runtime-match.js +43 -0
  228. package/dist/corpus/standing-allow-catalog.generated.d.ts +13 -0
  229. package/dist/corpus/standing-allow-catalog.generated.js +99 -0
  230. package/dist/corpus/types.d.ts +47 -0
  231. package/dist/corpus/types.js +157 -0
  232. package/dist/installer.js +4 -1
  233. package/dist/judge-broker-daemon.d.ts +1 -0
  234. package/dist/judge-broker-daemon.js +137 -0
  235. package/dist/services/sandbox-service.d.ts +5 -0
  236. package/dist/services/sandbox-service.js +30 -2
  237. package/dist/types.d.ts +2 -2
  238. package/dist/version.d.ts +1 -1
  239. package/dist/version.js +1 -1
  240. package/package.json +7 -3
  241. package/skills/belay/SKILL.md +7 -1
  242. package/skills/belay/belay-approve.md +17 -0
@@ -1,11 +1,14 @@
1
1
  import path from 'node:path';
2
+ import { BOUNDARY_PROFILE_L3_L4_ONLY } from './capability/boundary-profile.js';
3
+ import { policyReasonToLegacyReason } from './capability/policy-bridge.js';
4
+ import { evaluateFileMutationPolicy, policyDecisionRequiresAsk, } from './capability/policy-engine.js';
2
5
  import { canonicalStringify, toolFingerprint } from './fingerprint.js';
3
6
  import { matchesSensitivePath } from './glob.js';
4
- import { pathWithinRoot, relativeWithinRepo } from './path-utils.js';
7
+ import { pathWithinRoot, resolveWorkspaceRootMatch } from './path-utils.js';
5
8
  import { scrubValue } from './scrub.js';
6
9
  import { classifyShell, resolveClassifierTrustedCwd } from './verdict/adapter.js';
7
- import { mutationPrescanRequiresAsk, tier1RequiresAsk } from './verdict/judge.js';
8
- import { createJudgeFromConfig } from './verdict/judge-factory.js';
10
+ import { isGitPath } from './verdict/containment.js';
11
+ import { mutationPrescanRequiresAsk } from './verdict/prescan.js';
9
12
  const DEFAULT_SENSITIVE_PATHS = ['.env', '.env.*', '**/credentials/**'];
10
13
  const FILE_WRITE_TOOL_NAMES = new Set(['write']);
11
14
  const FILE_EDIT_TOOL_NAMES = new Set([
@@ -18,6 +21,19 @@ const FILE_EDIT_TOOL_NAMES = new Set([
18
21
  ]);
19
22
  const FILE_DELETE_TOOL_NAMES = new Set(['delete']);
20
23
  const APPLY_PATCH_TOOL_NAMES = new Set(['apply_patch', 'applypatch']);
24
+ function policyAuth(options) {
25
+ if (!options.grants &&
26
+ options.attestation === undefined &&
27
+ options.egressProxyActive === undefined) {
28
+ return undefined;
29
+ }
30
+ return {
31
+ grants: options.grants,
32
+ attestation: options.attestation,
33
+ egressProxyActive: options.egressProxyActive,
34
+ sensitivePaths: options.sensitivePaths,
35
+ };
36
+ }
21
37
  function scrubPayload(value, options) {
22
38
  return scrubValue(value, options.scrubOptions);
23
39
  }
@@ -76,25 +92,40 @@ function applyPatchTargets(patch) {
76
92
  function normalizedToolName(toolName) {
77
93
  return toolName.trim().toLowerCase();
78
94
  }
79
- function resolveFileTier1Judge(config, options, repoRoot) {
80
- return options.tier1Judge ?? createJudgeFromConfig(config, { repoRoot });
81
- }
82
- async function classifyFileMutationWithTier1(params) {
83
- const judge = resolveFileTier1Judge(params.config, params.options, params.repoRoot);
95
+ function classifyFileMutationWithPolicy(params) {
84
96
  const trustedCwd = resolveClassifierTrustedCwd(params.cwd, params.options);
85
97
  const prescan = mutationPrescanRequiresAsk({
86
98
  targets: [params.filePath],
87
99
  cwd: params.cwd,
88
100
  repoRoot: params.repoRoot,
89
101
  trustedCwd,
102
+ trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
90
103
  sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths,
91
104
  });
92
105
  if (prescan) {
106
+ const fingerprint = toolFingerprint(params.toolName, { path: params.filePath }, params.repoRoot);
107
+ const { request, decision } = evaluateFileMutationPolicy({
108
+ hookKind: 'tool',
109
+ toolKind: params.toolKind,
110
+ filePath: params.filePath,
111
+ resolvedPath: params.resolvedPath,
112
+ repoRoot: params.repoRoot,
113
+ cwd: params.cwd,
114
+ inputFingerprint: fingerprint,
115
+ signals: [...params.signals, 'tier1_catastrophic', prescan.reason],
116
+ isDelete: params.isDelete,
117
+ locationLabel: params.locationLabel,
118
+ trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
119
+ sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths,
120
+ }, params.config, policyAuth(params.options));
121
+ const legacyReason = policyDecisionRequiresAsk(decision)
122
+ ? policyReasonToLegacyReason(decision)
123
+ : 'tier1_catastrophic';
93
124
  return {
94
125
  verdict: 'deny_pending_approval',
95
- reason: 'tier1_catastrophic',
126
+ reason: legacyReason,
96
127
  summary: params.filePath,
97
- fingerprint: toolFingerprint(params.toolName, { path: params.filePath }, params.repoRoot),
128
+ fingerprint,
98
129
  assessment: {
99
130
  reversibility: 'irreversible',
100
131
  external: params.locationLabel === 'outside_repo',
@@ -102,20 +133,32 @@ async function classifyFileMutationWithTier1(params) {
102
133
  ? 'outside the repository'
103
134
  : 'sensitive repository file',
104
135
  confidence: 0.95,
105
- signals: [...params.signals, 'tier1_catastrophic', prescan.reason],
136
+ signals: [...params.signals, 'tier1_catastrophic', prescan.reason, ...decision.signals],
106
137
  },
138
+ capabilityRequests: [request],
139
+ authorizationDecision: decision,
140
+ boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY,
107
141
  };
108
142
  }
109
- const tier1Text = `file_mutation: ${params.toolKind} path=${params.resolvedPath} location=${params.locationLabel}`;
110
- const tier1 = await judge.evaluate({
111
- text: tier1Text,
112
- context: { cwd: params.cwd, repoRoot: params.repoRoot },
113
- });
114
143
  const fingerprint = toolFingerprint(params.toolName, { path: params.filePath }, params.repoRoot);
115
- if (tier1RequiresAsk(tier1)) {
144
+ const { request, decision } = evaluateFileMutationPolicy({
145
+ hookKind: 'tool',
146
+ toolKind: params.toolKind,
147
+ filePath: params.filePath,
148
+ resolvedPath: params.resolvedPath,
149
+ repoRoot: params.repoRoot,
150
+ cwd: params.cwd,
151
+ inputFingerprint: fingerprint,
152
+ signals: params.signals,
153
+ isDelete: params.isDelete,
154
+ locationLabel: params.locationLabel,
155
+ trustedWorkspaceRoots: params.options.trustedWorkspaceRoots,
156
+ sensitivePaths: params.options.sensitivePaths ?? params.config.classifier.sensitivePaths,
157
+ }, params.config, policyAuth(params.options));
158
+ if (policyDecisionRequiresAsk(decision)) {
116
159
  return {
117
160
  verdict: 'deny_pending_approval',
118
- reason: 'tier1_catastrophic',
161
+ reason: policyReasonToLegacyReason(decision),
119
162
  summary: params.filePath,
120
163
  fingerprint,
121
164
  assessment: {
@@ -124,9 +167,12 @@ async function classifyFileMutationWithTier1(params) {
124
167
  blastRadius: params.locationLabel === 'outside_repo'
125
168
  ? 'outside the repository'
126
169
  : 'sensitive repository file',
127
- confidence: 0.82,
128
- signals: [...params.signals, 'tier1_catastrophic', tier1.reason],
170
+ confidence: 0.95,
171
+ signals: [...params.signals, ...decision.signals],
129
172
  },
173
+ capabilityRequests: [request],
174
+ authorizationDecision: decision,
175
+ boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY,
130
176
  };
131
177
  }
132
178
  const reason = params.isDelete ? 'file_delete' : 'file_mutation';
@@ -140,8 +186,11 @@ async function classifyFileMutationWithTier1(params) {
140
186
  external: params.locationLabel === 'outside_repo',
141
187
  blastRadius: params.locationLabel === 'outside_repo' ? 'outside the repository' : 'this repository',
142
188
  confidence: 0.72,
143
- signals: [...params.signals, 'tier1_restorable', tier1.reason],
189
+ signals: [...params.signals, ...decision.signals],
144
190
  },
191
+ capabilityRequests: [request],
192
+ authorizationDecision: decision,
193
+ boundaryProfile: params.options.boundaryProfile ?? BOUNDARY_PROFILE_L3_L4_ONLY,
145
194
  };
146
195
  }
147
196
  export async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
@@ -229,24 +278,24 @@ export async function classifyToolUse(payload, repoRoot, cwd, config, options =
229
278
  const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
230
279
  if (hitsProtectedRoot) {
231
280
  signals.push('control_plane_path');
232
- return {
233
- verdict: 'deny_pending_approval',
234
- reason: 'control_plane_mutation',
235
- summary: filePath,
236
- fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
237
- assessment: {
238
- reversibility: 'irreversible',
239
- external: false,
240
- blastRadius: 'agent-belay control plane',
241
- confidence: 0.97,
242
- signals,
243
- },
244
- };
281
+ return classifyFileMutationWithPolicy({
282
+ toolName,
283
+ toolKind,
284
+ filePath,
285
+ resolvedPath,
286
+ repoRoot,
287
+ cwd,
288
+ config,
289
+ options,
290
+ signals,
291
+ isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
292
+ locationLabel: 'control_plane',
293
+ });
245
294
  }
246
- const relativePath = relativeWithinRepo(repoRoot, resolvedPath);
247
- if (relativePath === null) {
295
+ const workspaceMatch = resolveWorkspaceRootMatch(repoRoot, options.trustedWorkspaceRoots, resolvedPath);
296
+ if (workspaceMatch === null) {
248
297
  signals.push('outside_repo_path');
249
- return classifyFileMutationWithTier1({
298
+ return classifyFileMutationWithPolicy({
250
299
  toolName,
251
300
  toolKind,
252
301
  filePath,
@@ -260,9 +309,37 @@ export async function classifyToolUse(payload, repoRoot, cwd, config, options =
260
309
  locationLabel: 'outside_repo',
261
310
  });
262
311
  }
312
+ if (workspaceMatch.kind === 'trusted') {
313
+ signals.push('trusted_workspace_root');
314
+ }
315
+ const trustedCwd = resolveClassifierTrustedCwd(cwd, options);
316
+ const workspacePrescan = mutationPrescanRequiresAsk({
317
+ targets: [filePath],
318
+ cwd,
319
+ repoRoot,
320
+ trustedCwd,
321
+ trustedWorkspaceRoots: options.trustedWorkspaceRoots,
322
+ sensitivePaths,
323
+ });
324
+ if (workspacePrescan) {
325
+ return classifyFileMutationWithPolicy({
326
+ toolName,
327
+ toolKind,
328
+ filePath,
329
+ resolvedPath,
330
+ repoRoot,
331
+ cwd,
332
+ config,
333
+ options,
334
+ signals,
335
+ isDelete: FILE_DELETE_TOOL_NAMES.has(toolKind),
336
+ locationLabel: 'sensitive_path',
337
+ });
338
+ }
339
+ const relativePath = workspaceMatch.relativePath;
263
340
  if (matchesSensitivePath(relativePath, sensitivePaths)) {
264
341
  signals.push('sensitive_path');
265
- return classifyFileMutationWithTier1({
342
+ return classifyFileMutationWithPolicy({
266
343
  toolName,
267
344
  toolKind,
268
345
  filePath,
@@ -277,35 +354,51 @@ export async function classifyToolUse(payload, repoRoot, cwd, config, options =
277
354
  });
278
355
  }
279
356
  if (FILE_DELETE_TOOL_NAMES.has(toolKind)) {
280
- signals.push('file_delete');
281
- return {
282
- verdict: 'allow_flagged',
283
- reason: 'file_delete',
284
- summary: filePath,
285
- fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
286
- assessment: {
287
- reversibility: 'recoverable_with_cost',
288
- external: false,
289
- blastRadius: 'this repository',
290
- confidence: 0.7,
357
+ if (isGitPath(resolvedPath, repoRoot)) {
358
+ signals.push('protected_artifact');
359
+ return classifyFileMutationWithPolicy({
360
+ toolName,
361
+ toolKind,
362
+ filePath,
363
+ resolvedPath,
364
+ repoRoot,
365
+ cwd,
366
+ config,
367
+ options,
291
368
  signals,
292
- },
293
- };
369
+ isDelete: true,
370
+ locationLabel: 'sensitive_path',
371
+ });
372
+ }
373
+ signals.push('file_delete');
374
+ return classifyFileMutationWithPolicy({
375
+ toolName,
376
+ toolKind,
377
+ filePath,
378
+ resolvedPath,
379
+ repoRoot,
380
+ cwd,
381
+ config,
382
+ options,
383
+ signals,
384
+ isDelete: true,
385
+ locationLabel: 'repo_local',
386
+ });
294
387
  }
295
388
  signals.push('file_mutation');
296
- return {
297
- verdict: 'allow_flagged',
298
- reason: 'file_mutation',
299
- summary: filePath,
300
- fingerprint: toolFingerprint(toolName, { path: filePath }, repoRoot),
301
- assessment: {
302
- reversibility: 'recoverable_with_cost',
303
- external: false,
304
- blastRadius: 'this repository',
305
- confidence: 0.68,
306
- signals,
307
- },
308
- };
389
+ return classifyFileMutationWithPolicy({
390
+ toolName,
391
+ toolKind,
392
+ filePath,
393
+ resolvedPath,
394
+ repoRoot,
395
+ cwd,
396
+ config,
397
+ options,
398
+ signals,
399
+ isDelete: false,
400
+ locationLabel: 'repo_local',
401
+ });
309
402
  }
310
403
  if (APPLY_PATCH_TOOL_NAMES.has(toolKind)) {
311
404
  const patch = extractPatch(payload);
@@ -1,5 +1,6 @@
1
- import type { ClassifierOptions, ControlPlaneIntegrity, ScrubOptions, UnknownLocalEffectPolicy, UnparseableShellPolicy } from './types.js';
2
- export type BelayMode = 'enforce' | 'audit';
1
+ import type { BoundaryDriverId } from './capability/attestation.js';
2
+ import type { BelayMode, ClassifierOptions, ControlPlaneIntegrity, ScrubOptions, UnknownLocalEffectPolicy, UnparseableShellPolicy } from './types.js';
3
+ import { type BelayJudgeRuntimeConfig } from './verdict/judge-runtime-config.js';
3
4
  export type { UnknownLocalEffectPolicy };
4
5
  export interface BelayConfigV1 {
5
6
  version: 1;
@@ -93,7 +94,10 @@ export interface JudgeCloudConsent {
93
94
  endpoint: string;
94
95
  by: string;
95
96
  }
97
+ export type BelayJudgeMode = 'shadow' | 'off';
96
98
  export interface BelayJudgeConfig {
99
+ /** Gate uses PolicyEngine; judge runs async shadow/compare only. */
100
+ mode?: BelayJudgeMode;
97
101
  provider: JudgeProvider;
98
102
  providerId?: JudgeProviderId | DeprecatedJudgeProviderId;
99
103
  model: string;
@@ -102,6 +106,7 @@ export interface BelayJudgeConfig {
102
106
  keepAlive: string | null;
103
107
  cloudConsent?: JudgeCloudConsent;
104
108
  credential?: JudgeCredentialConfig;
109
+ runtime?: BelayJudgeRuntimeConfig;
105
110
  }
106
111
  export declare const DEFAULT_JUDGE_LOCAL_OLLAMA: BelayJudgeConfig;
107
112
  export declare const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE: BelayJudgeConfig;
@@ -137,6 +142,17 @@ export interface BelayApprovalSigningConfig {
137
142
  /** When true, out-of-band approvals must present a signed token. */
138
143
  required: boolean;
139
144
  }
145
+ export type ApprovalFlow = 'one_step' | 'two_step';
146
+ export interface BelayApprovalAutoReplayScopes {
147
+ shell: boolean;
148
+ tool: boolean;
149
+ subagent: boolean;
150
+ }
151
+ export interface BelayApprovalConfig {
152
+ flow: ApprovalFlow;
153
+ autoReplayScopes: BelayApprovalAutoReplayScopes;
154
+ executionLeaseMs: number;
155
+ }
140
156
  export interface BelayEgressConfig {
141
157
  enabled: boolean;
142
158
  listenHost: string;
@@ -144,8 +160,14 @@ export interface BelayEgressConfig {
144
160
  /** When true with egress enabled, L3 external command lists become hints only. */
145
161
  demoteL3External: boolean;
146
162
  }
163
+ export interface BelayCapabilityConfig {
164
+ grantsEnabled?: boolean;
165
+ boundaryDriver?: BoundaryDriverId;
166
+ attestationRelPath?: string;
167
+ }
168
+ export declare const DEFAULT_CAPABILITY_V5: BelayCapabilityConfig;
147
169
  export interface BelayConfigV4 {
148
- version: 4;
170
+ version: 4 | 5;
149
171
  adapter?: 'cursor' | 'claude' | 'codex';
150
172
  /** Where hooks/runtime/skill artifacts are installed. Defaults to project. */
151
173
  installScope?: 'project' | 'global';
@@ -160,10 +182,12 @@ export interface BelayConfigV4 {
160
182
  controlPlane: BelayControlPlaneConfig;
161
183
  notifications: BelayNotificationsConfig;
162
184
  approvalSigning: BelayApprovalSigningConfig;
185
+ approval: BelayApprovalConfig;
163
186
  egress: BelayEgressConfig;
164
187
  sandbox: BelaySandboxConfig;
165
188
  audit: BelayConfigV2['audit'];
166
189
  judge: BelayJudgeConfig;
190
+ capability?: BelayCapabilityConfig;
167
191
  }
168
192
  /** @deprecated Use BelayConfigV4 */
169
193
  export type BelayConfigV3 = BelayConfigV4;
@@ -184,6 +208,7 @@ export declare const DEFAULT_CONTROL_PLANE_V3: BelayControlPlaneConfig;
184
208
  export declare const DEFAULT_SANDBOX_V3: BelaySandboxConfig;
185
209
  export declare const DEFAULT_NOTIFICATIONS_V3: BelayNotificationsConfig;
186
210
  export declare const DEFAULT_APPROVAL_SIGNING_V3: BelayApprovalSigningConfig;
211
+ export declare const DEFAULT_APPROVAL_CONFIG: BelayApprovalConfig;
187
212
  export declare const DEFAULT_EGRESS_V3: BelayEgressConfig;
188
213
  export declare function normalizeEgressListenHost(host: string): string;
189
214
  export declare const DEFAULT_CONFIG_V2: BelayConfigV2;
@@ -217,10 +242,14 @@ type RawConfigInput = Partial<{
217
242
  controlPlane: Partial<BelayControlPlaneConfig>;
218
243
  notifications: Partial<BelayNotificationsConfig>;
219
244
  approvalSigning: Partial<BelayApprovalSigningConfig>;
245
+ approval: Partial<BelayApprovalConfig> & {
246
+ autoReplayScopes?: Partial<BelayApprovalAutoReplayScopes>;
247
+ };
220
248
  egress: Partial<BelayEgressConfig>;
221
249
  sandbox: Partial<BelaySandboxConfig>;
222
250
  audit: Partial<BelayConfigV2['audit']>;
223
251
  installScope: 'project' | 'global';
252
+ capability: Partial<BelayCapabilityConfig>;
224
253
  }>;
225
254
  export declare function migrateConfig(loaded: unknown): BelayConfigV4;
226
255
  export declare function normalizeConfigV2(config: BelayConfigV2): BelayConfigV2;
@@ -1,7 +1,9 @@
1
1
  import path from 'node:path';
2
2
  import { warnDeprecatedJudgeModelAuto } from './judge-model-policy.js';
3
3
  import { getJudgeProviderSpec, inferProviderIdFromConfig, isRemovedProviderId, normalizeLegacyProviderId, warnRemovedProviderId, } from './verdict/judge-catalog.js';
4
+ import { normalizeJudgeRuntimeConfig, } from './verdict/judge-runtime-config.js';
4
5
  export const DEFAULT_JUDGE_LOCAL_OLLAMA = {
6
+ mode: 'shadow',
5
7
  provider: 'ollama',
6
8
  providerId: 'ollama',
7
9
  model: 'gemma4:e2b',
@@ -10,6 +12,7 @@ export const DEFAULT_JUDGE_LOCAL_OLLAMA = {
10
12
  keepAlive: '30m',
11
13
  };
12
14
  export const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE = {
15
+ mode: 'shadow',
13
16
  provider: 'openai-compatible',
14
17
  providerId: 'codex',
15
18
  model: 'gpt-5.3-codex-high',
@@ -19,6 +22,23 @@ export const DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE = {
19
22
  };
20
23
  /** @deprecated Use DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE */
21
24
  export const DEFAULT_JUDGE_CURSOR_COMPOSER = DEFAULT_JUDGE_OPENAI_COMPATIBLE_TEMPLATE;
25
+ export const DEFAULT_CAPABILITY_V5 = {
26
+ grantsEnabled: true,
27
+ boundaryDriver: 'host-integration',
28
+ attestationRelPath: '.belay/attestation.json',
29
+ };
30
+ function normalizeCapabilityConfig(capability) {
31
+ if (!capability) {
32
+ return undefined;
33
+ }
34
+ return {
35
+ ...DEFAULT_CAPABILITY_V5,
36
+ ...capability,
37
+ grantsEnabled: capability.grantsEnabled !== false,
38
+ boundaryDriver: capability.boundaryDriver ?? DEFAULT_CAPABILITY_V5.boundaryDriver,
39
+ attestationRelPath: capability.attestationRelPath ?? DEFAULT_CAPABILITY_V5.attestationRelPath,
40
+ };
41
+ }
22
42
  /** Pre-v0.4 defaults preserved when migrating existing v1/v2/v3 configs. */
23
43
  import { DEFAULT_SILENT_PASS_THRESHOLD } from './audit-summary.js';
24
44
  /** @deprecated Use DEFAULT_SILENT_PASS_THRESHOLD from audit-summary.js */
@@ -95,6 +115,15 @@ export const DEFAULT_NOTIFICATIONS_V3 = {};
95
115
  export const DEFAULT_APPROVAL_SIGNING_V3 = {
96
116
  required: false,
97
117
  };
118
+ export const DEFAULT_APPROVAL_CONFIG = {
119
+ flow: 'one_step',
120
+ autoReplayScopes: {
121
+ shell: true,
122
+ tool: false,
123
+ subagent: false,
124
+ },
125
+ executionLeaseMs: 60_000,
126
+ };
98
127
  export const DEFAULT_EGRESS_V3 = {
99
128
  enabled: false,
100
129
  listenHost: '127.0.0.1',
@@ -148,6 +177,7 @@ export const DEFAULT_CONFIG_V4 = {
148
177
  controlPlane: { ...DEFAULT_CONTROL_PLANE_V3 },
149
178
  notifications: { ...DEFAULT_NOTIFICATIONS_V3 },
150
179
  approvalSigning: { ...DEFAULT_APPROVAL_SIGNING_V3 },
180
+ approval: { ...DEFAULT_APPROVAL_CONFIG },
151
181
  egress: { ...DEFAULT_EGRESS_V3 },
152
182
  sandbox: { ...DEFAULT_SANDBOX_V3 },
153
183
  audit: { ...DEFAULT_CONFIG_V2.audit },
@@ -190,6 +220,7 @@ export function migrateV2ToV3(v2, rawOverrides) {
190
220
  controlPlane: { ...LEGACY_CONTROL_PLANE_V3 },
191
221
  notifications: { ...DEFAULT_NOTIFICATIONS_V3 },
192
222
  approvalSigning: { ...DEFAULT_APPROVAL_SIGNING_V3 },
223
+ approval: { ...DEFAULT_APPROVAL_CONFIG },
193
224
  egress: { ...DEFAULT_EGRESS_V3 },
194
225
  sandbox: { ...DEFAULT_SANDBOX_V3 },
195
226
  audit: v2.audit,
@@ -210,7 +241,8 @@ export function isConfigV3(value) {
210
241
  return version === 3 || version === 4;
211
242
  }
212
243
  export function isConfigV4(value) {
213
- return typeof value === 'object' && value !== null && value.version === 4;
244
+ const version = typeof value === 'object' && value !== null ? value.version : null;
245
+ return version === 4 || version === 5;
214
246
  }
215
247
  export function normalizeJudgeProvider(provider) {
216
248
  if (provider === 'anthropic') {
@@ -227,6 +259,7 @@ function defaultJudgeTemplateForProvider(provider) {
227
259
  }
228
260
  if (provider === 'anthropic') {
229
261
  return {
262
+ mode: 'shadow',
230
263
  provider: 'anthropic',
231
264
  providerId: 'claude',
232
265
  model: 'claude-sonnet-4-6',
@@ -271,6 +304,7 @@ export function normalizeJudgeConfig(judge) {
271
304
  const timeoutMs = typeof judge.timeoutMs === 'number' && judge.timeoutMs > 0 ? judge.timeoutMs : base.timeoutMs;
272
305
  const endpoint = typeof judge.endpoint === 'string' && judge.endpoint.trim() ? judge.endpoint.trim() : null;
273
306
  return {
307
+ mode: judge.mode === 'off' ? 'off' : 'shadow',
274
308
  provider,
275
309
  providerId: rawProviderId,
276
310
  model,
@@ -283,6 +317,7 @@ export function normalizeJudgeConfig(judge) {
283
317
  : null,
284
318
  ...(judge.cloudConsent ? { cloudConsent: judge.cloudConsent } : {}),
285
319
  ...(judge.credential ? { credential: judge.credential } : {}),
320
+ runtime: normalizeJudgeRuntimeConfig(judge.runtime),
286
321
  };
287
322
  }
288
323
  let providerId = rawProviderId && normalizeLegacyProviderId(rawProviderId)
@@ -307,6 +342,7 @@ export function normalizeJudgeConfig(judge) {
307
342
  endpoint = catalogSpec.defaultEndpoint;
308
343
  }
309
344
  const normalized = {
345
+ mode: judge.mode === 'off' ? 'off' : 'shadow',
310
346
  provider,
311
347
  providerId,
312
348
  model,
@@ -333,6 +369,7 @@ export function normalizeJudgeConfig(judge) {
333
369
  ...(judge.credential.ref ? { ref: judge.credential.ref } : {}),
334
370
  };
335
371
  }
372
+ normalized.runtime = normalizeJudgeRuntimeConfig(judge.runtime);
336
373
  return normalized;
337
374
  }
338
375
  export function rejectTeamLayerJudgeSecrets(judge, source) {
@@ -395,6 +432,14 @@ function mergeV3FromRaw(base, raw) {
395
432
  ...base.approvalSigning,
396
433
  ...(raw.approvalSigning ?? {}),
397
434
  },
435
+ approval: {
436
+ ...base.approval,
437
+ ...(raw.approval ?? {}),
438
+ autoReplayScopes: {
439
+ ...base.approval.autoReplayScopes,
440
+ ...(raw.approval?.autoReplayScopes ?? {}),
441
+ },
442
+ },
398
443
  egress: {
399
444
  ...base.egress,
400
445
  ...(raw.egress ?? {}),
@@ -446,6 +491,14 @@ function normalizeV3Raw(raw) {
446
491
  approvalSigning: {
447
492
  required: raw.approvalSigning?.required === true,
448
493
  },
494
+ approval: {
495
+ ...DEFAULT_APPROVAL_CONFIG,
496
+ ...(raw.approval ?? {}),
497
+ autoReplayScopes: {
498
+ ...DEFAULT_APPROVAL_CONFIG.autoReplayScopes,
499
+ ...(raw.approval?.autoReplayScopes ?? {}),
500
+ },
501
+ },
449
502
  egress: {
450
503
  ...DEFAULT_EGRESS_V3,
451
504
  ...(raw.egress ?? {}),
@@ -460,6 +513,19 @@ function normalizeV3Raw(raw) {
460
513
  },
461
514
  });
462
515
  }
516
+ function normalizeV5Raw(raw) {
517
+ const base = normalizeV3Raw({ ...raw, version: 4 });
518
+ return {
519
+ ...base,
520
+ version: 5,
521
+ capability: {
522
+ grantsEnabled: raw.capability?.grantsEnabled !== false,
523
+ boundaryDriver: raw.capability?.boundaryDriver ?? 'host-integration',
524
+ attestationRelPath: raw.capability?.attestationRelPath ?? '.belay/attestation.json',
525
+ ...(raw.capability ?? {}),
526
+ },
527
+ };
528
+ }
463
529
  export function migrateConfig(loaded) {
464
530
  if (typeof loaded !== 'object' || loaded === null) {
465
531
  return { ...DEFAULT_CONFIG_V4 };
@@ -468,6 +534,9 @@ export function migrateConfig(loaded) {
468
534
  if (raw.version === 4) {
469
535
  return normalizeV3Raw(raw);
470
536
  }
537
+ if (raw.version === 5) {
538
+ return normalizeV5Raw(raw);
539
+ }
471
540
  if (raw.version === 3 || (raw.version === undefined && hasV3Sections(raw))) {
472
541
  return normalizeV3Raw(raw);
473
542
  }
@@ -546,8 +615,9 @@ export function normalizeConfig(config) {
546
615
  return normalizeConfigV2(config);
547
616
  }
548
617
  const v4 = config;
549
- return {
550
- version: 4,
618
+ const version = v4.version === 5 ? 5 : 4;
619
+ const normalized = {
620
+ version,
551
621
  ...(v4.installScope === 'global' || v4.installScope === 'project'
552
622
  ? { installScope: v4.installScope }
553
623
  : {}),
@@ -676,6 +746,17 @@ export function normalizeConfig(config) {
676
746
  approvalSigning: {
677
747
  required: v4.approvalSigning?.required === true,
678
748
  },
749
+ approval: {
750
+ flow: v4.approval?.flow === 'two_step' ? 'two_step' : DEFAULT_APPROVAL_CONFIG.flow,
751
+ autoReplayScopes: {
752
+ shell: v4.approval?.autoReplayScopes?.shell !== false,
753
+ tool: v4.approval?.autoReplayScopes?.tool === true,
754
+ subagent: v4.approval?.autoReplayScopes?.subagent === true,
755
+ },
756
+ executionLeaseMs: typeof v4.approval?.executionLeaseMs === 'number' && v4.approval.executionLeaseMs > 0
757
+ ? v4.approval.executionLeaseMs
758
+ : DEFAULT_APPROVAL_CONFIG.executionLeaseMs,
759
+ },
679
760
  egress: {
680
761
  enabled: v4.egress?.enabled === true,
681
762
  listenHost: normalizeEgressListenHost(typeof v4.egress?.listenHost === 'string' && v4.egress.listenHost.trim()
@@ -702,6 +783,10 @@ export function normalizeConfig(config) {
702
783
  },
703
784
  judge: normalizeJudgeConfig(v4.judge ?? DEFAULT_JUDGE_LOCAL_OLLAMA),
704
785
  };
786
+ if (version === 5 || v4.capability) {
787
+ normalized.capability = normalizeCapabilityConfig(v4.capability ?? DEFAULT_CAPABILITY_V5);
788
+ }
789
+ return normalized;
705
790
  }
706
791
  export function isFreshConfigInput(loaded) {
707
792
  if (loaded === null || loaded === undefined) {
@@ -752,6 +837,14 @@ export function mergeConfig(existing, defaults = DEFAULT_CONFIG_V4) {
752
837
  ...defaults.approvalSigning,
753
838
  ...migrated.approvalSigning,
754
839
  },
840
+ approval: {
841
+ ...defaults.approval,
842
+ ...migrated.approval,
843
+ autoReplayScopes: {
844
+ ...defaults.approval.autoReplayScopes,
845
+ ...migrated.approval.autoReplayScopes,
846
+ },
847
+ },
755
848
  egress: {
756
849
  ...defaults.egress,
757
850
  ...migrated.egress,
@@ -765,6 +858,15 @@ export function mergeConfig(existing, defaults = DEFAULT_CONFIG_V4) {
765
858
  ...migrated.audit,
766
859
  },
767
860
  ...(migrated.installScope ? { installScope: migrated.installScope } : {}),
861
+ ...(migrated.version === 5 || migrated.capability
862
+ ? {
863
+ version: migrated.version === 5 ? 5 : 4,
864
+ capability: normalizeCapabilityConfig({
865
+ ...DEFAULT_CAPABILITY_V5,
866
+ ...migrated.capability,
867
+ }),
868
+ }
869
+ : {}),
768
870
  });
769
871
  }
770
872
  export function scrubOptionsFromConfig(config) {
@@ -29,6 +29,9 @@ export interface GateVerdict extends GatePermissionResponse {
29
29
  wouldBlock: boolean;
30
30
  mode: 'enforce' | 'audit';
31
31
  axes?: ClassifyResult['axes'];
32
+ capabilityRequests?: ClassifyResult['capabilityRequests'];
33
+ authorizationDecision?: ClassifyResult['authorizationDecision'];
34
+ boundaryProfile?: string;
32
35
  }
33
36
  export declare function isGatedAction(value: unknown): value is GatedAction;
34
37
  export declare function classifyResultToGateVerdict(params: {
@@ -26,6 +26,9 @@ export function classifyResultToGateVerdict(params) {
26
26
  user_message,
27
27
  agent_message,
28
28
  axes: result.axes,
29
+ capabilityRequests: result.capabilityRequests,
30
+ authorizationDecision: result.authorizationDecision,
31
+ boundaryProfile: result.boundaryProfile,
29
32
  };
30
33
  }
31
34
  export function unnormalizedGateVerdict(params) {