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.
- package/.claude-plugin/marketplace.json +85 -0
- package/.claude-plugin/plugin.json +3 -4
- package/.well-known/llms.txt +12 -33
- package/.well-known/mcp/server-card.json +8 -8
- package/README.md +30 -215
- package/adapters/chatgpt/openapi.yaml +1695 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/gemini/function-declarations.json +0 -1
- package/adapters/mcp/server-stdio.js +11 -263
- package/adapters/opencode/opencode.json +1 -1
- package/bench/thumbgate-bench.json +2 -2
- package/bin/cli.js +122 -1421
- package/bin/postinstall.js +27 -11
- package/config/gate-templates.json +0 -216
- package/config/gates/claim-verification.json +0 -12
- package/config/gates/default.json +2 -31
- package/config/github-about.json +2 -2
- package/config/mcp-allowlists.json +13 -23
- package/config/merge-quality-checks.json +1 -0
- package/config/model-candidates.json +6 -121
- package/openapi/openapi.yaml +0 -12
- package/package.json +98 -228
- package/public/blog.html +4 -4
- package/public/codex-plugin.html +20 -72
- package/public/compare.html +8 -31
- package/public/dashboard.html +166 -930
- package/public/federal.html +2 -2
- package/public/guide.html +9 -33
- package/public/index.html +116 -495
- package/public/learn.html +18 -191
- package/public/lessons.html +10 -168
- package/public/numbers.html +7 -7
- package/public/pro.html +11 -34
- package/scripts/agent-memory-lifecycle.js +0 -211
- package/scripts/agent-readiness.js +3 -167
- package/scripts/agent-reward-model.js +1 -53
- package/scripts/auto-promote-gates.js +10 -82
- package/scripts/auto-wire-hooks.js +0 -14
- package/scripts/billing.js +1 -93
- package/scripts/build-metadata.js +10 -50
- package/scripts/cli-feedback.js +6 -18
- package/scripts/cli-schema.js +0 -90
- package/scripts/cli-telemetry.js +1 -6
- package/scripts/commercial-offer.js +2 -82
- package/scripts/context-manager.js +6 -74
- package/scripts/dashboard.js +2 -68
- package/scripts/durability/step.js +3 -3
- package/scripts/export-databricks-bundle.js +1 -5
- package/scripts/export-dpo-pairs.js +2 -7
- package/scripts/feedback-loop.js +1 -123
- package/scripts/feedback-quality.js +0 -87
- package/scripts/filesystem-search.js +10 -35
- package/scripts/gate-stats.js +0 -89
- package/scripts/gates-engine.js +85 -1105
- package/scripts/gemini-embedding-policy.js +1 -2
- package/scripts/hook-runtime.js +14 -20
- package/scripts/hook-thumbgate-cache-updater.js +2 -18
- package/scripts/hybrid-feedback-context.js +7 -142
- package/scripts/lesson-inference.js +3 -8
- package/scripts/lesson-search.js +1 -17
- package/scripts/license.js +1 -0
- package/scripts/llm-client.js +9 -390
- package/scripts/local-model-profile.js +8 -15
- package/scripts/memory-scope-readiness.js +0 -159
- package/scripts/meta-agent-loop.js +0 -36
- package/scripts/operational-integrity.js +5 -39
- package/scripts/oss-pr-opportunity-scout.js +5 -35
- package/scripts/plausible-server-events.js +6 -9
- package/scripts/pro-local-dashboard.js +4 -4
- package/scripts/proxy-pointer-rag-guardrails.js +1 -42
- package/scripts/rate-limiter.js +13 -64
- package/scripts/secret-scanner.js +5 -44
- package/scripts/security-scanner.js +10 -260
- package/scripts/self-distill-agent.js +1 -3
- package/scripts/seo-gsd.js +2 -916
- package/scripts/statusline-cache-path.js +2 -17
- package/scripts/statusline-local-stats.js +1 -9
- package/scripts/statusline-meta.js +2 -28
- package/scripts/statusline.sh +4 -20
- package/scripts/telemetry-analytics.js +0 -357
- package/scripts/thompson-sampling.js +10 -31
- package/scripts/thumbgate-bench.js +1 -16
- package/scripts/thumbgate-search.js +19 -85
- package/scripts/tool-registry.js +1 -169
- package/scripts/vector-store.js +0 -45
- package/scripts/workflow-sentinel.js +53 -286
- package/scripts/workspace-evolver.js +2 -62
- package/src/api/server.js +290 -2578
- package/.claude/commands/dashboard.md +0 -15
- package/.claude/commands/thumbgate-blocked.md +0 -27
- package/.claude/commands/thumbgate-dashboard.md +0 -15
- package/.claude/commands/thumbgate-doctor.md +0 -30
- package/.claude/commands/thumbgate-guard.md +0 -36
- package/.claude/commands/thumbgate-protect.md +0 -30
- package/.claude/commands/thumbgate-rules.md +0 -30
- package/.well-known/agentic-verify.txt +0 -1
- package/adapters/gcp/dfcx-webhook-gate.js +0 -295
- package/adapters/letta/README.md +0 -41
- package/adapters/letta/thumbgate-letta-adapter.js +0 -133
- package/adapters/policy-engine/ethicore-guardian-client.js +0 -68
- package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +0 -260
- package/bench/observability-eval-suite.json +0 -26
- package/bin/dashboard-cli.js +0 -7
- package/commands/dashboard.md +0 -15
- package/commands/thumbgate-dashboard.md +0 -15
- package/config/builtin-lessons.json +0 -23
- package/config/gate-classifier-routing.json +0 -98
- package/config/post-deploy-marketing-pages.json +0 -61
- package/public/about.html +0 -162
- package/public/agent-manager.html +0 -179
- package/public/agents-cost-savings.html +0 -153
- package/public/ai-malpractice-prevention.html +0 -818
- package/public/assets/brand/github-social-preview.png +0 -0
- package/public/assets/brand/thumbgate-icon-512.png +0 -0
- package/public/assets/brand/thumbgate-icon-pro-512.png +0 -0
- package/public/assets/brand/thumbgate-icon-team-512.png +0 -0
- package/public/assets/brand/thumbgate-logo-1200x360.png +0 -0
- package/public/assets/brand/thumbgate-logo-transparent.svg +0 -22
- package/public/assets/brand/thumbgate-mark-inline-v3.svg +0 -19
- package/public/assets/brand/thumbgate-mark-pro.svg +0 -23
- package/public/assets/brand/thumbgate-mark-team.svg +0 -26
- package/public/assets/brand/thumbgate-mark.svg +0 -21
- package/public/assets/brand/thumbgate-wordmark.svg +0 -20
- package/public/assets/claude-thumbgate-statusbar.svg +0 -8
- package/public/assets/codex-thumbgate-statusbar-test.svg +0 -9
- package/public/assets/legal-intake-control-flow.svg +0 -66
- package/public/brand/thumbgate-mark.svg +0 -19
- package/public/brand/thumbgate-og.svg +0 -16
- package/public/chatgpt-app.html +0 -330
- package/public/codex-enterprise.html +0 -123
- package/public/js/buyer-intent.js +0 -672
- package/public/pricing.html +0 -399
- package/scripts/action-receipts.js +0 -324
- package/scripts/activation-quickstart.js +0 -187
- package/scripts/agent-operations-planner.js +0 -621
- package/scripts/ai-component-inventory.js +0 -367
- package/scripts/async-eval-observability.js +0 -236
- package/scripts/audit.js +0 -65
- package/scripts/aws-blocks-guardrails.js +0 -228
- package/scripts/classifier-routing.js +0 -130
- package/scripts/dashboard-chat.js +0 -332
- package/scripts/feedback-aggregate.js +0 -281
- package/scripts/feedback-sanitizer.js +0 -105
- package/scripts/hob-pack.js +0 -591
- package/scripts/hook-stop-anti-claim.js +0 -301
- package/scripts/install-shim.js +0 -87
- package/scripts/mcp-oauth.js +0 -293
- package/scripts/noop-detect.js +0 -285
- package/scripts/omlx-smoke.js +0 -192
- package/scripts/parallel-workflow-orchestrator.js +0 -293
- package/scripts/plan-gate.js +0 -243
- package/scripts/plausible-domain-config.js +0 -99
- package/scripts/qa-scenario-planner.js +0 -136
- package/scripts/repeat-metric.js +0 -137
- package/scripts/secret-fixture-tokens.js +0 -61
- package/scripts/secret-redaction.js +0 -166
- package/scripts/self-harness-optimizer.js +0 -141
- package/scripts/self-healing-check.js +0 -193
- package/scripts/silent-failure-cluster.js +0 -531
- package/scripts/statusline-cache-read.js +0 -57
- package/scripts/sync-telemetry-from-prod.js +0 -374
- package/scripts/tool-contract-validator.js +0 -76
- package/scripts/trajectory-scorer.js +0 -63
- package/scripts/verify-marketing-pages-deployed.js +0 -195
- 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
|
|
68
|
-
protectedApprovals: Array.isArray(raw
|
|
69
|
-
branchGovernance: raw
|
|
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 (
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
1258
|
-
const hasCostWarning = costControl
|
|
1259
|
-
const hasCostBlock = costControl
|
|
1260
|
-
const hasWorkflowWarning = workflowControl
|
|
1261
|
-
const hasWorkflowBlock = workflowControl
|
|
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
|
|
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
|
|
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
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
&&
|
|
1320
|
-
&&
|
|
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
|
-
|
|
1325
|
-
|
|
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
|
-
&&
|
|
1159
|
+
&& lowBlastRadius
|
|
1344
1160
|
&& !hasOperationalBlockers
|
|
1345
|
-
&& memoryGuard
|
|
1161
|
+
&& memoryGuard
|
|
1162
|
+
&& memoryGuard.mode !== 'allow'
|
|
1346
1163
|
&& riskScore <= 0.62;
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
|
156
|
-
|
|
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',
|