thumbgate 1.25.1 โ 1.25.2
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 +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/gemini/function-declarations.json +1 -0
- package/adapters/mcp/server-stdio.js +2 -1
- package/adapters/opencode/opencode.json +1 -1
- package/openapi/openapi.yaml +2 -0
- package/package.json +4 -3
- package/public/index.html +2 -2
- package/public/numbers.html +2 -2
- package/scripts/gates-engine.js +1 -4
- package/scripts/tool-registry.js +1 -0
- package/src/api/server.js +72 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate-marketplace",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.2",
|
|
4
4
|
"owner": {
|
|
5
5
|
"name": "Igor Ganapolsky",
|
|
6
6
|
"email": "ig5973700@gmail.com"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"source": "npm",
|
|
15
15
|
"package": "thumbgate"
|
|
16
16
|
},
|
|
17
|
-
"version": "1.25.
|
|
17
|
+
"version": "1.25.2",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "Igor Ganapolsky",
|
|
20
20
|
"email": "ig5973700@gmail.com",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
3
|
"description": "One ๐ becomes a hard rule the agent cannot bypass. Captures thumbs-down feedback, distills it into PreToolUse Pre-Action Checks, enforced across every future Claude Code session.",
|
|
4
|
-
"version": "1.25.
|
|
4
|
+
"version": "1.25.2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Igor Ganapolsky",
|
|
7
7
|
"email": "ig5973700@gmail.com",
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"thumbgate": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--yes", "--package", "thumbgate@1.25.
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.25.2", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@1.25.
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.25.2", "thumbgate", "gate-check"]
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -216,7 +216,7 @@ const {
|
|
|
216
216
|
finalizeSession: finalizeFeedbackSession,
|
|
217
217
|
} = require('../../scripts/feedback-session');
|
|
218
218
|
|
|
219
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.25.
|
|
219
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.25.2' };
|
|
220
220
|
const COMMERCE_CATEGORIES = [
|
|
221
221
|
'product_recommendation',
|
|
222
222
|
'brand_compliance',
|
|
@@ -779,6 +779,7 @@ async function callToolInner(name, args) {
|
|
|
779
779
|
bundleId: args.bundleId,
|
|
780
780
|
partnerProfile: args.partnerProfile,
|
|
781
781
|
delegationMode: args.delegationMode,
|
|
782
|
+
enforcePlanQuality: args.enforcePlanQuality === true,
|
|
782
783
|
approved: args.approved === true,
|
|
783
784
|
repoPath: args.repoPath,
|
|
784
785
|
}));
|
package/openapi/openapi.yaml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.2",
|
|
4
4
|
"description": "ThumbGate self-improving agent governance: thumbs-up/down turns every mistake into a prevention rule and blocks repeat patterns. 36 pre-action checks, budget enforcement, and self-protection for Claude Code, Cursor, Codex, Gemini CLI, and Amp.",
|
|
5
5
|
"homepage": "https://thumbgate.ai",
|
|
6
6
|
"repository": {
|
|
@@ -340,7 +340,7 @@
|
|
|
340
340
|
"social:prospect:bluesky:dry": "node scripts/social-bluesky-prospecting.js --dry-run",
|
|
341
341
|
"social:reply-publish:bluesky:dry": "node scripts/social-reply-monitor-bluesky.js --publish-approved --dry-run",
|
|
342
342
|
"test:python": "python3 -m pytest tests/*.py",
|
|
343
|
-
"test": "npm run test:python && npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:session-analyzer && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:platform-limits && npm run test:post-video && npm run test:post-everywhere-instagram && npm run test:post-everywhere-channels && npm run test:post-everywhere-zernio-default && npm run test:zernio-canonical-pollers && npm run test:zernio-status && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:memory-scope-readiness && npm run test:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operational-dashboard && npm run test:operator-artifacts && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:mcp-tool-annotations && npm run test:mcp-oauth && npm run test:mcp-oauth-flow && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:audit-pr-bot-contamination && npm run test:stripe-bootstrap-saas-catalog && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:semantic-dedup && npm run test:fs-utils && npm run test:cli-schema && npm run test:explore && npm run test:lesson-reranker && npm run test:lesson-retrieval && npm run test:lesson-semantic-retrieval && npm run test:cross-encoder && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:predictive-credible-range && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:lesson-canonical && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-post-hourly && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:budget && npm run test:quick-start && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:community-course-platform-launch-kit && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:social-dedupe-cleanup && npm run test:sync-launch-assets && npm run test:ai-search-visibility && npm run test:perplexity && npm run test:security-scanner && npm run test:llm-client && npm run test:managed-lesson-agent && npm run test:self-distill && npm run test:meta-agent && npm run test:harness-selector && npm run test:thumbgate-bench && npm run test:seo-guides && npm run test:enforcement-loop && npm run test:cli-agent-experience && npm run test:bot-detection && npm run test:checkout-archived-product-guard && npm run test:postgres-guard && npm run test:checkout-bot-guard && npm run test:checkout-pro-confirmation-gate && npm run test:session-health && npm run test:session-episodes && npm run test:spec-gate && npm run test:decision-trace && npm run test:dashboard-insights && npm run test:telemetry-tracked-link-slug && npm run test:prompt-eval && npm run test:demo-voiceover && npm run test:gate-coherence && npm run test:gate-eval && npm run test:high-roi && npm run test:public-static-assets && npm run test:token-savings && npm run test:numbers-page && npm run test:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:competitive-positioning-marketing && npm run test:medium-weekly && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity && npm run test:token-savings-dashboard && npm run test:cursor-wiring && npm run test:pretooluse-injection && npm run test:recent-corrective-context && npm run test:durability-step && npm run test:mailer && npm run test:brand-assets && npm run test:enforcement-teeth && npm run test:bayes-optimal-gate && npm run test:swarm-coordinator && npm run test:session-report && npm run test:agent-reasoning-traces && npm run test:judge-reward && npm run test:llm-behavior-monitor && npm run test:prompting-os && npm run test:single-use-credential-gate && npm run test:structured-prompt-driven && npm run test:require-evidence-gate && npm run test:rule-validator && npm run test:bluesky-atproto && npm run test:social-reply-monitor-bluesky && npm run test:bluesky-delete-replies && npm run test:architect-kit-memory-bridge && npm run test:sonar-review-hotspots && npm run test:actionable-remediations && npm run test:gemini-embedding-policy && npm run test:agent-design-governance && npm run test:public-core-boundary && npm run test:hook-stop-verify-deploy && npm run test:hook-stop-anti-claim && npm run test:plausible-server-events && npm run test:activation-tracker && npm run test:unified-revenue-rollup && npm run test:conversion-rate-stats && npm run test:external-customer-audit && npm run test:telemetry-export && npm run test:stripe-checkout-diagnostic && npm run test:stripe-business-identity-probe && npm run test:revenue-observability-doctor && npm run test:public-bundle-ratchet && npm run test:stripe-payment-link-update && npm run test:ci-cd-hygiene-audit && npm run test:verify-marketing-pages-deployed && npm run test:install-email-capture && npm run test:install-shim && npm run test:hook-runtime-subcommands && npm run test:implementation-notes && npm run test:daily-block-cap && npm run test:free-to-paid-conversion-units && npm run test:metrics-real-endpoint && npm run test:cli-trial-and-help && npm run test:cost-cli && npm run test:silent-failure-cluster && npm run test:proof:truth && node --test tests/adaptive-reliability.test.js",
|
|
343
|
+
"test": "npm run test:python && npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:session-analyzer && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:platform-limits && npm run test:post-video && npm run test:post-everywhere-instagram && npm run test:post-everywhere-channels && npm run test:post-everywhere-zernio-default && npm run test:zernio-canonical-pollers && npm run test:zernio-status && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:memory-scope-readiness && npm run test:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operational-dashboard && npm run test:operator-artifacts && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:mcp-tool-annotations && npm run test:mcp-oauth && npm run test:mcp-oauth-flow && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:audit-pr-bot-contamination && npm run test:stripe-bootstrap-saas-catalog && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:semantic-dedup && npm run test:fs-utils && npm run test:cli-schema && npm run test:explore && npm run test:lesson-reranker && npm run test:lesson-retrieval && npm run test:lesson-semantic-retrieval && npm run test:cross-encoder && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:predictive-credible-range && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:lesson-canonical && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-post-hourly && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:budget && npm run test:quick-start && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:community-course-platform-launch-kit && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:social-dedupe-cleanup && npm run test:sync-launch-assets && npm run test:ai-search-visibility && npm run test:perplexity && npm run test:security-scanner && npm run test:llm-client && npm run test:managed-lesson-agent && npm run test:self-distill && npm run test:meta-agent && npm run test:harness-selector && npm run test:thumbgate-bench && npm run test:seo-guides && npm run test:enforcement-loop && npm run test:cli-agent-experience && npm run test:bot-detection && npm run test:checkout-archived-product-guard && npm run test:postgres-guard && npm run test:checkout-bot-guard && npm run test:checkout-pro-confirmation-gate && npm run test:session-health && npm run test:session-episodes && npm run test:spec-gate && npm run test:decision-trace && npm run test:dashboard-insights && npm run test:telemetry-tracked-link-slug && npm run test:prompt-eval && npm run test:demo-voiceover && npm run test:gate-coherence && npm run test:gate-eval && npm run test:high-roi && npm run test:public-static-assets && npm run test:token-savings && npm run test:numbers-page && npm run test:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:competitive-positioning-marketing && npm run test:medium-weekly && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity && npm run test:token-savings-dashboard && npm run test:cursor-wiring && npm run test:pretooluse-injection && npm run test:recent-corrective-context && npm run test:durability-step && npm run test:mailer && npm run test:brand-assets && npm run test:enforcement-teeth && npm run test:bayes-optimal-gate && npm run test:swarm-coordinator && npm run test:session-report && npm run test:agent-reasoning-traces && npm run test:judge-reward && npm run test:llm-behavior-monitor && npm run test:prompting-os && npm run test:single-use-credential-gate && npm run test:structured-prompt-driven && npm run test:require-evidence-gate && npm run test:rule-validator && npm run test:bluesky-atproto && npm run test:social-reply-monitor-bluesky && npm run test:bluesky-delete-replies && npm run test:architect-kit-memory-bridge && npm run test:sonar-review-hotspots && npm run test:actionable-remediations && npm run test:gemini-embedding-policy && npm run test:agent-design-governance && npm run test:public-core-boundary && npm run test:hook-stop-verify-deploy && npm run test:hook-stop-anti-claim && npm run test:plausible-server-events && npm run test:activation-tracker && npm run test:unified-revenue-rollup && npm run test:conversion-rate-stats && npm run test:external-customer-audit && npm run test:telemetry-export && npm run test:stripe-checkout-diagnostic && npm run test:stripe-business-identity-probe && npm run test:revenue-observability-doctor && npm run test:public-bundle-ratchet && npm run test:stripe-payment-link-update && npm run test:ci-cd-hygiene-audit && npm run test:verify-marketing-pages-deployed && npm run test:install-email-capture && npm run test:install-shim && npm run test:hook-runtime-subcommands && npm run test:implementation-notes && npm run test:daily-block-cap && npm run test:free-to-paid-conversion-units && npm run test:metrics-real-endpoint && npm run test:cli-trial-and-help && npm run test:cost-cli && npm run test:silent-failure-cluster && npm run test:proof:truth && node --test tests/adaptive-reliability.test.js && npm run test:mcp-oauth-reviewer",
|
|
344
344
|
"test:hook-stop-verify-deploy": "node --test tests/hook-stop-verify-deploy.test.js",
|
|
345
345
|
"test:hook-stop-anti-claim": "node --test tests/hook-stop-anti-claim.test.js",
|
|
346
346
|
"test:plausible-server-events": "node --test tests/plausible-server-events.test.js tests/plausible-poller.test.js",
|
|
@@ -691,7 +691,8 @@
|
|
|
691
691
|
"build:grok-plugin": "node scripts/build-grok-plugin.js",
|
|
692
692
|
"promote:launch": "node scripts/x-autonomous-marketing.js",
|
|
693
693
|
"feedback:ingest": "node scripts/ingest-manual-feedback.js",
|
|
694
|
-
"verify-proof": "node scripts/require-proof.js"
|
|
694
|
+
"verify-proof": "node scripts/require-proof.js",
|
|
695
|
+
"test:mcp-oauth-reviewer": "node --test tests/mcp-oauth-reviewer.test.js"
|
|
695
696
|
},
|
|
696
697
|
"keywords": [
|
|
697
698
|
"mcp",
|
package/public/index.html
CHANGED
|
@@ -20,7 +20,7 @@ __GOOGLE_SITE_VERIFICATION_META__
|
|
|
20
20
|
<meta property="og:image" content="https://thumbgate.ai/og.png">
|
|
21
21
|
<meta name="twitter:card" content="summary_large_image">
|
|
22
22
|
<meta name="twitter:image" content="https://thumbgate.ai/og.png">
|
|
23
|
-
<meta name="thumbgate-version" content="1.25.
|
|
23
|
+
<meta name="thumbgate-version" content="1.25.2">
|
|
24
24
|
<meta name="keywords" content="ThumbGate, thumbgate, AI agent orchestration, AI experience orchestration, agentic development cycle, AC/DC framework, Guide Generate Verify Solve, agent enforcement layer, save LLM tokens, reduce Claude API cost, reduce OpenAI cost, AI agent token savings, prevent LLM retries, prevent hallucination retries, stop AI token waste, pre-action checks, agent governance, Claude Code, Cursor, Codex, Gemini, Amp, Cline, OpenCode, workflow hardening, context engineering, AI authenticity, brand authenticity AI">
|
|
25
25
|
<link rel="canonical" href="__APP_ORIGIN__/">
|
|
26
26
|
<link rel="alternate" type="text/markdown" title="ThumbGate LLM context" href="__APP_ORIGIN__/llm-context.md">
|
|
@@ -1586,7 +1586,7 @@ __GA_BOOTSTRAP__
|
|
|
1586
1586
|
<a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
|
|
1587
1587
|
<a href="/blog">Blog</a>
|
|
1588
1588
|
</div>
|
|
1589
|
-
<span class="footer-copy">ยฉ 2026 ThumbGate ยท MIT License ยท npm v1.25.
|
|
1589
|
+
<span class="footer-copy">ยฉ 2026 ThumbGate ยท MIT License ยท npm v1.25.2</span>
|
|
1590
1590
|
</div>
|
|
1591
1591
|
</footer>
|
|
1592
1592
|
|
package/public/numbers.html
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"alternateName": "thumbgate",
|
|
26
26
|
"applicationCategory": "DeveloperApplication",
|
|
27
27
|
"operatingSystem": "Cross-platform, Node.js >=18.18.0",
|
|
28
|
-
"softwareVersion": "1.25.
|
|
28
|
+
"softwareVersion": "1.25.2",
|
|
29
29
|
"url": "https://thumbgate.ai/numbers",
|
|
30
30
|
"dateModified": "2026-05-07",
|
|
31
31
|
"creator": {
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
<main class="container">
|
|
203
203
|
<h1>The Numbers</h1>
|
|
204
204
|
<p class="subtitle">Generated first-party operational snapshot from the ThumbGate runtime. This is not customer traction, install volume, revenue, or proof that a configured gate has fired.</p>
|
|
205
|
-
<div class="freshness">Updated: 2026-05-07 ยท Version 1.25.
|
|
205
|
+
<div class="freshness">Updated: 2026-05-07 ยท Version 1.25.2</div>
|
|
206
206
|
<div class="truth-note"><strong>Read this first:</strong> configured checks are inventory. Recorded blocks and warnings are usage evidence. This snapshot currently reports 0 recorded hard-block event(s) and 0 recorded warning event(s).</div>
|
|
207
207
|
|
|
208
208
|
<h2>Gate enforcement</h2>
|
package/scripts/gates-engine.js
CHANGED
|
@@ -2135,10 +2135,7 @@ function buildRecentCorrectiveActionsContext(options = {}) {
|
|
|
2135
2135
|
function buildRelevantLessonContext(toolName, toolInput) {
|
|
2136
2136
|
if (!toolName) return null;
|
|
2137
2137
|
|
|
2138
|
-
const { retrieveRelevantLessons, calculateRetrievalEntropy } = loadOptionalModule(
|
|
2139
|
-
retrieveRelevantLessons: () => [],
|
|
2140
|
-
calculateRetrievalEntropy: () => 0,
|
|
2141
|
-
}));
|
|
2138
|
+
const { retrieveRelevantLessons, calculateRetrievalEntropy, filterTopP } = loadOptionalModule("./lesson-retrieval", () => ({ retrieveRelevantLessons: () => [], calculateRetrievalEntropy: () => 0, filterTopP: (l) => l }));
|
|
2142
2139
|
|
|
2143
2140
|
// Extract a searchable action context from the tool input
|
|
2144
2141
|
const actionContext = extractActionContext(toolName, toolInput);
|
package/scripts/tool-registry.js
CHANGED
|
@@ -476,6 +476,7 @@ const TOOLS = [
|
|
|
476
476
|
bundleId: { type: 'string' },
|
|
477
477
|
partnerProfile: { type: 'string' },
|
|
478
478
|
delegationMode: { type: 'string', enum: ['off', 'auto', 'sequential'] },
|
|
479
|
+
enforcePlanQuality: { type: 'boolean' },
|
|
479
480
|
approved: { type: 'boolean' },
|
|
480
481
|
repoPath: { type: 'string' },
|
|
481
482
|
},
|
package/src/api/server.js
CHANGED
|
@@ -3662,6 +3662,49 @@ function extractApiKey(req) {
|
|
|
3662
3662
|
return '';
|
|
3663
3663
|
}
|
|
3664
3664
|
|
|
3665
|
+
/**
|
|
3666
|
+
* Map a ThumbGate key presented at the OAuth consent screen to a role.
|
|
3667
|
+
*
|
|
3668
|
+
* - When any key is configured (production), the presented key MUST match a
|
|
3669
|
+
* configured admin/operator/reviewer key; otherwise returns null (reject) so
|
|
3670
|
+
* the OAuth flow actually authenticates the holder.
|
|
3671
|
+
* - When NO keys are configured (insecure/dev mode, e.g. local tests), any
|
|
3672
|
+
* non-empty key is accepted as role 'dev' to preserve local development.
|
|
3673
|
+
*
|
|
3674
|
+
* 'reviewer' (THUMBGATE_REVIEWER_KEY) is a read-only, independently-revocable
|
|
3675
|
+
* credential safe to share with a directory reviewer โ tool execution enforces
|
|
3676
|
+
* read-only for it (see the tools/call handler).
|
|
3677
|
+
*/
|
|
3678
|
+
// Constant-time comparison of two API/OAuth bearer keys. We compare the raw
|
|
3679
|
+
// bytes with crypto.timingSafeEqual after an explicit equal-length guard
|
|
3680
|
+
// (timingSafeEqual throws on a length mismatch). No digest is taken: these are
|
|
3681
|
+
// high-entropy random credentials compared transiently at request time, not
|
|
3682
|
+
// user passwords stored at rest, so neither a KDF (bcrypt/scrypt/argon2) nor a
|
|
3683
|
+
// length-normalizing hash is appropriate โ and hashing the credential here is
|
|
3684
|
+
// exactly what static analysis (correctly, for *stored* passwords) flags. The
|
|
3685
|
+
// only side-channel is whether the two keys share a length, which reveals
|
|
3686
|
+
// nothing useful about a random secret. Once lengths match, the byte compare
|
|
3687
|
+
// is constant-time and leaks no information about where they differ.
|
|
3688
|
+
function safeKeyEqual(a, b) {
|
|
3689
|
+
const x = Buffer.from(String(a || ''), 'utf8');
|
|
3690
|
+
const y = Buffer.from(String(b || ''), 'utf8');
|
|
3691
|
+
if (x.length === 0 || y.length === 0 || x.length !== y.length) return false;
|
|
3692
|
+
return require('crypto').timingSafeEqual(x, y);
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
function resolveKeyRole(key) {
|
|
3696
|
+
const k = String(key || '').trim();
|
|
3697
|
+
const adminKey = String(process.env.THUMBGATE_API_KEY || '').trim();
|
|
3698
|
+
const operatorKey = String(process.env.THUMBGATE_OPERATOR_KEY || '').trim();
|
|
3699
|
+
const reviewerKey = String(process.env.THUMBGATE_REVIEWER_KEY || '').trim();
|
|
3700
|
+
const configured = [adminKey, operatorKey, reviewerKey].filter(Boolean);
|
|
3701
|
+
if (configured.length === 0) return k ? 'dev' : null;
|
|
3702
|
+
if (safeKeyEqual(k, adminKey)) return 'admin';
|
|
3703
|
+
if (safeKeyEqual(k, operatorKey)) return 'operator';
|
|
3704
|
+
if (safeKeyEqual(k, reviewerKey)) return 'reviewer';
|
|
3705
|
+
return null;
|
|
3706
|
+
}
|
|
3707
|
+
|
|
3665
3708
|
/**
|
|
3666
3709
|
* Admin-only guard for static THUMBGATE_API_KEY.
|
|
3667
3710
|
* Billing keys are intentionally excluded from admin actions.
|
|
@@ -3883,7 +3926,8 @@ function createApiServer() {
|
|
|
3883
3926
|
// operator/admin key โ never "any non-empty bearer".
|
|
3884
3927
|
const adminKey = String(process.env.THUMBGATE_API_KEY || '').trim();
|
|
3885
3928
|
const operatorKey = String(process.env.THUMBGATE_OPERATOR_KEY || '').trim();
|
|
3886
|
-
const
|
|
3929
|
+
const reviewerKey = String(process.env.THUMBGATE_REVIEWER_KEY || '').trim();
|
|
3930
|
+
const rawKeyValid = Boolean(bearer) && (safeKeyEqual(bearer, adminKey) || safeKeyEqual(bearer, operatorKey) || safeKeyEqual(bearer, reviewerKey));
|
|
3887
3931
|
const authed = oauthSession
|
|
3888
3932
|
? mcpOauth.tokenAudienceValid(oauthSession, resourceUrl)
|
|
3889
3933
|
: rawKeyValid;
|
|
@@ -3899,6 +3943,24 @@ function createApiServer() {
|
|
|
3899
3943
|
}));
|
|
3900
3944
|
return;
|
|
3901
3945
|
}
|
|
3946
|
+
// The reviewer credential (THUMBGATE_REVIEWER_KEY) is read-only: it may
|
|
3947
|
+
// only invoke tools annotated readOnlyHint:true. This makes a credential
|
|
3948
|
+
// safe to share (e.g. with a directory reviewer) without granting the
|
|
3949
|
+
// ability to mutate shared server state.
|
|
3950
|
+
const effectiveKey = oauthSession ? String(oauthSession.boundKey || '') : bearer;
|
|
3951
|
+
const isReviewer = Boolean(reviewerKey) && safeKeyEqual(effectiveKey, reviewerKey);
|
|
3952
|
+
if (isReviewer) {
|
|
3953
|
+
const name = msg.params && msg.params.name;
|
|
3954
|
+
const tool = MCP_TOOLS.find((t) => t.name === name);
|
|
3955
|
+
const readOnly = Boolean(tool && tool.annotations && tool.annotations.readOnlyHint === true);
|
|
3956
|
+
if (!readOnly) {
|
|
3957
|
+
sendJson(res, 200, {
|
|
3958
|
+
jsonrpc: '2.0', id: msg.id,
|
|
3959
|
+
error: { code: -32002, message: `Tool "${name}" requires write access; the reviewer credential is read-only.` },
|
|
3960
|
+
});
|
|
3961
|
+
return;
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3902
3964
|
(async () => {
|
|
3903
3965
|
try {
|
|
3904
3966
|
const { callTool } = require('../../adapters/mcp/server-stdio');
|
|
@@ -5278,6 +5340,14 @@ ${hidden}
|
|
|
5278
5340
|
const form = new URLSearchParams(body);
|
|
5279
5341
|
const redirectUri = form.get('redirect_uri') || '';
|
|
5280
5342
|
const state = form.get('state') || '';
|
|
5343
|
+
// Validate the presented ThumbGate key before issuing a code. When keys
|
|
5344
|
+
// are configured (production) the key MUST match a configured admin /
|
|
5345
|
+
// operator / reviewer key โ otherwise OAuth would authenticate nobody.
|
|
5346
|
+
// In insecure/dev mode (no keys configured) any non-empty key is accepted.
|
|
5347
|
+
if (!resolveKeyRole(form.get('api_key') || '')) {
|
|
5348
|
+
sendJson(res, 400, { error: 'access_denied', error_description: 'invalid ThumbGate API key' });
|
|
5349
|
+
return;
|
|
5350
|
+
}
|
|
5281
5351
|
const issued = mcpOauth.createAuthorizationCode(oauthStore, {
|
|
5282
5352
|
clientId: form.get('client_id') || '',
|
|
5283
5353
|
redirectUri,
|
|
@@ -6796,6 +6866,7 @@ ${hidden}
|
|
|
6796
6866
|
bundleId: body.bundleId,
|
|
6797
6867
|
partnerProfile: body.partnerProfile,
|
|
6798
6868
|
delegationMode: body.delegationMode,
|
|
6869
|
+
enforcePlanQuality: body.enforcePlanQuality === true,
|
|
6799
6870
|
approved: body.approved === true,
|
|
6800
6871
|
repoPath: body.repoPath,
|
|
6801
6872
|
});
|