thumbgate 1.2.0 → 1.4.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.
- package/.claude-plugin/README.md +4 -4
- package/.claude-plugin/marketplace.json +32 -13
- package/.claude-plugin/plugin.json +15 -2
- package/.well-known/llms.txt +60 -0
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +133 -23
- package/adapters/README.md +1 -1
- package/adapters/chatgpt/openapi.yaml +168 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/mcp/server-stdio.js +85 -2
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +215 -19
- package/bin/postinstall.js +8 -2
- package/config/budget.json +18 -0
- package/config/gates/code-edit.json +61 -0
- package/config/gates/db-write.json +61 -0
- package/config/gates/default.json +154 -3
- package/config/gates/deploy.json +61 -0
- package/config/github-about.json +2 -1
- package/config/merge-quality-checks.json +23 -0
- package/config/model-tiers.json +11 -0
- package/openapi/openapi.yaml +168 -0
- package/package.json +47 -13
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-codex-bridge/.mcp.json +1 -1
- package/plugins/claude-codex-bridge/scripts/codex-bridge.js +1 -3
- package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
- package/plugins/codex-profile/.mcp.json +1 -1
- package/plugins/codex-profile/INSTALL.md +27 -4
- package/plugins/codex-profile/README.md +33 -9
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
- package/plugins/cursor-marketplace/README.md +2 -2
- package/plugins/cursor-marketplace/commands/capture-feedback.md +2 -2
- package/plugins/cursor-marketplace/rules/feedback-capture.mdc +3 -3
- package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +3 -2
- package/plugins/opencode-profile/INSTALL.md +1 -1
- package/public/blog.html +73 -0
- package/public/compare/mem0.html +189 -0
- package/public/compare/speclock.html +180 -0
- package/public/compare.html +12 -4
- package/public/guide.html +5 -5
- package/public/guides/claude-code-prevent-repeated-mistakes.html +161 -0
- package/public/guides/codex-cli-guardrails.html +158 -0
- package/public/guides/cursor-prevent-repeated-mistakes.html +161 -0
- package/public/guides/pre-action-gates.html +162 -0
- package/public/guides/stop-repeated-ai-agent-mistakes.html +159 -0
- package/public/index.html +169 -70
- package/public/learn/ai-agent-persistent-memory.html +1 -0
- package/public/lessons.html +334 -17
- package/public/llm-context.md +140 -0
- package/public/pro.html +24 -22
- package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
- package/scripts/access-anomaly-detector.js +1 -1
- package/scripts/adk-consolidator.js +1 -5
- package/scripts/agent-security-hardening.js +4 -6
- package/scripts/agentic-data-pipeline.js +1 -3
- package/scripts/async-job-runner.js +1 -5
- package/scripts/audit-trail.js +7 -5
- package/scripts/background-agent-governance.js +2 -10
- package/scripts/billing.js +2 -16
- package/scripts/budget-enforcer.js +173 -0
- package/scripts/build-codex-plugin.js +152 -0
- package/scripts/capture-railway-diagnostics.sh +97 -0
- package/scripts/check-congruence.js +133 -15
- package/scripts/claude-feedback-sync.js +320 -0
- package/scripts/cli-telemetry.js +4 -1
- package/scripts/commercial-offer.js +5 -7
- package/scripts/content-engine/linkedin-content-generator.js +154 -0
- package/scripts/content-engine/output/linkedin-memento-validation.md +17 -0
- package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +175 -0
- package/scripts/content-engine/reddit-thread-finder.js +154 -0
- package/scripts/context-engine.js +21 -6
- package/scripts/contextfs.js +33 -44
- package/scripts/dashboard.js +104 -0
- package/scripts/decision-journal.js +341 -0
- package/scripts/delegation-runtime.js +1 -5
- package/scripts/distribution-surfaces.js +26 -0
- package/scripts/document-intake.js +927 -0
- package/scripts/ephemeral-agent-store.js +1 -8
- package/scripts/evolution-state.js +1 -5
- package/scripts/experiment-tracker.js +1 -5
- package/scripts/export-databricks-bundle.js +1 -5
- package/scripts/export-hf-dataset.js +1 -5
- package/scripts/export-training.js +1 -5
- package/scripts/feedback-attribution.js +1 -16
- package/scripts/feedback-history-distiller.js +1 -16
- package/scripts/feedback-loop.js +17 -5
- package/scripts/feedback-root-consolidator.js +2 -21
- package/scripts/feedback-session.js +49 -0
- package/scripts/feedback-to-rules.js +188 -28
- package/scripts/filesystem-search.js +1 -9
- package/scripts/fs-utils.js +104 -0
- package/scripts/gates-engine.js +149 -4
- package/scripts/github-about.js +32 -8
- package/scripts/gtm-revenue-loop.js +1 -5
- package/scripts/harness-selector.js +148 -0
- package/scripts/hosted-job-launcher.js +1 -5
- package/scripts/hybrid-feedback-context.js +7 -33
- package/scripts/intervention-policy.js +753 -0
- package/scripts/lesson-db.js +3 -18
- package/scripts/lesson-inference.js +194 -16
- package/scripts/lesson-retrieval.js +60 -24
- package/scripts/llm-client.js +59 -0
- package/scripts/local-model-profile.js +18 -2
- package/scripts/managed-lesson-agent.js +183 -0
- package/scripts/marketing-experiment.js +8 -22
- package/scripts/meta-agent-loop.js +624 -0
- package/scripts/metered-billing.js +1 -1
- package/scripts/model-tier-router.js +10 -1
- package/scripts/money-watcher.js +1 -4
- package/scripts/obsidian-export.js +1 -5
- package/scripts/operational-integrity.js +369 -34
- package/scripts/org-dashboard.js +6 -1
- package/scripts/per-step-scoring.js +2 -4
- package/scripts/pr-manager.js +201 -19
- package/scripts/pro-features.js +3 -2
- package/scripts/prompt-dlp.js +3 -3
- package/scripts/prove-adapters.js +2 -5
- package/scripts/prove-attribution.js +1 -5
- package/scripts/prove-automation.js +3 -5
- package/scripts/prove-cloudflare-sandbox.js +1 -3
- package/scripts/prove-data-pipeline.js +1 -3
- package/scripts/prove-intelligence.js +1 -3
- package/scripts/prove-lancedb.js +1 -5
- package/scripts/prove-local-intelligence.js +1 -3
- package/scripts/prove-packaged-runtime.js +326 -0
- package/scripts/prove-predictive-insights.js +1 -3
- package/scripts/prove-runtime.js +13 -0
- package/scripts/prove-training-export.js +1 -3
- package/scripts/prove-workflow-contract.js +1 -5
- package/scripts/rate-limiter.js +6 -4
- package/scripts/reddit-dm-outreach.js +14 -4
- package/scripts/schedule-manager.js +3 -5
- package/scripts/security-scanner.js +448 -0
- package/scripts/self-distill-agent.js +579 -0
- package/scripts/semantic-dedup.js +115 -0
- package/scripts/skill-exporter.js +1 -3
- package/scripts/skill-generator.js +1 -5
- package/scripts/social-analytics/engagement-audit.js +1 -18
- package/scripts/social-analytics/pollers/linkedin.js +26 -16
- package/scripts/social-analytics/publishers/linkedin.js +1 -1
- package/scripts/social-analytics/publishers/zernio.js +51 -0
- package/scripts/social-pipeline.js +1 -3
- package/scripts/social-post-hourly.js +47 -4
- package/scripts/statusline-links.js +6 -5
- package/scripts/statusline-local-stats.js +2 -0
- package/scripts/statusline.sh +38 -7
- package/scripts/sync-branch-protection.js +340 -0
- package/scripts/tessl-export.js +1 -3
- package/scripts/thumbgate-search.js +32 -1
- package/scripts/tool-kpi-tracker.js +1 -1
- package/scripts/tool-registry.js +108 -4
- package/scripts/vector-store.js +1 -5
- package/scripts/weekly-auto-post.js +1 -1
- package/scripts/workflow-sentinel.js +205 -4
- package/skills/thumbgate/SKILL.md +2 -2
- package/src/api/server.js +273 -4
- package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
- /package/scripts/social-analytics/db/{social-analytics.db-wal → analytics.sqlite} +0 -0
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
} = require('./operational-integrity');
|
|
17
17
|
const { buildDockerSandboxPlan } = require('./docker-sandbox-planner');
|
|
18
18
|
const { evaluatePretool } = require('./hybrid-feedback-context');
|
|
19
|
+
const { getInterventionRecommendation } = require('./intervention-policy');
|
|
19
20
|
|
|
20
21
|
const GOVERNANCE_STATE_PATH = path.join(process.env.HOME || '/tmp', '.thumbgate', 'governance-state.json');
|
|
21
22
|
const DEFAULT_PROTECTED_FILE_GLOBS = [
|
|
@@ -387,6 +388,7 @@ function scoreRisk({
|
|
|
387
388
|
affectedFiles,
|
|
388
389
|
integrity,
|
|
389
390
|
memoryGuard,
|
|
391
|
+
learnedPolicy,
|
|
390
392
|
blastRadius,
|
|
391
393
|
taskScopeViolation,
|
|
392
394
|
protectedSurface,
|
|
@@ -472,6 +474,43 @@ function scoreRisk({
|
|
|
472
474
|
{ mode: memoryGuard.mode }
|
|
473
475
|
);
|
|
474
476
|
}
|
|
477
|
+
if (learnedPolicy && learnedPolicy.enabled && learnedPolicy.prediction) {
|
|
478
|
+
const confidence = learnedPolicy.prediction.confidence || 0;
|
|
479
|
+
const label = learnedPolicy.prediction.label;
|
|
480
|
+
if (label === 'deny' && confidence >= 0.6) {
|
|
481
|
+
addDriver(
|
|
482
|
+
drivers,
|
|
483
|
+
'learned_policy_deny',
|
|
484
|
+
Math.min(0.26, 0.16 + (confidence * 0.12)),
|
|
485
|
+
'Learned intervention policy predicts a deny-worthy failure pattern.',
|
|
486
|
+
{ confidence, label }
|
|
487
|
+
);
|
|
488
|
+
} else if (label === 'warn' && confidence >= 0.3) {
|
|
489
|
+
addDriver(
|
|
490
|
+
drivers,
|
|
491
|
+
'learned_policy_warn',
|
|
492
|
+
Math.min(0.18, 0.1 + (confidence * 0.08)),
|
|
493
|
+
'Learned intervention policy predicts elevated execution risk.',
|
|
494
|
+
{ confidence, label }
|
|
495
|
+
);
|
|
496
|
+
} else if (label === 'verify' && confidence >= 0.3) {
|
|
497
|
+
addDriver(
|
|
498
|
+
drivers,
|
|
499
|
+
'learned_policy_verify',
|
|
500
|
+
Math.min(0.16, 0.08 + (confidence * 0.06)),
|
|
501
|
+
'Learned intervention policy predicts a verification gap before close-out.',
|
|
502
|
+
{ confidence, label }
|
|
503
|
+
);
|
|
504
|
+
} else if (label === 'recall' && confidence >= 0.3) {
|
|
505
|
+
addDriver(
|
|
506
|
+
drivers,
|
|
507
|
+
'learned_policy_recall',
|
|
508
|
+
Math.min(0.14, 0.06 + (confidence * 0.05)),
|
|
509
|
+
'Learned intervention policy predicts prior lessons are needed before execution.',
|
|
510
|
+
{ confidence, label }
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
475
514
|
|
|
476
515
|
const score = Math.min(1, drivers.reduce((sum, driver) => sum + driver.weight, 0));
|
|
477
516
|
return {
|
|
@@ -492,6 +531,7 @@ function scoreRisk({
|
|
|
492
531
|
function buildEvidence({
|
|
493
532
|
integrity,
|
|
494
533
|
memoryGuard,
|
|
534
|
+
learnedPolicy,
|
|
495
535
|
blastRadius,
|
|
496
536
|
taskScopeViolation,
|
|
497
537
|
protectedSurface,
|
|
@@ -500,6 +540,16 @@ function buildEvidence({
|
|
|
500
540
|
if (memoryGuard && memoryGuard.mode && memoryGuard.mode !== 'allow') {
|
|
501
541
|
evidence.push(`Memory guard predicted ${memoryGuard.mode}: ${memoryGuard.reason}`);
|
|
502
542
|
}
|
|
543
|
+
if (learnedPolicy && learnedPolicy.enabled && learnedPolicy.prediction) {
|
|
544
|
+
const topTokens = Array.isArray(learnedPolicy.topTokens)
|
|
545
|
+
? learnedPolicy.topTokens.map((entry) => entry.token).slice(0, 3)
|
|
546
|
+
: [];
|
|
547
|
+
evidence.push(
|
|
548
|
+
`Learned policy predicted ${learnedPolicy.prediction.label} (${Math.round((learnedPolicy.prediction.confidence || 0) * 100)}% confidence)`
|
|
549
|
+
+ (topTokens.length ? ` from ${topTokens.join(', ')}` : '')
|
|
550
|
+
+ '.'
|
|
551
|
+
);
|
|
552
|
+
}
|
|
503
553
|
if (taskScopeViolation) {
|
|
504
554
|
evidence.push(
|
|
505
555
|
taskScopeViolation.reasonCode === 'missing_task_scope'
|
|
@@ -575,6 +625,7 @@ function buildRemediations({
|
|
|
575
625
|
protectedSurface,
|
|
576
626
|
blastRadius,
|
|
577
627
|
memoryGuard,
|
|
628
|
+
learnedPolicy,
|
|
578
629
|
executionSurface,
|
|
579
630
|
}) {
|
|
580
631
|
const remediations = [];
|
|
@@ -611,6 +662,24 @@ function buildRemediations({
|
|
|
611
662
|
'The system already has evidence that this action pattern failed before.'
|
|
612
663
|
);
|
|
613
664
|
}
|
|
665
|
+
if (learnedPolicy && learnedPolicy.enabled && learnedPolicy.prediction) {
|
|
666
|
+
if (learnedPolicy.prediction.label === 'verify' && learnedPolicy.prediction.confidence >= 0.3) {
|
|
667
|
+
push(
|
|
668
|
+
'verify_before_closeout',
|
|
669
|
+
'Raise verification before claiming success',
|
|
670
|
+
'Run the relevant proof or test command and confirm the exact output before retrying or closing out.',
|
|
671
|
+
'The learned policy predicts this path tends to fail at verification time.'
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
if (learnedPolicy.prediction.label === 'recall' && learnedPolicy.prediction.confidence >= 0.3) {
|
|
675
|
+
push(
|
|
676
|
+
'retrieve_lessons',
|
|
677
|
+
'Inspect prior lessons',
|
|
678
|
+
'Call retrieve_lessons or search_lessons for this tool context before retrying.',
|
|
679
|
+
'The learned policy predicts this action needs prior lessons and corrective context.'
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
614
683
|
if (blastRadius.fileCount >= 4 || blastRadius.surfaceCount >= 3) {
|
|
615
684
|
push(
|
|
616
685
|
'split_blast_radius',
|
|
@@ -636,6 +705,16 @@ function buildReasoning(report) {
|
|
|
636
705
|
`Workflow sentinel risk ${report.band} (${report.riskScore}) for ${report.toolName}.`,
|
|
637
706
|
`Blast radius: ${report.blastRadius.summary}.`,
|
|
638
707
|
];
|
|
708
|
+
if (report.decisionControl) {
|
|
709
|
+
lines.push(
|
|
710
|
+
`Decision control: ${report.decisionControl.decisionOwner} owns a ${report.decisionControl.reversibility} action via ${report.decisionControl.executionMode}.`
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
if (report.learnedPolicy && report.learnedPolicy.enabled && report.learnedPolicy.prediction) {
|
|
714
|
+
lines.push(
|
|
715
|
+
`Learned policy predicted ${report.learnedPolicy.prediction.label} (${report.learnedPolicy.prediction.confidence}).`
|
|
716
|
+
);
|
|
717
|
+
}
|
|
639
718
|
if (report.executionSurface?.shouldSandbox) {
|
|
640
719
|
lines.push(`Execution surface: ${report.executionSurface.summary}`);
|
|
641
720
|
}
|
|
@@ -658,15 +737,106 @@ function getSentinelActionType(toolName) {
|
|
|
658
737
|
return '';
|
|
659
738
|
}
|
|
660
739
|
|
|
661
|
-
function
|
|
740
|
+
function classifyReversibility({ command, blastRadius, integrity, protectedSurface }) {
|
|
741
|
+
const text = String(command || '');
|
|
742
|
+
const blockers = integrity && Array.isArray(integrity.blockers) ? integrity.blockers : [];
|
|
743
|
+
const destructiveCommand = /\bgit\s+push\b.*(?:--force|-f)\b/i.test(text)
|
|
744
|
+
|| /\bgh\s+pr\s+merge\b.*--admin\b/i.test(text)
|
|
745
|
+
|| /\brm\s+-rf\b/i.test(text)
|
|
746
|
+
|| /\b(?:npm|yarn|pnpm)\s+publish\b/i.test(text)
|
|
747
|
+
|| /\bgh\s+release\s+create\b/i.test(text)
|
|
748
|
+
|| /\bgit\s+tag\b/i.test(text);
|
|
749
|
+
const releaseSensitive = blastRadius && Array.isArray(blastRadius.releaseSensitiveFiles)
|
|
750
|
+
? blastRadius.releaseSensitiveFiles.length > 0
|
|
751
|
+
: false;
|
|
752
|
+
const unapprovedProtected = protectedSurface && Array.isArray(protectedSurface.unapprovedProtectedFiles)
|
|
753
|
+
? protectedSurface.unapprovedProtectedFiles.length > 0
|
|
754
|
+
: false;
|
|
755
|
+
const hardBlockers = blockers.some((blocker) => /publish|merge|release|protected/i.test(String(blocker.code || '')));
|
|
756
|
+
|
|
757
|
+
if (destructiveCommand || releaseSensitive || unapprovedProtected || hardBlockers) {
|
|
758
|
+
return 'one_way_door';
|
|
759
|
+
}
|
|
760
|
+
if ((blastRadius && blastRadius.fileCount >= 4) || (blastRadius && blastRadius.surfaceCount >= 2)) {
|
|
761
|
+
return 'reviewable';
|
|
762
|
+
}
|
|
763
|
+
return 'two_way_door';
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function buildDecisionControl({
|
|
767
|
+
decision,
|
|
768
|
+
risk,
|
|
769
|
+
command,
|
|
770
|
+
blastRadius,
|
|
771
|
+
integrity,
|
|
772
|
+
protectedSurface,
|
|
773
|
+
}) {
|
|
774
|
+
const reversibility = classifyReversibility({
|
|
775
|
+
command,
|
|
776
|
+
blastRadius,
|
|
777
|
+
integrity,
|
|
778
|
+
protectedSurface,
|
|
779
|
+
});
|
|
780
|
+
const hasOperationalBlockers = Boolean(integrity && Array.isArray(integrity.blockers) && integrity.blockers.length > 0);
|
|
781
|
+
const requiresCheckpoint = decision === 'warn'
|
|
782
|
+
|| (decision === 'allow' && (reversibility !== 'two_way_door' || hasOperationalBlockers));
|
|
783
|
+
const executionMode = decision === 'deny'
|
|
784
|
+
? 'blocked'
|
|
785
|
+
: requiresCheckpoint
|
|
786
|
+
? 'checkpoint_required'
|
|
787
|
+
: 'auto_execute';
|
|
788
|
+
const decisionOwner = executionMode === 'blocked'
|
|
789
|
+
? 'human'
|
|
790
|
+
: executionMode === 'checkpoint_required'
|
|
791
|
+
? reversibility === 'two_way_door' && !hasOperationalBlockers
|
|
792
|
+
? 'shared'
|
|
793
|
+
: 'human'
|
|
794
|
+
: 'agent';
|
|
795
|
+
|
|
796
|
+
return {
|
|
797
|
+
executionMode,
|
|
798
|
+
decisionOwner,
|
|
799
|
+
reversibility,
|
|
800
|
+
requiresHumanApproval: executionMode === 'checkpoint_required' && decisionOwner !== 'agent',
|
|
801
|
+
recommendedAction: executionMode === 'blocked'
|
|
802
|
+
? 'halt'
|
|
803
|
+
: executionMode === 'checkpoint_required'
|
|
804
|
+
? 'review'
|
|
805
|
+
: 'proceed',
|
|
806
|
+
summary: executionMode === 'blocked'
|
|
807
|
+
? 'Do not proceed until the remediation steps are completed.'
|
|
808
|
+
: executionMode === 'checkpoint_required'
|
|
809
|
+
? 'Pause for explicit review before executing this action.'
|
|
810
|
+
: 'Safe to execute quickly with standard evidence capture.',
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function chooseDecision({ riskScore, integrity, memoryGuard, learnedPolicy, blastRadius, command }) {
|
|
662
815
|
const hasOperationalBlockers = Boolean(integrity && Array.isArray(integrity.blockers) && integrity.blockers.length > 0);
|
|
663
816
|
const destructiveBypass = /\bgit\s+push\b.*(?:--force|-f)\b/i.test(command) || /\bgh\s+pr\s+merge\b.*--admin\b/i.test(command);
|
|
817
|
+
const learnedPrediction = learnedPolicy && learnedPolicy.enabled ? learnedPolicy.prediction : null;
|
|
818
|
+
const learnedHardStop = Boolean(
|
|
819
|
+
learnedPrediction
|
|
820
|
+
&& learnedPrediction.label === 'deny'
|
|
821
|
+
&& learnedPrediction.confidence >= 0.7
|
|
822
|
+
);
|
|
823
|
+
const learnedWarning = Boolean(
|
|
824
|
+
learnedPrediction
|
|
825
|
+
&& ['warn', 'verify', 'deny'].includes(learnedPrediction.label)
|
|
826
|
+
&& learnedPrediction.confidence >= 0.3
|
|
827
|
+
);
|
|
828
|
+
const learnedRecall = Boolean(
|
|
829
|
+
learnedPrediction
|
|
830
|
+
&& learnedPrediction.label === 'recall'
|
|
831
|
+
&& learnedPrediction.confidence >= 0.3
|
|
832
|
+
);
|
|
664
833
|
const lowBlastRadius = blastRadius.fileCount <= 1
|
|
665
834
|
&& blastRadius.surfaceCount <= 1
|
|
666
835
|
&& blastRadius.releaseSensitiveFiles.length === 0
|
|
667
836
|
&& blastRadius.unapprovedProtectedFiles === 0;
|
|
668
837
|
const lowRiskHandoff = /\bgit\s+push\b|\bgh\s+pr\s+(?:create|merge)\b/i.test(command)
|
|
669
838
|
&& !destructiveBypass
|
|
839
|
+
&& !learnedHardStop
|
|
670
840
|
&& lowBlastRadius
|
|
671
841
|
&& !hasOperationalBlockers
|
|
672
842
|
&& memoryGuard
|
|
@@ -686,10 +856,10 @@ function chooseDecision({ riskScore, integrity, memoryGuard, blastRadius, comman
|
|
|
686
856
|
if (lowRiskHandoff) {
|
|
687
857
|
return 'allow';
|
|
688
858
|
}
|
|
689
|
-
if (destructiveBypass || repeatedHighBlast || (hasOperationalBlockers && riskScore >= 0.72) || riskScore >= 0.86) {
|
|
859
|
+
if (destructiveBypass || learnedHardStop || repeatedHighBlast || (hasOperationalBlockers && riskScore >= 0.72) || riskScore >= 0.86) {
|
|
690
860
|
return 'deny';
|
|
691
861
|
}
|
|
692
|
-
if (riskScore >= 0.45) {
|
|
862
|
+
if (riskScore >= 0.45 || (learnedWarning && riskScore >= 0.3) || (learnedRecall && riskScore >= 0.34)) {
|
|
693
863
|
return 'warn';
|
|
694
864
|
}
|
|
695
865
|
return 'allow';
|
|
@@ -732,6 +902,20 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
732
902
|
affectedFiles,
|
|
733
903
|
}), options.feedbackOptions || {});
|
|
734
904
|
const memoryGuard = normalizeMemoryGuardForSentinel(rawMemoryGuard, highRiskAction);
|
|
905
|
+
const learnedPolicy = getInterventionRecommendation({
|
|
906
|
+
toolName,
|
|
907
|
+
command: toolInput.command || '',
|
|
908
|
+
affectedFiles,
|
|
909
|
+
integrity,
|
|
910
|
+
memoryGuard,
|
|
911
|
+
riskBand: highRiskAction ? 'high' : 'low',
|
|
912
|
+
taskScopeViolation,
|
|
913
|
+
protectedSurface: protectedSurfaceForRisk,
|
|
914
|
+
}, {
|
|
915
|
+
feedbackDir: options.feedbackDir
|
|
916
|
+
|| process.env.THUMBGATE_FEEDBACK_DIR
|
|
917
|
+
|| (repoRoot ? path.join(repoRoot, '.thumbgate') : null),
|
|
918
|
+
});
|
|
735
919
|
const blastRadius = buildBlastRadius({
|
|
736
920
|
affectedFiles,
|
|
737
921
|
integrity,
|
|
@@ -743,6 +927,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
743
927
|
affectedFiles,
|
|
744
928
|
integrity,
|
|
745
929
|
memoryGuard,
|
|
930
|
+
learnedPolicy,
|
|
746
931
|
blastRadius,
|
|
747
932
|
taskScopeViolation,
|
|
748
933
|
protectedSurface: protectedSurfaceForRisk,
|
|
@@ -763,6 +948,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
763
948
|
riskScore: risk.score,
|
|
764
949
|
integrity,
|
|
765
950
|
memoryGuard,
|
|
951
|
+
learnedPolicy,
|
|
766
952
|
blastRadius: {
|
|
767
953
|
...blastRadius,
|
|
768
954
|
unapprovedProtectedFiles: protectedSurfaceForRisk.unapprovedProtectedFiles.length,
|
|
@@ -772,6 +958,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
772
958
|
const evidence = buildEvidence({
|
|
773
959
|
integrity,
|
|
774
960
|
memoryGuard,
|
|
961
|
+
learnedPolicy,
|
|
775
962
|
blastRadius,
|
|
776
963
|
taskScopeViolation,
|
|
777
964
|
protectedSurface: protectedSurfaceForRisk,
|
|
@@ -782,6 +969,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
782
969
|
protectedSurface: protectedSurfaceForRisk,
|
|
783
970
|
blastRadius,
|
|
784
971
|
memoryGuard,
|
|
972
|
+
learnedPolicy,
|
|
785
973
|
executionSurface,
|
|
786
974
|
});
|
|
787
975
|
const summary = decision === 'allow'
|
|
@@ -790,7 +978,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
790
978
|
? 'Predicted workflow risk is elevated before execution.'
|
|
791
979
|
: 'Predicted workflow failure before execution.';
|
|
792
980
|
const report = {
|
|
793
|
-
sentinelVersion: 'workflow-sentinel-
|
|
981
|
+
sentinelVersion: 'workflow-sentinel-v2',
|
|
794
982
|
toolName,
|
|
795
983
|
decision,
|
|
796
984
|
riskScore: risk.score,
|
|
@@ -802,6 +990,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
802
990
|
remediations,
|
|
803
991
|
executionSurface,
|
|
804
992
|
memoryGuard,
|
|
993
|
+
learnedPolicy,
|
|
805
994
|
taskScopeViolation,
|
|
806
995
|
operationalIntegrity: {
|
|
807
996
|
ok: integrity.ok,
|
|
@@ -813,11 +1002,23 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
|
|
|
813
1002
|
commandInfo: integrity.commandInfo,
|
|
814
1003
|
},
|
|
815
1004
|
};
|
|
1005
|
+
report.decisionControl = buildDecisionControl({
|
|
1006
|
+
decision,
|
|
1007
|
+
risk,
|
|
1008
|
+
command: toolInput.command || '',
|
|
1009
|
+
blastRadius: {
|
|
1010
|
+
...blastRadius,
|
|
1011
|
+
unapprovedProtectedFiles: protectedSurfaceForRisk.unapprovedProtectedFiles.length,
|
|
1012
|
+
},
|
|
1013
|
+
integrity,
|
|
1014
|
+
protectedSurface: protectedSurfaceForRisk,
|
|
1015
|
+
});
|
|
816
1016
|
report.reasoning = buildReasoning(report);
|
|
817
1017
|
return report;
|
|
818
1018
|
}
|
|
819
1019
|
|
|
820
1020
|
module.exports = {
|
|
1021
|
+
buildDecisionControl,
|
|
821
1022
|
DEFAULT_PROTECTED_FILE_GLOBS,
|
|
822
1023
|
buildBlastRadius,
|
|
823
1024
|
buildEvidence,
|
|
@@ -86,13 +86,13 @@ Bounded retrieval of relevant feedback history for the current task. The agent g
|
|
|
86
86
|
|
|
87
87
|
| | Free | Pro | Team |
|
|
88
88
|
|---|---|---|---|
|
|
89
|
-
| Feedback capture |
|
|
89
|
+
| Feedback capture | 3/day | Unlimited | Unlimited |
|
|
90
90
|
| Lesson search | 5/day | Unlimited | Unlimited |
|
|
91
91
|
| Active gates | 5 | Unlimited | Unlimited |
|
|
92
92
|
| Dashboard | - | Yes | Yes |
|
|
93
93
|
| DPO export | - | Yes | Yes |
|
|
94
94
|
| Seats | 1 | 1 | Per-seat |
|
|
95
|
-
| Price | $0 | $19/mo | $
|
|
95
|
+
| Price | $0 | $19/mo | $99/seat/mo |
|
|
96
96
|
|
|
97
97
|
Start a 7-day free trial of Pro: <https://buy.stripe.com/fZu9AT3Ug6zcdWh0XN3sI08>
|
|
98
98
|
|