thumbgate 1.5.4 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/CHANGELOG.md +198 -0
- package/README.md +7 -6
- package/adapters/README.md +1 -1
- package/adapters/chatgpt/openapi.yaml +25 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +4 -4
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +61 -5
- package/openapi/openapi.yaml +25 -0
- package/package.json +16 -3
- package/public/codex-plugin.html +277 -0
- package/public/dashboard.html +193 -13
- package/public/index.html +150 -48
- package/public/learn.html +13 -2
- package/public/lessons.html +5 -2
- package/public/pro.html +8 -1
- package/scripts/auto-wire-hooks.js +71 -6
- package/scripts/billing.js +503 -8
- package/scripts/contextfs.js +1 -1
- package/scripts/dashboard.js +249 -0
- package/scripts/gates-engine.js +153 -2
- package/scripts/hook-runtime.js +42 -0
- package/scripts/llm-client.js +25 -10
- package/scripts/mailer/index.js +13 -0
- package/scripts/mailer/resend-mailer.js +350 -0
- package/scripts/mcp-config.js +13 -0
- package/scripts/published-cli.js +8 -0
- package/scripts/seo-gsd.js +118 -4
- package/scripts/statusline.sh +8 -0
- package/scripts/vector-store.js +21 -7
- package/src/api/server.js +126 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
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": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"config/",
|
|
37
37
|
"openapi/",
|
|
38
38
|
"public/blog.html",
|
|
39
|
+
"public/codex-plugin.html",
|
|
39
40
|
"public/compare.html",
|
|
40
41
|
"public/dashboard.html",
|
|
41
42
|
"public/guide.html",
|
|
@@ -126,6 +127,8 @@
|
|
|
126
127
|
"scripts/lesson-synthesis.js",
|
|
127
128
|
"scripts/license.js",
|
|
128
129
|
"scripts/llm-client.js",
|
|
130
|
+
"scripts/mailer/index.js",
|
|
131
|
+
"scripts/mailer/resend-mailer.js",
|
|
129
132
|
"scripts/local-model-profile.js",
|
|
130
133
|
"scripts/managed-lesson-agent.js",
|
|
131
134
|
"scripts/mcp-config.js",
|
|
@@ -248,7 +251,7 @@
|
|
|
248
251
|
"trace:eval": "node scripts/decision-trace.js eval",
|
|
249
252
|
"social:reply-monitor": "node scripts/social-reply-monitor.js",
|
|
250
253
|
"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",
|
|
254
|
+
"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:platform-limits && 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 && 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",
|
|
252
255
|
"test:session-health": "node --test tests/session-health-sensor.test.js",
|
|
253
256
|
"test:session-episodes": "node --test tests/session-episode-store.test.js",
|
|
254
257
|
"test:spec-gate": "node --test tests/spec-gate.test.js",
|
|
@@ -380,6 +383,8 @@
|
|
|
380
383
|
"social:poll:zernio": "node scripts/social-analytics/pollers/zernio.js",
|
|
381
384
|
"social:publish:zernio": "node scripts/social-analytics/publishers/zernio.js",
|
|
382
385
|
"test:zernio": "node --test tests/zernio-integration.test.js",
|
|
386
|
+
"test:platform-limits": "node --test tests/platform-limits.test.js",
|
|
387
|
+
"test:durability-step": "node --test tests/durability-step.test.js",
|
|
383
388
|
"test:post-video": "node --test tests/post-video.test.js",
|
|
384
389
|
"test:post-everywhere-instagram": "node --test tests/post-everywhere-instagram.test.js",
|
|
385
390
|
"test:license": "node --test tests/license.test.js",
|
|
@@ -485,7 +490,15 @@
|
|
|
485
490
|
"test:lesson-export-import": "node --test tests/lesson-export-import.test.js",
|
|
486
491
|
"test:landing-page-claims": "node --test tests/landing-page-claims.test.js",
|
|
487
492
|
"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"
|
|
493
|
+
"test:public-package-parity": "node --test tests/public-package-parity.test.js",
|
|
494
|
+
"prepare": "bash bin/install-hooks.sh >/dev/null 2>&1 || true",
|
|
495
|
+
"install:hooks": "bash bin/install-hooks.sh",
|
|
496
|
+
"test:token-savings-dashboard": "node --test tests/token-savings-dashboard.test.js",
|
|
497
|
+
"test:cursor-wiring": "node --test tests/cursor-wiring.test.js",
|
|
498
|
+
"test:pretooluse-injection": "node --test tests/pretooluse-lesson-injection.test.js",
|
|
499
|
+
"test:recent-corrective-context": "node --test tests/recent-corrective-actions-context.test.js",
|
|
500
|
+
"test:mailer": "node --test tests/mailer.test.js tests/billing-webhook-email.test.js",
|
|
501
|
+
"test:brand-assets": "node --test tests/brand-assets.test.js"
|
|
489
502
|
},
|
|
490
503
|
"keywords": [
|
|
491
504
|
"mcp",
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ThumbGate for Codex - Auto-Updating MCP Plugin</title>
|
|
7
|
+
<script defer data-domain="thumbgate-production.up.railway.app" src="https://plausible.io/js/script.js"></script>
|
|
8
|
+
<meta name="description" content="Install ThumbGate for Codex with an auto-updating MCP plugin, Pre-Action Gates, thumbs-up/down feedback memory, and a local-first Reliability Gateway.">
|
|
9
|
+
<meta name="keywords" content="ThumbGate Codex plugin, Codex MCP server, Codex pre-action gates, Codex guardrails, thumbgate latest, AI coding agent reliability">
|
|
10
|
+
<meta property="og:title" content="ThumbGate for Codex">
|
|
11
|
+
<meta property="og:description" content="Auto-updating MCP and hook launcher for Codex. One install, then ThumbGate resolves the latest npm runtime when Codex starts.">
|
|
12
|
+
<meta property="og:type" content="website">
|
|
13
|
+
<meta property="og:url" content="https://thumbgate-production.up.railway.app/codex-plugin">
|
|
14
|
+
<link rel="canonical" href="https://thumbgate-production.up.railway.app/codex-plugin">
|
|
15
|
+
<link rel="llm-context" href="/public/llm-context.md" type="text/markdown">
|
|
16
|
+
|
|
17
|
+
<script type="application/ld+json">
|
|
18
|
+
{
|
|
19
|
+
"@context": "https://schema.org",
|
|
20
|
+
"@type": "SoftwareApplication",
|
|
21
|
+
"name": "ThumbGate for Codex",
|
|
22
|
+
"applicationCategory": "DeveloperApplication",
|
|
23
|
+
"operatingSystem": "macOS, Linux, Windows with Node.js",
|
|
24
|
+
"description": "ThumbGate for Codex installs an MCP server and hook launcher that resolves thumbgate@latest at startup, captures thumbs-up/down feedback, and enforces Pre-Action Gates before risky agent actions run.",
|
|
25
|
+
"url": "https://thumbgate-production.up.railway.app/codex-plugin",
|
|
26
|
+
"downloadUrl": "https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip",
|
|
27
|
+
"installUrl": "https://thumbgate-production.up.railway.app/codex-plugin",
|
|
28
|
+
"license": "https://opensource.org/licenses/MIT",
|
|
29
|
+
"creator": {
|
|
30
|
+
"@type": "Person",
|
|
31
|
+
"name": "Igor Ganapolsky",
|
|
32
|
+
"url": "https://github.com/IgorGanapolsky"
|
|
33
|
+
},
|
|
34
|
+
"offers": {
|
|
35
|
+
"@type": "Offer",
|
|
36
|
+
"price": "0",
|
|
37
|
+
"priceCurrency": "USD",
|
|
38
|
+
"description": "Free local Codex MCP setup with optional Pro dashboard upgrade."
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<script type="application/ld+json">
|
|
44
|
+
{
|
|
45
|
+
"@context": "https://schema.org",
|
|
46
|
+
"@type": "FAQPage",
|
|
47
|
+
"mainEntity": [
|
|
48
|
+
{
|
|
49
|
+
"@type": "Question",
|
|
50
|
+
"name": "Does the ThumbGate Codex MCP server update automatically?",
|
|
51
|
+
"acceptedAnswer": {
|
|
52
|
+
"@type": "Answer",
|
|
53
|
+
"text": "The Codex MCP and hook launcher resolves thumbgate@latest when Codex starts. After a new npm release is published, restarting Codex lets the launcher install the latest runtime into the local ThumbGate runtime cache before it serves MCP or checks gates."
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"@type": "Question",
|
|
58
|
+
"name": "Do Codex thumbs-up and thumbs-down signals work by default?",
|
|
59
|
+
"acceptedAnswer": {
|
|
60
|
+
"@type": "Answer",
|
|
61
|
+
"text": "ThumbGate works when the MCP server and hooks are enabled in Codex settings. The Codex settings page should show the thumbgate MCP server toggled on. Typed thumbs-up/down feedback with concrete context can then be captured and promoted into prevention rules."
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"@type": "Question",
|
|
66
|
+
"name": "What is the fastest Codex install path?",
|
|
67
|
+
"acceptedAnswer": {
|
|
68
|
+
"@type": "Answer",
|
|
69
|
+
"text": "Run npx thumbgate init --agent codex for the automatic local setup, or use the standalone Codex plugin bundle if you want a portable plugin surface."
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<style>
|
|
77
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
78
|
+
:root {
|
|
79
|
+
--bg: #090a0d;
|
|
80
|
+
--panel: #12141a;
|
|
81
|
+
--panel-2: #171a21;
|
|
82
|
+
--line: #2b313c;
|
|
83
|
+
--text: #f1f5f9;
|
|
84
|
+
--muted: #9aa4b2;
|
|
85
|
+
--cyan: #22d3ee;
|
|
86
|
+
--green: #4ade80;
|
|
87
|
+
--red: #fb7185;
|
|
88
|
+
--yellow: #facc15;
|
|
89
|
+
}
|
|
90
|
+
body {
|
|
91
|
+
margin: 0;
|
|
92
|
+
background: var(--bg);
|
|
93
|
+
color: var(--text);
|
|
94
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
95
|
+
line-height: 1.65;
|
|
96
|
+
}
|
|
97
|
+
a { color: var(--cyan); }
|
|
98
|
+
nav {
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
justify-content: space-between;
|
|
102
|
+
gap: 16px;
|
|
103
|
+
padding: 18px 28px;
|
|
104
|
+
border-bottom: 1px solid var(--line);
|
|
105
|
+
background: rgba(9, 10, 13, 0.88);
|
|
106
|
+
position: sticky;
|
|
107
|
+
top: 0;
|
|
108
|
+
z-index: 10;
|
|
109
|
+
backdrop-filter: blur(12px);
|
|
110
|
+
}
|
|
111
|
+
nav a { color: var(--muted); text-decoration: none; font-size: 14px; }
|
|
112
|
+
nav .brand { color: var(--text); font-weight: 800; }
|
|
113
|
+
.nav-links { display: flex; gap: 14px; flex-wrap: wrap; justify-content: flex-end; }
|
|
114
|
+
.wrap { width: min(1120px, calc(100% - 32px)); margin: 0 auto; }
|
|
115
|
+
.hero { padding: 72px 0 42px; }
|
|
116
|
+
.eyebrow { color: var(--green); font: 700 13px ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 14px; }
|
|
117
|
+
h1 { font-size: clamp(38px, 7vw, 76px); line-height: 1.02; margin: 0 0 22px; letter-spacing: 0; max-width: 980px; }
|
|
118
|
+
.sub { color: var(--muted); font-size: 20px; max-width: 820px; margin: 0 0 28px; }
|
|
119
|
+
.actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
|
|
120
|
+
.button {
|
|
121
|
+
display: inline-flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
border-radius: 8px;
|
|
125
|
+
padding: 13px 18px;
|
|
126
|
+
min-height: 48px;
|
|
127
|
+
text-decoration: none;
|
|
128
|
+
font-weight: 800;
|
|
129
|
+
border: 1px solid var(--line);
|
|
130
|
+
}
|
|
131
|
+
.button.primary { background: var(--cyan); color: #061014; border-color: var(--cyan); }
|
|
132
|
+
.button.secondary { background: var(--panel); color: var(--text); }
|
|
133
|
+
.terminal {
|
|
134
|
+
background: #050608;
|
|
135
|
+
border: 1px solid var(--line);
|
|
136
|
+
border-radius: 8px;
|
|
137
|
+
padding: 18px;
|
|
138
|
+
color: var(--green);
|
|
139
|
+
font: 14px ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
140
|
+
overflow-x: auto;
|
|
141
|
+
margin: 28px 0 0;
|
|
142
|
+
}
|
|
143
|
+
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin: 38px 0; }
|
|
144
|
+
.tile, .proof, .step, .faq {
|
|
145
|
+
background: var(--panel);
|
|
146
|
+
border: 1px solid var(--line);
|
|
147
|
+
border-radius: 8px;
|
|
148
|
+
padding: 22px;
|
|
149
|
+
}
|
|
150
|
+
.tile h3, .step h3, .faq h3 { margin: 0 0 10px; font-size: 19px; }
|
|
151
|
+
.tile p, .step p, .faq p { color: var(--muted); margin: 0; }
|
|
152
|
+
.split { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 28px; align-items: center; margin: 54px 0; }
|
|
153
|
+
.proof img { width: 100%; height: auto; display: block; border-radius: 8px; border: 1px solid var(--line); background: #050608; }
|
|
154
|
+
.caption { color: var(--muted); font-size: 14px; margin-top: 10px; }
|
|
155
|
+
h2 { font-size: 32px; line-height: 1.15; margin: 0 0 16px; letter-spacing: 0; }
|
|
156
|
+
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin: 24px 0 44px; }
|
|
157
|
+
code {
|
|
158
|
+
background: rgba(34, 211, 238, 0.1);
|
|
159
|
+
border: 1px solid rgba(34, 211, 238, 0.2);
|
|
160
|
+
border-radius: 6px;
|
|
161
|
+
padding: 2px 6px;
|
|
162
|
+
color: var(--text);
|
|
163
|
+
}
|
|
164
|
+
.status { color: var(--yellow); }
|
|
165
|
+
.faq-list { display: grid; gap: 14px; margin: 24px 0 54px; }
|
|
166
|
+
footer { border-top: 1px solid var(--line); padding: 28px 0 42px; color: var(--muted); }
|
|
167
|
+
@media (max-width: 820px) {
|
|
168
|
+
nav { align-items: flex-start; flex-direction: column; }
|
|
169
|
+
.grid, .split, .steps { grid-template-columns: 1fr; }
|
|
170
|
+
.hero { padding-top: 44px; }
|
|
171
|
+
h1 { font-size: 38px; }
|
|
172
|
+
.sub { font-size: 18px; }
|
|
173
|
+
}
|
|
174
|
+
</style>
|
|
175
|
+
</head>
|
|
176
|
+
<body>
|
|
177
|
+
<nav>
|
|
178
|
+
<a class="brand" href="/">ThumbGate</a>
|
|
179
|
+
<div class="nav-links">
|
|
180
|
+
<a href="/guide">Setup Guide</a>
|
|
181
|
+
<a href="/dashboard">Dashboard</a>
|
|
182
|
+
<a href="https://github.com/IgorGanapolsky/ThumbGate" target="_blank" rel="noopener">GitHub</a>
|
|
183
|
+
<a href="https://www.npmjs.com/package/thumbgate" target="_blank" rel="noopener">npm</a>
|
|
184
|
+
</div>
|
|
185
|
+
</nav>
|
|
186
|
+
|
|
187
|
+
<main>
|
|
188
|
+
<section class="hero">
|
|
189
|
+
<div class="wrap">
|
|
190
|
+
<div class="eyebrow">Codex MCP plugin + Pre-Action Gates</div>
|
|
191
|
+
<h1>Give Codex a thumbs-down once. Block the repeat before it runs again.</h1>
|
|
192
|
+
<p class="sub">ThumbGate wires Codex into local-first feedback memory, MCP tools, and hook enforcement. The launcher resolves <code>thumbgate@latest</code> when Codex starts, so published npm fixes reach your active MCP server after a restart.</p>
|
|
193
|
+
<div class="actions">
|
|
194
|
+
<a class="button primary" href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" target="_blank" rel="noopener" onclick="if(typeof plausible==='function')plausible('codex_plugin_download')">Download Codex plugin</a>
|
|
195
|
+
<a class="button secondary" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/plugins/codex-profile/INSTALL.md" target="_blank" rel="noopener">Read install docs</a>
|
|
196
|
+
<a class="button secondary" href="/guide">Use CLI setup</a>
|
|
197
|
+
</div>
|
|
198
|
+
<pre class="terminal">$ npx thumbgate init --agent codex
|
|
199
|
+
# Writes ~/.codex/config.toml and ~/.codex/config.json
|
|
200
|
+
# MCP + hooks install thumbgate@latest before serving or checking gates</pre>
|
|
201
|
+
</div>
|
|
202
|
+
</section>
|
|
203
|
+
|
|
204
|
+
<section class="wrap grid" aria-label="Codex install promises">
|
|
205
|
+
<div class="tile">
|
|
206
|
+
<h3>Always-on when enabled</h3>
|
|
207
|
+
<p>If Codex settings show the <code>thumbgate</code> MCP server toggled on, Codex can call the local ThumbGate tools. Typed feedback still needs useful context before it becomes a durable rule.</p>
|
|
208
|
+
</div>
|
|
209
|
+
<div class="tile">
|
|
210
|
+
<h3>Latest runtime on restart</h3>
|
|
211
|
+
<p>The Codex launcher installs <code>thumbgate@latest</code> into <code>~/.thumbgate/runtime</code> before running MCP or gate checks. A new npm publish reaches Codex after the app restarts.</p>
|
|
212
|
+
</div>
|
|
213
|
+
<div class="tile">
|
|
214
|
+
<h3>Hard stop before action</h3>
|
|
215
|
+
<p>Pre-Action Gates evaluate commands, file edits, publishes, merges, and other high-risk actions before execution. Bad repeats get blocked before they burn time or tokens.</p>
|
|
216
|
+
</div>
|
|
217
|
+
</section>
|
|
218
|
+
|
|
219
|
+
<section class="wrap split">
|
|
220
|
+
<div>
|
|
221
|
+
<div class="eyebrow">What Codex gets</div>
|
|
222
|
+
<h2>MCP memory, hook checks, and a dashboard lane in the same install path.</h2>
|
|
223
|
+
<p>Use the standalone plugin when you want a portable Codex bundle. Use <code>npx thumbgate init --agent codex</code> when you want the shortest path on this machine. Both paths point at the same Reliability Gateway and the same npm runtime.</p>
|
|
224
|
+
<p class="status">The Codex launcher checks npm on startup. Restart Codex after a ThumbGate publish to let the MCP server and hook bundle pick up the latest runtime.</p>
|
|
225
|
+
</div>
|
|
226
|
+
<figure class="proof">
|
|
227
|
+
<img src="/assets/codex-thumbgate-statusbar-test.svg" alt="Codex terminal footer test lane with ThumbGate status and enforcement proof.">
|
|
228
|
+
<figcaption class="caption">Codex test lane after ThumbGate writes MCP, PreToolUse, UserPromptSubmit, PostToolUse, SessionStart, and the status line target.</figcaption>
|
|
229
|
+
</figure>
|
|
230
|
+
</section>
|
|
231
|
+
|
|
232
|
+
<section class="wrap">
|
|
233
|
+
<div class="eyebrow">Install flow</div>
|
|
234
|
+
<h2>Three paths. Same local gateway.</h2>
|
|
235
|
+
<div class="steps">
|
|
236
|
+
<div class="step">
|
|
237
|
+
<h3>1. Automatic setup</h3>
|
|
238
|
+
<p>Run <code>npx thumbgate init --agent codex</code>. ThumbGate writes the MCP server block and hook bundle into your Codex config files.</p>
|
|
239
|
+
</div>
|
|
240
|
+
<div class="step">
|
|
241
|
+
<h3>2. Standalone plugin</h3>
|
|
242
|
+
<p>Use the release bundle when Codex loads plugin surfaces directly. The bundle includes the manifest, MCP config, marketplace entry, and install docs.</p>
|
|
243
|
+
</div>
|
|
244
|
+
<div class="step">
|
|
245
|
+
<h3>3. Verify in Codex</h3>
|
|
246
|
+
<p>Open Codex settings, confirm <code>thumbgate</code> is toggled on, then restart Codex after npm releases to pick up the latest runtime.</p>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
</section>
|
|
250
|
+
|
|
251
|
+
<section class="wrap">
|
|
252
|
+
<div class="eyebrow">Operator questions</div>
|
|
253
|
+
<h2>What happens when I click thumbs up or thumbs down?</h2>
|
|
254
|
+
<div class="faq-list">
|
|
255
|
+
<div class="faq">
|
|
256
|
+
<h3>Is the MCP server always on?</h3>
|
|
257
|
+
<p>It is on when the Codex MCP settings toggle is enabled and the configured command can start successfully. In the Codex app, the blue toggle next to <code>thumbgate</code> is the visible check.</p>
|
|
258
|
+
</div>
|
|
259
|
+
<div class="faq">
|
|
260
|
+
<h3>Does bare feedback become a rule?</h3>
|
|
261
|
+
<p>No. Bare "thumbs down" is intentionally too vague for memory promotion. Add one concrete sentence about what went wrong, the file, command, or behavior to block next time.</p>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="faq">
|
|
264
|
+
<h3>Where is the direct asset?</h3>
|
|
265
|
+
<p>The standalone zip remains available at <a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" target="_blank" rel="noopener">GitHub Releases</a>. This page is the human install surface so users do not land on an unexplained file download.</p>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</section>
|
|
269
|
+
</main>
|
|
270
|
+
|
|
271
|
+
<footer>
|
|
272
|
+
<div class="wrap">
|
|
273
|
+
ThumbGate MIT License. Pre-Action Gates, DPO-ready feedback, and local-first Codex enforcement.
|
|
274
|
+
</div>
|
|
275
|
+
</footer>
|
|
276
|
+
</body>
|
|
277
|
+
</html>
|
package/public/dashboard.html
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
<title>ThumbGate Dashboard — Gate Stats, Approval Rate, Prevention Impact</title>
|
|
7
7
|
<meta name="description" content="Live dashboard showing gate enforcement stats, approval rate trends, prevention impact, and system health for ThumbGate pre-action gates.">
|
|
8
8
|
<link rel="canonical" href="https://thumbgate-production.up.railway.app/dashboard">
|
|
9
|
+
<link rel="icon" type="image/png" href="/thumbgate-icon.png">
|
|
10
|
+
<link rel="apple-touch-icon" href="/assets/brand/thumbgate-mark.svg">
|
|
9
11
|
<meta name="robots" content="noindex">
|
|
10
12
|
<!-- Privacy-friendly analytics by Plausible -->
|
|
11
13
|
<script defer data-domain="thumbgate-production.up.railway.app" src="https://plausible.io/js/script.js"></script>
|
|
@@ -26,7 +28,8 @@
|
|
|
26
28
|
/* NAV */
|
|
27
29
|
nav { position: sticky; top: 0; z-index: 50; background: rgba(10,10,11,0.85); backdrop-filter: blur(12px); border-bottom: 1px solid var(--border); padding: 14px 0; }
|
|
28
30
|
nav .container { display: flex; justify-content: space-between; align-items: center; }
|
|
29
|
-
.nav-logo { font-weight: 700; font-size: 15px; color: var(--text); text-decoration: none; }
|
|
31
|
+
.nav-logo { font-weight: 700; font-size: 15px; color: var(--text); text-decoration: none; display: inline-flex; align-items: center; gap: 8px; }
|
|
32
|
+
.nav-logo .logo-mark { width: 28px; height: 28px; display: block; }
|
|
30
33
|
.nav-links { display: flex; gap: 16px; align-items: center; }
|
|
31
34
|
.nav-links a { color: var(--text-muted); text-decoration: none; font-size: 13px; }
|
|
32
35
|
.nav-links a:hover { color: var(--text); }
|
|
@@ -168,7 +171,7 @@
|
|
|
168
171
|
|
|
169
172
|
<nav>
|
|
170
173
|
<div class="container">
|
|
171
|
-
<a href="/" class="nav-logo"
|
|
174
|
+
<a href="/" class="nav-logo"><img src="/assets/brand/thumbgate-mark-inline.svg" alt="ThumbGate" class="logo-mark" width="28" height="28"><span class="logo-text">ThumbGate Dashboard</span></a>
|
|
172
175
|
<div class="nav-links">
|
|
173
176
|
<a href="/dashboard" class="active" style="color:var(--cyan);">Dashboard</a>
|
|
174
177
|
<a href="/lessons">Lessons</a>
|
|
@@ -219,6 +222,32 @@
|
|
|
219
222
|
<a class="stat-card" data-card-action="gates" onclick="selectCard(this,'gates');return false;" href="#" style="cursor:pointer;text-decoration:none;color:inherit;display:block;" title="Click to view active gates"><div class="stat-label">Active Gates</div><div class="stat-value cyan" id="statGates">—</div></a>
|
|
220
223
|
</div>
|
|
221
224
|
|
|
225
|
+
<div class="panel" id="reviewDeltaPanel" style="margin-bottom:20px;">
|
|
226
|
+
<div style="display:flex;justify-content:space-between;gap:16px;align-items:flex-start;flex-wrap:wrap;">
|
|
227
|
+
<div>
|
|
228
|
+
<h3 style="margin:0 0 8px 0;font-size:14px;letter-spacing:0.04em;text-transform:uppercase;color:var(--text-muted);">🆕 Since Last Review</h3>
|
|
229
|
+
<p class="template-summary" id="reviewDeltaHeadline" style="margin-bottom:0;">No review checkpoint yet. Mark the current dashboard as reviewed to start seeing only new changes.</p>
|
|
230
|
+
</div>
|
|
231
|
+
<button class="btn-outline" id="reviewCheckpointBtn" onclick="markReviewed()">Mark Current Dashboard Reviewed</button>
|
|
232
|
+
</div>
|
|
233
|
+
<div class="generated-grid" id="reviewDeltaStats" style="margin-top:16px;">
|
|
234
|
+
<div class="team-card"><div class="team-kicker">New feedback</div><div class="team-value" id="reviewDeltaFeedback">0</div><div class="team-note">events since checkpoint</div></div>
|
|
235
|
+
<div class="team-card"><div class="team-kicker">New negatives</div><div class="team-value" id="reviewDeltaNegative">0</div><div class="team-note">fresh review risk</div></div>
|
|
236
|
+
<div class="team-card"><div class="team-kicker">New lessons</div><div class="team-value" id="reviewDeltaLessons">0</div><div class="team-note">promoted since checkpoint</div></div>
|
|
237
|
+
<div class="team-card"><div class="team-kicker">New blocks</div><div class="team-value" id="reviewDeltaBlocks">0</div><div class="team-note">gate hits since checkpoint</div></div>
|
|
238
|
+
</div>
|
|
239
|
+
<div class="team-columns" style="margin-top:16px;">
|
|
240
|
+
<div class="panel">
|
|
241
|
+
<h3>Checkpoint</h3>
|
|
242
|
+
<div id="reviewDeltaCheckpoint" class="template-summary" style="margin-bottom:0;">Waiting for dashboard data...</div>
|
|
243
|
+
</div>
|
|
244
|
+
<div class="panel">
|
|
245
|
+
<h3>Newest items</h3>
|
|
246
|
+
<div id="reviewDeltaLatest" class="template-summary" style="margin-bottom:0;">No new review activity yet.</div>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
222
251
|
<!-- TABS -->
|
|
223
252
|
<div class="tabs">
|
|
224
253
|
<div class="tab active" onclick="switchTab('search')">🔍 Search Memories</div>
|
|
@@ -330,6 +359,21 @@
|
|
|
330
359
|
<h2>📊 Feedback Insights & Lesson Pipeline</h2>
|
|
331
360
|
<p class="template-summary">How your thumbs-up/down signals turn into lessons that prevent repeat mistakes.</p>
|
|
332
361
|
|
|
362
|
+
<!-- Token Savings — computed from real gate-block counts -->
|
|
363
|
+
<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);">
|
|
364
|
+
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap;">
|
|
365
|
+
<div style="flex:1;min-width:240px;">
|
|
366
|
+
<h3 style="margin-bottom:6px;">💸 Estimated tokens saved</h3>
|
|
367
|
+
<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>
|
|
368
|
+
</div>
|
|
369
|
+
<div style="text-align:right;min-width:220px;">
|
|
370
|
+
<div id="tokenSavingsDollars" style="font-size:40px;font-weight:800;color:#4ade80;letter-spacing:-0.02em;line-height:1;">—</div>
|
|
371
|
+
<div id="tokenSavingsTokens" style="font-size:13px;color:var(--text-muted);margin-top:6px;">— tokens · from <span id="tokenSavingsBlocks">—</span> blocked calls</div>
|
|
372
|
+
</div>
|
|
373
|
+
</div>
|
|
374
|
+
<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>
|
|
375
|
+
</div>
|
|
376
|
+
|
|
333
377
|
<!-- Pipeline Flow -->
|
|
334
378
|
<div class="panel" style="margin-bottom:24px;">
|
|
335
379
|
<h3 style="margin-bottom:16px;">Feedback → Lesson Pipeline</h3>
|
|
@@ -691,8 +735,70 @@ async function loadDashboardData() {
|
|
|
691
735
|
} catch (e) { /* insights degrade gracefully */ }
|
|
692
736
|
}
|
|
693
737
|
|
|
738
|
+
function formatReviewTimestamp(value) {
|
|
739
|
+
if (!value) return 'Not reviewed yet';
|
|
740
|
+
var date = new Date(value);
|
|
741
|
+
if (Number.isNaN(date.getTime())) return String(value);
|
|
742
|
+
return date.toLocaleString();
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function renderReviewDelta(reviewDelta) {
|
|
746
|
+
var summary = reviewDelta || {};
|
|
747
|
+
var button = document.getElementById('reviewCheckpointBtn');
|
|
748
|
+
document.getElementById('reviewDeltaHeadline').textContent = summary.headline || 'No review checkpoint yet. Mark the current dashboard as reviewed to start seeing only new changes.';
|
|
749
|
+
document.getElementById('reviewDeltaFeedback').textContent = String(summary.feedbackAdded || 0);
|
|
750
|
+
document.getElementById('reviewDeltaNegative').textContent = String(summary.negativeAdded || 0);
|
|
751
|
+
document.getElementById('reviewDeltaLessons').textContent = String(summary.lessonsAdded || 0);
|
|
752
|
+
document.getElementById('reviewDeltaBlocks').textContent = String(summary.blocksAdded || 0);
|
|
753
|
+
|
|
754
|
+
var checkpointParts = [];
|
|
755
|
+
checkpointParts.push('<div><strong>Reviewed:</strong> ' + escHtml(formatReviewTimestamp(summary.reviewedAt)) + '</div>');
|
|
756
|
+
if (summary.previousHead || summary.currentHead) {
|
|
757
|
+
checkpointParts.push('<div style="margin-top:8px;"><strong>Git:</strong> ' + escHtml(summary.previousHead ? summary.previousHead.slice(0, 8) : 'none') + ' → ' + escHtml(summary.currentHead ? summary.currentHead.slice(0, 8) : 'none') + '</div>');
|
|
758
|
+
}
|
|
759
|
+
document.getElementById('reviewDeltaCheckpoint').innerHTML = checkpointParts.join('');
|
|
760
|
+
|
|
761
|
+
var latestBits = [];
|
|
762
|
+
if (summary.latestFeedback) {
|
|
763
|
+
latestBits.push('<div><strong>Feedback:</strong> ' + escHtml(summary.latestFeedback.title || 'Feedback event') + ' <span style="color:var(--text-muted);">(' + escHtml(formatReviewTimestamp(summary.latestFeedback.timestamp)) + ')</span></div>');
|
|
764
|
+
}
|
|
765
|
+
if (summary.latestLesson) {
|
|
766
|
+
latestBits.push('<div style="margin-top:8px;"><strong>Lesson:</strong> ' + escHtml(summary.latestLesson.title || 'Lesson event') + ' <span style="color:var(--text-muted);">(' + escHtml(formatReviewTimestamp(summary.latestLesson.timestamp)) + ')</span></div>');
|
|
767
|
+
}
|
|
768
|
+
document.getElementById('reviewDeltaLatest').innerHTML = latestBits.length
|
|
769
|
+
? latestBits.join('')
|
|
770
|
+
: 'No new review activity yet.';
|
|
771
|
+
|
|
772
|
+
if (button) {
|
|
773
|
+
button.textContent = summary.hasBaseline ? 'Reset Review Baseline to Current State' : 'Mark Current Dashboard Reviewed';
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
async function markReviewed() {
|
|
778
|
+
var button = document.getElementById('reviewCheckpointBtn');
|
|
779
|
+
var previousLabel = button.textContent;
|
|
780
|
+
button.disabled = true;
|
|
781
|
+
button.textContent = 'Saving...';
|
|
782
|
+
try {
|
|
783
|
+
var res = await fetch('/v1/dashboard/review-state', {
|
|
784
|
+
method: 'POST',
|
|
785
|
+
headers: getHeaders()
|
|
786
|
+
});
|
|
787
|
+
if (!res.ok) throw new Error('Failed to save review checkpoint');
|
|
788
|
+
var body = await res.json();
|
|
789
|
+
renderReviewDelta(body.reviewDelta || {});
|
|
790
|
+
} catch (e) {
|
|
791
|
+
document.getElementById('reviewDeltaHeadline').textContent = e && e.message ? e.message : 'Failed to save review checkpoint';
|
|
792
|
+
} finally {
|
|
793
|
+
button.disabled = false;
|
|
794
|
+
if (button.textContent === 'Saving...') button.textContent = previousLabel;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
694
798
|
function renderDashboardData(data) {
|
|
695
799
|
dashboardSnapshot = data;
|
|
800
|
+
var reviewButton = document.getElementById('reviewCheckpointBtn');
|
|
801
|
+
if (reviewButton) reviewButton.disabled = false;
|
|
696
802
|
const gates = data.gates || data.activeGates || [];
|
|
697
803
|
const gateStats = data.gateStats || {};
|
|
698
804
|
document.getElementById('statGates').textContent = gates.length || gateStats.totalGates || 0;
|
|
@@ -708,6 +814,7 @@ function renderDashboardData(data) {
|
|
|
708
814
|
}
|
|
709
815
|
|
|
710
816
|
renderTeam(data.team || {}, data.analytics || {});
|
|
817
|
+
renderReviewDelta(data.reviewDelta || {});
|
|
711
818
|
renderPredictive(data.predictive || {});
|
|
712
819
|
renderSettingsStatus(data.settingsStatus || {});
|
|
713
820
|
renderTemplates(data.templateLibrary || {});
|
|
@@ -1043,6 +1150,44 @@ function loadDemo() {
|
|
|
1043
1150
|
document.getElementById('statNegative').textContent = '260';
|
|
1044
1151
|
document.getElementById('statGates').textContent = '21';
|
|
1045
1152
|
setSelectedCard('all');
|
|
1153
|
+
// Demo: 260 negative-feedback events have produced ~180 actual gate blocks
|
|
1154
|
+
// and ~85 bot deflections on /checkout/pro. Kept as illustrative defaults
|
|
1155
|
+
// so the savings card never reads "0" in demo mode.
|
|
1156
|
+
var demoSavings = TG_TOKEN_SAVINGS.compute(180, 85);
|
|
1157
|
+
var tEl = document.getElementById('statTokensSaved');
|
|
1158
|
+
var dEl = document.getElementById('statDollarsSaved');
|
|
1159
|
+
if (tEl) tEl.textContent = demoSavings.tokensSavedDisplay;
|
|
1160
|
+
if (dEl) dEl.textContent = '≈ ' + demoSavings.dollarsSavedDisplay + ' saved';
|
|
1161
|
+
renderTopBlockedGates([
|
|
1162
|
+
{ name: 'gate:no-force-push', blocked: 47 },
|
|
1163
|
+
{ name: 'gate:no-drop-prod', blocked: 31 },
|
|
1164
|
+
{ name: 'gate:no-hallucinated-import', blocked: 28 },
|
|
1165
|
+
{ name: 'gate:no-secret-commit', blocked: 19 },
|
|
1166
|
+
{ name: 'gate:require-tests-before-done', blocked: 14 },
|
|
1167
|
+
{ name: 'gate:no-figma-claim-without-check', blocked: 9 },
|
|
1168
|
+
]);
|
|
1169
|
+
renderReviewDelta({
|
|
1170
|
+
hasBaseline: true,
|
|
1171
|
+
reviewedAt: '2025-06-18T09:00:00Z',
|
|
1172
|
+
previousHead: '9f1a2c3d',
|
|
1173
|
+
currentHead: '5c7e9b1a',
|
|
1174
|
+
feedbackAdded: 6,
|
|
1175
|
+
negativeAdded: 4,
|
|
1176
|
+
lessonsAdded: 2,
|
|
1177
|
+
blocksAdded: 5,
|
|
1178
|
+
warnsAdded: 1,
|
|
1179
|
+
headline: 'Since your last review: 6 feedback events · 4 negative · 2 lessons · 5 gate blocks.',
|
|
1180
|
+
latestFeedback: {
|
|
1181
|
+
title: 'Claimed fix worked without running tests',
|
|
1182
|
+
timestamp: '2025-06-22T10:20:00Z'
|
|
1183
|
+
},
|
|
1184
|
+
latestLesson: {
|
|
1185
|
+
title: 'MISTAKE: Claimed Figma compliance without visual verification',
|
|
1186
|
+
timestamp: '2025-06-21T08:10:00Z'
|
|
1187
|
+
}
|
|
1188
|
+
});
|
|
1189
|
+
document.getElementById('reviewCheckpointBtn').disabled = true;
|
|
1190
|
+
document.getElementById('reviewCheckpointBtn').textContent = 'Connect to save your own review checkpoint';
|
|
1046
1191
|
// Sample memories — realistic scenarios from real agent-driven development
|
|
1047
1192
|
var demoResults = [
|
|
1048
1193
|
{ signal: 'down', title: 'Claimed fix worked without running tests', context: 'Agent announced "fixed and pushed" but never ran the test suite. CI failed on 3 tests. Gate now requires test evidence before any completion claim.', tags: ['anti-lying', 'verification-gap', 'ci', 'trust-breach'], timestamp: '2025-06-22T10:20:00Z' },
|
|
@@ -1064,19 +1209,17 @@ function loadDemo() {
|
|
|
1064
1209
|
{ signal: 'up', title: 'DPO export caught systematic failure pattern', context: 'Exported 47 preference pairs revealing that 80% of negative feedback involved claiming work was done without verification. Led to a new mandatory evidence gate.', tags: ['dpo-export', 'evidence-based', 'prevention', 'metric:ROI'], timestamp: '2025-06-05T10:15:00Z' }
|
|
1065
1210
|
];
|
|
1066
1211
|
isDemo = true;
|
|
1067
|
-
demoData = demoResults
|
|
1212
|
+
demoData = demoResults;
|
|
1068
1213
|
var teaserHtml = demoData.map(renderResult).join('');
|
|
1069
|
-
var
|
|
1070
|
-
'<div style="
|
|
1071
|
-
'<
|
|
1072
|
-
'<
|
|
1073
|
-
'
|
|
1074
|
-
'<div style="color:#aaa;margin-bottom:16px;">Pro shows your real feedback, gates, and lessons — not sample data.</div>' +
|
|
1214
|
+
var upgradeBanner = '<div style="margin-bottom:12px;padding:12px 16px;background:linear-gradient(90deg,rgba(184,92,45,0.14),rgba(184,92,45,0.06));border:1px solid rgba(184,92,45,0.35);border-radius:10px;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;">' +
|
|
1215
|
+
'<div style="color:#ddd;font-size:14px;">' +
|
|
1216
|
+
'<span style="color:#ffb98a;font-weight:700;">Live demo data below.</span> ' +
|
|
1217
|
+
'Point ThumbGate at your own feedback to see <em>your</em> gates, lessons, and team signals — no signup required.' +
|
|
1218
|
+
'</div>' +
|
|
1075
1219
|
'<a href="https://buy.stripe.com/7sYcN5bmIf5IcSd8qf3sI0a" target="_blank" rel="noopener" ' +
|
|
1076
|
-
'style="
|
|
1077
|
-
'
|
|
1078
|
-
|
|
1079
|
-
document.getElementById('searchResults').innerHTML = teaserHtml + upgradeWall;
|
|
1220
|
+
'style="flex:none;background:#b85c2d;color:#fff;padding:8px 18px;border-radius:8px;text-decoration:none;font-weight:700;font-size:13px;white-space:nowrap;">Go Pro — $19/mo</a>' +
|
|
1221
|
+
'</div>';
|
|
1222
|
+
document.getElementById('searchResults').innerHTML = upgradeBanner + teaserHtml;
|
|
1080
1223
|
// Sample gates
|
|
1081
1224
|
var demoGates = [
|
|
1082
1225
|
{ name: 'no-force-push', pattern: 'Block git push --force to main or master branches', action: 'block' },
|
|
@@ -1220,12 +1363,49 @@ var lessonChart = null;
|
|
|
1220
1363
|
var gateAuditChart = null;
|
|
1221
1364
|
|
|
1222
1365
|
function renderInsights(data) {
|
|
1366
|
+
renderTokenSavings(data.tokenSavings, data.gateStats || {});
|
|
1223
1367
|
renderPipeline(data.lessonPipeline || {});
|
|
1224
1368
|
renderFeedbackTrendChart(data.feedbackTimeSeries || {});
|
|
1225
1369
|
renderLessonTrendChart(data.feedbackTimeSeries || {});
|
|
1226
1370
|
renderGateAuditChartFromData(data.gateAudit || {});
|
|
1227
1371
|
}
|
|
1228
1372
|
|
|
1373
|
+
/**
|
|
1374
|
+
* Render token-savings panel from /v1/dashboard.tokenSavings.
|
|
1375
|
+
* Only shows a dollar figure when it's backed by real gate blocks.
|
|
1376
|
+
* Otherwise shows an honest "$0.00 — no blocks yet" state, NEVER
|
|
1377
|
+
* a marketing placeholder.
|
|
1378
|
+
*/
|
|
1379
|
+
function renderTokenSavings(savings, gateStats) {
|
|
1380
|
+
var panel = document.getElementById('tokenSavingsPanel');
|
|
1381
|
+
if (!panel) return;
|
|
1382
|
+
var dollarsEl = document.getElementById('tokenSavingsDollars');
|
|
1383
|
+
var tokensEl = document.getElementById('tokenSavingsTokens');
|
|
1384
|
+
var blocksEl = document.getElementById('tokenSavingsBlocks');
|
|
1385
|
+
var sourceEl = document.getElementById('tokenSavingsSource');
|
|
1386
|
+
|
|
1387
|
+
if (!savings || typeof savings.dollarsSaved !== 'number') {
|
|
1388
|
+
dollarsEl.textContent = '$0.00';
|
|
1389
|
+
tokensEl.innerHTML = 'No blocked calls yet — estimate will appear after your first gate fires';
|
|
1390
|
+
if (blocksEl) blocksEl.textContent = '0';
|
|
1391
|
+
sourceEl.textContent = '';
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
dollarsEl.textContent = savings.dollarsSavedDisplay || ('$' + Number(savings.dollarsSaved).toFixed(2));
|
|
1396
|
+
tokensEl.innerHTML = (savings.tokensSavedDisplay || '0') + ' tokens · from <span id="tokenSavingsBlocks">' +
|
|
1397
|
+
(savings.blockedCalls || 0) + '</span> blocked calls';
|
|
1398
|
+
|
|
1399
|
+
var mix = savings.modelMix || {};
|
|
1400
|
+
var mixParts = [];
|
|
1401
|
+
for (var m in mix) { mixParts.push(Math.round(mix[m] * 100) + '% ' + m); }
|
|
1402
|
+
var blend = savings.blendedPricePer1M || { input: 0, output: 0 };
|
|
1403
|
+
sourceEl.textContent =
|
|
1404
|
+
'Methodology: blended ' + mixParts.join(' / ') +
|
|
1405
|
+
' at $' + blend.input.toFixed(2) + '/1M input + $' + blend.output.toFixed(2) + '/1M output. ' +
|
|
1406
|
+
'Data source: actual blocked count from gate-stats.json. No sample numbers.';
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1229
1409
|
function renderPipeline(pipeline) {
|
|
1230
1410
|
var stages = pipeline.stages || [];
|
|
1231
1411
|
var rates = pipeline.rates || {};
|