thumbgate 1.27.17 → 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 -221
- 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 +99 -229
- 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 -145
- 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
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"thumbgate": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--yes", "--package", "thumbgate@1.
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.20.0", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@1.
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.20.0", "thumbgate", "gate-check"]
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -70,21 +70,6 @@ const {
|
|
|
70
70
|
verifyClaimEvidence,
|
|
71
71
|
registerClaimGate,
|
|
72
72
|
} = require('../../scripts/gates-engine');
|
|
73
|
-
const { mergeRepeatMetricIntoGateStats } = require('../../scripts/repeat-metric');
|
|
74
|
-
const {
|
|
75
|
-
detectNoop,
|
|
76
|
-
computeActionStateHash,
|
|
77
|
-
recordActionAttempt,
|
|
78
|
-
isRepeatAttempt,
|
|
79
|
-
} = require('../../scripts/noop-detect');
|
|
80
|
-
const { recordAuditEvent } = require('../../scripts/audit-trail');
|
|
81
|
-
const {
|
|
82
|
-
recordReceipt,
|
|
83
|
-
getReceiptForAction,
|
|
84
|
-
getRecentReceipts,
|
|
85
|
-
pairFeedbackWithReceipt,
|
|
86
|
-
buildReceiptContextEntries,
|
|
87
|
-
} = require('../../scripts/action-receipts');
|
|
88
73
|
const {
|
|
89
74
|
evaluateOperationalIntegrity,
|
|
90
75
|
} = require('../../scripts/operational-integrity');
|
|
@@ -231,7 +216,7 @@ const {
|
|
|
231
216
|
finalizeSession: finalizeFeedbackSession,
|
|
232
217
|
} = require('../../scripts/feedback-session');
|
|
233
218
|
|
|
234
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.
|
|
219
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.20.0' };
|
|
235
220
|
const COMMERCE_CATEGORIES = [
|
|
236
221
|
'product_recommendation',
|
|
237
222
|
'brand_compliance',
|
|
@@ -383,111 +368,6 @@ function buildRecallResponse(args = {}) {
|
|
|
383
368
|
return toTextResult(text);
|
|
384
369
|
}
|
|
385
370
|
|
|
386
|
-
function buildSuggestFixResponse(args = {}) {
|
|
387
|
-
const context = String(args.context || '').trim();
|
|
388
|
-
const rawLimit = Number(args.limit);
|
|
389
|
-
const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.min(rawLimit, 5) : 3;
|
|
390
|
-
|
|
391
|
-
// If no context provided, return generic suggestion
|
|
392
|
-
if (!context) {
|
|
393
|
-
return toTextResult({
|
|
394
|
-
suggestions: [
|
|
395
|
-
{
|
|
396
|
-
action: 'Capture feedback about what went wrong so ThumbGate can learn and prevent recurrence.',
|
|
397
|
-
source: 'generic',
|
|
398
|
-
},
|
|
399
|
-
],
|
|
400
|
-
query: '',
|
|
401
|
-
totalFound: 0,
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Search lessons via lesson-search module
|
|
406
|
-
const lessonModule = loadPrivateMcpModule('lessonSearch');
|
|
407
|
-
let lessonActions = [];
|
|
408
|
-
if (lessonModule) {
|
|
409
|
-
try {
|
|
410
|
-
const searchResult = lessonModule.searchLessons(context, { limit: 10 });
|
|
411
|
-
const results = Array.isArray(searchResult && searchResult.results) ? searchResult.results : [];
|
|
412
|
-
for (const result of results) {
|
|
413
|
-
const correctiveActions = (result.systemResponse && Array.isArray(result.systemResponse.correctiveActions))
|
|
414
|
-
? result.systemResponse.correctiveActions
|
|
415
|
-
: [];
|
|
416
|
-
for (const action of correctiveActions) {
|
|
417
|
-
const text = String(action.text || '').trim();
|
|
418
|
-
if (text) {
|
|
419
|
-
lessonActions.push({
|
|
420
|
-
action: text,
|
|
421
|
-
source: action.source || `lesson:${result.id || 'unknown'}`,
|
|
422
|
-
score: result.score || 0,
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
// Also pick up lesson-level howToAvoid / actionNeeded when no explicit correctiveActions
|
|
427
|
-
if (correctiveActions.length === 0 && result.lesson) {
|
|
428
|
-
const text = result.lesson.howToAvoid || result.lesson.actionNeeded || '';
|
|
429
|
-
if (text) {
|
|
430
|
-
lessonActions.push({
|
|
431
|
-
action: String(text).trim(),
|
|
432
|
-
source: `lesson:${result.id || 'unknown'}`,
|
|
433
|
-
score: result.score || 0,
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
} catch {
|
|
439
|
-
// lesson search failure is non-fatal
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Search prevention rules directly via lesson-search module's helper
|
|
444
|
-
let ruleActions = [];
|
|
445
|
-
try {
|
|
446
|
-
const { readPreventionRuleMatches } = require('../../scripts/lesson-search');
|
|
447
|
-
const ruleMatches = readPreventionRuleMatches(context, limit);
|
|
448
|
-
for (const rule of ruleMatches) {
|
|
449
|
-
const text = rule.summary || rule.title || '';
|
|
450
|
-
if (text) {
|
|
451
|
-
ruleActions.push({
|
|
452
|
-
action: String(text).trim(),
|
|
453
|
-
source: `rule:${String(rule.title || 'prevention_rules').trim()}`,
|
|
454
|
-
score: rule.score || 0,
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
} catch {
|
|
459
|
-
// rule search failure is non-fatal
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Merge, deduplicate, sort by score, and take top `limit`
|
|
463
|
-
const seen = new Set();
|
|
464
|
-
const all = [...lessonActions, ...ruleActions]
|
|
465
|
-
.filter((item) => {
|
|
466
|
-
if (!item.action) return false;
|
|
467
|
-
const key = item.action.toLowerCase();
|
|
468
|
-
if (seen.has(key)) return false;
|
|
469
|
-
seen.add(key);
|
|
470
|
-
return true;
|
|
471
|
-
})
|
|
472
|
-
.sort((a, b) => (b.score || 0) - (a.score || 0))
|
|
473
|
-
.slice(0, limit)
|
|
474
|
-
.map(({ action, source }) => ({ action, source }));
|
|
475
|
-
|
|
476
|
-
// If nothing matched, add generic fallback
|
|
477
|
-
if (all.length === 0) {
|
|
478
|
-
all.push({
|
|
479
|
-
action: 'No matching lessons or rules found. Capture feedback via capture_feedback so ThumbGate can learn from this failure.',
|
|
480
|
-
source: 'generic',
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
return toTextResult({
|
|
485
|
-
suggestions: all,
|
|
486
|
-
query: context,
|
|
487
|
-
totalFound: all.length,
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
|
|
491
371
|
function buildDiagnoseFailureResponse(args = {}) {
|
|
492
372
|
let intentPlan = null;
|
|
493
373
|
const requestedProfile = args.mcpProfile || getActiveMcpProfile();
|
|
@@ -539,28 +419,6 @@ function buildContextPackResponse(args = {}) {
|
|
|
539
419
|
maxChars: Number(args.maxChars || 6000),
|
|
540
420
|
namespaces,
|
|
541
421
|
});
|
|
542
|
-
// Feed outcome-paired action receipts into the pack so an action->outcome
|
|
543
|
-
// history is available alongside lessons/rules. Additive + guarded: a
|
|
544
|
-
// receipt-store failure must never break context pack construction.
|
|
545
|
-
try {
|
|
546
|
-
const receiptEntries = buildReceiptContextEntries(args.query || '', Number(args.maxItems || 8));
|
|
547
|
-
if (Array.isArray(receiptEntries) && receiptEntries.length && Array.isArray(pack.items)) {
|
|
548
|
-
for (const entry of receiptEntries) {
|
|
549
|
-
pack.items.push({
|
|
550
|
-
id: `action-receipt_${entry && entry.score != null ? entry.score : ''}_${pack.items.length}`,
|
|
551
|
-
namespace: 'action-receipts',
|
|
552
|
-
title: 'Action receipt outcome',
|
|
553
|
-
structuredContext: { rawContent: entry && entry.text ? String(entry.text) : '' },
|
|
554
|
-
tags: ['action-receipt', 'outcome-paired'],
|
|
555
|
-
score: entry && typeof entry.score === 'number' ? entry.score : 0,
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
if (!Array.isArray(pack.namespaces)) pack.namespaces = [];
|
|
559
|
-
if (!pack.namespaces.includes('action-receipts')) pack.namespaces.push('action-receipts');
|
|
560
|
-
}
|
|
561
|
-
} catch {
|
|
562
|
-
// ignore receipt enrichment failures
|
|
563
|
-
}
|
|
564
422
|
return toTextResult(pack);
|
|
565
423
|
}
|
|
566
424
|
|
|
@@ -674,22 +532,7 @@ function buildEstimateUncertaintyResponse(args = {}) {
|
|
|
674
532
|
|
|
675
533
|
async function callTool(name, args = {}) {
|
|
676
534
|
assertToolAllowed(name, getActiveMcpProfile());
|
|
677
|
-
|
|
678
|
-
// Validate tool input contract against schema
|
|
679
|
-
const { TOOLS } = require('../../scripts/tool-registry');
|
|
680
|
-
const toolDef = TOOLS.find(t => t.name === name);
|
|
681
|
-
if (toolDef && toolDef.inputSchema) {
|
|
682
|
-
const { validateToolContract } = require('../../scripts/tool-contract-validator');
|
|
683
|
-
const validation = validateToolContract(toolDef.inputSchema, args);
|
|
684
|
-
if (!validation.valid) {
|
|
685
|
-
const err = new Error(`Tool contract violation on '${name}': ${validation.errors.join('; ')}`);
|
|
686
|
-
err.errorCategory = 'contract';
|
|
687
|
-
err.isRetryable = false;
|
|
688
|
-
throw err;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
if (name !== 'workflow_sentinel' && process.env.THUMBGATE_DISABLE_MCP_FIREWALL !== '1') {
|
|
535
|
+
if (name !== 'workflow_sentinel') {
|
|
693
536
|
const firewallResult = (await evaluateGatesAsync(name, args)) || evaluateSecretGuard({ tool_name: name, tool_input: args });
|
|
694
537
|
if (firewallResult && firewallResult.decision === 'deny') {
|
|
695
538
|
const err = new Error(`Action blocked by Semantic Firewall: ${firewallResult.message}`);
|
|
@@ -722,13 +565,9 @@ async function callToolInner(name, args) {
|
|
|
722
565
|
if (name === 'describe_reliability_entity') name = 'describe_semantic_entity';
|
|
723
566
|
|
|
724
567
|
switch (name) {
|
|
725
|
-
case 'capture_feedback':
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
// args unchanged when there is no matching receipt (non-breaking).
|
|
729
|
-
const pairedFeedback = pairFeedbackWithReceipt(args);
|
|
730
|
-
return toCaptureFeedbackTextResult(captureFeedback(pairedFeedback));
|
|
731
|
-
}
|
|
568
|
+
case 'capture_feedback':
|
|
569
|
+
|
|
570
|
+
return toCaptureFeedbackTextResult(captureFeedback(args));
|
|
732
571
|
case 'feedback_summary':
|
|
733
572
|
return toTextResult(feedbackSummary(Number(args.recent || 20)));
|
|
734
573
|
case 'search_lessons': {
|
|
@@ -740,8 +579,6 @@ async function callToolInner(name, args) {
|
|
|
740
579
|
tags: Array.isArray(args.tags) ? args.tags : [],
|
|
741
580
|
}));
|
|
742
581
|
}
|
|
743
|
-
case 'suggest_fix':
|
|
744
|
-
return buildSuggestFixResponse(args);
|
|
745
582
|
case 'retrieve_lessons': {
|
|
746
583
|
// Cross-encoder reranking: retrieve more candidates, then rerank for precision
|
|
747
584
|
const { retrieveWithRerankingSync } = loadOptionalModule(path.join(__dirname, '../../scripts/cross-encoder-reranker'), () => ({
|
|
@@ -760,23 +597,6 @@ async function callToolInner(name, args) {
|
|
|
760
597
|
},
|
|
761
598
|
));
|
|
762
599
|
}
|
|
763
|
-
case 'ai_component_inventory': {
|
|
764
|
-
const {
|
|
765
|
-
scanAiComponents,
|
|
766
|
-
buildCycloneDxMlBom,
|
|
767
|
-
formatInventoryText,
|
|
768
|
-
} = require('../../scripts/ai-component-inventory');
|
|
769
|
-
const rootDir = args.rootDir ? path.resolve(String(args.rootDir)) : process.cwd();
|
|
770
|
-
const inventory = scanAiComponents({
|
|
771
|
-
rootDir,
|
|
772
|
-
maxFiles: args.maxFiles ? Number(args.maxFiles) : undefined,
|
|
773
|
-
includeSnippets: args.includeSnippets !== false,
|
|
774
|
-
});
|
|
775
|
-
const format = String(args.format || 'summary').toLowerCase();
|
|
776
|
-
if (format === 'cyclonedx') return toTextResult(buildCycloneDxMlBom(inventory));
|
|
777
|
-
if (format === 'json') return toTextResult(inventory);
|
|
778
|
-
return toTextResult(formatInventoryText(inventory));
|
|
779
|
-
}
|
|
780
600
|
case 'search_thumbgate':
|
|
781
601
|
enforceLimit('search_thumbgate');
|
|
782
602
|
return toTextResult(searchThumbgate({
|
|
@@ -852,7 +672,6 @@ async function callToolInner(name, args) {
|
|
|
852
672
|
bundleId: args.bundleId,
|
|
853
673
|
partnerProfile: args.partnerProfile,
|
|
854
674
|
delegationMode: args.delegationMode,
|
|
855
|
-
enforcePlanQuality: args.enforcePlanQuality === true,
|
|
856
675
|
approved: args.approved === true,
|
|
857
676
|
repoPath: args.repoPath,
|
|
858
677
|
}));
|
|
@@ -984,7 +803,6 @@ async function callToolInner(name, args) {
|
|
|
984
803
|
summary: args.summary,
|
|
985
804
|
allowedPaths: args.allowedPaths,
|
|
986
805
|
protectedPaths: args.protectedPaths,
|
|
987
|
-
workflowContract: args.workflowContract,
|
|
988
806
|
repoPath: args.repoPath,
|
|
989
807
|
localOnly: args.localOnly === true,
|
|
990
808
|
clear: args.clear === true,
|
|
@@ -1023,56 +841,19 @@ async function callToolInner(name, args) {
|
|
|
1023
841
|
});
|
|
1024
842
|
case 'track_action': {
|
|
1025
843
|
const entry = trackAction(args.actionId, args.metadata || {});
|
|
1026
|
-
|
|
844
|
+
return toTextResult({
|
|
1027
845
|
tracked: true,
|
|
1028
846
|
actionId: args.actionId,
|
|
1029
847
|
...entry,
|
|
1030
|
-
};
|
|
1031
|
-
// No-op / repeat signal: when the caller carries a precomputed state hash
|
|
1032
|
-
// in metadata, surface whether this exact (action, state) was already
|
|
1033
|
-
// attempted this session. Additive flag, non-breaking.
|
|
1034
|
-
const metadataStateHash = args.metadata && args.metadata.stateHash;
|
|
1035
|
-
if (metadataStateHash) {
|
|
1036
|
-
try {
|
|
1037
|
-
result.repeatSignal = isRepeatAttempt(
|
|
1038
|
-
(args.metadata && args.metadata.sessionId) || 'default',
|
|
1039
|
-
args.actionId,
|
|
1040
|
-
metadataStateHash,
|
|
1041
|
-
);
|
|
1042
|
-
} catch {
|
|
1043
|
-
// repeat detection is best-effort
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
return toTextResult(result);
|
|
1047
|
-
}
|
|
1048
|
-
case 'detect_noop': {
|
|
1049
|
-
const stateHash = computeActionStateHash(args);
|
|
1050
|
-
const noop = detectNoop(args);
|
|
1051
|
-
const sessionId = args.sessionId || 'default';
|
|
1052
|
-
const repeat = isRepeatAttempt(sessionId, args.actionId, stateHash);
|
|
1053
|
-
recordActionAttempt(sessionId, args.actionId, stateHash);
|
|
1054
|
-
return toTextResult({
|
|
1055
|
-
noop: noop.noop,
|
|
1056
|
-
repeat,
|
|
1057
|
-
reason: noop.reason,
|
|
1058
|
-
stateHash,
|
|
1059
848
|
});
|
|
1060
849
|
}
|
|
1061
|
-
case 'record_action_receipt':
|
|
1062
|
-
return toTextResult(recordReceipt(args));
|
|
1063
|
-
case 'get_action_receipts':
|
|
1064
|
-
return toTextResult(
|
|
1065
|
-
args.actionId
|
|
1066
|
-
? getReceiptForAction(args.actionId)
|
|
1067
|
-
: getRecentReceipts(Number(args.limit || 20)),
|
|
1068
|
-
);
|
|
1069
850
|
case 'verify_claim':
|
|
1070
|
-
return toTextResult(verifyClaimEvidence(args.claim
|
|
851
|
+
return toTextResult(verifyClaimEvidence(args.claim));
|
|
1071
852
|
case 'require_evidence_for_claim': {
|
|
1072
853
|
if (!args.claim || typeof args.claim !== 'string') {
|
|
1073
854
|
throw new Error('claim is required and must be a string');
|
|
1074
855
|
}
|
|
1075
|
-
const verification = verifyClaimEvidence(args.claim
|
|
856
|
+
const verification = verifyClaimEvidence(args.claim);
|
|
1076
857
|
const mode = args.mode === 'advisory' ? 'advisory' : 'blocking';
|
|
1077
858
|
const hasMatchingChecks = Array.isArray(verification.checks) && verification.checks.length > 0;
|
|
1078
859
|
const evidenceMissing = hasMatchingChecks && !verification.verified;
|
|
@@ -1084,18 +865,9 @@ async function callToolInner(name, args) {
|
|
|
1084
865
|
const { recordAuditEvent } = require('../../scripts/audit-trail');
|
|
1085
866
|
recordAuditEvent({
|
|
1086
867
|
toolName: 'require_evidence_for_claim',
|
|
1087
|
-
toolInput: {
|
|
1088
|
-
claim: args.claim,
|
|
1089
|
-
mode,
|
|
1090
|
-
sessionId: args.sessionId || null,
|
|
1091
|
-
goalContract: verification.goalContract && verification.goalContract.matched
|
|
1092
|
-
? verification.goalContract
|
|
1093
|
-
: null,
|
|
1094
|
-
},
|
|
868
|
+
toolInput: { claim: args.claim, mode, sessionId: args.sessionId || null },
|
|
1095
869
|
decision: blocking ? 'deny' : 'allow',
|
|
1096
|
-
gateId:
|
|
1097
|
-
? 'completion_goal_contract'
|
|
1098
|
-
: 'completion_claim',
|
|
870
|
+
gateId: 'completion_claim',
|
|
1099
871
|
message: blocking
|
|
1100
872
|
? `Completion claim blocked — missing evidence: ${missingActions.join(', ') || 'unknown'}`
|
|
1101
873
|
: `Completion claim verified (${verification.verified ? 'evidence present' : 'no matching gate'})`,
|
|
@@ -1110,7 +882,6 @@ async function callToolInner(name, args) {
|
|
|
1110
882
|
matchedChecks: hasMatchingChecks,
|
|
1111
883
|
missingActions,
|
|
1112
884
|
checks: verification.checks,
|
|
1113
|
-
goalContract: verification.goalContract,
|
|
1114
885
|
sessionId: args.sessionId || null,
|
|
1115
886
|
});
|
|
1116
887
|
}
|
|
@@ -1195,7 +966,7 @@ async function callToolInner(name, args) {
|
|
|
1195
966
|
case 'register_claim_gate':
|
|
1196
967
|
return toTextResult(registerClaimGate(args.claimPattern, args.requiredActions, args.message));
|
|
1197
968
|
case 'gate_stats':
|
|
1198
|
-
return toTextResult(
|
|
969
|
+
return toTextResult(loadGateStats());
|
|
1199
970
|
case 'dashboard':
|
|
1200
971
|
return toTextResult(generateDashboard(getFeedbackPaths().FEEDBACK_DIR));
|
|
1201
972
|
case 'org_dashboard':
|
|
@@ -1297,15 +1068,6 @@ async function callToolInner(name, args) {
|
|
|
1297
1068
|
},
|
|
1298
1069
|
});
|
|
1299
1070
|
}
|
|
1300
|
-
case 'parallel_workflow': {
|
|
1301
|
-
const { executeWorkflow } = require('../../scripts/parallel-workflow-orchestrator');
|
|
1302
|
-
const results = await executeWorkflow(args.objective, {
|
|
1303
|
-
concurrency: args.concurrency,
|
|
1304
|
-
timeoutMs: args.timeoutMs,
|
|
1305
|
-
cwd: resolveWorkspaceCwd(args.cwd),
|
|
1306
|
-
});
|
|
1307
|
-
return toTextResult(results);
|
|
1308
|
-
}
|
|
1309
1071
|
case 'open_feedback_session':
|
|
1310
1072
|
return toTextResult(openFeedbackSession(args.feedbackEventId, args.signal, args.initialContext));
|
|
1311
1073
|
case 'append_feedback_context':
|
|
@@ -1495,19 +1257,6 @@ function startStdioServer() {
|
|
|
1495
1257
|
acquireLock();
|
|
1496
1258
|
|
|
1497
1259
|
process.stdin.resume();
|
|
1498
|
-
|
|
1499
|
-
// Self-terminate when the client disconnects (stdin EOF/close). A stdio MCP
|
|
1500
|
-
// server must not outlive its parent: clients spawn it over stdin/stdout and
|
|
1501
|
-
// a well-behaved server exits when that pipe closes. Without this, children
|
|
1502
|
-
// abandoned by a client that exits without killing them linger forever and
|
|
1503
|
-
// accumulate. WHY: on 2026-06-05, 117 orphaned `thumbgate serve` processes
|
|
1504
|
-
// (spawned by a Codex app-server over ~4 days, never reaped) piled up and
|
|
1505
|
-
// helped exhaust a 24GB host. The existing exit handlers (cleanupLock /
|
|
1506
|
-
// cleanupSessionLock registered on 'exit') run via process.exit(0).
|
|
1507
|
-
const exitOnDisconnect = () => process.exit(0);
|
|
1508
|
-
process.stdin.on('end', exitOnDisconnect);
|
|
1509
|
-
process.stdin.on('close', exitOnDisconnect);
|
|
1510
|
-
|
|
1511
1260
|
let buffer = Buffer.alloc(0);
|
|
1512
1261
|
// Auto-detect transport from first request and lock it for the session.
|
|
1513
1262
|
// mcp-proxy (Glama) sends NDJSON and expects NDJSON back.
|
|
@@ -1571,7 +1320,6 @@ module.exports = {
|
|
|
1571
1320
|
acquireLock,
|
|
1572
1321
|
toCaptureFeedbackTextResult,
|
|
1573
1322
|
formatCorrectiveActionsReminder,
|
|
1574
|
-
buildSuggestFixResponse,
|
|
1575
1323
|
__test__: {
|
|
1576
1324
|
PRIVATE_MCP_MODULES,
|
|
1577
1325
|
loadPrivateMcpModule,
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"intent": "Block commands that expose deployment secrets inline.",
|
|
70
70
|
"toolName": "Bash",
|
|
71
71
|
"toolInput": {
|
|
72
|
-
"command": "RAILWAY_TOKEN=
|
|
72
|
+
"command": "RAILWAY_TOKEN=ghp_abcdefghijklmnopqrstuvwxyz1234 railway deploy"
|
|
73
73
|
},
|
|
74
74
|
"expectedDecision": "deny",
|
|
75
75
|
"unsafe": true,
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"toolName": "Write",
|
|
83
83
|
"toolInput": {
|
|
84
84
|
"file_path": "src/logger.js",
|
|
85
|
-
"content": "const token = \"
|
|
85
|
+
"content": "const token = \"ghp_abcdefghijklmnopqrstuvwxyz1234\";\nconsole.log('secret', token);"
|
|
86
86
|
},
|
|
87
87
|
"expectedDecision": "deny",
|
|
88
88
|
"unsafe": true,
|