thumbgate 1.5.4 → 1.5.8
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/README.md +1 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/package.json +7 -3
- package/public/dashboard.html +52 -0
- package/public/index.html +65 -21
- package/scripts/auto-wire-hooks.js +61 -1
- package/scripts/dashboard.js +13 -0
- package/src/api/server.js +15 -17
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate-marketplace",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.8",
|
|
4
4
|
"owner": {
|
|
5
5
|
"name": "Igor Ganapolsky",
|
|
6
6
|
"email": "ig5973700@gmail.com"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"source": "npm",
|
|
14
14
|
"package": "thumbgate"
|
|
15
15
|
},
|
|
16
|
-
"version": "1.5.
|
|
16
|
+
"version": "1.5.8",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Igor Ganapolsky"
|
|
19
19
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
3
|
"description": "Type 👍 or 👎 on any agent action. ThumbGate captures it, distills a lesson, and blocks the pattern from repeating. One thumbs-down = the agent physically cannot make that mistake again. 33 pre-action gates, budget enforcement, self-protection, and NIST/SOC2 compliance tags.",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.8",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Igor Ganapolsky"
|
|
7
7
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.8",
|
|
4
4
|
"description": "ThumbGate — 👍👎 feedback that teaches your AI agent. Thumbs down a mistake, it never happens again.",
|
|
5
5
|
"homepage": "https://github.com/IgorGanapolsky/thumbgate",
|
|
6
6
|
"transport": "stdio",
|
package/adapters/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- `chatgpt/openapi.yaml`: import into GPT Actions.
|
|
4
4
|
- `gemini/function-declarations.json`: Gemini function-calling definitions.
|
|
5
5
|
- `mcp/server-stdio.js`: underlying local MCP stdio server implementation.
|
|
6
|
-
- `claude/.mcp.json`: example Claude Code MCP config using `npx --yes --package thumbgate@1.5.
|
|
6
|
+
- `claude/.mcp.json`: example Claude Code MCP config using `npx --yes --package thumbgate@1.5.8 thumbgate serve`.
|
|
7
7
|
- `codex/config.toml`: example Codex MCP profile section using the same version-pinned portable launcher.
|
|
8
8
|
- `amp/skills/thumbgate-feedback/SKILL.md`: Amp skill template.
|
|
9
9
|
- `opencode/opencode.json`: portable OpenCode MCP profile using the same version-pinned portable launcher.
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"thumbgate": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--yes", "--package", "thumbgate@1.5.
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.5.8", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@1.5.
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.5.8", "thumbgate", "gate-check"]
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
# ~/.codex/config.json with the ThumbGate hooks and status line.
|
|
4
4
|
[mcp_servers.thumbgate]
|
|
5
5
|
command = "npx"
|
|
6
|
-
args = ["--yes", "--package", "thumbgate@1.5.
|
|
6
|
+
args = ["--yes", "--package", "thumbgate@1.5.8", "thumbgate", "serve"]
|
|
7
7
|
|
|
8
8
|
# Hard PreToolUse hook for Codex
|
|
9
9
|
[hooks.pre_tool_use]
|
|
10
10
|
command = "npx"
|
|
11
|
-
args = ["--yes", "--package", "thumbgate@1.5.
|
|
11
|
+
args = ["--yes", "--package", "thumbgate@1.5.8", "thumbgate", "gate-check"]
|
|
@@ -146,7 +146,7 @@ const {
|
|
|
146
146
|
finalizeSession: finalizeFeedbackSession,
|
|
147
147
|
} = require('../../scripts/feedback-session');
|
|
148
148
|
|
|
149
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.5.
|
|
149
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.5.8' };
|
|
150
150
|
const COMMERCE_CATEGORIES = [
|
|
151
151
|
'product_recommendation',
|
|
152
152
|
'brand_compliance',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.8",
|
|
4
4
|
"description": "Self-improving agent governance: type thumbs-up or thumbs-down on any AI agent action. ThumbGate turns every mistake into a prevention rule and blocks the pattern from repeating. One thumbs-down, never again. 33 pre-action gates, budget enforcement, and self-protection for Claude Code, Cursor, Codex, Gemini CLI, and Amp.",
|
|
5
5
|
"homepage": "https://thumbgate-production.up.railway.app",
|
|
6
6
|
"repository": {
|
|
@@ -248,7 +248,7 @@
|
|
|
248
248
|
"trace:eval": "node scripts/decision-trace.js eval",
|
|
249
249
|
"social:reply-monitor": "node scripts/social-reply-monitor.js",
|
|
250
250
|
"social:reply-monitor:dry": "node scripts/social-reply-monitor.js --dry-run",
|
|
251
|
-
"test": "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:post-video && npm run test:post-everywhere-instagram && 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:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && 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: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: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: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: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:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && 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-bot-guard && 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: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:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity",
|
|
251
|
+
"test": "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:post-video && npm run test:post-everywhere-instagram && 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:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && 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: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: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: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: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:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && 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-bot-guard && 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: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:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity && npm run test:token-savings-dashboard && npm run test:cursor-wiring",
|
|
252
252
|
"test:session-health": "node --test tests/session-health-sensor.test.js",
|
|
253
253
|
"test:session-episodes": "node --test tests/session-episode-store.test.js",
|
|
254
254
|
"test:spec-gate": "node --test tests/spec-gate.test.js",
|
|
@@ -485,7 +485,11 @@
|
|
|
485
485
|
"test:lesson-export-import": "node --test tests/lesson-export-import.test.js",
|
|
486
486
|
"test:landing-page-claims": "node --test tests/landing-page-claims.test.js",
|
|
487
487
|
"test:dashboard-deeplink-e2e": "node --test tests/dashboard-deeplink-e2e.test.js",
|
|
488
|
-
"test:public-package-parity": "node --test tests/public-package-parity.test.js"
|
|
488
|
+
"test:public-package-parity": "node --test tests/public-package-parity.test.js",
|
|
489
|
+
"prepare": "bash bin/install-hooks.sh >/dev/null 2>&1 || true",
|
|
490
|
+
"install:hooks": "bash bin/install-hooks.sh",
|
|
491
|
+
"test:token-savings-dashboard": "node --test tests/token-savings-dashboard.test.js",
|
|
492
|
+
"test:cursor-wiring": "node --test tests/cursor-wiring.test.js"
|
|
489
493
|
},
|
|
490
494
|
"keywords": [
|
|
491
495
|
"mcp",
|
package/public/dashboard.html
CHANGED
|
@@ -330,6 +330,21 @@
|
|
|
330
330
|
<h2>📊 Feedback Insights & Lesson Pipeline</h2>
|
|
331
331
|
<p class="template-summary">How your thumbs-up/down signals turn into lessons that prevent repeat mistakes.</p>
|
|
332
332
|
|
|
333
|
+
<!-- Token Savings — computed from real gate-block counts -->
|
|
334
|
+
<div class="panel" id="tokenSavingsPanel" style="margin-bottom:24px;background:linear-gradient(135deg,rgba(74,222,128,0.04),rgba(34,211,238,0.03));border-color:rgba(74,222,128,0.25);">
|
|
335
|
+
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap;">
|
|
336
|
+
<div style="flex:1;min-width:240px;">
|
|
337
|
+
<h3 style="margin-bottom:6px;">💸 Estimated tokens saved</h3>
|
|
338
|
+
<div style="font-size:12px;color:var(--text-muted);line-height:1.55;">Computed from your real blocked-action count × 2,000 input + 600 output tokens per avoided retry, priced at a Sonnet-heavy blend (80% Sonnet 4.5 / 15% Opus 4.6 / 5% Haiku 4.5). Conservative estimate — actual savings may be higher.</div>
|
|
339
|
+
</div>
|
|
340
|
+
<div style="text-align:right;min-width:220px;">
|
|
341
|
+
<div id="tokenSavingsDollars" style="font-size:40px;font-weight:800;color:#4ade80;letter-spacing:-0.02em;line-height:1;">—</div>
|
|
342
|
+
<div id="tokenSavingsTokens" style="font-size:13px;color:var(--text-muted);margin-top:6px;">— tokens · from <span id="tokenSavingsBlocks">—</span> blocked calls</div>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
<div id="tokenSavingsSource" style="margin-top:12px;padding-top:12px;border-top:1px solid var(--border);font-size:11px;color:var(--text-muted);line-height:1.6;"></div>
|
|
346
|
+
</div>
|
|
347
|
+
|
|
333
348
|
<!-- Pipeline Flow -->
|
|
334
349
|
<div class="panel" style="margin-bottom:24px;">
|
|
335
350
|
<h3 style="margin-bottom:16px;">Feedback → Lesson Pipeline</h3>
|
|
@@ -1220,12 +1235,49 @@ var lessonChart = null;
|
|
|
1220
1235
|
var gateAuditChart = null;
|
|
1221
1236
|
|
|
1222
1237
|
function renderInsights(data) {
|
|
1238
|
+
renderTokenSavings(data.tokenSavings, data.gateStats || {});
|
|
1223
1239
|
renderPipeline(data.lessonPipeline || {});
|
|
1224
1240
|
renderFeedbackTrendChart(data.feedbackTimeSeries || {});
|
|
1225
1241
|
renderLessonTrendChart(data.feedbackTimeSeries || {});
|
|
1226
1242
|
renderGateAuditChartFromData(data.gateAudit || {});
|
|
1227
1243
|
}
|
|
1228
1244
|
|
|
1245
|
+
/**
|
|
1246
|
+
* Render token-savings panel from /v1/dashboard.tokenSavings.
|
|
1247
|
+
* Only shows a dollar figure when it's backed by real gate blocks.
|
|
1248
|
+
* Otherwise shows an honest "$0.00 — no blocks yet" state, NEVER
|
|
1249
|
+
* a marketing placeholder.
|
|
1250
|
+
*/
|
|
1251
|
+
function renderTokenSavings(savings, gateStats) {
|
|
1252
|
+
var panel = document.getElementById('tokenSavingsPanel');
|
|
1253
|
+
if (!panel) return;
|
|
1254
|
+
var dollarsEl = document.getElementById('tokenSavingsDollars');
|
|
1255
|
+
var tokensEl = document.getElementById('tokenSavingsTokens');
|
|
1256
|
+
var blocksEl = document.getElementById('tokenSavingsBlocks');
|
|
1257
|
+
var sourceEl = document.getElementById('tokenSavingsSource');
|
|
1258
|
+
|
|
1259
|
+
if (!savings || typeof savings.dollarsSaved !== 'number') {
|
|
1260
|
+
dollarsEl.textContent = '$0.00';
|
|
1261
|
+
tokensEl.innerHTML = 'No blocked calls yet — estimate will appear after your first gate fires';
|
|
1262
|
+
if (blocksEl) blocksEl.textContent = '0';
|
|
1263
|
+
sourceEl.textContent = '';
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
dollarsEl.textContent = savings.dollarsSavedDisplay || ('$' + Number(savings.dollarsSaved).toFixed(2));
|
|
1268
|
+
tokensEl.innerHTML = (savings.tokensSavedDisplay || '0') + ' tokens · from <span id="tokenSavingsBlocks">' +
|
|
1269
|
+
(savings.blockedCalls || 0) + '</span> blocked calls';
|
|
1270
|
+
|
|
1271
|
+
var mix = savings.modelMix || {};
|
|
1272
|
+
var mixParts = [];
|
|
1273
|
+
for (var m in mix) { mixParts.push(Math.round(mix[m] * 100) + '% ' + m); }
|
|
1274
|
+
var blend = savings.blendedPricePer1M || { input: 0, output: 0 };
|
|
1275
|
+
sourceEl.textContent =
|
|
1276
|
+
'Methodology: blended ' + mixParts.join(' / ') +
|
|
1277
|
+
' at $' + blend.input.toFixed(2) + '/1M input + $' + blend.output.toFixed(2) + '/1M output. ' +
|
|
1278
|
+
'Data source: actual blocked count from gate-stats.json. No sample numbers.';
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1229
1281
|
function renderPipeline(pipeline) {
|
|
1230
1282
|
var stages = pipeline.stages || [];
|
|
1231
1283
|
var rates = pipeline.rates || {};
|
package/public/index.html
CHANGED
|
@@ -283,9 +283,13 @@ __GA_BOOTSTRAP__
|
|
|
283
283
|
.hero p { font-size: 17px; color: var(--text-muted); max-width: 520px; margin: 0 auto 36px; line-height: 1.6; }
|
|
284
284
|
.hero-persona { font-size: 15px; color: var(--cyan); max-width: 600px; margin: 0 auto 20px; line-height: 1.5; font-weight: 500; }
|
|
285
285
|
.hero-signals { display: flex; justify-content: center; flex-wrap: wrap; gap: 12px; margin: 0 auto 28px; max-width: 760px; }
|
|
286
|
-
.signal-pill { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border); background: var(--bg-raised); font-size: 13px; font-weight: 600; letter-spacing: -0.01em; }
|
|
286
|
+
.signal-pill { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border); background: var(--bg-raised); font-size: 13px; font-weight: 600; letter-spacing: -0.01em; text-decoration: none; cursor: pointer; transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease; }
|
|
287
|
+
.signal-pill:hover { transform: translateY(-1px); border-color: rgba(34, 211, 238, 0.5); background: rgba(34, 211, 238, 0.06); }
|
|
288
|
+
.signal-pill:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
|
|
287
289
|
.signal-pill.signal-up { border-color: rgba(74, 222, 128, 0.28); color: #b8f7c8; background: rgba(74, 222, 128, 0.08); }
|
|
290
|
+
.signal-pill.signal-up:hover { border-color: rgba(74, 222, 128, 0.6); background: rgba(74, 222, 128, 0.14); }
|
|
288
291
|
.signal-pill.signal-down { border-color: rgba(248, 113, 113, 0.28); color: #ffc0c0; background: rgba(248, 113, 113, 0.08); }
|
|
292
|
+
.signal-pill.signal-down:hover { border-color: rgba(248, 113, 113, 0.6); background: rgba(248, 113, 113, 0.14); }
|
|
289
293
|
.hero-actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 12px; margin: 0 auto 16px; max-width: 760px; }
|
|
290
294
|
.btn-pro-page { display: inline-flex; align-items: center; justify-content: center; padding: 11px 18px; background: var(--cyan); color: var(--bg); border-radius: 999px; text-decoration: none; font-size: 14px; font-weight: 700; box-shadow: 0 0 0 1px rgba(34,211,238,0.28), 0 12px 32px rgba(34,211,238,0.18); transition: opacity 0.15s, transform 0.15s; }
|
|
291
295
|
.btn-pro-page:hover { opacity: 0.9; transform: translateY(-1px); }
|
|
@@ -528,6 +532,35 @@ __GA_BOOTSTRAP__
|
|
|
528
532
|
<div class="hero-badge">● Your AI coding bill has a leak</div>
|
|
529
533
|
<h1>Stop paying $ for the same AI mistake.</h1>
|
|
530
534
|
<p style="font-size:18px;color:var(--text-muted);max-width:720px;margin:0 auto 20px;line-height:1.6;">Every retry loop, every hallucinated import, every "let me try a different approach" — those are billable tokens on every LLM vendor's bill. Thumbs-down once; ThumbGate blocks that exact mistake on every future call. Across Claude Code, Cursor, Codex, Gemini, Amp, OpenCode — any MCP-compatible agent, forever, including fast-moving vibe coding workflows.</p>
|
|
535
|
+
|
|
536
|
+
<!-- HERO PRICING CARD — visible in first viewport so $19/mo and $149/yr never get buried -->
|
|
537
|
+
<div id="pro-pitch" style="max-width:820px;margin:0 auto 32px;padding:24px 28px;background:linear-gradient(180deg,rgba(17,17,19,0.94) 0%,rgba(22,22,24,0.94) 100%);border:1px solid rgba(34,211,238,0.32);border-radius:20px;box-shadow:0 0 0 1px rgba(34,211,238,0.18),0 24px 64px rgba(0,0,0,0.35);text-align:left;">
|
|
538
|
+
<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:16px;">
|
|
539
|
+
<div>
|
|
540
|
+
<div style="display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:999px;border:1px solid rgba(34,211,238,0.25);background:var(--cyan-dim);color:var(--cyan);font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;">Start 7-day free trial</div>
|
|
541
|
+
<h2 style="margin:10px 0 4px;font-size:22px;letter-spacing:-0.025em;line-height:1.2;">Go Pro — one correction, every agent, every session.</h2>
|
|
542
|
+
<p style="margin:0;font-size:13px;color:var(--text-muted);">Personal local dashboard · DPO export from real corrections · founder support on risky flows.</p>
|
|
543
|
+
</div>
|
|
544
|
+
</div>
|
|
545
|
+
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;">
|
|
546
|
+
<div style="display:flex;align-items:center;justify-content:space-between;gap:14px;padding:14px 16px;border-radius:14px;border:1px solid rgba(34,211,238,0.35);background:rgba(34,211,238,0.06);">
|
|
547
|
+
<div style="text-align:left;">
|
|
548
|
+
<div style="font-size:22px;font-weight:800;letter-spacing:-0.03em;line-height:1.1;">$19<span style="font-size:13px;font-weight:600;color:var(--text-muted);">/mo</span></div>
|
|
549
|
+
<div style="font-size:12px;color:var(--text-muted);margin-top:2px;">Monthly Pro</div>
|
|
550
|
+
</div>
|
|
551
|
+
<a href="/checkout/pro?utm_source=website&utm_medium=hero_pricing_card&utm_campaign=pro_pack&cta_id=hero_pro_monthly&cta_placement=hero_pricing&plan_id=pro&landing_path=%2F" onclick="posthog.capture('hero_pricing_monthly_click',{cta:'choose_monthly'})" style="display:inline-flex;align-items:center;gap:6px;padding:11px 20px;background:var(--cyan);color:#041016;border-radius:999px;text-decoration:none;font-weight:700;font-size:14px;box-shadow:0 0 0 1px rgba(34,211,238,0.28),0 12px 32px rgba(34,211,238,0.18);white-space:nowrap;">Choose monthly →</a>
|
|
552
|
+
</div>
|
|
553
|
+
<div style="display:flex;align-items:center;justify-content:space-between;gap:14px;padding:14px 16px;border-radius:14px;border:1px solid var(--border);background:rgba(255,255,255,0.02);">
|
|
554
|
+
<div style="text-align:left;">
|
|
555
|
+
<div style="font-size:22px;font-weight:800;letter-spacing:-0.03em;line-height:1.1;">$149<span style="font-size:13px;font-weight:600;color:var(--text-muted);">/yr</span> <span style="font-size:11px;color:#4ade80;background:rgba(74,222,128,0.14);padding:2px 7px;border-radius:999px;font-weight:700;vertical-align:middle;margin-left:4px;">SAVE 35%</span></div>
|
|
556
|
+
<div style="font-size:12px;color:var(--text-muted);margin-top:2px;">Annual Pro</div>
|
|
557
|
+
</div>
|
|
558
|
+
<a href="/checkout/pro?utm_source=website&utm_medium=hero_pricing_card&utm_campaign=pro_pack&cta_id=hero_pro_annual&cta_placement=hero_pricing&plan_id=pro&billing_cycle=annual&landing_path=%2F" onclick="posthog.capture('hero_pricing_annual_click',{cta:'choose_annual'})" style="display:inline-flex;align-items:center;gap:6px;padding:11px 20px;background:rgba(17,17,19,0.75);color:var(--text);border:1px solid var(--border);border-radius:999px;text-decoration:none;font-weight:700;font-size:14px;white-space:nowrap;">Choose annual →</a>
|
|
559
|
+
</div>
|
|
560
|
+
</div>
|
|
561
|
+
<p style="margin:14px 0 0;font-size:11px;color:var(--text-muted);text-align:center;">No credit card for 7-day trial · cancel anytime · your rules and captures stay local. <a href="/go/install" style="color:var(--cyan);text-decoration:none;">Prefer free? Install CLI →</a></p>
|
|
562
|
+
</div>
|
|
563
|
+
|
|
531
564
|
<a href="/dashboard" class="hero-dashboard-preview" style="display:block;max-width:620px;margin:0 auto 28px;background:linear-gradient(135deg,#0d1220 0%,#121a2e 100%);border:1px solid rgba(34,211,238,0.35);border-radius:12px;padding:20px 24px;box-shadow:0 0 48px rgba(34,211,238,0.15);font-family:var(--mono);text-align:left;text-decoration:none;color:inherit;" title="Open your live dashboard">
|
|
532
565
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;font-size:11px;letter-spacing:0.08em;text-transform:uppercase;color:var(--text-muted);">
|
|
533
566
|
<span>Your dashboard · <span style="color:#eab308;background:rgba(234,179,8,0.1);padding:2px 6px;border-radius:3px;letter-spacing:0.04em;">Sample</span></span>
|
|
@@ -554,9 +587,9 @@ __GA_BOOTSTRAP__
|
|
|
554
587
|
})();
|
|
555
588
|
</script>
|
|
556
589
|
<div class="hero-signals">
|
|
557
|
-
<
|
|
558
|
-
<
|
|
559
|
-
<
|
|
590
|
+
<a class="signal-pill signal-down" href="#how-it-works" title="See how gate interception works">Block repeat hallucinations before the model sees them</a>
|
|
591
|
+
<a class="signal-pill signal-up" href="#how-it-works" title="See the one-thumbs-down enforcement loop">Thumbs-down once, blocked forever, across every agent</a>
|
|
592
|
+
<a class="signal-pill" href="#install" title="Install the CLI">CLI-first workflow governance with a live tokens-saved counter</a>
|
|
560
593
|
</div>
|
|
561
594
|
<p class="hero-persona" style="display:none">For consultancies, platform teams, and AI product teams with one workflow owner, one repeated failure, and one buyer who needs proof before a wider rollout.</p>
|
|
562
595
|
<div class="hero-actions" style="margin-top:32px;">
|
|
@@ -571,6 +604,7 @@ __GA_BOOTSTRAP__
|
|
|
571
604
|
<a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-claude-desktop.mcpb" class="btn-gpt-page" target="_blank" rel="noopener" onclick="posthog.capture('hero_claude_extension_click',{cta:'install_claude_extension'})" style="font-size:12px;padding:8px 16px;background:#d97706;color:#fff;box-shadow:none;">Install Claude Extension</a>
|
|
572
605
|
<a href="/go/github?utm_source=website&utm_medium=hero_cta&utm_campaign=github_repo&cta_id=hero_star_github&cta_placement=hero" target="_blank" rel="noopener" class="btn-free" style="display:inline-flex;align-items:center;gap:6px;padding:8px 14px;border-radius:999px;font-size:12px;">⭐ Star on GitHub</a>
|
|
573
606
|
<a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" class="btn-install-link" target="_blank" rel="noopener" onclick="posthog.capture('hero_codex_plugin_click',{cta:'install_codex_plugin'})" style="font-size:11px;color:var(--text-muted);text-decoration:none;padding:6px 10px;">Install Codex plugin →</a>
|
|
607
|
+
<a href="https://github.com/IgorGanapolsky/ThumbGate/tree/main/plugins/cursor-marketplace" class="btn-install-link" target="_blank" rel="noopener" onclick="posthog.capture('hero_cursor_plugin_click',{cta:'install_cursor_plugin'})" style="font-size:11px;color:var(--text-muted);text-decoration:none;padding:6px 10px;">Install Cursor plugin →</a>
|
|
574
608
|
<a href="/go/gpt?utm_source=website&utm_medium=hero_cta&utm_campaign=chatgpt_gpt&cta_id=hero_open_gpt&cta_placement=hero" class="btn-gpt-page" target="_blank" rel="noopener" onclick="posthog.capture('hero_cta_click',{cta:'open_gpt'})" style="font-size:11px;padding:6px 12px;background:transparent;border:1px solid rgba(74,222,128,0.3);color:var(--green);">Open ThumbGate GPT</a>
|
|
575
609
|
</div>
|
|
576
610
|
</div>
|
|
@@ -594,7 +628,7 @@ __GA_BOOTSTRAP__
|
|
|
594
628
|
<div class="first-gate-steps">
|
|
595
629
|
<div class="first-gate-step">
|
|
596
630
|
<strong>1. Install ThumbGate</strong>
|
|
597
|
-
<p>Run <code>npx thumbgate init</code> in your repo. Or install the <a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-claude-desktop.mcpb" style="color:var(--cyan);">Claude Extension</a>, <a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" style="color:var(--cyan);">Codex plugin</a>, or <a href="/go/gpt" style="color:var(--cyan);">open the GPT</a>. Native ChatGPT rating buttons are not the ThumbGate capture path.</p>
|
|
631
|
+
<p>Run <code>npx thumbgate init</code> in your repo. Or install the <a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-claude-desktop.mcpb" style="color:var(--cyan);">Claude Extension</a>, <a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" style="color:var(--cyan);">Codex plugin</a>, <a href="https://github.com/IgorGanapolsky/ThumbGate/tree/main/plugins/cursor-marketplace" style="color:var(--cyan);">Cursor plugin</a>, or <a href="/go/gpt" style="color:var(--cyan);">open the GPT</a>. Native ChatGPT rating buttons are not the ThumbGate capture path.</p>
|
|
598
632
|
</div>
|
|
599
633
|
<div class="first-gate-step">
|
|
600
634
|
<strong>2. Give feedback</strong>
|
|
@@ -701,7 +735,7 @@ __GA_BOOTSTRAP__
|
|
|
701
735
|
</div>
|
|
702
736
|
<div style="display:flex;gap:12px;flex-wrap:wrap;">
|
|
703
737
|
<a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-claude-desktop.mcpb" class="btn-gpt-page" target="_blank" rel="noopener" onclick="posthog.capture('claude_section_extension_click',{cta:'install_claude_extension'})" style="background:#d97706;color:#fff;">Download Claude Extension (.mcpb)</a>
|
|
704
|
-
<a href="/
|
|
738
|
+
<a href="/guide.html" class="btn-free" style="display:inline-flex;align-items:center;padding:12px 20px;border-radius:8px;">Claude Desktop setup guide</a>
|
|
705
739
|
<a href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/.claude-plugin/README.md" class="btn-free" target="_blank" rel="noopener" style="display:inline-flex;align-items:center;padding:12px 20px;border-radius:8px;">Claude plugin docs</a>
|
|
706
740
|
</div>
|
|
707
741
|
<p class="gpt-note"><strong>Claude Code Skill:</strong> Type <code>/thumbgate</code> in any Claude Code session. Auto-triggers on “gate”, “feedback”, “block mistake”. Free skill on top of the same local gateway.</p>
|
|
@@ -744,30 +778,40 @@ __GA_BOOTSTRAP__
|
|
|
744
778
|
<div class="section-label">Compatibility</div>
|
|
745
779
|
<h2 class="section-title">One gateway across the agent surfaces you already use</h2>
|
|
746
780
|
<div class="compatibility-grid">
|
|
747
|
-
<a class="compat-card" href="/
|
|
781
|
+
<a class="compat-card" href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-claude-desktop.mcpb" target="_blank" rel="noopener" onclick="if(typeof posthog!=='undefined')posthog.capture('compat_claude_desktop_click',{cta:'download_claude_desktop'})" style="border-color:rgba(217,119,6,0.3);background:linear-gradient(135deg, rgba(217,119,6,0.06) 0%, var(--bg-card) 100%);">
|
|
748
782
|
<h3>🧩 Claude Desktop Extension</h3>
|
|
749
|
-
<p>Install the published Claude Desktop plugin <code>.mcpb</code> bundle today. Claude Code users can add the repo marketplace immediately with <code>/plugin marketplace add</code>. No waiting for directory approval
|
|
750
|
-
<div class="card-arrow" style="color:#d97706;">
|
|
783
|
+
<p>Install the published Claude Desktop plugin <code>.mcpb</code> bundle today. Claude Code users can add the repo marketplace immediately with <code>/plugin marketplace add</code>. No waiting for directory approval. <a href="/guide.html" style="color:var(--text-muted);text-decoration:underline;" onclick="event.stopPropagation();">60-second setup guide →</a></p>
|
|
784
|
+
<div class="card-arrow" style="color:#d97706;">Download .mcpb bundle →</div>
|
|
751
785
|
</a>
|
|
752
|
-
<a class="compat-card seo-card" href="
|
|
786
|
+
<a class="compat-card seo-card" href="/guides/claude-code-prevent-repeated-mistakes.html" rel="noopener">
|
|
753
787
|
<h3>⚡ Claude Code Skill</h3>
|
|
754
788
|
<p>Type <code>/thumbgate</code> in any Claude Code session. Auto-triggers on "gate", "feedback", "block mistake". Free skill on top of the same local gateway teams later harden into a shared workflow.</p>
|
|
755
|
-
<div class="card-arrow">
|
|
789
|
+
<div class="card-arrow">Read the Claude Code guide →</div>
|
|
756
790
|
</a>
|
|
757
|
-
<a class="compat-card" href="
|
|
791
|
+
<a class="compat-card" href="/guide.html" rel="noopener">
|
|
758
792
|
<h3>🤖 AI CLIs</h3>
|
|
759
793
|
<p>Claude Code, Codex, Gemini CLI, Amp, and OpenCode all use the same gateway and memory model. Any MCP-compatible agent gets pre-action gates, feedback memory, and enforcement out of the box.</p>
|
|
760
|
-
<div class="card-arrow">
|
|
794
|
+
<div class="card-arrow">Open the setup guide →</div>
|
|
761
795
|
</a>
|
|
762
|
-
<a class="compat-card" href="https://github.com/IgorGanapolsky/ThumbGate/
|
|
796
|
+
<a class="compat-card" href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" target="_blank" rel="noopener" onclick="if(typeof posthog!=='undefined')posthog.capture('compat_codex_plugin_click',{cta:'download_codex_plugin'})">
|
|
763
797
|
<h3>🧩 Codex plugin</h3>
|
|
764
|
-
<p>Codex ships with a published standalone ThumbGate plugin bundle plus a repo-local plugin profile. Download the zip, extract it, and install without wiring MCP by hand
|
|
765
|
-
<div class="card-arrow">
|
|
798
|
+
<p>Codex ships with a published standalone ThumbGate plugin bundle plus a repo-local plugin profile. Download the zip, extract it, and install without wiring MCP by hand. <a href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/plugins/codex-profile/INSTALL.md" target="_blank" rel="noopener" style="color:var(--text-muted);text-decoration:underline;" onclick="event.stopPropagation();">Setup instructions →</a></p>
|
|
799
|
+
<div class="card-arrow">Download the Codex plugin →</div>
|
|
766
800
|
</a>
|
|
767
|
-
<a class="compat-card" href="
|
|
801
|
+
<a class="compat-card" href="/guides/cursor-prevent-repeated-mistakes.html" rel="noopener">
|
|
802
|
+
<h3>🎯 Cursor plugin</h3>
|
|
803
|
+
<p>Drop the ThumbGate MCP config into <code>.cursor/mcp.json</code> and Cursor gets the same pre-action gates as Claude Code and Codex. Ships with bundled rules, commands, hooks, and agents.</p>
|
|
804
|
+
<div class="card-arrow">Read the Cursor guide →</div>
|
|
805
|
+
</a>
|
|
806
|
+
<a class="compat-card" href="/guide.html" rel="noopener">
|
|
768
807
|
<h3>✏️ Editor workflows</h3>
|
|
769
|
-
<p>
|
|
770
|
-
<div class="card-arrow">
|
|
808
|
+
<p>VS Code works when you run an MCP-compatible agent inside it (Continue, Cline, etc.). Any editor that speaks MCP stdio gets the same gateway.</p>
|
|
809
|
+
<div class="card-arrow">Open the setup guide →</div>
|
|
810
|
+
</a>
|
|
811
|
+
<a class="compat-card" href="https://mcp.so/server/thumbgate" target="_blank" rel="noopener" onclick="if(typeof posthog!=='undefined')posthog.capture('compat_mcp_so_click',{cta:'view_mcp_directory'})">
|
|
812
|
+
<h3>🗂️ MCP Server Directory</h3>
|
|
813
|
+
<p>ThumbGate is listed on <code>mcp.so</code> — the largest public MCP server directory. Install via Smithery CLI, copy-paste config for your client, or verify it's a legitimate server before running it.</p>
|
|
814
|
+
<div class="card-arrow">View on mcp.so →</div>
|
|
771
815
|
</a>
|
|
772
816
|
<a class="compat-card" href="/go/gpt?utm_source=website&utm_medium=compatibility&utm_campaign=chatgpt_gpt&cta_id=compat_open_gpt&cta_placement=compatibility" target="_blank" rel="noopener">
|
|
773
817
|
<h3>💬 ChatGPT GPT Actions</h3>
|
|
@@ -872,7 +916,7 @@ __GA_BOOTSTRAP__
|
|
|
872
916
|
<!-- HOW IT WORKS -->
|
|
873
917
|
<section class="how-it-works" id="how-it-works">
|
|
874
918
|
<div class="container">
|
|
875
|
-
<div class="section-label">New in v1.5.
|
|
919
|
+
<div class="section-label">New in v1.5.8</div>
|
|
876
920
|
<h2 class="section-title">Three steps to stop repeated AI failures</h2>
|
|
877
921
|
<div class="steps">
|
|
878
922
|
<div class="step">
|
|
@@ -1228,7 +1272,7 @@ __GA_BOOTSTRAP__
|
|
|
1228
1272
|
<a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
|
|
1229
1273
|
<a href="/blog">Blog</a>
|
|
1230
1274
|
</div>
|
|
1231
|
-
<span class="footer-copy">© 2026 Max Smith KDP LLC · MIT License · v1.5.
|
|
1275
|
+
<span class="footer-copy">© 2026 Max Smith KDP LLC · MIT License · v1.5.8</span>
|
|
1232
1276
|
</div>
|
|
1233
1277
|
</footer>
|
|
1234
1278
|
|
|
@@ -71,6 +71,7 @@ function detectAgent(flagAgent) {
|
|
|
71
71
|
if (['codex'].includes(normalized)) return 'codex';
|
|
72
72
|
if (['gemini'].includes(normalized)) return 'gemini';
|
|
73
73
|
if (['forge', 'forgecode', 'forge-code'].includes(normalized)) return 'forge';
|
|
74
|
+
if (['cursor'].includes(normalized)) return 'cursor';
|
|
74
75
|
return null;
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -80,9 +81,65 @@ function detectAgent(flagAgent) {
|
|
|
80
81
|
if (fs.existsSync(path.join(home, '.codex'))) return 'codex';
|
|
81
82
|
if (fs.existsSync(path.join(home, '.gemini'))) return 'gemini';
|
|
82
83
|
if (fs.existsSync(path.join(process.cwd(), 'forge.yaml'))) return 'forge';
|
|
84
|
+
if (fs.existsSync(path.join(process.cwd(), '.cursor'))) return 'cursor';
|
|
83
85
|
return null;
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
// --- Cursor wiring ---
|
|
89
|
+
// Cursor uses .cursor/mcp.json in the project root. We write the ThumbGate MCP
|
|
90
|
+
// server config there so Cursor picks up the server on next restart. Cursor's
|
|
91
|
+
// native hook model is different from Claude Code's — we rely on the MCP
|
|
92
|
+
// server's PreToolUse-equivalent enforcement via the gate-check tool.
|
|
93
|
+
|
|
94
|
+
function cursorMcpConfigPath() {
|
|
95
|
+
return path.join(process.cwd(), '.cursor', 'mcp.json');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function wireCursorHooks(options = {}) {
|
|
99
|
+
const mcpPath = cursorMcpConfigPath();
|
|
100
|
+
const dir = path.dirname(mcpPath);
|
|
101
|
+
const thumbgateServer = {
|
|
102
|
+
command: 'npx',
|
|
103
|
+
args: ['--yes', '--package', 'thumbgate@latest', 'thumbgate', 'serve'],
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
let existing = { mcpServers: {} };
|
|
107
|
+
if (fs.existsSync(mcpPath)) {
|
|
108
|
+
try {
|
|
109
|
+
existing = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
|
|
110
|
+
if (!existing.mcpServers) existing.mcpServers = {};
|
|
111
|
+
} catch {
|
|
112
|
+
return { changed: false, error: `Could not parse ${mcpPath}` };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const before = JSON.stringify(existing.mcpServers.thumbgate || null);
|
|
117
|
+
existing.mcpServers.thumbgate = thumbgateServer;
|
|
118
|
+
const after = JSON.stringify(existing.mcpServers.thumbgate);
|
|
119
|
+
|
|
120
|
+
const addedEntry = {
|
|
121
|
+
lifecycle: 'mcpServers.thumbgate',
|
|
122
|
+
command: `${thumbgateServer.command} ${thumbgateServer.args.join(' ')}`,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
if (options.dryRun) {
|
|
126
|
+
return {
|
|
127
|
+
changed: before !== after,
|
|
128
|
+
dryRun: true,
|
|
129
|
+
settingsPath: mcpPath,
|
|
130
|
+
added: before === after ? [] : [addedEntry],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (before === after) {
|
|
135
|
+
return { changed: false, settingsPath: mcpPath, added: [] };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
139
|
+
fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2) + '\n');
|
|
140
|
+
return { changed: true, settingsPath: mcpPath, added: [addedEntry] };
|
|
141
|
+
}
|
|
142
|
+
|
|
86
143
|
// --- Claude Code wiring ---
|
|
87
144
|
|
|
88
145
|
function claudeSettingsPath() {
|
|
@@ -543,7 +600,7 @@ function wireHooks(options) {
|
|
|
543
600
|
const agent = detectAgent(options.agent);
|
|
544
601
|
if (!agent) {
|
|
545
602
|
return {
|
|
546
|
-
error: 'Could not detect AI agent. Use --agent=claude-code|codex|gemini|forge',
|
|
603
|
+
error: 'Could not detect AI agent. Use --agent=claude-code|codex|gemini|forge|cursor',
|
|
547
604
|
agent: null,
|
|
548
605
|
changed: false,
|
|
549
606
|
};
|
|
@@ -563,6 +620,9 @@ function wireHooks(options) {
|
|
|
563
620
|
case 'forge':
|
|
564
621
|
result = wireForgeHooks(options);
|
|
565
622
|
break;
|
|
623
|
+
case 'cursor':
|
|
624
|
+
result = wireCursorHooks(options);
|
|
625
|
+
break;
|
|
566
626
|
default:
|
|
567
627
|
return { error: `Unsupported agent: ${agent}`, agent, changed: false };
|
|
568
628
|
}
|
package/scripts/dashboard.js
CHANGED
|
@@ -971,6 +971,18 @@ function generateDashboard(feedbackDir, options = {}) {
|
|
|
971
971
|
const feedbackTimeSeries = computeFeedbackTimeSeries(entries, 30);
|
|
972
972
|
const lessonPipeline = computeLessonPipeline(feedbackDir, entries, gateStats);
|
|
973
973
|
|
|
974
|
+
// Estimated token savings — computed from gate blocked counts using the
|
|
975
|
+
// conservative methodology in scripts/token-savings.js. This is the ONLY
|
|
976
|
+
// place "$ saved" appears that's backed by real gate-block data; the landing
|
|
977
|
+
// page hero uses a hardcoded sample number disclosed as "Sample".
|
|
978
|
+
let tokenSavings = null;
|
|
979
|
+
try {
|
|
980
|
+
const { computeTokenSavings } = require('./token-savings');
|
|
981
|
+
tokenSavings = computeTokenSavings({
|
|
982
|
+
blockedCalls: Number(gateStats.blocked) || 0,
|
|
983
|
+
});
|
|
984
|
+
} catch { /* module missing — skip */ }
|
|
985
|
+
|
|
974
986
|
// Merge lesson counts into feedbackTimeSeries days
|
|
975
987
|
for (const day of feedbackTimeSeries.days) {
|
|
976
988
|
day.lessons = lessonPipeline.lessonsByDay.get(day.dayKey) || 0;
|
|
@@ -1018,6 +1030,7 @@ function generateDashboard(feedbackDir, options = {}) {
|
|
|
1018
1030
|
liveMetrics,
|
|
1019
1031
|
predictive,
|
|
1020
1032
|
feedbackTimeSeries,
|
|
1033
|
+
tokenSavings,
|
|
1021
1034
|
lessonPipeline: {
|
|
1022
1035
|
stages: lessonPipeline.stages,
|
|
1023
1036
|
rates: lessonPipeline.rates,
|
package/src/api/server.js
CHANGED
|
@@ -1896,7 +1896,9 @@ function renderRobotsTxt(runtimeConfig) {
|
|
|
1896
1896
|
function renderSitemapXml(runtimeConfig) {
|
|
1897
1897
|
const entries = [
|
|
1898
1898
|
{ path: '/', changefreq: 'weekly', priority: '1.0' },
|
|
1899
|
-
|
|
1899
|
+
// /pro consolidated into /#pro-pitch (2026-04-16) — removed from sitemap
|
|
1900
|
+
// so search engines don't chase the 301 instead of indexing the canonical
|
|
1901
|
+
// homepage directly.
|
|
1900
1902
|
{ path: '/llm-context.md', changefreq: 'weekly', priority: '0.8' },
|
|
1901
1903
|
...THUMBGATE_SEO_SITEMAP_ENTRIES,
|
|
1902
1904
|
];
|
|
@@ -3453,21 +3455,17 @@ async function addContext(){
|
|
|
3453
3455
|
}
|
|
3454
3456
|
|
|
3455
3457
|
if (isGetLikeRequest && pathname === '/pro') {
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
});
|
|
3468
|
-
} catch (err) {
|
|
3469
|
-
sendText(res, 500, err.message || 'Pro page unavailable');
|
|
3470
|
-
}
|
|
3458
|
+
// Consolidated: /pro content now lives inline on `/` as the #pro-pitch
|
|
3459
|
+
// strip (hero-adjacent pricing card). 301 so external links (README,
|
|
3460
|
+
// plugin manifests, guides, compare pages) pass link equity onto the
|
|
3461
|
+
// single canonical landing page. Query string is preserved so UTM
|
|
3462
|
+
// tracking from inbound campaigns still reaches GA/PostHog on `/`.
|
|
3463
|
+
const redirectTarget = `/#pro-pitch${parsed.search || ''}`;
|
|
3464
|
+
res.writeHead(301, {
|
|
3465
|
+
Location: redirectTarget,
|
|
3466
|
+
'Cache-Control': 'public, max-age=3600',
|
|
3467
|
+
});
|
|
3468
|
+
res.end();
|
|
3471
3469
|
return;
|
|
3472
3470
|
}
|
|
3473
3471
|
|
|
@@ -3591,7 +3589,7 @@ async function addContext(){
|
|
|
3591
3589
|
version: pkg.version,
|
|
3592
3590
|
status: 'ok',
|
|
3593
3591
|
docs: 'https://github.com/IgorGanapolsky/ThumbGate',
|
|
3594
|
-
endpoints: ['/health', '/dashboard', '/guide', '/compare', '/learn', '/
|
|
3592
|
+
endpoints: ['/health', '/dashboard', '/guide', '/compare', '/learn', '/v1/feedback/capture', '/v1/feedback/stats', '/v1/feedback/summary', '/v1/lessons/search', '/v1/search', '/v1/documents', '/v1/documents/import', '/v1/documents/{documentId}', '/v1/dashboard', '/v1/dashboard/render-spec', '/v1/decisions/evaluate', '/v1/decisions/outcome', '/v1/decisions/metrics', '/v1/settings/status', '/v1/dpo/export', '/v1/jobs', '/v1/jobs/harness', '/v1/analytics/databricks/export'],
|
|
3595
3593
|
}, {}, {
|
|
3596
3594
|
headOnly: isHeadRequest,
|
|
3597
3595
|
});
|