thumbgate 1.27.16 → 1.27.18

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 (165) hide show
  1. package/.claude-plugin/marketplace.json +85 -0
  2. package/.claude-plugin/plugin.json +3 -4
  3. package/.well-known/llms.txt +12 -33
  4. package/.well-known/mcp/server-card.json +8 -8
  5. package/README.md +30 -215
  6. package/adapters/chatgpt/openapi.yaml +1695 -0
  7. package/adapters/claude/.mcp.json +2 -2
  8. package/adapters/gemini/function-declarations.json +0 -1
  9. package/adapters/mcp/server-stdio.js +11 -263
  10. package/adapters/opencode/opencode.json +1 -1
  11. package/bench/thumbgate-bench.json +2 -2
  12. package/bin/cli.js +122 -1421
  13. package/bin/postinstall.js +27 -11
  14. package/config/gate-templates.json +0 -216
  15. package/config/gates/claim-verification.json +0 -12
  16. package/config/gates/default.json +2 -31
  17. package/config/github-about.json +2 -2
  18. package/config/mcp-allowlists.json +13 -23
  19. package/config/merge-quality-checks.json +1 -0
  20. package/config/model-candidates.json +6 -121
  21. package/openapi/openapi.yaml +0 -12
  22. package/package.json +98 -228
  23. package/public/blog.html +4 -4
  24. package/public/codex-plugin.html +20 -72
  25. package/public/compare.html +8 -31
  26. package/public/dashboard.html +166 -930
  27. package/public/federal.html +2 -2
  28. package/public/guide.html +9 -33
  29. package/public/index.html +116 -495
  30. package/public/learn.html +18 -191
  31. package/public/lessons.html +10 -168
  32. package/public/numbers.html +7 -7
  33. package/public/pro.html +11 -34
  34. package/scripts/agent-memory-lifecycle.js +0 -211
  35. package/scripts/agent-readiness.js +3 -167
  36. package/scripts/agent-reward-model.js +1 -53
  37. package/scripts/auto-promote-gates.js +10 -82
  38. package/scripts/auto-wire-hooks.js +0 -14
  39. package/scripts/billing.js +1 -93
  40. package/scripts/build-metadata.js +10 -50
  41. package/scripts/cli-feedback.js +6 -18
  42. package/scripts/cli-schema.js +0 -90
  43. package/scripts/cli-telemetry.js +1 -6
  44. package/scripts/commercial-offer.js +2 -82
  45. package/scripts/context-manager.js +6 -74
  46. package/scripts/dashboard.js +2 -68
  47. package/scripts/durability/step.js +3 -3
  48. package/scripts/export-databricks-bundle.js +1 -5
  49. package/scripts/export-dpo-pairs.js +2 -7
  50. package/scripts/feedback-loop.js +1 -123
  51. package/scripts/feedback-quality.js +0 -87
  52. package/scripts/filesystem-search.js +10 -35
  53. package/scripts/gate-stats.js +0 -89
  54. package/scripts/gates-engine.js +85 -1105
  55. package/scripts/gemini-embedding-policy.js +1 -2
  56. package/scripts/hook-runtime.js +14 -20
  57. package/scripts/hook-thumbgate-cache-updater.js +2 -18
  58. package/scripts/hybrid-feedback-context.js +7 -142
  59. package/scripts/lesson-inference.js +3 -8
  60. package/scripts/lesson-search.js +1 -17
  61. package/scripts/license.js +1 -0
  62. package/scripts/llm-client.js +9 -390
  63. package/scripts/local-model-profile.js +8 -15
  64. package/scripts/memory-scope-readiness.js +0 -159
  65. package/scripts/meta-agent-loop.js +0 -36
  66. package/scripts/operational-integrity.js +5 -39
  67. package/scripts/oss-pr-opportunity-scout.js +5 -35
  68. package/scripts/plausible-server-events.js +6 -9
  69. package/scripts/pro-local-dashboard.js +4 -4
  70. package/scripts/proxy-pointer-rag-guardrails.js +1 -42
  71. package/scripts/rate-limiter.js +13 -64
  72. package/scripts/secret-scanner.js +5 -44
  73. package/scripts/security-scanner.js +10 -260
  74. package/scripts/self-distill-agent.js +1 -3
  75. package/scripts/seo-gsd.js +2 -916
  76. package/scripts/statusline-cache-path.js +2 -17
  77. package/scripts/statusline-local-stats.js +1 -9
  78. package/scripts/statusline-meta.js +2 -28
  79. package/scripts/statusline.sh +4 -20
  80. package/scripts/telemetry-analytics.js +0 -357
  81. package/scripts/thompson-sampling.js +10 -31
  82. package/scripts/thumbgate-bench.js +1 -16
  83. package/scripts/thumbgate-search.js +19 -85
  84. package/scripts/tool-registry.js +1 -169
  85. package/scripts/vector-store.js +0 -45
  86. package/scripts/workflow-sentinel.js +53 -286
  87. package/scripts/workspace-evolver.js +2 -62
  88. package/src/api/server.js +290 -2578
  89. package/.claude/commands/dashboard.md +0 -15
  90. package/.claude/commands/thumbgate-blocked.md +0 -27
  91. package/.claude/commands/thumbgate-dashboard.md +0 -15
  92. package/.claude/commands/thumbgate-doctor.md +0 -30
  93. package/.claude/commands/thumbgate-guard.md +0 -36
  94. package/.claude/commands/thumbgate-protect.md +0 -30
  95. package/.claude/commands/thumbgate-rules.md +0 -30
  96. package/.well-known/agentic-verify.txt +0 -1
  97. package/adapters/gcp/dfcx-webhook-gate.js +0 -295
  98. package/adapters/letta/README.md +0 -41
  99. package/adapters/letta/thumbgate-letta-adapter.js +0 -133
  100. package/adapters/policy-engine/ethicore-guardian-client.js +0 -68
  101. package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +0 -260
  102. package/bench/observability-eval-suite.json +0 -26
  103. package/bin/dashboard-cli.js +0 -7
  104. package/commands/dashboard.md +0 -15
  105. package/commands/thumbgate-dashboard.md +0 -15
  106. package/config/builtin-lessons.json +0 -23
  107. package/config/gate-classifier-routing.json +0 -98
  108. package/config/post-deploy-marketing-pages.json +0 -61
  109. package/public/about.html +0 -162
  110. package/public/agent-manager.html +0 -179
  111. package/public/agents-cost-savings.html +0 -153
  112. package/public/ai-malpractice-prevention.html +0 -818
  113. package/public/assets/brand/github-social-preview.png +0 -0
  114. package/public/assets/brand/thumbgate-icon-512.png +0 -0
  115. package/public/assets/brand/thumbgate-icon-pro-512.png +0 -0
  116. package/public/assets/brand/thumbgate-icon-team-512.png +0 -0
  117. package/public/assets/brand/thumbgate-logo-1200x360.png +0 -0
  118. package/public/assets/brand/thumbgate-logo-transparent.svg +0 -22
  119. package/public/assets/brand/thumbgate-mark-inline-v3.svg +0 -19
  120. package/public/assets/brand/thumbgate-mark-pro.svg +0 -23
  121. package/public/assets/brand/thumbgate-mark-team.svg +0 -26
  122. package/public/assets/brand/thumbgate-mark.svg +0 -21
  123. package/public/assets/brand/thumbgate-wordmark.svg +0 -20
  124. package/public/assets/claude-thumbgate-statusbar.svg +0 -8
  125. package/public/assets/codex-thumbgate-statusbar-test.svg +0 -9
  126. package/public/assets/legal-intake-control-flow.svg +0 -66
  127. package/public/brand/thumbgate-mark.svg +0 -19
  128. package/public/brand/thumbgate-og.svg +0 -16
  129. package/public/chatgpt-app.html +0 -330
  130. package/public/codex-enterprise.html +0 -123
  131. package/public/js/buyer-intent.js +0 -672
  132. package/public/pricing.html +0 -399
  133. package/scripts/action-receipts.js +0 -324
  134. package/scripts/activation-quickstart.js +0 -187
  135. package/scripts/agent-operations-planner.js +0 -621
  136. package/scripts/ai-component-inventory.js +0 -367
  137. package/scripts/async-eval-observability.js +0 -236
  138. package/scripts/audit.js +0 -65
  139. package/scripts/aws-blocks-guardrails.js +0 -228
  140. package/scripts/classifier-routing.js +0 -130
  141. package/scripts/dashboard-chat.js +0 -332
  142. package/scripts/feedback-aggregate.js +0 -281
  143. package/scripts/feedback-sanitizer.js +0 -105
  144. package/scripts/hob-pack.js +0 -591
  145. package/scripts/hook-stop-anti-claim.js +0 -301
  146. package/scripts/install-shim.js +0 -87
  147. package/scripts/mcp-oauth.js +0 -293
  148. package/scripts/noop-detect.js +0 -285
  149. package/scripts/omlx-smoke.js +0 -192
  150. package/scripts/parallel-workflow-orchestrator.js +0 -293
  151. package/scripts/plan-gate.js +0 -243
  152. package/scripts/plausible-domain-config.js +0 -99
  153. package/scripts/qa-scenario-planner.js +0 -136
  154. package/scripts/repeat-metric.js +0 -137
  155. package/scripts/secret-fixture-tokens.js +0 -61
  156. package/scripts/secret-redaction.js +0 -166
  157. package/scripts/self-harness-optimizer.js +0 -141
  158. package/scripts/self-healing-check.js +0 -193
  159. package/scripts/silent-failure-cluster.js +0 -531
  160. package/scripts/statusline-cache-read.js +0 -57
  161. package/scripts/sync-telemetry-from-prod.js +0 -374
  162. package/scripts/tool-contract-validator.js +0 -76
  163. package/scripts/trajectory-scorer.js +0 -63
  164. package/scripts/verify-marketing-pages-deployed.js +0 -195
  165. package/scripts/visitor-journey.js +0 -172
@@ -64,14 +64,11 @@ function loadJson(filePath) {
64
64
  function loadGovernanceState() {
65
65
  const raw = loadJson(GOVERNANCE_STATE_PATH);
66
66
  return {
67
- taskScope: raw?.taskScope && typeof raw.taskScope === 'object' ? raw.taskScope : null,
68
- protectedApprovals: Array.isArray(raw?.protectedApprovals) ? raw.protectedApprovals : [],
69
- branchGovernance: raw?.branchGovernance && typeof raw.branchGovernance === 'object'
67
+ taskScope: raw && raw.taskScope && typeof raw.taskScope === 'object' ? raw.taskScope : null,
68
+ protectedApprovals: Array.isArray(raw && raw.protectedApprovals) ? raw.protectedApprovals : [],
69
+ branchGovernance: raw && raw.branchGovernance && typeof raw.branchGovernance === 'object'
70
70
  ? raw.branchGovernance
71
71
  : null,
72
- workflowContract: raw?.workflowContract && typeof raw.workflowContract === 'object'
73
- ? raw.workflowContract
74
- : null,
75
72
  };
76
73
  }
77
74
 
@@ -364,131 +361,6 @@ function formatFileList(files, limit = 5) {
364
361
  return `${items.slice(0, limit).join(', ')} (+${items.length - limit} more)`;
365
362
  }
366
363
 
367
- function normalizeStringList(values) {
368
- if (!Array.isArray(values)) return [];
369
- return [...new Set(values.map((value) => String(value || '').trim()).filter(Boolean))];
370
- }
371
-
372
- function normalizeWorkflowContract(contract) {
373
- if (!contract || typeof contract !== 'object') return null;
374
- return {
375
- workflowId: String(contract.workflowId || contract.workflow_id || '').trim() || null,
376
- allowedBranches: normalizeStringList(contract.allowedBranches || contract.allowed_branches),
377
- blockedActions: normalizeStringList(contract.blockedActions || contract.blocked_actions),
378
- requiredEvidence: normalizeStringList(contract.requiredEvidence || contract.required_evidence),
379
- completionGate: String(contract.completionGate || contract.completion_gate || '').trim() || null,
380
- };
381
- }
382
-
383
- function commandMatchesPattern(command, pattern) {
384
- const text = String(command || '');
385
- const raw = String(pattern || '').trim();
386
- if (!text || !raw) return false;
387
- try {
388
- return new RegExp(raw, 'i').test(text);
389
- } catch {
390
- return text.toLowerCase().includes(raw.toLowerCase());
391
- }
392
- }
393
-
394
- const COMPLETION_ACTION_PATTERNS = [
395
- /\bgit\s+(?:commit|push)\b/i,
396
- /\bgh\s+pr\s+(?:create|merge)\b/i,
397
- /\bgh\s+release\s+create\b/i,
398
- /\bnpm\s+publish\b/i,
399
- /\byarn\s+publish\b/i,
400
- /\bpnpm\s+publish\b/i,
401
- ];
402
-
403
- function isCompletionLikeAction(command) {
404
- const text = String(command || '');
405
- return COMPLETION_ACTION_PATTERNS.some((pattern) => pattern.test(text));
406
- }
407
-
408
- function collectEvidenceLabels(toolInput = {}, options = {}) {
409
- const values = [];
410
- for (const source of [
411
- toolInput.evidence,
412
- toolInput.evidenceLabels,
413
- toolInput.proof,
414
- toolInput.proofArtifacts,
415
- toolInput.requiredEvidenceSatisfied,
416
- options.evidence,
417
- options.evidenceLabels,
418
- options.proofArtifacts,
419
- ]) {
420
- if (Array.isArray(source)) values.push(...source);
421
- else if (source && typeof source === 'object') values.push(...Object.keys(source).filter((key) => source[key]));
422
- else if (typeof source === 'string') values.push(...source.split(/[,;\n]/));
423
- }
424
- return normalizeStringList(values).map((value) => value.toLowerCase());
425
- }
426
-
427
- function evaluateWorkflowContract(contractInput, context = {}) {
428
- const contract = normalizeWorkflowContract(contractInput);
429
- if (!contract) {
430
- return {
431
- active: false,
432
- contract: null,
433
- violations: [],
434
- mode: 'allow',
435
- };
436
- }
437
- const violations = [];
438
- const command = String(context.command || '');
439
- const currentBranch = String(context.currentBranch || '').trim();
440
-
441
- const blockedAction = contract.blockedActions.find((pattern) => commandMatchesPattern(command, pattern));
442
- if (blockedAction) {
443
- violations.push({
444
- code: 'blocked_action',
445
- severity: 'block',
446
- message: `Workflow contract blocks this action: ${blockedAction}`,
447
- pattern: blockedAction,
448
- });
449
- }
450
-
451
- if (contract.allowedBranches.length > 0 && currentBranch) {
452
- const allowed = contract.allowedBranches.some((glob) => matchesAnyGlob(currentBranch, [glob]));
453
- if (!allowed) {
454
- violations.push({
455
- code: 'branch_outside_contract',
456
- severity: 'warn',
457
- message: `Current branch ${currentBranch} is outside the workflow contract.`,
458
- currentBranch,
459
- allowedBranches: contract.allowedBranches,
460
- });
461
- }
462
- }
463
-
464
- if (contract.requiredEvidence.length > 0 && isCompletionLikeAction(command)) {
465
- const evidenceLabels = collectEvidenceLabels(context.toolInput || {}, context.options || {});
466
- const missing = contract.requiredEvidence.filter((label) => !evidenceLabels.includes(label.toLowerCase()));
467
- if (missing.length > 0) {
468
- violations.push({
469
- code: 'missing_required_evidence',
470
- severity: 'block',
471
- message: `Workflow completion is missing required evidence: ${missing.join(', ')}`,
472
- missingEvidence: missing,
473
- });
474
- }
475
- }
476
-
477
- const hasBlock = violations.some((violation) => violation.severity === 'block');
478
- let mode = 'allow';
479
- if (hasBlock) {
480
- mode = 'block';
481
- } else if (violations.length > 0) {
482
- mode = 'warn';
483
- }
484
- return {
485
- active: true,
486
- contract,
487
- violations,
488
- mode,
489
- };
490
- }
491
-
492
364
  function severityFromScore(score) {
493
365
  if (score >= 0.8) return 'critical';
494
366
  if (score >= 0.55) return 'high';
@@ -562,7 +434,6 @@ function scoreRisk({
562
434
  protectedSurface,
563
435
  costControl,
564
436
  workflowControl,
565
- workflowContract,
566
437
  actionProfile,
567
438
  }) {
568
439
  const drivers = [];
@@ -719,18 +590,7 @@ function scoreRisk({
719
590
  );
720
591
  }
721
592
  }
722
- if (workflowContract?.active && workflowContract.violations.length > 0) {
723
- for (const violation of workflowContract.violations) {
724
- addDriver(
725
- drivers,
726
- `workflow_contract_${violation.code}`,
727
- violation.severity === 'block' ? 0.38 : 0.18,
728
- violation.message,
729
- { workflowId: workflowContract.contract?.workflowId }
730
- );
731
- }
732
- }
733
- if (memoryGuard?.mode && memoryGuard.mode !== 'allow') {
593
+ if (memoryGuard && memoryGuard.mode && memoryGuard.mode !== 'allow') {
734
594
  addDriver(
735
595
  drivers,
736
596
  'memory_recurrence',
@@ -739,7 +599,7 @@ function scoreRisk({
739
599
  { mode: memoryGuard.mode }
740
600
  );
741
601
  }
742
- if (learnedPolicy?.enabled && learnedPolicy.prediction) {
602
+ if (learnedPolicy && learnedPolicy.enabled && learnedPolicy.prediction) {
743
603
  const confidence = learnedPolicy.prediction.confidence || 0;
744
604
  const label = learnedPolicy.prediction.label;
745
605
  if (label === 'deny' && confidence >= 0.6) {
@@ -803,7 +663,6 @@ function buildEvidence({
803
663
  normalizedAction,
804
664
  costControl,
805
665
  workflowControl,
806
- workflowContract,
807
666
  actionProfile,
808
667
  }) {
809
668
  const evidence = [];
@@ -824,17 +683,10 @@ function buildEvidence({
824
683
  evidence.push(`Workflow control ${workflowControl.mode}: ${workflowControl.reasons.join(' ')}`);
825
684
  }
826
685
  }
827
- if (workflowContract?.active) {
828
- const workflowId = workflowContract.contract?.workflowId || 'unnamed';
829
- evidence.push(`Workflow contract active: ${workflowId}.`);
830
- for (const violation of workflowContract.violations.slice(0, 3)) {
831
- evidence.push(`Workflow contract ${violation.severity}: ${violation.message}`);
832
- }
833
- }
834
- if (actionProfile?.backgroundAgent) {
686
+ if (actionProfile && actionProfile.backgroundAgent) {
835
687
  evidence.push('Background or scheduled agent context detected for this action.');
836
688
  }
837
- if (actionProfile?.economicAction) {
689
+ if (actionProfile && actionProfile.economicAction) {
838
690
  evidence.push('Economic action keywords detected (billing, refunds, payouts, invoices, or subscriptions).');
839
691
  }
840
692
  if (actionProfile && actionProfile.customerSystemAction) {
@@ -949,7 +801,6 @@ function buildRemediations({
949
801
  executionSurface,
950
802
  costControl,
951
803
  workflowControl,
952
- workflowContract,
953
804
  actionProfile,
954
805
  }) {
955
806
  const remediations = [];
@@ -1044,7 +895,7 @@ function buildRemediations({
1044
895
  'Isolated execution limits host damage when a high-risk local action goes wrong.'
1045
896
  );
1046
897
  }
1047
- if (costControl?.mode && costControl.mode !== 'allow') {
898
+ if (costControl && costControl.mode && costControl.mode !== 'allow') {
1048
899
  push(
1049
900
  'reduce_model_budget',
1050
901
  'Reduce model budget before execution',
@@ -1052,33 +903,6 @@ function buildRemediations({
1052
903
  'High token or cost estimates should be reviewed before the model/tool loop continues.'
1053
904
  );
1054
905
  }
1055
- if (workflowContract?.active && workflowContract.violations.length > 0) {
1056
- const codes = new Set(workflowContract.violations.map((violation) => violation.code));
1057
- if (codes.has('missing_required_evidence')) {
1058
- push(
1059
- 'attach_workflow_evidence',
1060
- 'Attach workflow evidence before completion',
1061
- 'Attach every required evidence label from the workflow contract before commit, push, PR, merge, release, or publish.',
1062
- 'Deterministic workflows should not claim completion until the run contract is proven.'
1063
- );
1064
- }
1065
- if (codes.has('branch_outside_contract')) {
1066
- push(
1067
- 'switch_to_contract_branch',
1068
- 'Move to an allowed workflow branch',
1069
- 'Switch to a branch allowed by the workflow contract or update the contract before retrying.',
1070
- 'Workflow contracts define where repeatable agent runs are allowed to mutate state.'
1071
- );
1072
- }
1073
- if (codes.has('blocked_action')) {
1074
- push(
1075
- 'remove_blocked_workflow_action',
1076
- 'Remove blocked workflow action',
1077
- 'Change the workflow step or request an explicit contract update before retrying this action.',
1078
- 'The run contract blocks this action before execution.'
1079
- );
1080
- }
1081
- }
1082
906
  if (workflowControl && workflowControl.mode && workflowControl.mode !== 'allow') {
1083
907
  push(
1084
908
  'add_environment_inspection',
@@ -1244,7 +1068,6 @@ function buildDecisionControl({
1244
1068
  protectedSurface,
1245
1069
  costControl,
1246
1070
  workflowControl,
1247
- workflowContract,
1248
1071
  actionProfile,
1249
1072
  }) {
1250
1073
  const reversibility = classifyReversibility({
@@ -1254,19 +1077,16 @@ function buildDecisionControl({
1254
1077
  protectedSurface,
1255
1078
  actionProfile,
1256
1079
  });
1257
- const hasOperationalBlockers = Boolean(integrity?.blockers?.length);
1258
- const hasCostWarning = costControl?.mode === 'warn';
1259
- const hasCostBlock = costControl?.mode === 'block';
1260
- const hasWorkflowWarning = workflowControl?.mode === 'warn';
1261
- const hasWorkflowBlock = workflowControl?.mode === 'block';
1262
- const hasContractWarning = workflowContract?.mode === 'warn';
1263
- const hasContractBlock = workflowContract?.mode === 'block';
1080
+ const hasOperationalBlockers = Boolean(integrity && Array.isArray(integrity.blockers) && integrity.blockers.length > 0);
1081
+ const hasCostWarning = Boolean(costControl && costControl.mode === 'warn');
1082
+ const hasCostBlock = Boolean(costControl && costControl.mode === 'block');
1083
+ const hasWorkflowWarning = Boolean(workflowControl && workflowControl.mode === 'warn');
1084
+ const hasWorkflowBlock = Boolean(workflowControl && workflowControl.mode === 'block');
1264
1085
  const requiresCheckpoint = decision === 'warn'
1265
- || (decision === 'allow' && (reversibility !== 'two_way_door' || hasOperationalBlockers || hasCostWarning || hasWorkflowWarning || hasContractWarning));
1086
+ || (decision === 'allow' && (reversibility !== 'two_way_door' || hasOperationalBlockers || hasCostWarning || hasWorkflowWarning));
1266
1087
  const executionMode = decision === 'deny'
1267
1088
  || hasCostBlock
1268
1089
  || hasWorkflowBlock
1269
- || hasContractBlock
1270
1090
  ? 'blocked'
1271
1091
  : requiresCheckpoint
1272
1092
  ? 'checkpoint_required'
@@ -1290,7 +1110,7 @@ function buildDecisionControl({
1290
1110
  decisionOwner,
1291
1111
  reversibility,
1292
1112
  deliberation,
1293
- requiresHumanApproval: (executionMode === 'checkpoint_required' && decisionOwner !== 'agent') || hasCostBlock || hasWorkflowBlock || hasContractBlock,
1113
+ requiresHumanApproval: (executionMode === 'checkpoint_required' && decisionOwner !== 'agent') || hasCostBlock || hasWorkflowBlock,
1294
1114
  recommendedAction: executionMode === 'blocked'
1295
1115
  ? 'halt'
1296
1116
  : executionMode === 'checkpoint_required'
@@ -1304,51 +1124,46 @@ function buildDecisionControl({
1304
1124
  };
1305
1125
  }
1306
1126
 
1307
- function isDestructiveBypass(command) {
1308
- return /\bgit\s+push\b.*(?:--force|-f)\b/i.test(command)
1309
- || /\bgh\s+pr\s+merge\b.*--admin\b/i.test(command);
1310
- }
1311
-
1312
- function getLearnedPrediction(learnedPolicy) {
1313
- return learnedPolicy?.enabled ? learnedPolicy.prediction : null;
1314
- }
1315
-
1316
- function learnedPredictionMatches(prediction, labels, minConfidence) {
1317
- return Boolean(
1318
- prediction
1319
- && labels.includes(prediction.label)
1320
- && prediction.confidence >= minConfidence
1127
+ function chooseDecision({ riskScore, integrity, memoryGuard, learnedPolicy, blastRadius, command, costControl, workflowControl, actionProfile }) {
1128
+ const hasOperationalBlockers = Boolean(integrity && Array.isArray(integrity.blockers) && integrity.blockers.length > 0);
1129
+ if (costControl && costControl.mode === 'block') {
1130
+ return 'deny';
1131
+ }
1132
+ if (workflowControl && workflowControl.mode === 'block') {
1133
+ return 'deny';
1134
+ }
1135
+ const destructiveBypass = /\bgit\s+push\b.*(?:--force|-f)\b/i.test(command) || /\bgh\s+pr\s+merge\b.*--admin\b/i.test(command);
1136
+ const learnedPrediction = learnedPolicy && learnedPolicy.enabled ? learnedPolicy.prediction : null;
1137
+ const learnedHardStop = Boolean(
1138
+ learnedPrediction
1139
+ && learnedPrediction.label === 'deny'
1140
+ && learnedPrediction.confidence >= 0.7
1321
1141
  );
1322
- }
1323
-
1324
- function isLowBlastRadius(blastRadius) {
1325
- return blastRadius.fileCount <= 1
1142
+ const learnedWarning = Boolean(
1143
+ learnedPrediction
1144
+ && ['warn', 'verify', 'deny'].includes(learnedPrediction.label)
1145
+ && learnedPrediction.confidence >= 0.3
1146
+ );
1147
+ const learnedRecall = Boolean(
1148
+ learnedPrediction
1149
+ && learnedPrediction.label === 'recall'
1150
+ && learnedPrediction.confidence >= 0.3
1151
+ );
1152
+ const lowBlastRadius = blastRadius.fileCount <= 1
1326
1153
  && blastRadius.surfaceCount <= 1
1327
1154
  && blastRadius.releaseSensitiveFiles.length === 0
1328
1155
  && blastRadius.unapprovedProtectedFiles === 0;
1329
- }
1330
-
1331
- function isLowRiskHandoff({
1332
- command,
1333
- destructiveBypass,
1334
- learnedHardStop,
1335
- blastRadius,
1336
- hasOperationalBlockers,
1337
- memoryGuard,
1338
- riskScore,
1339
- }) {
1340
- return /\bgit\s+push\b|\bgh\s+pr\s+(?:create|merge)\b/i.test(command)
1156
+ const lowRiskHandoff = /\bgit\s+push\b|\bgh\s+pr\s+(?:create|merge)\b/i.test(command)
1341
1157
  && !destructiveBypass
1342
1158
  && !learnedHardStop
1343
- && isLowBlastRadius(blastRadius)
1159
+ && lowBlastRadius
1344
1160
  && !hasOperationalBlockers
1345
- && memoryGuard?.mode !== 'allow'
1161
+ && memoryGuard
1162
+ && memoryGuard.mode !== 'allow'
1346
1163
  && riskScore <= 0.62;
1347
- }
1348
-
1349
- function isRepeatedHighBlast(memoryGuard, blastRadius) {
1350
- return Boolean(
1351
- memoryGuard?.mode === 'block'
1164
+ const repeatedHighBlast = Boolean(
1165
+ memoryGuard
1166
+ && memoryGuard.mode === 'block'
1352
1167
  && (
1353
1168
  blastRadius.severity === 'high'
1354
1169
  || blastRadius.severity === 'critical'
@@ -1356,49 +1171,20 @@ function isRepeatedHighBlast(memoryGuard, blastRadius) {
1356
1171
  || blastRadius.unapprovedProtectedFiles > 0
1357
1172
  )
1358
1173
  );
1359
- }
1360
-
1361
- function hasSoftControlWarning({ workflowContract, workflowControl, costControl, riskScore, learnedWarning, learnedRecall }) {
1362
- return workflowContract?.mode === 'warn'
1363
- || workflowControl?.mode === 'warn'
1364
- || costControl?.mode === 'warn'
1365
- || riskScore >= 0.45
1366
- || (learnedWarning && riskScore >= 0.3)
1367
- || (learnedRecall && riskScore >= 0.34);
1368
- }
1369
-
1370
- function chooseDecision({ riskScore, integrity, memoryGuard, learnedPolicy, blastRadius, command, costControl, workflowControl, workflowContract, actionProfile }) {
1371
- if (costControl?.mode === 'block' || workflowControl?.mode === 'block' || workflowContract?.mode === 'block') {
1372
- return 'deny';
1373
- }
1374
-
1375
- const hasOperationalBlockers = Boolean(integrity?.blockers?.length);
1376
- const destructiveBypass = isDestructiveBypass(command);
1377
- const learnedPrediction = getLearnedPrediction(learnedPolicy);
1378
- const learnedHardStop = learnedPredictionMatches(learnedPrediction, ['deny'], 0.7);
1379
- const learnedWarning = learnedPredictionMatches(learnedPrediction, ['warn', 'verify', 'deny'], 0.3);
1380
- const learnedRecall = learnedPredictionMatches(learnedPrediction, ['recall'], 0.3);
1174
+ const economicAction = Boolean(actionProfile && actionProfile.economicAction);
1175
+ const backgroundAgent = Boolean(actionProfile && actionProfile.backgroundAgent);
1176
+ const customerSystemAction = Boolean(actionProfile && actionProfile.customerSystemAction);
1381
1177
 
1382
- if (isLowRiskHandoff({ command, destructiveBypass, learnedHardStop, blastRadius, hasOperationalBlockers, memoryGuard, riskScore })) {
1178
+ if (lowRiskHandoff) {
1383
1179
  return 'allow';
1384
1180
  }
1385
-
1386
- // Background customer-system actions checkpoint (warn), never hard-deny.
1387
- // The checkpoint IS the mitigation — blocking outright prevents legitimate work.
1388
- if (actionProfile?.backgroundAgent && actionProfile?.customerSystemAction) {
1389
- return 'warn';
1390
- }
1391
-
1392
- const repeatedHighBlast = isRepeatedHighBlast(memoryGuard, blastRadius);
1393
1181
  if (destructiveBypass || learnedHardStop || repeatedHighBlast || (hasOperationalBlockers && riskScore >= 0.72) || riskScore >= 0.86) {
1394
1182
  return 'deny';
1395
1183
  }
1396
-
1397
- if (actionProfile?.economicAction || (actionProfile?.backgroundAgent && riskScore >= 0.3)) {
1184
+ if (economicAction || (backgroundAgent && customerSystemAction) || (backgroundAgent && riskScore >= 0.3)) {
1398
1185
  return 'warn';
1399
1186
  }
1400
-
1401
- if (hasSoftControlWarning({ workflowContract, workflowControl, costControl, riskScore, learnedWarning, learnedRecall })) {
1187
+ if ((workflowControl && workflowControl.mode === 'warn') || (costControl && costControl.mode === 'warn') || riskScore >= 0.45 || (learnedWarning && riskScore >= 0.3) || (learnedRecall && riskScore >= 0.34)) {
1402
1188
  return 'warn';
1403
1189
  }
1404
1190
  return 'allow';
@@ -1447,24 +1233,11 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
1447
1233
  baseBranch,
1448
1234
  command: normalizedToolInput.command,
1449
1235
  changedFiles: affectedFiles,
1450
- currentBranch: options.currentBranch
1451
- || normalizedToolInput.currentBranch
1452
- || normalizedToolInput.branchName
1453
- || normalizedToolInput.branch,
1454
1236
  headSha: options.headSha || toolInput.headSha,
1455
1237
  requirePrForReleaseSensitive: options.requirePrForReleaseSensitive === true,
1456
1238
  requireVersionNotBehindBase: options.requireVersionNotBehindBase === true,
1457
1239
  branchGovernance: governanceState.branchGovernance,
1458
1240
  });
1459
- const workflowContract = evaluateWorkflowContract(
1460
- normalizedToolInput.workflowContract || options.workflowContract || governanceState.workflowContract,
1461
- {
1462
- command: normalizedToolInput.command || '',
1463
- currentBranch: integrity.currentBranch,
1464
- toolInput: normalizedToolInput,
1465
- options,
1466
- }
1467
- );
1468
1241
  const taskScopeViolation = buildTaskScopeViolation(governanceState.taskScope, affectedFiles);
1469
1242
  const protectedSurface = buildProtectedSurface(governanceState, affectedFiles);
1470
1243
  const protectedSurfaceForRisk = isProtectedApprovalRelevant(normalizedToolName, normalizedToolInput)
@@ -1512,7 +1285,6 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
1512
1285
  protectedSurface: protectedSurfaceForRisk,
1513
1286
  costControl,
1514
1287
  workflowControl,
1515
- workflowContract,
1516
1288
  actionProfile,
1517
1289
  });
1518
1290
  const executionSurface = buildDockerSandboxPlan({
@@ -1539,7 +1311,6 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
1539
1311
  command: normalizedToolInput.command || '',
1540
1312
  costControl,
1541
1313
  workflowControl,
1542
- workflowContract,
1543
1314
  actionProfile,
1544
1315
  });
1545
1316
  const evidence = buildEvidence({
@@ -1552,7 +1323,6 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
1552
1323
  normalizedAction,
1553
1324
  costControl,
1554
1325
  workflowControl,
1555
- workflowContract,
1556
1326
  actionProfile,
1557
1327
  });
1558
1328
  const remediations = buildRemediations({
@@ -1565,7 +1335,6 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
1565
1335
  executionSurface,
1566
1336
  costControl,
1567
1337
  workflowControl,
1568
- workflowContract,
1569
1338
  actionProfile,
1570
1339
  });
1571
1340
  const summary = decision === 'allow'
@@ -1579,7 +1348,6 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
1579
1348
  normalizedAction,
1580
1349
  costControl,
1581
1350
  workflowControl,
1582
- workflowContract,
1583
1351
  decision,
1584
1352
  riskScore: risk.score,
1585
1353
  band: risk.band,
@@ -1615,7 +1383,6 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
1615
1383
  protectedSurface: protectedSurfaceForRisk,
1616
1384
  costControl,
1617
1385
  workflowControl,
1618
- workflowContract,
1619
1386
  actionProfile,
1620
1387
  });
1621
1388
  report.reasoning = buildReasoning(report);
@@ -108,74 +108,14 @@ function parseCommandScore(output = '', status = 0, approvalRate = 0.5) {
108
108
  };
109
109
  }
110
110
 
111
- function parseCommandLine(cmdString) {
112
- const args = [];
113
- let current = '';
114
- let inDoubleQuote = false;
115
- let inSingleQuote = false;
116
- let escaped = false;
117
-
118
- for (let i = 0; i < cmdString.length; i++) {
119
- const char = cmdString[i];
120
-
121
- if (escaped) {
122
- current += char;
123
- escaped = false;
124
- } else if (char === '\\') {
125
- if (inSingleQuote) {
126
- current += char;
127
- } else {
128
- escaped = true;
129
- }
130
- } else if (char === '"' && !inSingleQuote) {
131
- inDoubleQuote = !inDoubleQuote;
132
- } else if (char === "'" && !inDoubleQuote) {
133
- inSingleQuote = !inSingleQuote;
134
- } else if (char === ' ' && !inDoubleQuote && !inSingleQuote) {
135
- if (current) {
136
- args.push(current);
137
- current = '';
138
- }
139
- } else {
140
- current += char;
141
- }
142
- }
143
- if (current) {
144
- args.push(current);
145
- }
146
- return args;
147
- }
148
-
149
111
  function runCommand(command, {
150
112
  cwd = process.cwd(),
151
113
  env = process.env,
152
114
  timeoutMs = DEFAULT_TIMEOUT_MS,
153
115
  } = {}) {
154
116
  const startedAt = Date.now();
155
- const args = parseCommandLine(command);
156
- const exec = args.shift();
157
-
158
- const execBase = require('node:path').basename(exec).toLowerCase();
159
- let safeExec;
160
- if (exec === process.execPath) {
161
- safeExec = process.execPath;
162
- } else if (execBase === 'node' || execBase === 'node.exe') {
163
- safeExec = process.execPath;
164
- } else if (execBase === 'npm') {
165
- safeExec = 'npm';
166
- } else if (execBase === 'npm.cmd') {
167
- safeExec = 'npm.cmd';
168
- } else if (execBase === 'python3') {
169
- safeExec = 'python3';
170
- } else if (execBase === 'python') {
171
- safeExec = 'python';
172
- } else if (execBase === 'pytest') {
173
- safeExec = 'pytest';
174
- } else {
175
- throw new Error(`Binary ${exec} is not authorized for workspace evolution.`);
176
- }
177
-
178
- const result = spawnSync(safeExec, args, {
117
+ const result = spawnSync(command, [], {
118
+ shell: true,
179
119
  cwd,
180
120
  env,
181
121
  encoding: 'utf8',