thumbgate 1.27.18 → 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 +6 -6
- package/.claude-plugin/plugin.json +4 -3
- package/.well-known/agentic-verify.txt +1 -0
- package/.well-known/llms.txt +33 -12
- package/.well-known/mcp/server-card.json +8 -8
- package/README.md +249 -30
- package/adapters/chatgpt/openapi.yaml +12 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/gemini/function-declarations.json +1 -0
- package/adapters/mcp/server-stdio.js +263 -11
- package/adapters/opencode/opencode.json +1 -1
- package/bench/thumbgate-bench.json +2 -2
- package/bin/cli.js +1429 -121
- package/bin/postinstall.js +1 -8
- package/config/gate-classifier-routing.json +98 -0
- package/config/gate-templates.json +216 -0
- package/config/gates/claim-verification.json +12 -0
- package/config/gates/default.json +31 -2
- package/config/github-about.json +2 -2
- package/config/mcp-allowlists.json +23 -13
- package/config/merge-quality-checks.json +0 -1
- package/config/model-candidates.json +121 -6
- package/config/post-deploy-marketing-pages.json +80 -0
- package/config/tessl-tiles.json +1 -3
- package/openapi/openapi.yaml +12 -0
- package/package.json +1 -1
- package/public/blog.html +4 -4
- package/public/codex-plugin.html +72 -20
- package/public/compare.html +31 -8
- package/public/dashboard.html +930 -166
- package/public/federal.html +2 -2
- package/public/guide.html +33 -13
- package/public/index.html +469 -111
- package/public/learn.html +183 -18
- package/public/lessons.html +168 -10
- package/public/numbers.html +7 -7
- package/public/pro.html +34 -11
- package/scripts/agent-memory-lifecycle.js +211 -0
- package/scripts/agent-readiness.js +20 -3
- package/scripts/agent-reward-model.js +53 -1
- package/scripts/auto-promote-gates.js +82 -10
- package/scripts/auto-wire-hooks.js +14 -0
- package/scripts/billing.js +93 -1
- package/scripts/bot-detection.js +61 -3
- package/scripts/build-metadata.js +50 -10
- package/scripts/cli-feedback.js +4 -2
- package/scripts/cli-schema.js +97 -0
- package/scripts/cli-telemetry.js +6 -1
- package/scripts/commercial-offer.js +82 -2
- package/scripts/context-manager.js +74 -6
- package/scripts/dashboard.js +68 -2
- package/scripts/export-databricks-bundle.js +5 -1
- package/scripts/export-dpo-pairs.js +7 -2
- package/scripts/feedback-loop.js +123 -1
- package/scripts/feedback-quality.js +87 -0
- package/scripts/filesystem-search.js +35 -10
- package/scripts/gate-stats.js +89 -0
- package/scripts/gates-engine.js +1176 -85
- package/scripts/gemini-embedding-policy.js +2 -1
- package/scripts/hook-runtime.js +20 -14
- package/scripts/hook-thumbgate-cache-updater.js +18 -2
- package/scripts/hybrid-feedback-context.js +142 -7
- package/scripts/lesson-inference.js +8 -3
- package/scripts/lesson-search.js +17 -1
- package/scripts/license.js +10 -10
- package/scripts/llm-client.js +169 -4
- package/scripts/local-model-profile.js +15 -8
- package/scripts/mcp-config.js +7 -1
- package/scripts/memory-scope-readiness.js +159 -0
- package/scripts/meta-agent-loop.js +36 -0
- package/scripts/operational-integrity.js +39 -5
- package/scripts/oss-pr-opportunity-scout.js +35 -5
- package/scripts/plausible-server-events.js +9 -6
- package/scripts/pro-local-dashboard.js +4 -4
- package/scripts/proxy-pointer-rag-guardrails.js +42 -1
- package/scripts/published-cli.js +0 -8
- package/scripts/rate-limiter.js +64 -13
- package/scripts/secret-scanner.js +44 -5
- package/scripts/security-scanner.js +260 -10
- package/scripts/self-distill-agent.js +3 -1
- package/scripts/seo-gsd.js +916 -7
- package/scripts/statusline-cache-path.js +17 -2
- package/scripts/statusline-local-stats.js +9 -1
- package/scripts/statusline-meta.js +28 -2
- package/scripts/statusline.sh +20 -4
- package/scripts/telemetry-analytics.js +357 -0
- package/scripts/thompson-sampling.js +31 -10
- package/scripts/thumbgate-bench.js +16 -1
- package/scripts/thumbgate-search.js +85 -19
- package/scripts/tool-registry.js +169 -1
- package/scripts/vector-store.js +45 -0
- package/scripts/workflow-sentinel.js +286 -53
- package/scripts/workspace-evolver.js +62 -2
- package/src/api/server.js +2683 -319
- package/scripts/bot-detector.js +0 -50
package/scripts/rate-limiter.js
CHANGED
|
@@ -6,42 +6,78 @@ const path = require('path');
|
|
|
6
6
|
const {
|
|
7
7
|
PRO_MONTHLY_PAYMENT_LINK,
|
|
8
8
|
PRO_PRICE_LABEL,
|
|
9
|
-
|
|
9
|
+
ENTERPRISE_PRICE_LABEL,
|
|
10
10
|
} = require('./commercial-offer');
|
|
11
11
|
|
|
12
12
|
const USAGE_FILE = path.join(process.env.HOME || '/tmp', '.thumbgate', 'usage-limits.json');
|
|
13
13
|
|
|
14
14
|
// ──────────────────────────────────────────────────────────
|
|
15
|
-
// Free tier:
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// Free tier: tight enough to create upgrade pressure after
|
|
16
|
+
// real usage. Captures and rules are capped so heavy users
|
|
17
|
+
// hit the wall within the first week, not the first quarter.
|
|
18
18
|
// ──────────────────────────────────────────────────────────
|
|
19
19
|
const FREE_TIER_LIMITS = {
|
|
20
|
-
capture_feedback: { daily:
|
|
21
|
-
prevention_rules: { daily:
|
|
20
|
+
capture_feedback: { daily: 2, lifetime: 10, label: 'feedback captures (2/day, 10 total on free)' },
|
|
21
|
+
prevention_rules: { daily: 2, lifetime: 3, label: 'prevention rules generated (2/day on free)' },
|
|
22
22
|
recall: { daily: 0, lifetime: 0, label: 'recall queries (Pro only)' },
|
|
23
23
|
search_lessons: { daily: 0, lifetime: 0, label: 'lesson searches (Pro only)' },
|
|
24
24
|
search_thumbgate: { daily: 0, lifetime: 0, label: 'ThumbGate searches (Pro only)' },
|
|
25
25
|
commerce_recall: { daily: 0, lifetime: 0, label: 'commerce recalls (Pro only)' },
|
|
26
26
|
export_dpo: { daily: 0, lifetime: 0, label: 'DPO exports (Pro only)' },
|
|
27
27
|
export_databricks: { daily: 0, lifetime: 0, label: 'Databricks exports (Pro only)' },
|
|
28
|
-
construct_context_pack: { daily:
|
|
28
|
+
construct_context_pack: { daily: 3, lifetime: Infinity, label: 'context packs (3/day on free)' },
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
const FREE_TIER_MAX_GATES =
|
|
31
|
+
const FREE_TIER_MAX_GATES = 3; // 3 active prevention rules on free; Pro is unlimited
|
|
32
|
+
const FREE_TIER_DAILY_BLOCKS = 2; // 3 gate blocks/day on free; after limit, deny → warn + upgrade CTA
|
|
32
33
|
|
|
33
|
-
const UPGRADE_MESSAGE = `Pro: ${PRO_PRICE_LABEL} — unlimited rules, recall, lesson search, dashboard, and exports: ${PRO_MONTHLY_PAYMENT_LINK}\n
|
|
34
|
+
const UPGRADE_MESSAGE = `Pro: ${PRO_PRICE_LABEL} — unlimited rules, recall, lesson search, dashboard, and exports: ${PRO_MONTHLY_PAYMENT_LINK}\n Enterprise: ${ENTERPRISE_PRICE_LABEL} after workflow qualification.`;
|
|
34
35
|
|
|
35
36
|
const PAYWALL_MESSAGES = {
|
|
36
|
-
|
|
37
|
+
capture_feedback: 'Free tier: 2 captures/day (10 total). Your feedback is stored locally — upgrade to capture unlimited.',
|
|
38
|
+
prevention_rules: 'Free tier includes 3 active prevention rules and 2 rule generations/day. Upgrade to Pro for unlimited rules.',
|
|
37
39
|
recall: 'Recall is a Pro feature. Your past feedback is stored locally — upgrade to search and reuse it.',
|
|
38
40
|
search_lessons: 'Lesson search is a Pro feature. Upgrade to find patterns in your agent\'s mistakes.',
|
|
41
|
+
construct_context_pack: 'Free tier: 3 context packs/day. Upgrade to Pro for unlimited.',
|
|
39
42
|
default: 'This feature requires Pro. Start Pro — card required; billed today.',
|
|
40
43
|
};
|
|
41
44
|
|
|
45
|
+
const TRIAL_DAYS = 7;
|
|
46
|
+
|
|
47
|
+
function getInstallAgeDays() {
|
|
48
|
+
try {
|
|
49
|
+
const { INSTALL_ID_PATH } = require('./cli-telemetry');
|
|
50
|
+
if (!fs.existsSync(INSTALL_ID_PATH)) return null;
|
|
51
|
+
// Use mtimeMs — birthtimeMs is unreliable on Linux (ext4 doesn't backdate creation time).
|
|
52
|
+
// The install-id file is written once at install, so mtime == creation time in practice.
|
|
53
|
+
const stat = fs.statSync(INSTALL_ID_PATH);
|
|
54
|
+
const created = stat.mtimeMs || stat.birthtimeMs;
|
|
55
|
+
if (!Number.isFinite(created) || created <= 0) return null;
|
|
56
|
+
return (Date.now() - created) / (1000 * 60 * 60 * 24);
|
|
57
|
+
} catch (_) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isInTrialPeriod() {
|
|
63
|
+
if (process.env.CI || process.env.GITHUB_ACTIONS) return false;
|
|
64
|
+
if (process.env.THUMBGATE_NO_TRIAL === '1') return false;
|
|
65
|
+
const age = getInstallAgeDays();
|
|
66
|
+
if (age === null) return false;
|
|
67
|
+
if (age < 0.0007) return false; // <1 minute old — just-created install, not a real trial
|
|
68
|
+
return age < TRIAL_DAYS;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function trialDaysRemaining() {
|
|
72
|
+
const age = getInstallAgeDays();
|
|
73
|
+
if (age === null) return 0;
|
|
74
|
+
return Math.max(0, Math.ceil(TRIAL_DAYS - age));
|
|
75
|
+
}
|
|
76
|
+
|
|
42
77
|
function isProTier(authContext) {
|
|
43
78
|
if (authContext && authContext.tier === 'pro') return true;
|
|
44
|
-
if (process.env.THUMBGATE_API_KEY
|
|
79
|
+
if (process.env.THUMBGATE_API_KEY) return true;
|
|
80
|
+
if (process.env.THUMBGATE_NO_RATE_LIMIT === '1') return true;
|
|
45
81
|
// Creator/dogfooding bypass: when the owner has the dev secret + bypass
|
|
46
82
|
// configured (env or ~/.config/thumbgate/dev.json), treat the install as Pro
|
|
47
83
|
// so marketing nudges and rate limits stop firing on the maintainer's own
|
|
@@ -57,6 +93,9 @@ function isProTier(authContext) {
|
|
|
57
93
|
const { isProLicensed } = require('./license');
|
|
58
94
|
if (isProLicensed()) return true;
|
|
59
95
|
} catch (_) {}
|
|
96
|
+
// 7-day reverse trial: new installs get full Pro access, then hit a clear
|
|
97
|
+
// hosted-sync/unlimited-rules pay moment while the product is still fresh.
|
|
98
|
+
if (isInTrialPeriod()) return true;
|
|
60
99
|
return false;
|
|
61
100
|
}
|
|
62
101
|
|
|
@@ -114,12 +153,18 @@ function checkLimit(action, authContext) {
|
|
|
114
153
|
const dailyCurrent = usage.counts[action] || 0;
|
|
115
154
|
const lifetimeCurrent = usage.lifetime[action] || 0;
|
|
116
155
|
|
|
156
|
+
const isCapture = action === 'capture_feedback';
|
|
157
|
+
const monthlyLink = isCapture
|
|
158
|
+
? 'https://buy.stripe.com/7sYfZhaiE1eSbO99uj3sI0d'
|
|
159
|
+
: PRO_MONTHLY_PAYMENT_LINK;
|
|
160
|
+
const upgradeMessage = `Pro: ${PRO_PRICE_LABEL} — unlimited rules, recall, lesson search, dashboard, and exports: ${monthlyLink}\n Enterprise: ${ENTERPRISE_PRICE_LABEL} after workflow qualification.`;
|
|
161
|
+
|
|
117
162
|
// Check lifetime limit first (the hard wall)
|
|
118
163
|
if (lifetimeLimit !== Infinity && lifetimeCurrent >= lifetimeLimit) {
|
|
119
164
|
const paywallMsg = PAYWALL_MESSAGES[action] || PAYWALL_MESSAGES.default;
|
|
120
165
|
return {
|
|
121
166
|
allowed: false,
|
|
122
|
-
message: `${paywallMsg}\n\n${
|
|
167
|
+
message: `${paywallMsg}\n\n${upgradeMessage}`,
|
|
123
168
|
used: lifetimeCurrent,
|
|
124
169
|
limit: lifetimeLimit,
|
|
125
170
|
limitType: 'lifetime',
|
|
@@ -128,9 +173,10 @@ function checkLimit(action, authContext) {
|
|
|
128
173
|
|
|
129
174
|
// Check daily limit
|
|
130
175
|
if (dailyLimit !== Infinity && dailyCurrent >= dailyLimit) {
|
|
176
|
+
const paywallMsg = PAYWALL_MESSAGES[action] || PAYWALL_MESSAGES.default;
|
|
131
177
|
return {
|
|
132
178
|
allowed: false,
|
|
133
|
-
message: `Daily limit reached. ${
|
|
179
|
+
message: `Daily limit reached. ${paywallMsg}\n\n${upgradeMessage}`,
|
|
134
180
|
used: dailyCurrent,
|
|
135
181
|
limit: dailyLimit,
|
|
136
182
|
limitType: 'daily',
|
|
@@ -179,12 +225,17 @@ function getUsage(action, authContext) {
|
|
|
179
225
|
module.exports = {
|
|
180
226
|
checkLimit,
|
|
181
227
|
getUsage,
|
|
228
|
+
getInstallAgeDays,
|
|
182
229
|
isProTier,
|
|
230
|
+
isInTrialPeriod,
|
|
231
|
+
trialDaysRemaining,
|
|
183
232
|
loadUsage,
|
|
184
233
|
saveUsage,
|
|
185
234
|
todayKey,
|
|
186
235
|
FREE_TIER_LIMITS,
|
|
187
236
|
FREE_TIER_MAX_GATES,
|
|
237
|
+
FREE_TIER_DAILY_BLOCKS,
|
|
238
|
+
TRIAL_DAYS,
|
|
188
239
|
UPGRADE_MESSAGE,
|
|
189
240
|
PAYWALL_MESSAGES,
|
|
190
241
|
USAGE_FILE,
|
|
@@ -55,6 +55,11 @@ const BASH_SECRET_READ_PREFIXES = [
|
|
|
55
55
|
];
|
|
56
56
|
|
|
57
57
|
const EDIT_LIKE_TOOLS = new Set(['Edit', 'Write', 'MultiEdit']);
|
|
58
|
+
const SAFE_SECRET_STORAGE_DIRS = [
|
|
59
|
+
'.resume_secrets',
|
|
60
|
+
'.thumbgate/secrets',
|
|
61
|
+
'.config/thumbgate',
|
|
62
|
+
];
|
|
58
63
|
|
|
59
64
|
function redactText(text) {
|
|
60
65
|
if (!text) return '';
|
|
@@ -172,6 +177,13 @@ function heuristicScanText(text, source = 'text') {
|
|
|
172
177
|
pattern.regex.lastIndex = 0;
|
|
173
178
|
let match = pattern.regex.exec(input);
|
|
174
179
|
while (match) {
|
|
180
|
+
// Safe test key bypass
|
|
181
|
+
const matchedString = match[0].toLowerCase();
|
|
182
|
+
if (pattern.id === 'generic_assignment' && (matchedString.includes('sk_test_') || matchedString.includes('test_token'))) {
|
|
183
|
+
match = pattern.regex.exec(input);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
175
187
|
findings.push({
|
|
176
188
|
id: pattern.id,
|
|
177
189
|
label: pattern.label,
|
|
@@ -295,6 +307,26 @@ function resolvePathToken(token, cwd) {
|
|
|
295
307
|
return path.join(cwd || process.cwd(), normalized);
|
|
296
308
|
}
|
|
297
309
|
|
|
310
|
+
function normalizePathForPolicy(filePath) {
|
|
311
|
+
return path.resolve(String(filePath || '').replace(/^~(?=\/|$)/, os.homedir()));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function isSafeSecretStoragePath(filePath) {
|
|
315
|
+
if (!filePath) return false;
|
|
316
|
+
const normalized = normalizePathForPolicy(filePath);
|
|
317
|
+
const home = normalizePathForPolicy(os.homedir());
|
|
318
|
+
return SAFE_SECRET_STORAGE_DIRS.some((dir) => {
|
|
319
|
+
const allowedRoot = path.join(home, dir);
|
|
320
|
+
return normalized === allowedRoot || normalized.startsWith(`${allowedRoot}${path.sep}`);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function isSafeSecretStorageWrite(toolName, toolInput = {}, cwd = process.cwd()) {
|
|
325
|
+
if (!EDIT_LIKE_TOOLS.has(toolName)) return false;
|
|
326
|
+
const paths = getToolInputPaths(toolInput, cwd);
|
|
327
|
+
return paths.length > 0 && paths.every((filePath) => isSafeSecretStoragePath(filePath));
|
|
328
|
+
}
|
|
329
|
+
|
|
298
330
|
function scanBashCommand(command, options = {}) {
|
|
299
331
|
const cwd = options.cwd || process.cwd();
|
|
300
332
|
const findings = [];
|
|
@@ -347,6 +379,7 @@ function scanHookInput(input = {}, options = {}) {
|
|
|
347
379
|
let provider = resolveProvider(options.provider);
|
|
348
380
|
let commandHash = null;
|
|
349
381
|
let fileHashes = [];
|
|
382
|
+
const safeSecretStorageWrite = isSafeSecretStorageWrite(toolName, toolInput, cwd);
|
|
350
383
|
|
|
351
384
|
const contentFields = [
|
|
352
385
|
toolInput.content,
|
|
@@ -376,11 +409,13 @@ function scanHookInput(input = {}, options = {}) {
|
|
|
376
409
|
}
|
|
377
410
|
}
|
|
378
411
|
|
|
379
|
-
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
412
|
+
if (!safeSecretStorageWrite) {
|
|
413
|
+
for (const content of contentFields) {
|
|
414
|
+
const result = scanText(content, { provider, source: 'tool_input' });
|
|
415
|
+
if (result.detected) {
|
|
416
|
+
provider = result.provider;
|
|
417
|
+
findings.push(...result.findings);
|
|
418
|
+
}
|
|
384
419
|
}
|
|
385
420
|
}
|
|
386
421
|
|
|
@@ -402,6 +437,8 @@ function buildSafeSummary(findings, prefix) {
|
|
|
402
437
|
module.exports = {
|
|
403
438
|
SECRET_PATTERNS,
|
|
404
439
|
SECRET_FILE_PATTERNS,
|
|
440
|
+
SAFE_SECRET_STORAGE_DIRS,
|
|
441
|
+
EDIT_LIKE_TOOLS,
|
|
405
442
|
redactText,
|
|
406
443
|
resolveProvider,
|
|
407
444
|
scanText,
|
|
@@ -409,6 +446,8 @@ module.exports = {
|
|
|
409
446
|
scanBashCommand,
|
|
410
447
|
scanHookInput,
|
|
411
448
|
classifySecretPath,
|
|
449
|
+
isSafeSecretStoragePath,
|
|
450
|
+
isSafeSecretStorageWrite,
|
|
412
451
|
buildSafeSummary,
|
|
413
452
|
tokenizeCommand,
|
|
414
453
|
};
|