@guilz-dev/belay 0.9.4 → 0.10.1

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 (62) hide show
  1. package/README.md +3 -2
  2. package/dist/adapters/claude/runtime-entry.js +5 -18
  3. package/dist/adapters/codex/runtime-entry.js +10 -11
  4. package/dist/adapters/cursor/hook-dispatch-entry.d.ts +3 -0
  5. package/dist/adapters/cursor/hook-dispatch-entry.js +11 -0
  6. package/dist/adapters/cursor/hook-router.d.ts +1 -0
  7. package/dist/adapters/cursor/hook-router.js +39 -9
  8. package/dist/adapters/cursor/hook-routing-health.d.ts +1 -0
  9. package/dist/adapters/cursor/hook-routing-health.js +53 -0
  10. package/dist/adapters/cursor/hooks.d.ts +1 -1
  11. package/dist/adapters/cursor/hooks.js +16 -5
  12. package/dist/adapters/cursor/routing-config-trust.d.ts +1 -0
  13. package/dist/adapters/cursor/routing-config-trust.js +67 -0
  14. package/dist/adapters/cursor/runtime-entry.d.ts +2 -2
  15. package/dist/adapters/cursor/runtime-entry.js +35 -10
  16. package/dist/adapters/shared/gate-runtime.d.ts +0 -2
  17. package/dist/adapters/shared/gate-runtime.js +12 -52
  18. package/dist/bundle/claude-runtime.mjs +1083 -669
  19. package/dist/bundle/codex-runtime.mjs +1092 -698
  20. package/dist/bundle/cursor-dispatcher.mjs +119 -28
  21. package/dist/bundle/cursor-runtime.mjs +1132 -677
  22. package/dist/cli.js +53 -4
  23. package/dist/commands/approval-token.d.ts +10 -0
  24. package/dist/commands/approval-token.js +26 -0
  25. package/dist/commands/audit.d.ts +2 -1
  26. package/dist/commands/audit.js +2 -2
  27. package/dist/commands/config.d.ts +1 -1
  28. package/dist/commands/config.js +28 -2
  29. package/dist/commands/doctor.js +14 -54
  30. package/dist/commands/dogfood-check.d.ts +3 -0
  31. package/dist/commands/dogfood-check.js +116 -0
  32. package/dist/commands/dogfood.d.ts +1 -0
  33. package/dist/commands/dogfood.js +4 -3
  34. package/dist/commands/judge.js +2 -2
  35. package/dist/commands/recovery-checkpoints.js +2 -11
  36. package/dist/config-io.d.ts +1 -0
  37. package/dist/config-io.js +8 -1
  38. package/dist/core/capability/index.d.ts +1 -1
  39. package/dist/core/capability/index.js +1 -1
  40. package/dist/core/capability/policy-engine.d.ts +19 -0
  41. package/dist/core/capability/policy-engine.js +31 -0
  42. package/dist/core/classify-tool.js +372 -148
  43. package/dist/core/config.js +2 -2
  44. package/dist/core/dogfood-environment.d.ts +8 -0
  45. package/dist/core/dogfood-environment.js +55 -0
  46. package/dist/core/effect-ir/shell-lower/decoders/belay.js +12 -0
  47. package/dist/core/egress-approval.js +0 -18
  48. package/dist/core/gate-engine.js +2 -9
  49. package/dist/core/notify.d.ts +8 -2
  50. package/dist/core/notify.js +63 -7
  51. package/dist/core/recovery/operator-guidance.js +4 -4
  52. package/dist/core/repo-config-trust.d.ts +31 -0
  53. package/dist/core/repo-config-trust.js +152 -0
  54. package/dist/corpus/benign-probe-cores.d.ts +1 -1
  55. package/dist/corpus/benign-probe-cores.js +0 -1
  56. package/dist/defaults.js +0 -25
  57. package/dist/installer/scope-config.js +2 -2
  58. package/dist/installer.js +4 -4
  59. package/dist/types.d.ts +19 -0
  60. package/dist/version.d.ts +1 -1
  61. package/dist/version.js +1 -1
  62. package/package.json +5 -1
@@ -5,7 +5,6 @@ import path from 'node:path';
5
5
  import { compactApprovals, createApprovalRecordWithEnvelope } from '../../core/approval.js';
6
6
  import { buildReplayHint, buildRetryInstructionForConfig, canAutoReplay, getExecutionLeaseMs, validateReplayEnvelope, } from '../../core/approval-replay.js';
7
7
  import { claimApprovedForReplay, gateApprovalStoreFromDeps, recordApproval, } from '../../core/approval-service.js';
8
- import { issueApprovalToken } from '../../core/approval-token.js';
9
8
  import { buildAuditActionSnapshot, buildAuditReplayContext, } from '../../core/audit-replay-context.js';
10
9
  import { approvalCorrelationId, serializeAuditRecordV3, toolInvocationCorrelationId, } from '../../core/audit-serialize.js';
11
10
  import { boundedUtf8Tail } from '../../core/bounded-output.js';
@@ -31,12 +30,13 @@ import { effectPlanAuditFields, hashEffectPlan } from '../../core/effect-ir/audi
31
30
  import { buildCapabilityEffectPlan } from '../../core/effect-ir/build.js';
32
31
  import { classifyResultToGateVerdict, unnormalizedGateVerdict, } from '../../core/gate-contract.js';
33
32
  import { classifyGatedActionAsync, extractAgentAssessment, GateNormalizationError, gateEnabledForAction, normalizeGatedAction, } from '../../core/gate-engine.js';
34
- import { approvalCommandMatch, approvedApprovalsFile, belayStateDir, canonicalStringify, classifierOptionsFromConfig, configuredControlPlaneDir, hashValue, pendingApprovalsFile, resolveControlPlaneDir, scrubOptionsFromConfig, scrubString, scrubValue, toolFingerprint, } from '../../core/index.js';
33
+ import { approvalCommandMatch, approvedApprovalsFile, belayStateDir, canonicalStringify, classifierOptionsFromConfig, configuredControlPlaneDir, hashValue, pendingApprovalsFile, resolveControlPlaneDir, scrubOptionsFromConfig, scrubString, scrubValue, } from '../../core/index.js';
35
34
  import { extractJudgeFallbackReason, formatJudgeInfrastructureDenyMessage, inferProviderIdFromFallbackReason, isJudgeInfrastructureFailure, } from '../../core/judge-fallback-hints.js';
36
35
  import { notifyDeny } from '../../core/notify.js';
37
36
  import { canonicalPath } from '../../core/path-utils.js';
38
37
  import { recoveryFailClosedResult, recoveryFailReasonFromSkip, } from '../../core/recovery/fail-closed.js';
39
38
  import { fingerprintReplayPayload, redactToolInvocationId } from '../../core/replay-scrub.js';
39
+ import { assertRepoConfigTrusted } from '../../core/repo-config-trust.js';
40
40
  import { FILE_CHECKPOINT_ISOLATION_UNAVAILABLE, isTransactionalEligible, runTransactionalExecution, TRANSACTIONAL_ALREADY_APPLIED, TRANSACTIONAL_APPROVAL_BYPASS_REASONS, } from '../../core/transactional/index.js';
41
41
  import { buildAuditProvenanceFields } from '../../runtime-provenance.js';
42
42
  import { egressStatus } from '../../services/egress-service.js';
@@ -91,7 +91,15 @@ async function loadJsonFile(filePath, fallback) {
91
91
  export function createDefaultGateRuntimeDeps() {
92
92
  return {
93
93
  async readConfig(configPath) {
94
- return loadJsonFile(configPath, {});
94
+ try {
95
+ return JSON.parse(await readFile(configPath, 'utf8'));
96
+ }
97
+ catch (error) {
98
+ if (error.code === 'ENOENT') {
99
+ return {};
100
+ }
101
+ throw error;
102
+ }
95
103
  },
96
104
  async appendAudit(ctx, event) {
97
105
  const auditPath = path.join(ctx.repoRoot, ctx.config.audit.logPath);
@@ -149,6 +157,7 @@ export function createDefaultGateRuntimeDeps() {
149
157
  }
150
158
  export async function resolveGateConfig(ctx, deps) {
151
159
  const loaded = await deps.readConfig(ctx.configPath);
160
+ await assertRepoConfigTrusted(ctx.repoRoot, ctx.layout.name, loaded);
152
161
  let teamConfig = null;
153
162
  const teamPath = teamConfigPath();
154
163
  if (existsSync(teamPath)) {
@@ -817,41 +826,6 @@ export async function evaluateGatedAction(ctx, deps, params) {
817
826
  scopeHintPayload: params.payload,
818
827
  });
819
828
  }
820
- /** R39: unmapped Codex tools ask via pending approval — not hard deny without approval path. */
821
- export async function gateUnmappedToolVerdict(ctx, deps, toolName, payload) {
822
- const scrubOpts = scrubOptionsFromConfig(ctx.config);
823
- const replayPayload = fingerprintReplayPayload('tool', payload, scrubOpts) ?? {};
824
- const result = {
825
- verdict: 'deny_pending_approval',
826
- reason: 'unmapped_tool',
827
- summary: toolName,
828
- fingerprint: toolFingerprint(toolName, replayPayload, ctx.repoRoot),
829
- assessment: {
830
- reversibility: 'irreversible',
831
- external: false,
832
- blastRadius: 'unknown Codex tool action',
833
- confidence: 0.5,
834
- signals: ['unmapped_tool'],
835
- },
836
- };
837
- return gateDecisionToVerdict(ctx, deps, 'tool', result, {
838
- approvalInput: {
839
- input: toolName,
840
- inputKind: 'tool',
841
- cwd: ctx.repoRoot,
842
- toolName,
843
- payload: replayPayload,
844
- },
845
- replayAction: {
846
- kind: 'tool',
847
- cwd: ctx.repoRoot,
848
- toolName,
849
- payload: replayPayload,
850
- fingerprint: result.fingerprint,
851
- repoRoot: ctx.repoRoot,
852
- },
853
- });
854
- }
855
829
  async function consumeCapabilityGrantIfUsed(ctx, deps, result) {
856
830
  if (result.reason !== 'capability_grant' &&
857
831
  result.authorizationDecision?.matchedRule !== 'grant.exact') {
@@ -937,19 +911,6 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
937
911
  if (created) {
938
912
  await recordGateApprovalAsk(stateDir, result.reason, false);
939
913
  }
940
- let approvalToken;
941
- try {
942
- approvalToken = await issueApprovalToken({
943
- approvalId: approval.approvalId,
944
- fingerprint: approval.fingerprint,
945
- repoRoot: approval.repoRoot,
946
- issuedAt: approval.createdAt,
947
- expiresAt: approval.expiresAt,
948
- }, configuredControlPlaneDir(ctx.config));
949
- }
950
- catch {
951
- approvalToken = undefined;
952
- }
953
914
  const denialReason = failure?.reason ?? result.reason;
954
915
  if (ctx.config.notifications.webhookUrl || ctx.config.notifications.commandHook) {
955
916
  await notifyDeny(ctx.config.notifications, {
@@ -958,7 +919,6 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
958
919
  summary: result.normalizedCommand ?? result.summary ?? '',
959
920
  repoRoot: ctx.repoRoot,
960
921
  fingerprint: result.fingerprint,
961
- approvalToken,
962
922
  });
963
923
  }
964
924
  const failureAuditFields = typeof failure?.auditFields === 'function'