thumbgate 1.27.12 → 1.27.14

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.
Files changed (133) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.well-known/llms.txt +2 -1
  3. package/.well-known/mcp/server-card.json +1 -1
  4. package/README.md +2 -4
  5. package/adapters/claude/.mcp.json +2 -2
  6. package/adapters/mcp/server-stdio.js +1 -1
  7. package/adapters/opencode/opencode.json +1 -1
  8. package/adapters/policy-engine/ethicore-guardian-client.js +68 -0
  9. package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +260 -0
  10. package/bin/cli.js +78 -259
  11. package/config/gate-templates.json +0 -228
  12. package/config/gates/claim-verification.json +0 -18
  13. package/package.json +35 -25
  14. package/public/assets/brand/thumbgate-logo-transparent.svg +22 -0
  15. package/public/assets/brand/thumbgate-mark-inline-v3.svg +19 -0
  16. package/public/assets/brand/thumbgate-mark.svg +11 -5
  17. package/public/blog.html +0 -30
  18. package/public/brand/thumbgate-mark.svg +9 -5
  19. package/public/chatgpt-app.html +2 -2
  20. package/public/compare.html +2 -1
  21. package/public/dashboard.html +1 -1
  22. package/public/federal.html +1 -1
  23. package/public/index.html +95 -216
  24. package/public/learn.html +59 -35
  25. package/public/lessons.html +1 -1
  26. package/public/numbers.html +2 -2
  27. package/public/pro.html +7 -7
  28. package/scripts/agent-readiness.js +142 -0
  29. package/scripts/aws-blocks-guardrails.js +228 -0
  30. package/scripts/cli-schema.js +22 -10
  31. package/scripts/dashboard-chat.js +2 -1
  32. package/scripts/document-intake.js +1 -49
  33. package/scripts/durability/step.js +3 -3
  34. package/scripts/gate-stats.js +5 -11
  35. package/scripts/gates-engine.js +0 -49
  36. package/scripts/gemini-embedding-policy.js +2 -1
  37. package/scripts/hook-stop-anti-claim.js +116 -184
  38. package/scripts/hosted-config.js +0 -12
  39. package/scripts/lesson-search.js +1 -15
  40. package/scripts/llm-client.js +187 -5
  41. package/scripts/plausible-domain-config.js +3 -1
  42. package/scripts/seo-gsd.js +240 -1
  43. package/scripts/tool-registry.js +2 -2
  44. package/scripts/vector-store.js +44 -0
  45. package/scripts/workspace-evolver.js +62 -2
  46. package/src/api/server.js +340 -131
  47. package/public/assets/brand/thumbgate-mark-inline.svg +0 -15
  48. package/public/compare/adopt-ai.html +0 -219
  49. package/public/compare/agentix-labs.html +0 -197
  50. package/public/compare/ai-experience-orchestration.html +0 -216
  51. package/public/compare/anthropic-claude-for-legal.html +0 -260
  52. package/public/compare/anthropic-containment.html +0 -280
  53. package/public/compare/arcade.html +0 -175
  54. package/public/compare/arcjet.html +0 -239
  55. package/public/compare/bumblebee.html +0 -307
  56. package/public/compare/claude-code-hooks.html +0 -294
  57. package/public/compare/databricks-unity-ai-gateway.html +0 -215
  58. package/public/compare/fallow.html +0 -351
  59. package/public/compare/heidi.html +0 -233
  60. package/public/compare/mem0.html +0 -342
  61. package/public/compare/oak-and-sparrow-gatekeeper.html +0 -289
  62. package/public/compare/rein.html +0 -236
  63. package/public/compare/sigmashake.html +0 -256
  64. package/public/compare/speclock.html +0 -342
  65. package/public/guides/agent-harness-optimization.html +0 -342
  66. package/public/guides/agentic-web-governance.html +0 -406
  67. package/public/guides/ai-agent-governance-sprint.html +0 -415
  68. package/public/guides/ai-agent-pre-action-approval-gates.html +0 -401
  69. package/public/guides/ai-agent-workflow-migration-checklist.html +0 -392
  70. package/public/guides/ai-deployment-readiness.html +0 -415
  71. package/public/guides/ai-mode-ads-agent-governance.html +0 -401
  72. package/public/guides/ai-search-topical-presence.html +0 -342
  73. package/public/guides/autoresearch-agent-safety.html +0 -342
  74. package/public/guides/background-agent-governance.html +0 -358
  75. package/public/guides/best-tools-stop-ai-agents-breaking-production.html +0 -363
  76. package/public/guides/browser-automation-safety.html +0 -342
  77. package/public/guides/chatgpt-ads-trust.html +0 -353
  78. package/public/guides/claude-code-feedback.html +0 -339
  79. package/public/guides/claude-code-prevent-repeated-mistakes.html +0 -161
  80. package/public/guides/claude-code-skills-guardrails.html +0 -343
  81. package/public/guides/claude-desktop.html +0 -356
  82. package/public/guides/code-knowledge-graph-guardrails.html +0 -365
  83. package/public/guides/codex-cli-guardrails.html +0 -339
  84. package/public/guides/cursor-agent-guardrails.html +0 -339
  85. package/public/guides/cursor-prevent-repeated-mistakes.html +0 -161
  86. package/public/guides/database-agent-safety.html +0 -406
  87. package/public/guides/deepseek-v4-runtime-guardrails.html +0 -346
  88. package/public/guides/developer-machine-supply-chain-guardrails.html +0 -358
  89. package/public/guides/gcp-mcp-guardrails.html +0 -147
  90. package/public/guides/gemini-cli-feedback-memory.html +0 -339
  91. package/public/guides/gpt-5-5-model-evaluation.html +0 -358
  92. package/public/guides/internal-ai-engineering-stack-guardrails.html +0 -348
  93. package/public/guides/long-running-agent-context-management.html +0 -346
  94. package/public/guides/mcp-tool-governance.html +0 -401
  95. package/public/guides/multica-thumbgate-setup.html +0 -134
  96. package/public/guides/native-messaging-host-security.html +0 -342
  97. package/public/guides/policy-engine-pre-action-gates.html +0 -346
  98. package/public/guides/pre-action-checks.html +0 -342
  99. package/public/guides/pretooluse-hooks-vs-advisory-prompt-rules.html +0 -342
  100. package/public/guides/prompt-tricks-to-workflow-rules.html +0 -365
  101. package/public/guides/proxy-pointer-rag-guardrails.html +0 -352
  102. package/public/guides/rag-precision-tuning-guardrails.html +0 -352
  103. package/public/guides/reasoning-compression-guardrails.html +0 -346
  104. package/public/guides/relational-knowledge-ai-recommendations.html +0 -342
  105. package/public/guides/roo-code-alternative-cline.html +0 -339
  106. package/public/guides/semantic-programmatic-seo-guardrails.html +0 -352
  107. package/public/guides/seo-agent-skills-guardrails.html +0 -344
  108. package/public/guides/stop-repeated-ai-agent-mistakes.html +0 -342
  109. package/public/learn/ac-dc-runtime-enforcement.html +0 -277
  110. package/public/learn/agent-harness-pattern.html +0 -181
  111. package/public/learn/agent-identity-connector-governance.html +0 -146
  112. package/public/learn/agent-swarms-shared-gates.html +0 -173
  113. package/public/learn/agentic-enterprise-context-brain.html +0 -117
  114. package/public/learn/agentic-os-team-governance.html +0 -146
  115. package/public/learn/ai-agent-governance.html +0 -158
  116. package/public/learn/ai-agent-persistent-memory.html +0 -211
  117. package/public/learn/anthropomorphic-claim-gates.html +0 -180
  118. package/public/learn/background-agent-control-layer.html +0 -184
  119. package/public/learn/claude-code-goal-with-rubrics.html +0 -205
  120. package/public/learn/codex-role-plugins-need-governance.html +0 -125
  121. package/public/learn/cost-aware-agent-gate-routing.html +0 -173
  122. package/public/learn/databricks-unity-ai-gateway-runtime-governance.html +0 -157
  123. package/public/learn/deterministic-agent-workflows.html +0 -185
  124. package/public/learn/feedback-loop-vs-decision-layer.html +0 -283
  125. package/public/learn/from-prototype-to-production.html +0 -223
  126. package/public/learn/learn.css +0 -51
  127. package/public/learn/mcp-pre-action-checks-explained.html +0 -172
  128. package/public/learn/pretix-stripe-connect-marketplaces.html +0 -161
  129. package/public/learn/regulated-agent-execution-boundary.html +0 -196
  130. package/public/learn/spec-driven-development.html +0 -168
  131. package/public/learn/stop-ai-agent-force-push.html +0 -134
  132. package/public/learn/vibe-coding-safety-net.html +0 -142
  133. package/scripts/reddit-browser-notification-watch.js +0 -230
@@ -1,230 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
- const { chromium } = require('playwright-core');
7
-
8
- const DEFAULT_CDP_ENDPOINT = 'http://127.0.0.1:9222';
9
- const DEFAULT_STATE_FILE = path.resolve(__dirname, '..', '.thumbgate', 'reddit-browser-notification-state.json');
10
- const DEFAULT_EVENTS_FILE = path.resolve(__dirname, '..', '.thumbgate', 'reddit-browser-notifications.jsonl');
11
- const REDDIT_NOTIFICATIONS_URL = 'https://www.reddit.com/notifications';
12
-
13
- function resolveRuntimeFile(envName, defaultPath) {
14
- const configured = process.env[envName];
15
- return configured ? path.resolve(configured) : defaultPath;
16
- }
17
-
18
- function loadJson(filePath, fallback) {
19
- try {
20
- if (fs.existsSync(filePath)) return JSON.parse(fs.readFileSync(filePath, 'utf8'));
21
- } catch {
22
- // Ignore corrupt transient state; a later write will repair it.
23
- }
24
- return fallback;
25
- }
26
-
27
- function writeJson(filePath, value) {
28
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
29
- fs.writeFileSync(filePath, JSON.stringify(value, null, 2));
30
- }
31
-
32
- function appendJsonl(filePath, rows) {
33
- if (rows.length === 0) return;
34
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
35
- fs.appendFileSync(filePath, `${rows.map((row) => JSON.stringify(row)).join('\n')}\n`);
36
- }
37
-
38
- function fingerprintNotification(notification) {
39
- return [
40
- notification.author || '',
41
- notification.kind || '',
42
- notification.subreddit || '',
43
- notification.preview || '',
44
- notification.age || '',
45
- ].join('|').toLowerCase();
46
- }
47
-
48
- function scoreNotification(notification) {
49
- const text = `${notification.author || ''} ${notification.kind || ''} ${notification.preview || ''}`.toLowerCase();
50
- let score = 0;
51
- const reasons = [];
52
-
53
- if (/accepted your chat invite|chat invite/i.test(text)) {
54
- score += 5;
55
- reasons.push('chat_accepted');
56
- }
57
- if (/\b(interested|try|paid|diagnostic|workflow|failure|gate|thumbgate|thubgate)\b/i.test(text)) {
58
- score += 4;
59
- reasons.push('buyer_signal');
60
- }
61
- if (/\b(replied|mentioned)\b/i.test(text)) {
62
- score += 2;
63
- reasons.push('reply_or_mention');
64
- }
65
- if (/\b(spam|slop|bot|report|ignore all previous instructions)\b/i.test(text)) {
66
- score -= 5;
67
- reasons.push('hostile_or_meta');
68
- }
69
- if (/automoderator|mod-bot|minimum karma|removed|reviewed shortly/i.test(text)) {
70
- score -= 1;
71
- reasons.push('platform_moderation');
72
- }
73
-
74
- return { score, reasons };
75
- }
76
-
77
- function ageMinutes(age) {
78
- const text = String(age || '').trim().toLowerCase();
79
- if (!text || text === 'just now') return 0;
80
- const match = /^(\d+)\s*([mhdw])\s+ago$/.exec(text);
81
- if (!match) return Number.POSITIVE_INFINITY;
82
- const value = Number(match[1]);
83
- const unit = match[2];
84
- if (unit === 'm') return value;
85
- if (unit === 'h') return value * 60;
86
- if (unit === 'd') return value * 24 * 60;
87
- return value * 7 * 24 * 60;
88
- }
89
-
90
- function isAgeLine(line) {
91
- return /^(?:just now|\d+\s*[mhdw]\s+ago)$/i.test(String(line || '').trim());
92
- }
93
-
94
- function isRecentNotification(notification, maxAgeMinutes = 48 * 60) {
95
- return ageMinutes(notification.age) <= maxAgeMinutes;
96
- }
97
-
98
- function parseNotificationBlocks(bodyText) {
99
- const lines = String(bodyText || '')
100
- .split('\n')
101
- .map((line) => line.trim())
102
- .filter(Boolean);
103
- const notifications = [];
104
-
105
- for (let index = 0; index < lines.length; index += 1) {
106
- let author = lines[index];
107
- let kind = lines[index + 1] || '';
108
- let kindIndex = index + 1;
109
- if (isAgeLine(author)) continue;
110
-
111
- if (/\b(replied to|mentioned you|new mentions)\b/i.test(author)) {
112
- kind = author;
113
- kindIndex = index;
114
- const authorMatch = /^u\/([^\s]+)/i.exec(kind);
115
- author = authorMatch ? authorMatch[1] : author;
116
- }
117
-
118
- if (!kind || !/\b(accepted your chat invite|replied to|mentioned you|new mentions)\b/i.test(kind)) continue;
119
-
120
- const hasPreview = !/accepted your chat invite|new mentions/i.test(kind);
121
- const preview = hasPreview ? (lines[kindIndex + 1] || '') : '';
122
- const age = hasPreview ? (lines[kindIndex + 2] || '') : (lines[kindIndex + 1] || '');
123
- const subredditMatch = /\bin\s+r\/([A-Za-z0-9_]+)/.exec(kind);
124
- const notification = {
125
- author,
126
- kind,
127
- subreddit: subredditMatch ? subredditMatch[1] : null,
128
- preview,
129
- age,
130
- };
131
- const scored = scoreNotification(notification);
132
- notifications.push({
133
- ...notification,
134
- ...scored,
135
- ageMinutes: ageMinutes(notification.age),
136
- fingerprint: fingerprintNotification(notification),
137
- });
138
- }
139
-
140
- return notifications;
141
- }
142
-
143
- async function readRedditNotifications({
144
- cdpEndpoint = process.env.THUMBGATE_CHROME_CDP_ENDPOINT || DEFAULT_CDP_ENDPOINT,
145
- timeoutMs = Number(process.env.THUMBGATE_REDDIT_BROWSER_TIMEOUT_MS || 15000),
146
- } = {}) {
147
- const browser = await chromium.connectOverCDP(cdpEndpoint);
148
- const context = browser.contexts()[0] || await browser.newContext();
149
- const page = await context.newPage();
150
- try {
151
- await page.goto(REDDIT_NOTIFICATIONS_URL, { waitUntil: 'domcontentloaded', timeout: timeoutMs });
152
- await page.waitForTimeout(3000);
153
- const bodyText = await page.locator('body').innerText({ timeout: timeoutMs });
154
- return parseNotificationBlocks(bodyText);
155
- } finally {
156
- await page.close().catch(() => {});
157
- await browser.close().catch(() => {});
158
- }
159
- }
160
-
161
- async function run({ dryRun = false, now = new Date().toISOString() } = {}) {
162
- const stateFile = resolveRuntimeFile('THUMBGATE_REDDIT_BROWSER_STATE_FILE', DEFAULT_STATE_FILE);
163
- const eventsFile = resolveRuntimeFile('THUMBGATE_REDDIT_BROWSER_EVENTS_FILE', DEFAULT_EVENTS_FILE);
164
- const state = loadJson(stateFile, { seen: {} });
165
- const notifications = await readRedditNotifications();
166
- const fresh = notifications.filter((notification) => !state.seen[notification.fingerprint]);
167
- const actionable = fresh.filter((notification) => notification.score > 0 && isRecentNotification(notification));
168
- const rows = actionable.map((notification) => ({
169
- checkedAt: now,
170
- platform: 'reddit',
171
- source: 'browser_notifications',
172
- status: 'pending_review',
173
- ...notification,
174
- }));
175
-
176
- for (const notification of fresh) {
177
- state.seen[notification.fingerprint] = { seenAt: now, score: notification.score };
178
- }
179
- state.lastCheck = now;
180
-
181
- if (!dryRun) {
182
- writeJson(stateFile, state);
183
- appendJsonl(eventsFile, rows);
184
- }
185
-
186
- return {
187
- notifications: notifications.length,
188
- fresh: fresh.length,
189
- actionable: actionable.length,
190
- eventsFile,
191
- actionableItems: actionable,
192
- dryRun,
193
- };
194
- }
195
-
196
- function parseArgs(argv = process.argv.slice(2)) {
197
- return {
198
- dryRun: argv.includes('--dry-run'),
199
- json: argv.includes('--json'),
200
- };
201
- }
202
-
203
- if (require.main === module) {
204
- const args = parseArgs();
205
- run({ dryRun: args.dryRun })
206
- .then((result) => {
207
- if (args.json) {
208
- console.log(JSON.stringify(result, null, 2));
209
- } else {
210
- console.log(`[reddit-browser-watch] notifications=${result.notifications} fresh=${result.fresh} actionable=${result.actionable} dryRun=${result.dryRun}`);
211
- for (const item of result.actionableItems) {
212
- console.log(`- score=${item.score} author=${item.author} kind=${item.kind} preview=${item.preview.slice(0, 120)}`);
213
- }
214
- }
215
- })
216
- .catch((err) => {
217
- console.error(`[reddit-browser-watch] ${err.message}`);
218
- process.exitCode = 1;
219
- });
220
- }
221
-
222
- module.exports = {
223
- fingerprintNotification,
224
- ageMinutes,
225
- isRecentNotification,
226
- parseNotificationBlocks,
227
- readRedditNotifications,
228
- run,
229
- scoreNotification,
230
- };