@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
package/dist/cli.js CHANGED
@@ -6,11 +6,15 @@ import { auditProject, formatAuditReport } from './commands/audit.js';
6
6
  import { doctorProject, formatDoctorReport } from './commands/doctor.js';
7
7
  import { dogfoodProject, formatDogfoodResult } from './commands/dogfood.js';
8
8
  import { explainCommand, formatExplainReport } from './commands/explain.js';
9
+ import { formatHarvestReport, harvestApplyProject, harvestListProject } from './commands/harvest.js';
9
10
  import { formatMetricsReport, metricsProject } from './commands/metrics.js';
11
+ import { formatQualityReport, qualityCheck } from './commands/quality.js';
10
12
  import { formatRecoverReport, recoverProject } from './commands/recover.js';
11
13
  import { formatReport, reportProject } from './commands/report.js';
12
14
  import { revokeApproval } from './commands/revoke.js';
15
+ import { formatSessionStatusReport, sessionStartProject, sessionStatusProject, } from './commands/session.js';
13
16
  import { formatSimulateReport, simulateProject } from './commands/simulate.js';
17
+ import { revokeStandingAllow } from './commands/standing-allow.js';
14
18
  import { formatStatusReport, statusProject } from './commands/status.js';
15
19
  import { loadConfigFile } from './config-io.js';
16
20
  import { rejectDeprecatedJudgeModelAuto } from './core/judge-model-policy.js';
@@ -154,6 +158,13 @@ function parseArgs(argv) {
154
158
  index += 1;
155
159
  continue;
156
160
  }
161
+ if (token === '--live-probe') {
162
+ if (command !== 'judge') {
163
+ throw new Error('--live-probe is only valid for judge test.');
164
+ }
165
+ options.judgeLiveProbe = true;
166
+ continue;
167
+ }
157
168
  if (token === '--json') {
158
169
  options.json = true;
159
170
  continue;
@@ -178,6 +189,24 @@ function parseArgs(argv) {
178
189
  index += 1;
179
190
  continue;
180
191
  }
192
+ if (token === '--outcome') {
193
+ const next = rest[index + 1];
194
+ if (!next || !['provably-benign', 'accepted-benign', 'reject'].includes(next)) {
195
+ throw new Error('--outcome requires provably-benign, accepted-benign, or reject.');
196
+ }
197
+ options.harvestOutcome = next;
198
+ index += 1;
199
+ continue;
200
+ }
201
+ if (token === '--corpus') {
202
+ const next = rest[index + 1];
203
+ if (!next) {
204
+ throw new Error('--corpus requires a path.');
205
+ }
206
+ options.corpusPath = next;
207
+ index += 1;
208
+ continue;
209
+ }
181
210
  if (token === '--kind') {
182
211
  const next = rest[index + 1];
183
212
  if (!next) {
@@ -252,11 +281,18 @@ function parseArgs(argv) {
252
281
  index += 1;
253
282
  continue;
254
283
  }
284
+ if (token === '--replay') {
285
+ if (command !== 'approve') {
286
+ throw new Error('--replay is only valid for approve.');
287
+ }
288
+ options.approveReplay = true;
289
+ continue;
290
+ }
255
291
  if (token === '--scope') {
256
292
  const next = rest[index + 1];
257
293
  if (command === 'approve') {
258
- if (!next || !['once', 'domain', 'path'].includes(next)) {
259
- throw new Error('--scope requires once, domain, or path.');
294
+ if (!next || !['once', 'domain', 'path', 'workspace-root'].includes(next)) {
295
+ throw new Error('--scope requires once, domain, path, or workspace-root.');
260
296
  }
261
297
  options.approveScope = next;
262
298
  }
@@ -315,6 +351,9 @@ function parseArgs(argv) {
315
351
  if (command === 'recover') {
316
352
  options.recoverCommand = next;
317
353
  }
354
+ else if (command === 'harvest') {
355
+ options.harvestCommand = next;
356
+ }
318
357
  else {
319
358
  options.explainCommand = next;
320
359
  }
@@ -343,7 +382,13 @@ function parseArgs(argv) {
343
382
  return { command: 'help', options };
344
383
  }
345
384
  if (token === '--') {
346
- options.explainCommand = rest.slice(index + 1).join(' ');
385
+ const remainder = rest.slice(index + 1).join(' ');
386
+ if (command === 'session' && options.sessionSubcommand === 'start') {
387
+ options.sessionAgentCommand = remainder;
388
+ }
389
+ else {
390
+ options.explainCommand = remainder;
391
+ }
347
392
  break;
348
393
  }
349
394
  if (command === 'audit' && !options.auditSubcommand) {
@@ -367,16 +412,38 @@ function parseArgs(argv) {
367
412
  }
368
413
  throw new Error('sandbox requires subcommand: status');
369
414
  }
415
+ if (command === 'session' && !options.sessionSubcommand) {
416
+ if (token === 'start' || token === 'status') {
417
+ options.sessionSubcommand = token;
418
+ continue;
419
+ }
420
+ throw new Error('session requires subcommand: start or status');
421
+ }
422
+ if (command === 'standing-allow' && !options.standingAllowSubcommand) {
423
+ if (token === 'revoke') {
424
+ options.standingAllowSubcommand = token;
425
+ continue;
426
+ }
427
+ throw new Error('standing-allow requires subcommand: revoke');
428
+ }
429
+ if (command === 'harvest' && !options.harvestSubcommand) {
430
+ if (token === 'list' || token === 'apply') {
431
+ options.harvestSubcommand = token;
432
+ continue;
433
+ }
434
+ throw new Error('harvest requires subcommand: list or apply');
435
+ }
370
436
  if (command === 'judge' && !options.judgeSubcommand) {
371
437
  if (token === 'status' ||
372
438
  token === 'list' ||
373
439
  token === 'use' ||
374
440
  token === 'test' ||
441
+ token === 'bench' ||
375
442
  token === 'consent') {
376
443
  options.judgeSubcommand = token;
377
444
  continue;
378
445
  }
379
- throw new Error('judge requires subcommand: status, list, use, test, or consent');
446
+ throw new Error('judge requires subcommand: status, list, use, test, bench, or consent');
380
447
  }
381
448
  if (command === 'config' && !options.configSubcommand) {
382
449
  if (token === 'list' ||
@@ -458,6 +525,7 @@ Usage:
458
525
  ${c} dogfood [--target <dir>] [--adapter cursor|claude|codex] [--enforce] [--force]
459
526
  ${c} doctor [--target <dir>] [--adapter cursor|claude|codex] [--json] [--fix] [--dry-run]
460
527
  ${c} metrics [--target <dir>] [--json]
528
+ ${c} quality [--target <dir>] [--corpus <path>] [--json]
461
529
  ${c} report [--target <dir>] [--since <iso>] [--until <iso>] [--limit <n>] [--json]
462
530
  ${c} recover [--target <dir>] [--since <iso>] [--fingerprint <fp>] [--command "<text>"] [--limit <n>] [--json]
463
531
  (--limit picks the Nth recover candidate after priority ranking: local_mutation first, then recency; 1 = highest priority, default 1)
@@ -467,11 +535,17 @@ Usage:
467
535
  ${c} explain [--target <dir>] [--cwd <dir>] [--kind shell|tool|subagent] [--tool <name>] [--payload-json <json>] [--command <text>] [--json] [-- <command>]
468
536
  ${c} egress <start|stop|status|env> [--target <dir>] [--json]
469
537
  ${c} sandbox status [--target <dir>] [--json]
470
- ${c} judge <status|list|use|test|consent> [--target <dir>] [--json]
538
+ ${c} session <start|status> [--target <dir>] [--json]
539
+ ${c} session start [--target <dir>] [-- <agent command>]
540
+ ${c} judge <status|list|use|test|bench|consent> [--target <dir>] [--json]
541
+ ${c} judge test [--target <dir>] [--json] [--live-probe]
471
542
  ${c} judge use <ollama|codex|claude|cursor> [--model <id>] [--endpoint <url>] [--timeout <ms>] [--accept-cloud] [--cloud-consent-approval-id <id>] [--credential project|apiKey] [--key-stdin] [--key-env <NAME>]
472
543
  ${c} judge consent <ollama|codex|claude|cursor> [--endpoint <url>]
473
- ${c} approve <approval-id> [--scope once|domain|path] [--path <path>] [--token <signed-token>] [--target <dir>]
544
+ ${c} approve <approval-id> [--replay] [--scope once|domain|path|workspace-root] [--path <path>] [--token <signed-token>] [--target <dir>]
474
545
  ${c} revoke <approval-id> [--target <dir>]
546
+ ${c} standing-allow revoke --fingerprint <fp> [--kind shell|tool|subagent] [--target <dir>]
547
+ ${c} harvest list [--target <dir>] [--since <iso>] [--until <iso>] [--json]
548
+ ${c} harvest apply --command "<text>" --outcome provably-benign|accepted-benign|reject [--reason <r>] [--corpus <path>] [--target <dir>]
475
549
  `);
476
550
  }
477
551
  async function main() {
@@ -545,6 +619,9 @@ async function main() {
545
619
  if (!options.judgeSubcommand) {
546
620
  throw new Error('judge requires subcommand: status, list, use, or test');
547
621
  }
622
+ if (options.judgeLiveProbe && options.judgeSubcommand !== 'test') {
623
+ throw new Error('--live-probe is only valid for judge test.');
624
+ }
548
625
  const result = await runJudgeCommand({
549
626
  targetDir: options.targetDir,
550
627
  json: options.json,
@@ -558,6 +635,7 @@ async function main() {
558
635
  credentialMode: options.credentialMode,
559
636
  keyStdin: options.keyStdin,
560
637
  keyEnv: options.keyEnv,
638
+ liveProbe: options.judgeLiveProbe,
561
639
  });
562
640
  if (options.json && typeof result === 'object') {
563
641
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
@@ -679,6 +757,21 @@ async function main() {
679
757
  }
680
758
  return;
681
759
  }
760
+ if (command === 'quality') {
761
+ const report = await qualityCheck({
762
+ targetDir: options.targetDir,
763
+ corpusDir: options.corpusPath,
764
+ json: options.json,
765
+ });
766
+ if (options.json) {
767
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
768
+ }
769
+ else {
770
+ process.stdout.write(`${formatQualityReport(report)}\n`);
771
+ }
772
+ process.exitCode = report.ok ? 0 : 1;
773
+ return;
774
+ }
682
775
  if (command === 'report') {
683
776
  const report = await reportProject({
684
777
  targetDir: options.targetDir,
@@ -695,6 +788,42 @@ async function main() {
695
788
  }
696
789
  return;
697
790
  }
791
+ if (command === 'harvest') {
792
+ if (options.harvestSubcommand === 'list') {
793
+ const report = await harvestListProject({
794
+ targetDir: options.targetDir,
795
+ since: options.since,
796
+ until: options.until,
797
+ json: options.json,
798
+ });
799
+ if (options.json) {
800
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
801
+ }
802
+ else {
803
+ process.stdout.write(`${formatHarvestReport(report)}\n`);
804
+ }
805
+ return;
806
+ }
807
+ if (options.harvestSubcommand === 'apply') {
808
+ if (!options.harvestCommand) {
809
+ throw new Error('harvest apply requires --command.');
810
+ }
811
+ if (!options.harvestOutcome) {
812
+ throw new Error('harvest apply requires --outcome.');
813
+ }
814
+ const result = await harvestApplyProject({
815
+ targetDir: options.targetDir,
816
+ command: options.harvestCommand,
817
+ outcome: options.harvestOutcome,
818
+ reason: options.reason,
819
+ corpusPath: options.corpusPath,
820
+ });
821
+ process.stdout.write(`${result.message}\n`);
822
+ process.exitCode = result.ok ? 0 : 1;
823
+ return;
824
+ }
825
+ throw new Error('harvest requires subcommand: list or apply');
826
+ }
698
827
  if (command === 'recover') {
699
828
  const report = await recoverProject({
700
829
  targetDir: options.targetDir,
@@ -794,6 +923,32 @@ async function main() {
794
923
  process.exitCode = report.issues.length > 0 && report.sandboxEnabled ? 1 : 0;
795
924
  return;
796
925
  }
926
+ if (command === 'session') {
927
+ if (!options.sessionSubcommand) {
928
+ throw new Error('session requires subcommand: start or status');
929
+ }
930
+ if (options.sessionSubcommand === 'start') {
931
+ const result = await sessionStartProject({
932
+ targetDir: options.targetDir,
933
+ agentCommand: options.sessionAgentCommand,
934
+ });
935
+ process.stdout.write(`${result.message}\n`);
936
+ process.exitCode = result.ok ? 0 : 1;
937
+ return;
938
+ }
939
+ const report = await sessionStatusProject({
940
+ targetDir: options.targetDir,
941
+ json: options.json,
942
+ });
943
+ if (options.json) {
944
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
945
+ }
946
+ else {
947
+ process.stdout.write(`${formatSessionStatusReport(report)}\n`);
948
+ }
949
+ process.exitCode = report.ok ? 0 : 1;
950
+ return;
951
+ }
797
952
  if (command === 'approve') {
798
953
  if (!options.approvalId) {
799
954
  throw new Error('approve requires an approval ID.');
@@ -804,6 +959,7 @@ async function main() {
804
959
  token: options.approvalToken,
805
960
  scope: options.approveScope,
806
961
  scopePath: options.approvePath,
962
+ replay: options.approveReplay,
807
963
  });
808
964
  process.stdout.write(`${result.message}\n`);
809
965
  process.exitCode = result.ok ? 0 : 1;
@@ -821,6 +977,24 @@ async function main() {
821
977
  process.exitCode = result.ok ? 0 : 1;
822
978
  return;
823
979
  }
980
+ if (command === 'standing-allow') {
981
+ if (options.standingAllowSubcommand === 'revoke') {
982
+ if (!options.fingerprint) {
983
+ throw new Error('standing-allow revoke requires --fingerprint.');
984
+ }
985
+ const result = await revokeStandingAllow({
986
+ targetDir: options.targetDir,
987
+ fingerprint: options.fingerprint,
988
+ kind: options.kind === 'tool' || options.kind === 'subagent' || options.kind === 'shell'
989
+ ? options.kind
990
+ : undefined,
991
+ });
992
+ process.stdout.write(`${result.message}\n`);
993
+ process.exitCode = result.ok ? 0 : 1;
994
+ return;
995
+ }
996
+ throw new Error('standing-allow requires subcommand: revoke');
997
+ }
824
998
  throw new Error(`Unknown command: ${command}`);
825
999
  }
826
1000
  catch (error) {
@@ -7,6 +7,7 @@ export interface ApproveOptions {
7
7
  token?: string;
8
8
  scope?: ApproveScope;
9
9
  scopePath?: string;
10
+ replay?: boolean;
10
11
  }
11
12
  export declare function approvePending(options: ApproveOptions): Promise<{
12
13
  ok: boolean;
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path';
2
- import { approvedApprovalsPath, loadApprovalState, loadConfigFile, pendingApprovalsPath, saveApprovalState, } from '../config-io.js';
3
- import { recordApproval } from '../core/approval-service.js';
2
+ import { loadApprovalState, loadConfigFile } from '../config-io.js';
3
+ import { canAutoReplay, getExecutionLeaseMs, replayShellCommand } from '../core/approval-replay.js';
4
+ import { consumeApprovedAfterCliReplay, createGateApprovalStore, recordApproval, } from '../core/approval-service.js';
4
5
  import { JUDGE_CLOUD_CONSENT_REASON } from '../core/capability/reasons.js';
5
6
  import { recordCapabilityApproval } from '../core/capability-approval.js';
6
7
  import { recordEgressApproval } from '../core/egress-approval.js';
@@ -32,11 +33,11 @@ export async function approvePending(options) {
32
33
  });
33
34
  return { ok: result.ok, message: result.message };
34
35
  }
35
- if (options.scope === 'path') {
36
+ if (options.scope === 'path' || options.scope === 'workspace-root') {
36
37
  const result = await recordCapabilityApproval({
37
38
  approvalId: options.approvalId,
38
39
  config,
39
- scope: 'path',
40
+ scope: options.scope,
40
41
  scopePath: options.scopePath,
41
42
  token: options.token,
42
43
  requireSignedToken: config.approvalSigning.required,
@@ -44,33 +45,51 @@ export async function approvePending(options) {
44
45
  });
45
46
  return { ok: result.ok, message: result.message };
46
47
  }
48
+ const approvalStore = createGateApprovalStore(repoRoot, config);
47
49
  const result = await recordApproval({
48
50
  approvalId: options.approvalId,
49
51
  config,
50
52
  token: options.token,
51
53
  requireSignedToken: config.approvalSigning.required,
52
- store: {
53
- async loadPending() {
54
- const filePath = pendingApprovalsPath(repoRoot, config);
55
- return {
56
- filePath,
57
- state: await loadApprovalState(repoRoot, 'pending-approvals.json', config),
58
- };
59
- },
60
- async loadApproved() {
61
- const filePath = approvedApprovalsPath(repoRoot, config);
62
- return {
63
- filePath,
64
- state: await loadApprovalState(repoRoot, 'approved-approvals.json', config),
65
- };
66
- },
67
- async writePending(_filePath, state) {
68
- await saveApprovalState(repoRoot, 'pending-approvals.json', state, config);
69
- },
70
- async writeApproved(_filePath, state) {
71
- await saveApprovalState(repoRoot, 'approved-approvals.json', state, config);
72
- },
73
- },
54
+ store: approvalStore,
74
55
  });
56
+ if (!result.ok) {
57
+ return { ok: result.ok, message: result.message };
58
+ }
59
+ if (options.replay) {
60
+ const approval = result.approval;
61
+ if (!approval) {
62
+ return { ok: false, message: 'Approval recorded but replay envelope is missing.' };
63
+ }
64
+ if (!canAutoReplay(config, approval.kind)) {
65
+ return {
66
+ ok: false,
67
+ message: 'Replay is not enabled for this approval kind. Retry the original action manually or enable approval.autoReplayScopes.',
68
+ };
69
+ }
70
+ if (approval.kind !== 'shell' || !approval.input) {
71
+ return {
72
+ ok: false,
73
+ message: 'CLI replay is only supported for shell approvals. Retry the original tool or subagent action manually.',
74
+ };
75
+ }
76
+ const replayResult = await replayShellCommand(approval.input, approval.cwd ?? repoRoot, getExecutionLeaseMs(config));
77
+ const output = [replayResult.stdout, replayResult.stderr].filter(Boolean).join('\n').trim();
78
+ if (replayResult.exitCode === 0) {
79
+ await consumeApprovedAfterCliReplay({
80
+ approvalId: options.approvalId,
81
+ store: approvalStore,
82
+ });
83
+ return {
84
+ ok: true,
85
+ message: `Belay replay succeeded for ${options.approvalId}. Do not retry via hooks; the one-shot grant was consumed.${output ? `\n${output}` : ''}`,
86
+ };
87
+ }
88
+ const timeoutNote = replayResult.timedOut ? ' Replay timed out.' : '';
89
+ return {
90
+ ok: false,
91
+ message: `Belay replay failed for ${options.approvalId} (exit ${replayResult.exitCode}).${timeoutNote} Approval remains active for one hook retry.${output ? `\n${output}` : ''}`,
92
+ };
93
+ }
75
94
  return { ok: result.ok, message: result.message };
76
95
  }
@@ -36,7 +36,7 @@ export async function classifyForReport(params) {
36
36
  if (!params.command && !params.payload) {
37
37
  throw new Error('classify-for-report requires command or payload for subagent classification.');
38
38
  }
39
- result = classifySubagent(payload, repoRoot, classifierOptions);
39
+ result = classifySubagent(payload, repoRoot, classifierOptions, config);
40
40
  input = params.command ?? JSON.stringify(payload);
41
41
  }
42
42
  else if (kind === 'tool') {
@@ -1,5 +1,6 @@
1
1
  import { type JudgeProviderId } from '../core/verdict/judge-catalog.js';
2
2
  import type { AdapterName, InitOptions } from '../types.js';
3
+ import { type SelectOptions } from './tui.js';
3
4
  export declare const BELAY_CONFIG_SUBCOMMANDS: readonly ["list", "get", "set", "unset", "credential", "judge"];
4
5
  export type BelayConfigSubcommand = (typeof BELAY_CONFIG_SUBCOMMANDS)[number];
5
6
  export interface BelayConfigOptions {
@@ -39,6 +40,13 @@ export interface BelayConfigInteractiveOptions {
39
40
  /** Suppress the interactive header when nested under runBelayConfigInteractive */
40
41
  skipBanner?: boolean;
41
42
  }
43
+ export declare const JUDGE_CREDENTIAL_MODE_PROMPT = "Judge API key source";
44
+ export declare const JUDGE_CREDENTIAL_STORE_KEY_PROMPT = "Paste API key to store locally (visible input; prefer belay config credential set --key-stdin): ";
45
+ export declare const JUDGE_TRANSPORT_MODE_PROMPT = "How should Belay reach the judge?";
46
+ export declare const JUDGE_HTTP_ENDPOINT_PROMPT = "Judge HTTP API URL:";
47
+ export type JudgeTransportWizardMode = 'cli' | 'http';
48
+ export declare function buildJudgeTransportSelectOptions(judgeProviderId: JudgeProviderId): SelectOptions<JudgeTransportWizardMode>;
49
+ export declare function buildJudgeCredentialModeSelectOptions(judgeProviderId: JudgeProviderId): SelectOptions<'project' | 'apiKey'>;
42
50
  export declare function resolveBelayConfigInteractiveMode(repoRoot: string): Promise<'full' | 'judge-only'>;
43
51
  export declare function runBelayConfigFullInteractive(options?: BelayConfigInteractiveOptions): Promise<{
44
52
  repoRoot: string;