thumbgate 1.27.3 → 1.27.4
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/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/package.json +1 -1
- package/public/index.html +2 -2
- package/public/numbers.html +2 -2
- package/scripts/dashboard.js +17 -3
- package/src/api/server.js +71 -2
|
@@ -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.27.
|
|
4
|
+
"version": "1.27.4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Igor Ganapolsky",
|
|
7
7
|
"email": "ig5973700@gmail.com",
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"thumbgate": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--yes", "--package", "thumbgate@1.27.
|
|
5
|
+
"args": ["--yes", "--package", "thumbgate@1.27.4", "thumbgate", "serve"]
|
|
6
6
|
}
|
|
7
7
|
},
|
|
8
8
|
"hooks": {
|
|
9
9
|
"preToolUse": {
|
|
10
10
|
"command": "npx",
|
|
11
|
-
"args": ["--yes", "--package", "thumbgate@1.27.
|
|
11
|
+
"args": ["--yes", "--package", "thumbgate@1.27.4", "thumbgate", "gate-check"]
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -231,7 +231,7 @@ const {
|
|
|
231
231
|
finalizeSession: finalizeFeedbackSession,
|
|
232
232
|
} = require('../../scripts/feedback-session');
|
|
233
233
|
|
|
234
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.27.
|
|
234
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.27.4' };
|
|
235
235
|
const COMMERCE_CATEGORIES = [
|
|
236
236
|
'product_recommendation',
|
|
237
237
|
'brand_compliance',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thumbgate",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.4",
|
|
4
4
|
"description": "ThumbGate self-improving agent governance: thumbs-up/down turns every mistake into a prevention rule and blocks repeat patterns. 36 pre-action checks, budget enforcement, and self-protection for Claude Code, Cursor, Codex, Gemini CLI, and Amp.",
|
|
5
5
|
"homepage": "https://thumbgate.ai",
|
|
6
6
|
"repository": {
|
package/public/index.html
CHANGED
|
@@ -20,7 +20,7 @@ __GOOGLE_SITE_VERIFICATION_META__
|
|
|
20
20
|
<meta property="og:image" content="https://thumbgate.ai/og.png">
|
|
21
21
|
<meta name="twitter:card" content="summary_large_image">
|
|
22
22
|
<meta name="twitter:image" content="https://thumbgate.ai/og.png">
|
|
23
|
-
<meta name="thumbgate-version" content="1.27.
|
|
23
|
+
<meta name="thumbgate-version" content="1.27.4">
|
|
24
24
|
<meta name="keywords" content="ThumbGate, thumbgate, AI agent orchestration, AI experience orchestration, agentic development cycle, AC/DC framework, Guide Generate Verify Solve, agent enforcement layer, save LLM tokens, reduce Claude API cost, reduce OpenAI cost, AI agent token savings, prevent LLM retries, prevent hallucination retries, stop AI token waste, pre-action checks, agent governance, Claude Code, Cursor, Codex, Gemini, Amp, Cline, OpenCode, workflow hardening, context engineering, AI authenticity, brand authenticity AI">
|
|
25
25
|
<link rel="canonical" href="__APP_ORIGIN__/">
|
|
26
26
|
<link rel="alternate" type="text/markdown" title="ThumbGate LLM context" href="__APP_ORIGIN__/llm-context.md">
|
|
@@ -1676,7 +1676,7 @@ __GA_BOOTSTRAP__
|
|
|
1676
1676
|
<a href="https://www.linkedin.com/in/igorganapolsky" target="_blank" rel="noopener">LinkedIn</a>
|
|
1677
1677
|
<a href="/blog">Blog</a>
|
|
1678
1678
|
</div>
|
|
1679
|
-
<span class="footer-copy">© 2026 ThumbGate · MIT License · npm v1.27.
|
|
1679
|
+
<span class="footer-copy">© 2026 ThumbGate · MIT License · npm v1.27.4</span>
|
|
1680
1680
|
</div>
|
|
1681
1681
|
</footer>
|
|
1682
1682
|
|
package/public/numbers.html
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"alternateName": "thumbgate",
|
|
26
26
|
"applicationCategory": "DeveloperApplication",
|
|
27
27
|
"operatingSystem": "Cross-platform, Node.js >=18.18.0",
|
|
28
|
-
"softwareVersion": "1.27.
|
|
28
|
+
"softwareVersion": "1.27.4",
|
|
29
29
|
"url": "https://thumbgate.ai/numbers",
|
|
30
30
|
"dateModified": "2026-05-07",
|
|
31
31
|
"creator": {
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
<main class="container">
|
|
203
203
|
<h1>The Numbers</h1>
|
|
204
204
|
<p class="subtitle">Generated first-party operational snapshot from the ThumbGate runtime. This is not customer traction, install volume, revenue, or proof that a configured gate has fired.</p>
|
|
205
|
-
<div class="freshness">Updated: 2026-05-07 · Version 1.27.
|
|
205
|
+
<div class="freshness">Updated: 2026-05-07 · Version 1.27.4</div>
|
|
206
206
|
<div class="truth-note"><strong>Read this first:</strong> configured checks are inventory. Recorded blocks and warnings are usage evidence. This snapshot currently reports 0 recorded hard-block event(s) and 0 recorded warning event(s).</div>
|
|
207
207
|
|
|
208
208
|
<h2>Gate enforcement</h2>
|
package/scripts/dashboard.js
CHANGED
|
@@ -449,9 +449,13 @@ function computeGateAuditSeries(feedbackDir, options = {}) {
|
|
|
449
449
|
const dayKey = toLocalDayKey(entry.timestamp);
|
|
450
450
|
if (!dayKey) continue;
|
|
451
451
|
if (!countsByDay.has(dayKey)) {
|
|
452
|
-
countsByDay.set(dayKey, { allow: 0, deny: 0, warn: 0 });
|
|
452
|
+
countsByDay.set(dayKey, { allow: 0, deny: 0, warn: 0, byGate: {} });
|
|
453
|
+
}
|
|
454
|
+
const bucket = countsByDay.get(dayKey);
|
|
455
|
+
bucket[entry.decision] += 1;
|
|
456
|
+
if ((entry.decision === 'deny' || entry.decision === 'warn') && entry.gateId) {
|
|
457
|
+
bucket.byGate[entry.gateId] = (bucket.byGate[entry.gateId] || 0) + 1;
|
|
453
458
|
}
|
|
454
|
-
countsByDay.get(dayKey)[entry.decision] += 1;
|
|
455
459
|
}
|
|
456
460
|
|
|
457
461
|
const days = [];
|
|
@@ -461,7 +465,7 @@ function computeGateAuditSeries(feedbackDir, options = {}) {
|
|
|
461
465
|
const day = new Date(today);
|
|
462
466
|
day.setDate(today.getDate() - offset);
|
|
463
467
|
const dayKey = toLocalDayKey(day);
|
|
464
|
-
const record = countsByDay.get(dayKey) || { allow: 0, deny: 0, warn: 0 };
|
|
468
|
+
const record = countsByDay.get(dayKey) || { allow: 0, deny: 0, warn: 0, byGate: {} };
|
|
465
469
|
const intercepted = record.deny + record.warn;
|
|
466
470
|
const total = intercepted + record.allow;
|
|
467
471
|
const summary = {
|
|
@@ -471,6 +475,7 @@ function computeGateAuditSeries(feedbackDir, options = {}) {
|
|
|
471
475
|
warn: record.warn,
|
|
472
476
|
intercepted,
|
|
473
477
|
total,
|
|
478
|
+
byGate: record.byGate || {},
|
|
474
479
|
};
|
|
475
480
|
totals.allow += record.allow;
|
|
476
481
|
totals.deny += record.deny;
|
|
@@ -525,7 +530,14 @@ function computePreventionImpact(feedbackDir, gateStats) {
|
|
|
525
530
|
// Last auto-promotion
|
|
526
531
|
const autoGates = readJsonFile(autoGatesPath);
|
|
527
532
|
let lastPromotion = null;
|
|
533
|
+
let promotionsToday = 0;
|
|
534
|
+
let promotionIdsToday = [];
|
|
528
535
|
if (autoGates && Array.isArray(autoGates.promotionLog) && autoGates.promotionLog.length > 0) {
|
|
536
|
+
const todayKey = toLocalDayKey(new Date());
|
|
537
|
+
promotionIdsToday = autoGates.promotionLog
|
|
538
|
+
.filter((p) => p && p.timestamp && toLocalDayKey(p.timestamp) === todayKey)
|
|
539
|
+
.map((p) => p.gateId || p.id || 'unknown');
|
|
540
|
+
promotionsToday = promotionIdsToday.length;
|
|
529
541
|
const sorted = autoGates.promotionLog
|
|
530
542
|
.filter((p) => p.timestamp)
|
|
531
543
|
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
@@ -540,6 +552,8 @@ function computePreventionImpact(feedbackDir, gateStats) {
|
|
|
540
552
|
estimatedHoursSaved,
|
|
541
553
|
ruleCount,
|
|
542
554
|
lastPromotion,
|
|
555
|
+
promotionsToday,
|
|
556
|
+
promotionIdsToday: promotionIdsToday.slice(0, 5),
|
|
543
557
|
};
|
|
544
558
|
}
|
|
545
559
|
|
package/src/api/server.js
CHANGED
|
@@ -1567,7 +1567,69 @@ function compactNumber(value) {
|
|
|
1567
1567
|
return Number.isFinite(n) ? n : 0;
|
|
1568
1568
|
}
|
|
1569
1569
|
|
|
1570
|
-
function
|
|
1570
|
+
function isTodayScopedPrompt(prompt) {
|
|
1571
|
+
return /\btoday\b|\bthis day\b|\blast 24\b|\b24 hours\b/i.test(String(prompt || ''));
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
function getTodayGateAudit(gateAudit) {
|
|
1575
|
+
const days = gateAudit && Array.isArray(gateAudit.days) ? gateAudit.days : [];
|
|
1576
|
+
return days.length > 0 ? days[days.length - 1] : null;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
function formatGateBuckets(byGate) {
|
|
1580
|
+
return Object.entries(byGate || {})
|
|
1581
|
+
.filter(([, count]) => compactNumber(count) > 0)
|
|
1582
|
+
.sort((a, b) => compactNumber(b[1]) - compactNumber(a[1]))
|
|
1583
|
+
.slice(0, 3)
|
|
1584
|
+
.map(([gateId, count]) => `${gateId} (${compactNumber(count)}x)`);
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
function buildTodayGateAnswer(prompt, dashboardData, gateStats, gates) {
|
|
1588
|
+
if (!isTodayScopedPrompt(prompt)) return null;
|
|
1589
|
+
const lower = String(prompt || '').toLowerCase();
|
|
1590
|
+
const gateAudit = dashboardData.gateAudit || {};
|
|
1591
|
+
const prevention = dashboardData.prevention || {};
|
|
1592
|
+
const today = getTodayGateAudit(gateAudit) || { deny: 0, warn: 0, intercepted: 0, byGate: {} };
|
|
1593
|
+
const activeGateCount = gates.length || compactNumber(gateStats.totalGates);
|
|
1594
|
+
|
|
1595
|
+
if (/\b(activated|promoted|created|enabled)\b/.test(lower)) {
|
|
1596
|
+
const promotionsToday = compactNumber(prevention.promotionsToday);
|
|
1597
|
+
const promotedIds = Array.isArray(prevention.promotionIdsToday) ? prevention.promotionIdsToday.filter(Boolean) : [];
|
|
1598
|
+
return [
|
|
1599
|
+
`Gates activated today: ${promotionsToday}.`,
|
|
1600
|
+
`Active gates now: ${activeGateCount}.`,
|
|
1601
|
+
promotedIds.length > 0 ? `Promoted today: ${promotedIds.slice(0, 3).join(', ')}.` : '',
|
|
1602
|
+
].filter(Boolean);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
if (/\b(what|which)\b/.test(lower) && /\b(mistake|mistakes|block|blocked|prevent|prevented)\b/.test(lower)) {
|
|
1606
|
+
const gateBuckets = formatGateBuckets(today.byGate);
|
|
1607
|
+
return [
|
|
1608
|
+
`Today: ${compactNumber(today.deny)} blocked actions and ${compactNumber(today.warn)} warning checkpoints.`,
|
|
1609
|
+
gateBuckets.length > 0
|
|
1610
|
+
? `Top blocked/warned gates today: ${gateBuckets.join(', ')}.`
|
|
1611
|
+
: 'No per-gate blocked mistake names are present in today\'s local audit snapshot.',
|
|
1612
|
+
];
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
if (/\b(prevent|prevented|intercept|intercepted)\b/.test(lower)) {
|
|
1616
|
+
return [
|
|
1617
|
+
`Mistakes prevented today: ${compactNumber(today.intercepted)} interventions (${compactNumber(today.deny)} blocked, ${compactNumber(today.warn)} warned).`,
|
|
1618
|
+
`All-time blocked actions recorded: ${compactNumber(gateStats.blocked || gateStats.denied || gateStats.totalBlocked)}.`,
|
|
1619
|
+
];
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
if (/\b(block|blocked|deny|denied)\b/.test(lower)) {
|
|
1623
|
+
return [
|
|
1624
|
+
`Mistakes blocked today: ${compactNumber(today.deny)} deny decisions.`,
|
|
1625
|
+
`Warnings today: ${compactNumber(today.warn)}; all-time blocked actions recorded: ${compactNumber(gateStats.blocked || gateStats.denied || gateStats.totalBlocked)}.`,
|
|
1626
|
+
];
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
return null;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
function buildEnterpriseChatSection(topic, dashboardData, status, prompt) {
|
|
1571
1633
|
const approval = dashboardData.approval || {};
|
|
1572
1634
|
const gates = Array.isArray(dashboardData.gates) ? dashboardData.gates : [];
|
|
1573
1635
|
const gateStats = dashboardData.gateStats || {};
|
|
@@ -1585,6 +1647,13 @@ function buildEnterpriseChatSection(topic, dashboardData, status) {
|
|
|
1585
1647
|
};
|
|
1586
1648
|
}
|
|
1587
1649
|
if (topic === 'gates') {
|
|
1650
|
+
const todayGateAnswer = buildTodayGateAnswer(prompt, dashboardData, gateStats, gates);
|
|
1651
|
+
if (todayGateAnswer) {
|
|
1652
|
+
return {
|
|
1653
|
+
lines: todayGateAnswer,
|
|
1654
|
+
sources: ['gate audit', 'gate stats'],
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1588
1657
|
return {
|
|
1589
1658
|
lines: [
|
|
1590
1659
|
`Active gates: ${gates.length || compactNumber(gateStats.totalGates)}.`,
|
|
@@ -1635,7 +1704,7 @@ function buildEnterpriseChatSection(topic, dashboardData, status) {
|
|
|
1635
1704
|
|
|
1636
1705
|
function buildEnterpriseChatAnswer(prompt, dashboardData, status) {
|
|
1637
1706
|
const topic = classifyEnterpriseChatTopic(prompt);
|
|
1638
|
-
const section = buildEnterpriseChatSection(topic, dashboardData, status);
|
|
1707
|
+
const section = buildEnterpriseChatSection(topic, dashboardData, status, prompt);
|
|
1639
1708
|
|
|
1640
1709
|
return {
|
|
1641
1710
|
topic,
|