thumbgate 1.27.17 → 1.27.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +85 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +33 -5
- package/adapters/chatgpt/openapi.yaml +1707 -0
- 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/bin/cli.js +63 -54
- package/bin/postinstall.js +23 -14
- package/config/post-deploy-marketing-pages.json +19 -0
- package/config/tessl-tiles.json +1 -3
- package/package.json +99 -229
- package/public/guide.html +0 -4
- package/public/index.html +28 -49
- package/public/learn.html +0 -8
- package/public/numbers.html +2 -2
- package/scripts/agent-readiness.js +0 -147
- package/scripts/bot-detection.js +61 -3
- package/scripts/cli-feedback.js +4 -14
- package/scripts/cli-schema.js +7 -0
- package/scripts/durability/step.js +3 -3
- package/scripts/feedback-loop.js +10 -32
- package/scripts/gates-engine.js +72 -1
- package/scripts/hook-runtime.js +2 -2
- package/scripts/license.js +10 -9
- package/scripts/llm-client.js +44 -260
- package/scripts/mcp-config.js +7 -1
- package/scripts/published-cli.js +0 -8
- package/scripts/seo-gsd.js +0 -5
- package/src/api/server.js +111 -35
- package/.claude/commands/dashboard.md +0 -15
- package/.claude/commands/thumbgate-blocked.md +0 -27
- package/.claude/commands/thumbgate-dashboard.md +0 -15
- package/.claude/commands/thumbgate-doctor.md +0 -30
- package/.claude/commands/thumbgate-guard.md +0 -36
- package/.claude/commands/thumbgate-protect.md +0 -30
- package/.claude/commands/thumbgate-rules.md +0 -30
- package/adapters/gcp/dfcx-webhook-gate.js +0 -295
- package/adapters/letta/README.md +0 -41
- package/adapters/letta/thumbgate-letta-adapter.js +0 -133
- package/adapters/policy-engine/ethicore-guardian-client.js +0 -68
- package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +0 -260
- package/bench/observability-eval-suite.json +0 -26
- package/bin/dashboard-cli.js +0 -7
- package/commands/dashboard.md +0 -15
- package/commands/thumbgate-dashboard.md +0 -15
- package/config/builtin-lessons.json +0 -23
- package/public/about.html +0 -162
- package/public/agent-manager.html +0 -179
- package/public/agents-cost-savings.html +0 -153
- package/public/ai-malpractice-prevention.html +0 -818
- package/public/assets/brand/github-social-preview.png +0 -0
- package/public/assets/brand/thumbgate-icon-512.png +0 -0
- package/public/assets/brand/thumbgate-icon-pro-512.png +0 -0
- package/public/assets/brand/thumbgate-icon-team-512.png +0 -0
- package/public/assets/brand/thumbgate-logo-1200x360.png +0 -0
- package/public/assets/brand/thumbgate-logo-transparent.svg +0 -22
- package/public/assets/brand/thumbgate-mark-inline-v3.svg +0 -19
- package/public/assets/brand/thumbgate-mark-pro.svg +0 -23
- package/public/assets/brand/thumbgate-mark-team.svg +0 -26
- package/public/assets/brand/thumbgate-mark.svg +0 -21
- package/public/assets/brand/thumbgate-wordmark.svg +0 -20
- package/public/assets/claude-thumbgate-statusbar.svg +0 -8
- package/public/assets/codex-thumbgate-statusbar-test.svg +0 -9
- package/public/assets/legal-intake-control-flow.svg +0 -66
- package/public/brand/thumbgate-mark.svg +0 -19
- package/public/brand/thumbgate-og.svg +0 -16
- package/public/chatgpt-app.html +0 -330
- package/public/codex-enterprise.html +0 -123
- package/public/js/buyer-intent.js +0 -672
- package/public/pricing.html +0 -399
- package/scripts/action-receipts.js +0 -324
- package/scripts/activation-quickstart.js +0 -187
- package/scripts/agent-operations-planner.js +0 -621
- package/scripts/ai-component-inventory.js +0 -367
- package/scripts/async-eval-observability.js +0 -236
- package/scripts/audit.js +0 -65
- package/scripts/aws-blocks-guardrails.js +0 -228
- package/scripts/bot-detector.js +0 -50
- package/scripts/classifier-routing.js +0 -130
- package/scripts/dashboard-chat.js +0 -332
- package/scripts/feedback-aggregate.js +0 -281
- package/scripts/feedback-sanitizer.js +0 -105
- package/scripts/hob-pack.js +0 -591
- package/scripts/hook-stop-anti-claim.js +0 -301
- package/scripts/install-shim.js +0 -87
- package/scripts/mcp-oauth.js +0 -293
- package/scripts/noop-detect.js +0 -285
- package/scripts/omlx-smoke.js +0 -192
- package/scripts/parallel-workflow-orchestrator.js +0 -293
- package/scripts/plan-gate.js +0 -243
- package/scripts/plausible-domain-config.js +0 -99
- package/scripts/qa-scenario-planner.js +0 -136
- package/scripts/repeat-metric.js +0 -137
- package/scripts/secret-fixture-tokens.js +0 -61
- package/scripts/secret-redaction.js +0 -166
- package/scripts/self-harness-optimizer.js +0 -141
- package/scripts/self-healing-check.js +0 -193
- package/scripts/silent-failure-cluster.js +0 -531
- package/scripts/statusline-cache-read.js +0 -57
- package/scripts/sync-telemetry-from-prod.js +0 -374
- package/scripts/tool-contract-validator.js +0 -76
- package/scripts/trajectory-scorer.js +0 -63
- package/scripts/verify-marketing-pages-deployed.js +0 -195
- package/scripts/visitor-journey.js +0 -172
package/src/api/server.js
CHANGED
|
@@ -20,7 +20,7 @@ const POSTHOG_STATIC_PATH_PREFIX = '/static/';
|
|
|
20
20
|
// Stripe catalog, with the per-tier thumbnails wired in. Re-run the
|
|
21
21
|
// bootstrap workflow to regenerate; the new URLs surface in the workflow
|
|
22
22
|
// summary log.
|
|
23
|
-
const FIRST_FAILURE_RULE_CHECKOUT_URL = 'https://buy.stripe.com/
|
|
23
|
+
const FIRST_FAILURE_RULE_CHECKOUT_URL = 'https://buy.stripe.com/7sY6oHaiEbTw6tP5e33sI3e';
|
|
24
24
|
const QUICK_READ_CHECKOUT_URL = 'https://buy.stripe.com/5kQ7sL76s1eSaK55e33sI2H';
|
|
25
25
|
const WORKFLOW_TEARDOWN_CHECKOUT_URL = 'https://buy.stripe.com/8x214n2Qc4r44lHayn3sI2I';
|
|
26
26
|
const SPRINT_DIAGNOSTIC_CHECKOUT_URL = 'https://buy.stripe.com/28E00j3Uge1E2dzgWL3sI2J';
|
|
@@ -241,6 +241,8 @@ const NUMBERS_PAGE_PATH = path.resolve(__dirname, '../../public/numbers.html');
|
|
|
241
241
|
const FEDERAL_PAGE_PATH = path.resolve(__dirname, '../../public/federal.html');
|
|
242
242
|
const PRICING_PAGE_PATH = path.resolve(__dirname, '../../public/pricing.html');
|
|
243
243
|
const ABOUT_PAGE_PATH = path.resolve(__dirname, '../../public/about.html');
|
|
244
|
+
const DIAGNOSTIC_PAGE_PATH = path.resolve(__dirname, '../../public/diagnostic.html');
|
|
245
|
+
const INSTALL_PAGE_PATH = path.resolve(__dirname, '../../public/install.html');
|
|
244
246
|
const LEARN_DIR = path.resolve(__dirname, '../../public/learn');
|
|
245
247
|
const GUIDES_DIR = path.resolve(__dirname, '../../public/guides');
|
|
246
248
|
const COMPARE_DIR = path.resolve(__dirname, '../../public/compare');
|
|
@@ -2220,7 +2222,7 @@ function renderCheckoutIntentPage(prefilledEmail = '', parsed = null, options =
|
|
|
2220
2222
|
body{background:#0a0a0a;color:#eee;font-family:system-ui,-apple-system,sans-serif;line-height:1.5}
|
|
2221
2223
|
main{max-width:520px;margin:8vh auto;padding:0 20px}
|
|
2222
2224
|
.brand{display:flex;align-items:center;gap:10px;margin-bottom:24px;font-size:14px;color:#94a3b8}
|
|
2223
|
-
.brand-mark{width:
|
|
2225
|
+
.brand-mark{width:24px;height:24px;background:#22d3ee;border-radius:6px;display:inline-block}
|
|
2224
2226
|
h1{font-size:24px;margin:0 0 8px;color:#fff}.price{font-size:32px;font-weight:700;color:#22d3ee;margin:8px 0 4px}.price small{font-size:14px;color:#94a3b8;font-weight:400}
|
|
2225
2227
|
p{color:#cbd5e1;margin:8px 0}form{margin:0}
|
|
2226
2228
|
input[type=email]{width:100%;box-sizing:border-box;padding:14px 16px;border:1px solid #374151;border-radius:8px;background:#111827;color:#fff;font-size:15px;margin:16px 0 0;outline:none}
|
|
@@ -2239,14 +2241,13 @@ a{display:block;text-decoration:none}a.secondary{border:1px solid #374151;color:
|
|
|
2239
2241
|
</head>
|
|
2240
2242
|
<body>
|
|
2241
2243
|
<main>
|
|
2242
|
-
<div class="brand"><
|
|
2244
|
+
<div class="brand"><span class="brand-mark"></span><span>ThumbGate</span></div>
|
|
2243
2245
|
<h1>Start ThumbGate Pro</h1>
|
|
2244
2246
|
<div class="price">$19<small>/mo</small></div>
|
|
2245
2247
|
<p>The npm package runs your gates locally. <strong>Pro</strong> is what keeps them working across every machine, every agent runtime, and every breaking-change week.</p>
|
|
2246
|
-
<form action="/
|
|
2248
|
+
<form action="https://buy.stripe.com/8x2dR91M84r4cSd9uj3sI3f" method="GET" data-i="pro_checkout_confirmed">
|
|
2247
2249
|
${hiddenInputs}
|
|
2248
|
-
<input type="
|
|
2249
|
-
<input type="email" name="customer_email" value="${escapeHtmlAttribute(prefilledEmail)}" placeholder="you@company.com" autocomplete="email">
|
|
2250
|
+
<input type="email" name="prefilled_email" value="${escapeHtmlAttribute(prefilledEmail)}" placeholder="you@company.com" autocomplete="email">
|
|
2250
2251
|
<p class="email-note">Optional. Stripe can collect your email on the secure checkout page.</p>
|
|
2251
2252
|
<button type="submit" class="primary">Pay $19/mo with Stripe →</button>
|
|
2252
2253
|
</form>
|
|
@@ -2862,8 +2863,8 @@ function loadPublicMarketingTemplateHtml(templatePath, runtimeConfig, pageContex
|
|
|
2862
2863
|
'__SERVER_ACQUISITION_ID__': pageContext.serverAcquisitionId || '',
|
|
2863
2864
|
'__SERVER_TELEMETRY_CAPTURED__': pageContext.serverTelemetryCaptured ? 'true' : 'false',
|
|
2864
2865
|
'__VERIFICATION_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/docs/VERIFICATION_EVIDENCE.md',
|
|
2865
|
-
'__COMPATIBILITY_REPORT_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/
|
|
2866
|
-
'__AUTOMATION_REPORT_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/
|
|
2866
|
+
'__COMPATIBILITY_REPORT_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/docs/VERIFICATION_EVIDENCE.md',
|
|
2867
|
+
'__AUTOMATION_REPORT_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/docs/VERIFICATION_EVIDENCE.md',
|
|
2867
2868
|
'__GTM_PLAN_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/docs/GO_TO_MARKET_REVENUE_WEDGE_2026-03.md',
|
|
2868
2869
|
'__GITHUB_URL__': 'https://github.com/IgorGanapolsky/ThumbGate',
|
|
2869
2870
|
'__POSTHOG_API_KEY__': runtimeConfig.posthogApiKey || '',
|
|
@@ -2878,6 +2879,14 @@ function loadProPageHtml(runtimeConfig, pageContext = {}) {
|
|
|
2878
2879
|
return loadPublicMarketingTemplateHtml(PRO_PAGE_PATH, runtimeConfig, pageContext);
|
|
2879
2880
|
}
|
|
2880
2881
|
|
|
2882
|
+
function loadDiagnosticPageHtml(runtimeConfig, pageContext = {}) {
|
|
2883
|
+
return loadPublicMarketingTemplateHtml(DIAGNOSTIC_PAGE_PATH, runtimeConfig, pageContext);
|
|
2884
|
+
}
|
|
2885
|
+
|
|
2886
|
+
function loadInstallPageHtml(runtimeConfig, pageContext = {}) {
|
|
2887
|
+
return loadPublicMarketingTemplateHtml(INSTALL_PAGE_PATH, runtimeConfig, pageContext);
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2881
2890
|
function loadPricingPageHtml(runtimeConfig, pageContext = {}) {
|
|
2882
2891
|
return loadPublicMarketingTemplateHtml(PRICING_PAGE_PATH, runtimeConfig, pageContext);
|
|
2883
2892
|
}
|
|
@@ -3511,6 +3520,9 @@ function renderSitemapXml(runtimeConfig) {
|
|
|
3511
3520
|
const entries = [
|
|
3512
3521
|
{ path: '/', changefreq: 'weekly', priority: '1.0' },
|
|
3513
3522
|
{ path: '/pro', changefreq: 'weekly', priority: '0.9' },
|
|
3523
|
+
{ path: '/diagnostic', changefreq: 'weekly', priority: '0.9' },
|
|
3524
|
+
{ path: '/workflow-hardening-sprint', changefreq: 'weekly', priority: '0.9' },
|
|
3525
|
+
{ path: '/install', changefreq: 'weekly', priority: '0.9' },
|
|
3514
3526
|
{ path: '/agent-manager', changefreq: 'weekly', priority: '0.9' },
|
|
3515
3527
|
{ path: '/llm-context.md', changefreq: 'weekly', priority: '0.8' },
|
|
3516
3528
|
{ path: '/chatgpt-app', changefreq: 'weekly', priority: '0.85' },
|
|
@@ -5209,7 +5221,7 @@ function createApiServer() {
|
|
|
5209
5221
|
if (req.method === 'POST' && pathname === '/api/event') {
|
|
5210
5222
|
// Filter bots from analytics to keep Plausible data clean
|
|
5211
5223
|
let _botDetector;
|
|
5212
|
-
try { _botDetector = require('../../scripts/bot-
|
|
5224
|
+
try { _botDetector = require('../../scripts/bot-detection'); } catch (_e) { _botDetector = null; }
|
|
5213
5225
|
if (_botDetector && _botDetector.shouldExcludeFromAnalytics(req)) {
|
|
5214
5226
|
sendJson(res, 202, { status: 'filtered', reason: 'bot' });
|
|
5215
5227
|
return;
|
|
@@ -5614,6 +5626,32 @@ async function addContext(){
|
|
|
5614
5626
|
return;
|
|
5615
5627
|
}
|
|
5616
5628
|
|
|
5629
|
+
if (isGetLikeRequest && (
|
|
5630
|
+
pathname === '/install'
|
|
5631
|
+
|| pathname === '/install.html'
|
|
5632
|
+
|| pathname === '/marketplace'
|
|
5633
|
+
|| pathname === '/marketplace.html'
|
|
5634
|
+
|| pathname === '/marketplaces'
|
|
5635
|
+
|| pathname === '/marketplaces.html'
|
|
5636
|
+
)) {
|
|
5637
|
+
try {
|
|
5638
|
+
servePublicMarketingPage({
|
|
5639
|
+
req,
|
|
5640
|
+
res,
|
|
5641
|
+
parsed,
|
|
5642
|
+
hostedConfig,
|
|
5643
|
+
isHeadRequest,
|
|
5644
|
+
renderHtml: loadInstallPageHtml,
|
|
5645
|
+
extraTelemetry: {
|
|
5646
|
+
pageType: 'install',
|
|
5647
|
+
},
|
|
5648
|
+
});
|
|
5649
|
+
} catch (err) {
|
|
5650
|
+
sendText(res, 500, err.message || 'Install page unavailable');
|
|
5651
|
+
}
|
|
5652
|
+
return;
|
|
5653
|
+
}
|
|
5654
|
+
|
|
5617
5655
|
if (isGetLikeRequest && (pathname === '/codex-plugin' || pathname === '/codex-plugin.html')) {
|
|
5618
5656
|
try {
|
|
5619
5657
|
const html = fs.readFileSync(CODEX_PLUGIN_PAGE_PATH, 'utf-8');
|
|
@@ -5704,13 +5742,16 @@ async function addContext(){
|
|
|
5704
5742
|
return;
|
|
5705
5743
|
}
|
|
5706
5744
|
|
|
5707
|
-
// Natural marketing URLs for the Workflow Hardening Sprint.
|
|
5708
|
-
//
|
|
5709
|
-
//
|
|
5710
|
-
//
|
|
5711
|
-
// Redirect them to the canonical intake anchor instead.
|
|
5745
|
+
// Natural marketing URLs for the Workflow Hardening Diagnostic/Sprint.
|
|
5746
|
+
// High-intent outreach refers to "the diagnostic", "the sprint", or
|
|
5747
|
+
// "workflow hardening"; serve a focused buyer page instead of sending
|
|
5748
|
+
// qualified traffic to the generic homepage anchor.
|
|
5712
5749
|
if (isGetLikeRequest && (
|
|
5713
|
-
pathname === '/
|
|
5750
|
+
pathname === '/diagnostic'
|
|
5751
|
+
|| pathname === '/diagnostic.html'
|
|
5752
|
+
|| pathname === '/workflow-diagnostic'
|
|
5753
|
+
|| pathname === '/workflow-diagnostic.html'
|
|
5754
|
+
|| pathname === '/sprint'
|
|
5714
5755
|
|| pathname === '/sprint.html'
|
|
5715
5756
|
|| pathname === '/workflow-hardening'
|
|
5716
5757
|
|| pathname === '/workflow-hardening.html'
|
|
@@ -5719,18 +5760,28 @@ async function addContext(){
|
|
|
5719
5760
|
|| pathname === '/workflow-sprint'
|
|
5720
5761
|
|| pathname === '/workflow-sprint.html'
|
|
5721
5762
|
)) {
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5763
|
+
try {
|
|
5764
|
+
servePublicMarketingPage({
|
|
5765
|
+
req,
|
|
5766
|
+
res,
|
|
5767
|
+
parsed,
|
|
5768
|
+
hostedConfig,
|
|
5769
|
+
isHeadRequest,
|
|
5770
|
+
renderHtml: loadDiagnosticPageHtml,
|
|
5771
|
+
extraTelemetry: {
|
|
5772
|
+
pageType: 'diagnostic',
|
|
5773
|
+
},
|
|
5774
|
+
});
|
|
5775
|
+
} catch (err) {
|
|
5776
|
+
sendText(res, 500, err.message || 'Diagnostic page unavailable');
|
|
5777
|
+
}
|
|
5727
5778
|
return;
|
|
5728
5779
|
}
|
|
5729
5780
|
|
|
5730
5781
|
if (isGetLikeRequest && (pathname === '/numbers' || pathname === '/numbers.html')) {
|
|
5731
5782
|
// Route through servePublicMarketingPage so landing_page_view telemetry
|
|
5732
5783
|
// + funnel-events.jsonl `discovery/landing_view` get captured with UTM
|
|
5733
|
-
// attribution — critical for
|
|
5784
|
+
// attribution — critical for Zernio social CTAs that target /numbers.
|
|
5734
5785
|
try {
|
|
5735
5786
|
servePublicMarketingPage({
|
|
5736
5787
|
req,
|
|
@@ -6021,16 +6072,20 @@ async function addContext(){
|
|
|
6021
6072
|
// (form submission JS-less bots don't do), (b) a `customer_email`
|
|
6022
6073
|
// query param treats the request as confirmed even from a bot UA,
|
|
6023
6074
|
// because no real crawler appends customer_email to discovered URLs.
|
|
6075
|
+
const rawCheckoutEmail = normalizeNullableText(bootstrapBody.customerEmail);
|
|
6076
|
+
const normalizedCheckoutEmail = normalizeCheckoutCustomerEmail(rawCheckoutEmail);
|
|
6024
6077
|
const hasCustomerEmailHint = !!parsed?.searchParams?.has('customer_email');
|
|
6025
|
-
const
|
|
6026
|
-
|
|
6027
|
-
//
|
|
6028
|
-
//
|
|
6029
|
-
//
|
|
6030
|
-
//
|
|
6031
|
-
//
|
|
6032
|
-
const isConfirmedCheckout = (
|
|
6033
|
-
|
|
6078
|
+
const hasValidCustomerEmailHint = !!normalizedCheckoutEmail;
|
|
6079
|
+
const botShouldBypass = !botClassification.isBot || hasValidCustomerEmailHint;
|
|
6080
|
+
// 2026-06-29 conversion audit: requiring email before Stripe gave us a
|
|
6081
|
+
// recoverable abandoned-session theory, but the hosted funnel showed
|
|
6082
|
+
// traffic with 0 checkout starts. Let confirmed human clicks reach
|
|
6083
|
+
// Stripe; Stripe can collect email on the secure checkout page. Bots
|
|
6084
|
+
// still need a valid email hint to bypass deflection.
|
|
6085
|
+
const isConfirmedCheckout = (
|
|
6086
|
+
(req.method === 'POST' && hasValidCustomerEmailHint)
|
|
6087
|
+
|| hasConfirmFlag
|
|
6088
|
+
) && botShouldBypass;
|
|
6034
6089
|
// 2026-06-05 revenue bypass: env-gated direct-to-Stripe redirect.
|
|
6035
6090
|
// Live 30d billing showed 254 interstitial views → 1 Stripe click-through
|
|
6036
6091
|
// → 0 paid. When THUMBGATE_CHECKOUT_INTERSTITIAL_BYPASS=1 is set we
|
|
@@ -6038,7 +6093,7 @@ async function addContext(){
|
|
|
6038
6093
|
// pro Stripe Payment Link, preserving UTM + attribution metadata via
|
|
6039
6094
|
// buildCheckoutFallbackUrl. Default-off; bot-deflection still applies
|
|
6040
6095
|
// (bot + no email hint still falls through to the existing interstitial).
|
|
6041
|
-
const interstitialBypassEnabled = process.env.THUMBGATE_CHECKOUT_INTERSTITIAL_BYPASS
|
|
6096
|
+
const interstitialBypassEnabled = process.env.THUMBGATE_CHECKOUT_INTERSTITIAL_BYPASS !== '0';
|
|
6042
6097
|
const interstitialSampleRate = normalizeCheckoutInterstitialSampleRate(
|
|
6043
6098
|
process.env.THUMBGATE_CHECKOUT_INTERSTITIAL_SAMPLE_RATE
|
|
6044
6099
|
);
|
|
@@ -6124,6 +6179,7 @@ async function addContext(){
|
|
|
6124
6179
|
const eventType = botClassification.isBot
|
|
6125
6180
|
? 'checkout_bot_deflected'
|
|
6126
6181
|
: 'checkout_interstitial_view';
|
|
6182
|
+
const missingConfirmedEmail = hasConfirmFlag && !hasValidCustomerEmailHint;
|
|
6127
6183
|
appendBestEffortTelemetry(FEEDBACK_DIR, {
|
|
6128
6184
|
eventType,
|
|
6129
6185
|
clientType: 'web',
|
|
@@ -6147,7 +6203,10 @@ async function addContext(){
|
|
|
6147
6203
|
isBot: botClassification.isBot ? 'true' : 'false',
|
|
6148
6204
|
interstitialSampled: interstitialSampled ? 'true' : 'false',
|
|
6149
6205
|
interstitialSampleRate,
|
|
6150
|
-
reason:
|
|
6206
|
+
reason: missingConfirmedEmail
|
|
6207
|
+
? (hasCustomerEmailHint ? 'invalid_customer_email' : 'missing_customer_email')
|
|
6208
|
+
: botClassification.reason,
|
|
6209
|
+
confirmEmailRequired: missingConfirmedEmail ? 'true' : 'false',
|
|
6151
6210
|
}, req.headers, eventType);
|
|
6152
6211
|
const prefilledEmail = parsed?.searchParams?.get('customer_email') || '';
|
|
6153
6212
|
const html = renderCheckoutIntentPage(prefilledEmail, parsed, {
|
|
@@ -6157,8 +6216,6 @@ async function addContext(){
|
|
|
6157
6216
|
return;
|
|
6158
6217
|
}
|
|
6159
6218
|
|
|
6160
|
-
const rawCheckoutEmail = normalizeNullableText(bootstrapBody.customerEmail);
|
|
6161
|
-
const normalizedCheckoutEmail = normalizeCheckoutCustomerEmail(rawCheckoutEmail);
|
|
6162
6219
|
if (!normalizedCheckoutEmail) {
|
|
6163
6220
|
appendBestEffortTelemetry(FEEDBACK_DIR, {
|
|
6164
6221
|
eventType: 'checkout_email_deferred_to_stripe',
|
|
@@ -6434,6 +6491,25 @@ async function addContext(){
|
|
|
6434
6491
|
return;
|
|
6435
6492
|
}
|
|
6436
6493
|
|
|
6494
|
+
if (isGetLikeRequest && pathname === '/leash-beta') {
|
|
6495
|
+
// Hermes Mobile founding beta landing (mac-yolo-safeguards/hermes-mobile/docs/beta-page).
|
|
6496
|
+
try {
|
|
6497
|
+
const html = fs.readFileSync(
|
|
6498
|
+
path.resolve(__dirname, '../../assets/static/leash-beta.html'),
|
|
6499
|
+
'utf8'
|
|
6500
|
+
);
|
|
6501
|
+
if (isHeadRequest) {
|
|
6502
|
+
sendHtml(res, 200, html, {}, { headOnly: true });
|
|
6503
|
+
return;
|
|
6504
|
+
}
|
|
6505
|
+
sendHtml(res, 200, html);
|
|
6506
|
+
} catch (err) {
|
|
6507
|
+
console.error('leash-beta page read failed:', err?.message);
|
|
6508
|
+
sendJson(res, 500, { error: 'leash-beta page unavailable' });
|
|
6509
|
+
}
|
|
6510
|
+
return;
|
|
6511
|
+
}
|
|
6512
|
+
|
|
6437
6513
|
if (isGetLikeRequest && pathname === '/.well-known/mcp.json') {
|
|
6438
6514
|
sendJson(res, 200, getMcpDiscoveryManifest(hostedConfig), {}, {
|
|
6439
6515
|
headOnly: isHeadRequest,
|
|
@@ -6809,7 +6885,7 @@ a{color:#8b9}</style></head><body><form class="card" method="post" action="/oaut
|
|
|
6809
6885
|
}
|
|
6810
6886
|
|
|
6811
6887
|
if (req.method === 'GET' && pathname === '/v1/metrics/real') {
|
|
6812
|
-
const bd = require('../../scripts/bot-
|
|
6888
|
+
const bd = require('../../scripts/bot-detection');
|
|
6813
6889
|
const { FEEDBACK_DIR: metricsDir } = getFeedbackPaths();
|
|
6814
6890
|
const telemetryPath = path.join(metricsDir, 'telemetry-pings.jsonl');
|
|
6815
6891
|
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: dashboard
|
|
3
|
-
description: Open the local HTTP dashboard for the current project in your web browser.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Open Dashboard
|
|
7
|
-
|
|
8
|
-
Open the local HTTP dashboard for the current project in your web browser.
|
|
9
|
-
|
|
10
|
-
## Instructions
|
|
11
|
-
Execute the following command in the project directory to open the browser dashboard scoped to the current repository:
|
|
12
|
-
```bash
|
|
13
|
-
thumbgate-dashboard
|
|
14
|
-
```
|
|
15
|
-
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: thumbgate-blocked
|
|
3
|
-
description: Show what ThumbGate has actually blocked — gate enforcement stats and the full enforcement matrix. Use for "what has ThumbGate blocked", "show gate stats", "is enforcement working", "how many tokens did we save", "enforcement matrix".
|
|
4
|
-
allowed-tools: mcp__thumbgate__gate_stats, mcp__thumbgate__enforcement_matrix, Bash(npx thumbgate gate-stats:*)
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# ThumbGate Blocked
|
|
8
|
-
|
|
9
|
-
Show the enforcement record: how many risky actions were blocked vs warned, which gates fire most, and the full feedback → check → rejection pipeline.
|
|
10
|
-
|
|
11
|
-
This command wraps existing ThumbGate capability — **no new logic**. It reads the live enforcement counters.
|
|
12
|
-
|
|
13
|
-
## Steps
|
|
14
|
-
|
|
15
|
-
1. Call the `gate_stats` MCP tool for the headline numbers: blocked count, warned count, and the top gates by hits. (CLI fallback: `npx thumbgate gate-stats`.)
|
|
16
|
-
2. Call the `enforcement_matrix` MCP tool for the full picture: feedback pipeline stats, active pre-action checks, and the rejection ledger with revival conditions.
|
|
17
|
-
3. Summarize for the user:
|
|
18
|
-
- Total blocks (each block = a repeat mistake stopped before it spent tokens or did damage).
|
|
19
|
-
- Most-triggered gates.
|
|
20
|
-
- Anything in the rejection ledger that is close to revival.
|
|
21
|
-
4. If counts are all zero, note that enforcement is wired but hasn't fired yet, and point to `/thumbgate-guard` to promote a rule.
|
|
22
|
-
|
|
23
|
-
## Example
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
/thumbgate-blocked
|
|
27
|
-
```
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: thumbgate-dashboard
|
|
3
|
-
description: Open the local HTTP dashboard for the current project in your web browser.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Open Scoped ThumbGate Dashboard
|
|
7
|
-
|
|
8
|
-
Open the local HTTP dashboard for the current project in your web browser.
|
|
9
|
-
|
|
10
|
-
## Instructions
|
|
11
|
-
Execute the following command in the project directory to open the browser dashboard:
|
|
12
|
-
```bash
|
|
13
|
-
thumbgate-dashboard
|
|
14
|
-
```
|
|
15
|
-
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: thumbgate-doctor
|
|
3
|
-
description: Health-check the ThumbGate wiring for this project — hooks, MCP server, and agent-readiness — and report what's broken. Use for "is ThumbGate wired up", "thumbgate doctor", "check my guardrails are installed", "why aren't my gates firing", "agent readiness".
|
|
4
|
-
allowed-tools: Bash(npx thumbgate doctor:*), mcp__thumbgate__check_operational_integrity
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# ThumbGate Doctor
|
|
8
|
-
|
|
9
|
-
Audit whether ThumbGate is actually wired into this agent: PreToolUse / SessionStart hooks installed, MCP server reachable, lesson store present, and overall agent-readiness — then tell the user exactly what to fix.
|
|
10
|
-
|
|
11
|
-
This command wraps existing ThumbGate capability — **no new logic**. It runs the existing doctor + integrity checks.
|
|
12
|
-
|
|
13
|
-
## Steps
|
|
14
|
-
|
|
15
|
-
1. Run the existing wiring/health audit:
|
|
16
|
-
```bash
|
|
17
|
-
npx thumbgate doctor
|
|
18
|
-
```
|
|
19
|
-
(Add `--json` for a machine-readable report.) It exits non-zero when the project is not `ready`.
|
|
20
|
-
2. For deeper runtime state, call the `check_operational_integrity` MCP tool to verify the server-side enforcement path is live, not just the local config.
|
|
21
|
-
3. Summarize:
|
|
22
|
-
- ✅ what's wired (hooks, MCP, store, statusline).
|
|
23
|
-
- ❌ what's missing, with the exact fix command (usually `npx thumbgate init`).
|
|
24
|
-
4. If everything is green, say so plainly with the readiness status; if not, lead with the single highest-impact fix.
|
|
25
|
-
|
|
26
|
-
## Example
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
/thumbgate-doctor
|
|
30
|
-
```
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: thumbgate-guard
|
|
3
|
-
description: Turn the last agent mistake into a hard prevention rule the agent cannot bypass. Use after a bad tool call, a wrong action, or a thumbs-down — "guard against this", "block this from happening again", "never do that again", "promote this to a rule".
|
|
4
|
-
allowed-tools: mcp__thumbgate__capture_feedback, Bash(npx thumbgate force-gate:*), Bash(npx thumbgate quickstart:*)
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# ThumbGate Guard
|
|
8
|
-
|
|
9
|
-
Capture the mistake the agent just made and promote it into a Pre-Action Check (a `block` gate) so the same tool-call shape is intercepted before it runs again — in this and every future session, across Claude Code, Cursor, Codex, Gemini, Amp, and Cline.
|
|
10
|
-
|
|
11
|
-
This command wraps existing ThumbGate capability. It adds **no new logic** — it routes to the real capture + force-promote path.
|
|
12
|
-
|
|
13
|
-
## Steps
|
|
14
|
-
|
|
15
|
-
1. Identify the specific bad action from the recent conversation (e.g. `git push --force origin main`, `DROP TABLE users`, deploy without tests). State it in one sentence.
|
|
16
|
-
2. Record the signal with the `capture_feedback` MCP tool:
|
|
17
|
-
- `signal: "down"`
|
|
18
|
-
- `context`: one sentence describing what went wrong
|
|
19
|
-
- `whatWentWrong`: the concrete failure
|
|
20
|
-
- `whatToChange`: the prevention action
|
|
21
|
-
- `tags`: the domain (e.g. `git`, `database`, `deploy`)
|
|
22
|
-
- If the user only gave a vague signal, pass the recent turns through `conversationWindow` / `chatHistory` for history-aware distillation instead of refusing.
|
|
23
|
-
3. Promote it to an enforced block gate using the existing force-promote path:
|
|
24
|
-
```bash
|
|
25
|
-
npx thumbgate force-gate "<one-sentence context of the mistake>"
|
|
26
|
-
```
|
|
27
|
-
This prints the new `gateId` and the total active gate count.
|
|
28
|
-
4. Show the user the promoted rule and confirm it is now enforced as a PreToolUse block.
|
|
29
|
-
|
|
30
|
-
> First rule of the project and want the guided walkthrough (capture → promote → watch it block once)? Run `npx thumbgate quickstart` instead.
|
|
31
|
-
|
|
32
|
-
## Example
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
/thumbgate-guard the agent force-pushed to main and overwrote a teammate's commit
|
|
36
|
-
```
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: thumbgate-protect
|
|
3
|
-
description: Show this repo's branch/release governance and grant a scoped, time-limited approval for an action that touches protected files. Use for "protect this branch", "is main protected", "approve this protected change", "branch governance", "let me edit a protected file".
|
|
4
|
-
allowed-tools: mcp__thumbgate__get_branch_governance, mcp__thumbgate__approve_protected_action
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# ThumbGate Protect
|
|
8
|
-
|
|
9
|
-
Inspect the protected-action posture for this project and, when the user explicitly approves, grant a scoped, expiring exception so a protected-file edit or publish can proceed under audit.
|
|
10
|
-
|
|
11
|
-
This command wraps existing ThumbGate capability — **no new logic**. It reads governance state and records a time-boxed approval.
|
|
12
|
-
|
|
13
|
-
## Steps
|
|
14
|
-
|
|
15
|
-
1. Read the current posture with the `get_branch_governance` MCP tool: which branches are protected, release rules, and the protected-file globs in effect.
|
|
16
|
-
2. Report it plainly: what is protected, and what the agent is currently blocked from touching without approval.
|
|
17
|
-
3. **Only if the user explicitly asks to proceed**, grant a scoped approval with `approve_protected_action`:
|
|
18
|
-
- `pathGlobs`: the smallest set of protected globs the action needs.
|
|
19
|
-
- `reason`: why this is approved (one sentence).
|
|
20
|
-
- `evidence`: supporting note (tests passing, owner sign-off, etc.) when available.
|
|
21
|
-
- `ttlMs`: keep it short — default is 1 hour, never exceed what the task needs.
|
|
22
|
-
4. Confirm the approval id, covered globs, and expiry. Approvals are deliberately temporary and audited; re-run for the next task.
|
|
23
|
-
|
|
24
|
-
> This is for granting *narrow, temporary* exceptions, not for disabling protection. Never use it to bypass branch governance wholesale.
|
|
25
|
-
|
|
26
|
-
## Example
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
/thumbgate-protect
|
|
30
|
-
```
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: thumbgate-rules
|
|
3
|
-
description: List the active prevention rules and learned lessons guarding this project. Use to answer "what is ThumbGate protecting me from", "show my gates/rules", "what has the agent learned", "what's blocked here".
|
|
4
|
-
allowed-tools: mcp__thumbgate__prevention_rules, mcp__thumbgate__get_reliability_rules, mcp__thumbgate__search_lessons, Bash(npx thumbgate rules:*)
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# ThumbGate Rules
|
|
8
|
-
|
|
9
|
-
Show the guardrails currently in force for this project: the auto-promoted prevention rules, the reliability rules, and the promoted lessons behind them.
|
|
10
|
-
|
|
11
|
-
This command wraps existing ThumbGate capability — **no new logic**. It reads the live rule + lesson stores.
|
|
12
|
-
|
|
13
|
-
## Steps
|
|
14
|
-
|
|
15
|
-
1. List the active prevention rules with the `prevention_rules` MCP tool (or the CLI fallback `npx thumbgate rules`).
|
|
16
|
-
2. Pull the reliability rules with `get_reliability_rules` to show which tool-call shapes are gated.
|
|
17
|
-
3. For each rule, surface the lesson it came from with `search_lessons` so the user sees *why* the rule exists, not just *what* it blocks.
|
|
18
|
-
4. Present a compact table:
|
|
19
|
-
|
|
20
|
-
| Rule / Gate | Blocks | From lesson | State |
|
|
21
|
-
|-------------|--------|-------------|-------|
|
|
22
|
-
| … | … | … | active / archived |
|
|
23
|
-
|
|
24
|
-
5. If there are zero active rules, point the user to `/thumbgate-guard` to promote their first one.
|
|
25
|
-
|
|
26
|
-
## Example
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
/thumbgate-rules
|
|
30
|
-
```
|