thumbgate 1.21.0 โ†’ 1.21.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate-marketplace",
3
- "version": "1.21.0",
3
+ "version": "1.21.1",
4
4
  "owner": {
5
5
  "name": "Igor Ganapolsky",
6
6
  "email": "ig5973700@gmail.com"
@@ -14,7 +14,7 @@
14
14
  "source": "npm",
15
15
  "package": "thumbgate"
16
16
  },
17
- "version": "1.21.0",
17
+ "version": "1.21.1",
18
18
  "author": {
19
19
  "name": "Igor Ganapolsky",
20
20
  "email": "ig5973700@gmail.com",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "thumbgate",
3
3
  "description": "One ๐Ÿ‘Ž becomes a hard rule the agent cannot bypass. Captures thumbs-down feedback, distills it into PreToolUse Pre-Action Checks, enforced across every future Claude Code session.",
4
- "version": "1.21.0",
4
+ "version": "1.21.1",
5
5
  "author": {
6
6
  "name": "Igor Ganapolsky",
7
7
  "email": "ig5973700@gmail.com",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.21.0",
3
+ "version": "1.21.1",
4
4
  "description": "ThumbGate โ€” ๐Ÿ‘๐Ÿ‘Ž feedback that teaches your AI agent. Thumbs down a mistake, it never happens again.",
5
5
  "homepage": "https://thumbgate-production.up.railway.app",
6
6
  "transport": "stdio",
@@ -2,13 +2,13 @@
2
2
  "mcpServers": {
3
3
  "thumbgate": {
4
4
  "command": "npx",
5
- "args": ["--yes", "--package", "thumbgate@1.21.0", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.21.1", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.21.0", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.21.1", "thumbgate", "gate-check"]
12
12
  }
13
13
  }
14
14
  }
@@ -216,7 +216,7 @@ const {
216
216
  finalizeSession: finalizeFeedbackSession,
217
217
  } = require('../../scripts/feedback-session');
218
218
 
219
- const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.21.0' };
219
+ const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.21.1' };
220
220
  const COMMERCE_CATEGORIES = [
221
221
  'product_recommendation',
222
222
  'brand_compliance',
@@ -7,7 +7,7 @@
7
7
  "npx",
8
8
  "--yes",
9
9
  "--package",
10
- "thumbgate@1.21.0",
10
+ "thumbgate@1.21.1",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],
package/bin/cli.js CHANGED
@@ -396,6 +396,26 @@ function whichExists(cmd) {
396
396
  function setupClaude() {
397
397
  const mcpChanged = mergeMcpJson(path.join(CWD, '.mcp.json'), 'Claude Code', 'project');
398
398
 
399
+ // Wire the canonical ThumbGate gate hooks (PreToolUse pre-action check,
400
+ // UserPromptSubmit, PostToolUse, SessionStart) through the shared wiring
401
+ // path so `init`, `init --agent claude-code`, and `install` all produce the
402
+ // same hook set. Before this, `install` shipped a Claude config with no
403
+ // PreToolUse gate โ€” the core ThumbGate feature was silently missing.
404
+ let wireChanged = false;
405
+ try {
406
+ const { wireHooks } = require(path.join(PKG_ROOT, 'scripts', 'auto-wire-hooks'));
407
+ const wireResult = wireHooks({ agent: 'claude-code' });
408
+ if (wireResult.error) {
409
+ console.log(` Claude Code: ${wireResult.error}`);
410
+ } else if (wireResult.changed) {
411
+ wireChanged = true;
412
+ const lifecycles = [...new Set(wireResult.added.map((h) => h.lifecycle))].join(', ');
413
+ console.log(` Claude Code: wired gate hooks (${lifecycles})`);
414
+ }
415
+ } catch (err) {
416
+ console.log(` Claude Code: hook wiring skipped (${err.message})`);
417
+ }
418
+
399
419
  // Upsert Stop hook into .claude/settings.json for autonomous self-scoring
400
420
  const settingsPath = path.join(CWD, '.claude', 'settings.json');
401
421
  const stopHookCommand = 'bash scripts/hook-stop-self-score.sh';
@@ -452,7 +472,7 @@ function setupClaude() {
452
472
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
453
473
  }
454
474
 
455
- return mcpChanged || hooksChanged;
475
+ return mcpChanged || hooksChanged || wireChanged;
456
476
  }
457
477
 
458
478
  function setupCodex() {
@@ -724,6 +744,7 @@ function init(cliArgs = parseArgs(process.argv.slice(3))) {
724
744
  let configured = 0;
725
745
 
726
746
  const platforms = [
747
+ { name: 'Claude Code', detect: [() => whichExists('claude'), () => fs.existsSync(path.join(HOME, '.claude'))], setup: setupClaude },
727
748
  { name: 'Codex', detect: [() => whichExists('codex'), () => fs.existsSync(path.join(HOME, '.codex'))], setup: setupCodex },
728
749
  { name: 'Gemini', detect: [() => whichExists('gemini'), () => fs.existsSync(path.join(HOME, '.gemini'))], setup: setupGemini },
729
750
  { name: 'Amp', detect: [() => whichExists('amp'), () => fs.existsSync(path.join(HOME, '.amp'))], setup: setupAmp },
@@ -2458,6 +2479,11 @@ if (COMMAND === 'daemon' || COMMAND === 'serve-daemon') {
2458
2479
  }
2459
2480
 
2460
2481
  switch (COMMAND) {
2482
+ case '--version':
2483
+ case '-v':
2484
+ case 'version':
2485
+ console.log(pkgVersion());
2486
+ break;
2461
2487
  case 'init':
2462
2488
  init();
2463
2489
  upgradeNudge();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.21.0",
3
+ "version": "1.21.1",
4
4
  "description": "ThumbGate self-improving agent governance: thumbs-up/down turns every mistake into a prevention rule and blocks repeat patterns. 33 pre-action checks, 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": {
@@ -639,6 +639,10 @@
639
639
  "test:competitive-positioning-marketing": "node --test tests/competitive-positioning-marketing.test.js tests/knowledge-graph-guardrails.test.js tests/supply-chain-guardrails.test.js",
640
640
  "test:medium-weekly": "node --test tests/medium-weekly.test.js",
641
641
  "test:dashboard-deeplink-e2e": "node --test tests/dashboard-deeplink-e2e.test.js",
642
+ "test:e2e:playwright": "playwright test",
643
+ "test:e2e:playwright:headed": "playwright test --headed",
644
+ "test:e2e:playwright:ui": "playwright test --ui",
645
+ "test:e2e:playwright:report": "playwright show-report",
642
646
  "test:public-package-parity": "node --test tests/public-package-parity.test.js",
643
647
  "prepare": "bash bin/install-hooks.sh >/dev/null 2>&1 || true",
644
648
  "install:hooks": "bash bin/install-hooks.sh",
@@ -730,6 +734,7 @@
730
734
  "devDependencies": {
731
735
  "@changesets/changelog-github": "^0.7.0",
732
736
  "@changesets/cli": "^2.31.0",
737
+ "@playwright/test": "^1.60.0",
733
738
  "c8": "^11.0.0",
734
739
  "undici": "^8.2.0"
735
740
  }
@@ -247,9 +247,9 @@
247
247
 
248
248
  <!-- STATS -->
249
249
  <div class="stats-grid" id="statsGrid">
250
- <a class="stat-card" data-card-action="all" onclick="selectCard(this,'all')" href="/lessons" style="cursor:pointer;text-decoration:none;color:inherit;display:block;" title="Click to view all feedback โ†’ Lessons page"><div class="stat-label">Total Feedback</div><div class="stat-value cyan" id="statTotal">โ€”</div></a>
251
- <a class="stat-card" data-card-action="up" onclick="selectCard(this,'up')" href="/lessons?signal=positive" style="cursor:pointer;text-decoration:none;color:inherit;display:block;" title="Click to view positive feedback โ†’ Lessons page"><div class="stat-label">๐Ÿ‘ Positive</div><div class="stat-value green" id="statPositive">โ€”</div></a>
252
- <a class="stat-card" data-card-action="down" onclick="selectCard(this,'down')" href="/lessons?signal=negative" style="cursor:pointer;text-decoration:none;color:inherit;display:block;" title="Click to view negative feedback โ†’ Lessons page"><div class="stat-label">๐Ÿ‘Ž Negative</div><div class="stat-value red" id="statNegative">โ€”</div></a>
250
+ <a class="stat-card" data-card-action="all" onclick="selectCard(this,'all')" href="/lessons?signal=all" style="cursor:pointer;text-decoration:none;color:inherit;display:block;" title="Click to view all feedback โ†’ Lessons page"><div class="stat-label">Total Feedback</div><div class="stat-value cyan" id="statTotal">โ€”</div></a>
251
+ <a class="stat-card" data-card-action="up" onclick="selectCard(this,'up')" href="/lessons?signal=up" style="cursor:pointer;text-decoration:none;color:inherit;display:block;" title="Click to view positive feedback โ†’ Lessons page"><div class="stat-label">๐Ÿ‘ Positive</div><div class="stat-value green" id="statPositive">โ€”</div></a>
252
+ <a class="stat-card" data-card-action="down" onclick="selectCard(this,'down')" href="/lessons?signal=down" style="cursor:pointer;text-decoration:none;color:inherit;display:block;" title="Click to view negative feedback โ†’ Lessons page"><div class="stat-label">๐Ÿ‘Ž Negative</div><div class="stat-value red" id="statNegative">โ€”</div></a>
253
253
  <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 checks"><div class="stat-label">Active Gates</div><div class="stat-value cyan" id="statGates">โ€”</div></a>
254
254
  </div>
255
255
 
package/public/index.html CHANGED
@@ -19,7 +19,7 @@ __GOOGLE_SITE_VERIFICATION_META__
19
19
  <meta property="og:image" content="https://thumbgate-production.up.railway.app/og.png">
20
20
  <meta name="twitter:card" content="summary_large_image">
21
21
  <meta name="twitter:image" content="https://thumbgate-production.up.railway.app/og.png">
22
- <meta name="thumbgate-version" content="1.21.0">
22
+ <meta name="thumbgate-version" content="1.21.1">
23
23
  <meta name="keywords" content="ThumbGate, thumbgate, AI agent orchestration, AI experience orchestration, agent enforcement layer, save LLM tokens, reduce Claude API cost, reduce OpenAI cost, AI agent token savings, prevent LLM retries, prevent hallucination retries, stop AI token waste, pre-action checks, agent governance, Claude Code, Cursor, Codex, Gemini, Amp, Cline, OpenCode, workflow hardening, context engineering, AI authenticity, brand authenticity AI">
24
24
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">
25
25
 
@@ -1492,7 +1492,7 @@ __GA_BOOTSTRAP__
1492
1492
  <a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
1493
1493
  <a href="/blog">Blog</a>
1494
1494
  </div>
1495
- <span class="footer-copy">ยฉ 2026 ThumbGate ยท MIT License ยท npm v1.21.0</span>
1495
+ <span class="footer-copy">ยฉ 2026 ThumbGate ยท MIT License ยท npm v1.21.1</span>
1496
1496
  </div>
1497
1497
  </footer>
1498
1498
 
@@ -922,6 +922,28 @@ async function loadLive() {
922
922
  }
923
923
 
924
924
  loadLive().then(function() {
925
+ // Handle ?signal= query param from dashboard stat-card navigation.
926
+ // Vocabulary: 'up' | 'down' | 'all' (canonical). Also accepts the legacy
927
+ // 'positive' | 'negative' aliases the dashboard once emitted.
928
+ var qsSignal = new URLSearchParams(window.location.search).get('signal');
929
+ if (qsSignal) {
930
+ var signalMap = { positive: 'up', negative: 'down', up: 'up', down: 'down', all: 'all' };
931
+ var mapped = signalMap[qsSignal];
932
+ if (mapped) {
933
+ switchTab('timeline');
934
+ filterTimeline(mapped, null);
935
+ var filterBtns = document.querySelectorAll('#tab-timeline .filter-btn');
936
+ filterBtns.forEach(function(b) {
937
+ var label = b.textContent.trim().toLowerCase();
938
+ var match = (mapped === 'all' && label === 'all') ||
939
+ (mapped === 'up' && (label.indexOf('๐Ÿ‘') !== -1 || label.indexOf('positive') !== -1 || label === 'up')) ||
940
+ (mapped === 'down' && (label.indexOf('๐Ÿ‘Ž') !== -1 || label.indexOf('negative') !== -1 || label === 'down'));
941
+ b.classList.toggle('active', match);
942
+ });
943
+ return;
944
+ }
945
+ }
946
+
925
947
  // Default: highlight Active Rules card on page load
926
948
  highlightCard(0);
927
949
 
@@ -25,7 +25,7 @@
25
25
  "alternateName": "thumbgate",
26
26
  "applicationCategory": "DeveloperApplication",
27
27
  "operatingSystem": "Cross-platform, Node.js >=18.18.0",
28
- "softwareVersion": "1.21.0",
28
+ "softwareVersion": "1.21.1",
29
29
  "url": "https://thumbgate-production.up.railway.app/numbers",
30
30
  "dateModified": "2026-05-07",
31
31
  "creator": {
@@ -202,7 +202,7 @@
202
202
  <main class="container">
203
203
  <h1>The Numbers</h1>
204
204
  <p class="subtitle">Generated first-party operational snapshot from the ThumbGate runtime. This is not customer traction, install volume, revenue, or proof that a configured gate has fired.</p>
205
- <div class="freshness">Updated: 2026-05-07 ยท Version 1.21.0</div>
205
+ <div class="freshness">Updated: 2026-05-07 ยท Version 1.21.1</div>
206
206
  <div class="truth-note"><strong>Read this first:</strong> configured checks are inventory. Recorded blocks and warnings are usage evidence. This snapshot currently reports 0 recorded hard-block event(s) and 0 recorded warning event(s).</div>
207
207
 
208
208
  <h2>Gate enforcement</h2>
@@ -1178,10 +1178,15 @@ function chooseDecision({ riskScore, integrity, memoryGuard, learnedPolicy, blas
1178
1178
  if (lowRiskHandoff) {
1179
1179
  return 'allow';
1180
1180
  }
1181
+ // Background customer-system actions checkpoint (warn), never hard-deny.
1182
+ // The checkpoint IS the mitigation โ€” blocking outright prevents legitimate work.
1183
+ if (backgroundAgent && customerSystemAction) {
1184
+ return 'warn';
1185
+ }
1181
1186
  if (destructiveBypass || learnedHardStop || repeatedHighBlast || (hasOperationalBlockers && riskScore >= 0.72) || riskScore >= 0.86) {
1182
1187
  return 'deny';
1183
1188
  }
1184
- if (economicAction || (backgroundAgent && customerSystemAction) || (backgroundAgent && riskScore >= 0.3)) {
1189
+ if (economicAction || (backgroundAgent && riskScore >= 0.3)) {
1185
1190
  return 'warn';
1186
1191
  }
1187
1192
  if ((workflowControl && workflowControl.mode === 'warn') || (costControl && costControl.mode === 'warn') || riskScore >= 0.45 || (learnedWarning && riskScore >= 0.3) || (learnedRecall && riskScore >= 0.34)) {