thumbgate 1.27.18 → 1.27.20
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/commands/dashboard.md +15 -0
- package/.claude/commands/thumbgate-blocked.md +27 -0
- package/.claude/commands/thumbgate-dashboard.md +15 -0
- package/.claude/commands/thumbgate-doctor.md +30 -0
- package/.claude/commands/thumbgate-guard.md +36 -0
- package/.claude/commands/thumbgate-protect.md +30 -0
- package/.claude/commands/thumbgate-rules.md +30 -0
- 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 +246 -30
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/gcp/dfcx-webhook-gate.js +295 -0
- package/adapters/gemini/function-declarations.json +1 -0
- package/adapters/letta/README.md +41 -0
- package/adapters/letta/thumbgate-letta-adapter.js +133 -0
- package/adapters/mcp/server-stdio.js +263 -11
- package/adapters/opencode/opencode.json +1 -1
- package/adapters/policy-engine/ethicore-guardian-client.js +68 -0
- package/adapters/policy-engine/thumbgate-policy-engine-adapter.js +260 -0
- package/bench/observability-eval-suite.json +26 -0
- package/bench/thumbgate-bench.json +2 -2
- package/bin/cli.js +1456 -122
- package/bin/dashboard-cli.js +7 -0
- package/bin/postinstall.js +11 -27
- package/commands/dashboard.md +15 -0
- package/commands/thumbgate-dashboard.md +15 -0
- 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 +225 -100
- package/public/about.html +162 -0
- package/public/agent-manager.html +179 -0
- package/public/agents-cost-savings.html +153 -0
- package/public/ai-malpractice-prevention.html +818 -0
- 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 +28 -0
- package/public/assets/brand/thumbgate-mark-inline-v3.svg +18 -0
- package/public/assets/brand/thumbgate-mark-pro.svg +23 -0
- package/public/assets/brand/thumbgate-mark-team.svg +26 -0
- package/public/assets/brand/thumbgate-mark.svg +21 -0
- package/public/assets/brand/thumbgate-wordmark.svg +20 -0
- package/public/assets/claude-thumbgate-statusbar.svg +8 -0
- package/public/assets/codex-thumbgate-statusbar-test.svg +9 -0
- package/public/assets/legal-intake-control-flow.svg +66 -0
- package/public/blog.html +4 -4
- package/public/brand/thumbgate-mark.svg +19 -0
- package/public/brand/thumbgate-og.svg +16 -0
- package/public/chatgpt-app.html +330 -0
- package/public/codex-enterprise.html +123 -0
- package/public/codex-plugin.html +72 -20
- package/public/compare.html +31 -8
- package/public/dashboard.html +930 -166
- package/public/diagnostic.html +345 -0
- package/public/federal.html +2 -2
- package/public/guide.html +33 -13
- package/public/index.html +469 -111
- package/public/install.html +193 -0
- package/public/js/buyer-intent.js +672 -0
- package/public/learn.html +183 -18
- package/public/lessons.html +168 -10
- package/public/numbers.html +7 -7
- package/public/pricing.html +399 -0
- package/public/pro.html +34 -11
- package/scripts/action-receipts.js +324 -0
- package/scripts/activation-quickstart.js +187 -0
- package/scripts/agent-memory-lifecycle.js +211 -0
- package/scripts/agent-operations-planner.js +621 -0
- package/scripts/agent-readiness.js +20 -3
- package/scripts/agent-reward-model.js +53 -1
- package/scripts/ai-component-inventory.js +367 -0
- package/scripts/async-eval-observability.js +236 -0
- package/scripts/audit.js +65 -0
- package/scripts/auto-promote-gates.js +82 -10
- package/scripts/auto-wire-hooks.js +14 -0
- package/scripts/aws-blocks-guardrails.js +272 -0
- package/scripts/billing.js +93 -1
- package/scripts/bot-detection.js +61 -3
- package/scripts/build-metadata.js +50 -10
- package/scripts/classifier-routing.js +130 -0
- 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-chat.js +332 -0
- 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-aggregate.js +281 -0
- package/scripts/feedback-loop.js +123 -1
- package/scripts/feedback-quality.js +87 -0
- package/scripts/feedback-sanitizer.js +105 -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-stop-anti-claim.js +301 -0
- package/scripts/hook-thumbgate-cache-updater.js +18 -2
- package/scripts/hybrid-feedback-context.js +142 -7
- package/scripts/install-shim.js +87 -0
- 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/mcp-oauth.js +293 -0
- package/scripts/memory-scope-readiness.js +159 -0
- package/scripts/meta-agent-loop.js +36 -0
- package/scripts/noop-detect.js +285 -0
- package/scripts/operational-integrity.js +39 -5
- package/scripts/oss-pr-opportunity-scout.js +35 -5
- package/scripts/parallel-workflow-orchestrator.js +293 -0
- package/scripts/plan-gate.js +243 -0
- package/scripts/plausible-domain-config.js +99 -0
- 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/qa-scenario-planner.js +136 -0
- package/scripts/rate-limiter.js +64 -13
- package/scripts/repeat-metric.js +137 -0
- package/scripts/secret-fixture-tokens.js +61 -0
- package/scripts/secret-redaction.js +166 -0
- package/scripts/secret-scanner.js +44 -5
- package/scripts/security-scanner.js +260 -10
- package/scripts/self-distill-agent.js +3 -1
- package/scripts/self-harness-optimizer.js +141 -0
- package/scripts/self-healing-check.js +193 -0
- package/scripts/self-protection.js +90 -0
- package/scripts/seo-gsd.js +916 -7
- package/scripts/silent-failure-cluster.js +531 -0
- package/scripts/statusline-cache-path.js +17 -2
- package/scripts/statusline-cache-read.js +57 -0
- package/scripts/statusline-local-stats.js +9 -1
- package/scripts/statusline-meta.js +28 -2
- package/scripts/statusline.sh +20 -4
- package/scripts/sync-telemetry-from-prod.js +374 -0
- 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-contract-validator.js +76 -0
- package/scripts/tool-registry.js +169 -1
- package/scripts/trajectory-scorer.js +63 -0
- package/scripts/vector-store.js +45 -0
- package/scripts/verify-marketing-pages-deployed.js +212 -0
- package/scripts/visitor-journey.js +172 -0
- package/scripts/workflow-sentinel.js +286 -53
- package/scripts/workspace-evolver.js +62 -2
- package/src/api/server.js +2683 -319
- package/.claude-plugin/marketplace.json +0 -85
- package/adapters/chatgpt/openapi.yaml +0 -1695
- package/scripts/bot-detector.js +0 -50
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const MEMORY_TYPES = new Set(['episodic', 'semantic', 'procedural', 'preference', 'working']);
|
|
5
|
+
const MEMORY_SCOPES = new Set(['task', 'session', 'user', 'project', 'org']);
|
|
6
|
+
const HIGH_RISK_TERMS = new Set([
|
|
7
|
+
'billing',
|
|
8
|
+
'checkout',
|
|
9
|
+
'compliance',
|
|
10
|
+
'credential',
|
|
11
|
+
'data-loss',
|
|
12
|
+
'deploy',
|
|
13
|
+
'deployment',
|
|
14
|
+
'git',
|
|
15
|
+
'payment',
|
|
16
|
+
'production',
|
|
17
|
+
'release',
|
|
18
|
+
'secret',
|
|
19
|
+
'security',
|
|
20
|
+
'stripe',
|
|
21
|
+
'verification',
|
|
22
|
+
]);
|
|
23
|
+
const KNOWN_ENTITY_PATTERNS = [
|
|
24
|
+
['Claude Code', /\bclaude\s+code\b/i, 'agent'],
|
|
25
|
+
['Codex', /\bcodex\b/i, 'agent'],
|
|
26
|
+
['Cursor', /\bcursor\b/i, 'agent'],
|
|
27
|
+
['Gemini CLI', /\bgemini\s+cli\b/i, 'agent'],
|
|
28
|
+
['MCP', /\bmcp\b/i, 'protocol'],
|
|
29
|
+
['Stripe', /\bstripe\b/i, 'service'],
|
|
30
|
+
['GitHub', /\bgithub\b|\bgh\s+/i, 'service'],
|
|
31
|
+
['Railway', /\brailway\b/i, 'service'],
|
|
32
|
+
['Plausible', /\bplausible\b/i, 'service'],
|
|
33
|
+
['PostHog', /\bposthog\b/i, 'service'],
|
|
34
|
+
['SQLite', /\bsqlite\b|\bfts5\b/i, 'storage'],
|
|
35
|
+
['LanceDB', /\blancedb\b/i, 'storage'],
|
|
36
|
+
['Docker', /\bdocker\b/i, 'runtime'],
|
|
37
|
+
['npm', /\bnpm\b|\bnpx\b/i, 'runtime'],
|
|
38
|
+
];
|
|
5
39
|
|
|
6
40
|
function normalizeText(value) {
|
|
7
41
|
if (value === undefined || value === null) return '';
|
|
@@ -13,6 +47,178 @@ function normalizeMemoryType(value) {
|
|
|
13
47
|
return MEMORY_TYPES.has(normalized) ? normalized : 'episodic';
|
|
14
48
|
}
|
|
15
49
|
|
|
50
|
+
function tokenize(value) {
|
|
51
|
+
return normalizeText(value)
|
|
52
|
+
.toLowerCase()
|
|
53
|
+
.split(/[^a-z0-9_.:/-]+/)
|
|
54
|
+
.filter(Boolean);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function uniqueByName(entities) {
|
|
58
|
+
const seen = new Set();
|
|
59
|
+
return entities.filter((entity) => {
|
|
60
|
+
const key = normalizeText(entity.name).toLowerCase();
|
|
61
|
+
if (!key || seen.has(key)) return false;
|
|
62
|
+
seen.add(key);
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function collectMemoryText(memory = {}) {
|
|
68
|
+
return [
|
|
69
|
+
memory.title,
|
|
70
|
+
memory.content,
|
|
71
|
+
memory.context,
|
|
72
|
+
memory.whatWentWrong,
|
|
73
|
+
memory.whatToChange,
|
|
74
|
+
memory.whatWorked,
|
|
75
|
+
memory.domain,
|
|
76
|
+
memory.skill,
|
|
77
|
+
Array.isArray(memory.tags) ? memory.tags.join(' ') : memory.tags,
|
|
78
|
+
].filter(Boolean).join(' ');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function extractMemoryEntities(memory = {}) {
|
|
82
|
+
const text = collectMemoryText(memory);
|
|
83
|
+
const entities = [];
|
|
84
|
+
|
|
85
|
+
for (const [name, pattern, type] of KNOWN_ENTITY_PATTERNS) {
|
|
86
|
+
if (pattern.test(text)) entities.push({ name, type });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const commandMatches = text.match(/`([^`]+)`/g) || [];
|
|
90
|
+
for (const match of commandMatches) {
|
|
91
|
+
const command = match.slice(1, -1).trim();
|
|
92
|
+
if (/^(git|npm|npx|node|gh|curl|docker|python|pytest|stripe)\b/i.test(command)) {
|
|
93
|
+
entities.push({ name: command, type: 'command' });
|
|
94
|
+
} else if (/[./-]/.test(command)) {
|
|
95
|
+
entities.push({ name: command, type: 'path' });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const pathMatches = text.match(/\b(?:[a-z0-9_-]+\/)+[a-z0-9_.-]+\b/gi) || [];
|
|
100
|
+
for (const filePath of pathMatches.slice(0, 8)) {
|
|
101
|
+
entities.push({ name: filePath, type: 'path' });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return uniqueByName(entities).slice(0, 16);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function inferMemoryScope(memory = {}) {
|
|
108
|
+
const explicit = normalizeText(memory.scope || memory.memoryScope).toLowerCase();
|
|
109
|
+
if (MEMORY_SCOPES.has(explicit)) return explicit;
|
|
110
|
+
|
|
111
|
+
const text = collectMemoryText(memory).toLowerCase();
|
|
112
|
+
const tags = new Set(Array.isArray(memory.tags) ? memory.tags.map((tag) => normalizeText(tag).toLowerCase()) : []);
|
|
113
|
+
|
|
114
|
+
if (tags.has('preference') || /\b(prefer|style|tone|my preference|user preference)\b/.test(text)) return 'user';
|
|
115
|
+
if (tags.has('org') || tags.has('team') || /\b(enterprise|seat|team|shared|org|compliance|policy|approval)\b/.test(text)) return 'org';
|
|
116
|
+
if (tags.has('repo') || tags.has('project') || tags.has('release') || tags.has('deployment')
|
|
117
|
+
|| /\b(repo|repository|branch|ci|pull request|github|deploy|production|release|publish)\b/.test(text)) return 'project';
|
|
118
|
+
if (tags.has('session') || /\b(this session|current session|today|right now)\b/.test(text)) return 'session';
|
|
119
|
+
return 'task';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function scoreMemoryDecay(memory = {}, options = {}) {
|
|
123
|
+
const nowMs = options.now ? new Date(options.now).getTime() : Date.now();
|
|
124
|
+
const timestampMs = memory.timestamp ? new Date(memory.timestamp).getTime() : NaN;
|
|
125
|
+
const ageDays = Number.isFinite(timestampMs)
|
|
126
|
+
? Math.max(0, (nowMs - timestampMs) / (1000 * 60 * 60 * 24))
|
|
127
|
+
: null;
|
|
128
|
+
const textTokens = new Set(tokenize(collectMemoryText(memory)));
|
|
129
|
+
const tags = Array.isArray(memory.tags) ? memory.tags.map((tag) => normalizeText(tag).toLowerCase()) : [];
|
|
130
|
+
const highRisk = tags.some((tag) => HIGH_RISK_TERMS.has(tag))
|
|
131
|
+
|| [...textTokens].some((token) => HIGH_RISK_TERMS.has(token))
|
|
132
|
+
|| ['critical', 'high'].includes(normalizeText(memory.importance).toLowerCase());
|
|
133
|
+
|
|
134
|
+
if (highRisk) {
|
|
135
|
+
return {
|
|
136
|
+
state: 'sticky',
|
|
137
|
+
ageDays,
|
|
138
|
+
score: 1,
|
|
139
|
+
reason: 'high-risk memories stay retrievable until explicitly retired',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (ageDays === null) {
|
|
143
|
+
return {
|
|
144
|
+
state: 'review',
|
|
145
|
+
ageDays,
|
|
146
|
+
score: 0.6,
|
|
147
|
+
reason: 'memory has no timestamp, so it needs review before durable promotion',
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (ageDays > 180) {
|
|
151
|
+
return {
|
|
152
|
+
state: 'archive_candidate',
|
|
153
|
+
ageDays,
|
|
154
|
+
score: 0.2,
|
|
155
|
+
reason: 'old low-risk memory should be consolidated or archived',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (ageDays > 60) {
|
|
159
|
+
return {
|
|
160
|
+
state: 'review',
|
|
161
|
+
ageDays,
|
|
162
|
+
score: 0.55,
|
|
163
|
+
reason: 'older low-risk memory should be refreshed before it dominates recall',
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
state: 'active',
|
|
168
|
+
ageDays,
|
|
169
|
+
score: 0.85,
|
|
170
|
+
reason: 'recent memory remains eligible for recall',
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function scoreHybridMemoryMatch(query, memory = {}, options = {}) {
|
|
175
|
+
const queryTokens = new Set(tokenize(query));
|
|
176
|
+
const memoryTokens = new Set(tokenize(collectMemoryText(memory)));
|
|
177
|
+
const queryText = normalizeText(query).toLowerCase();
|
|
178
|
+
const memoryText = collectMemoryText(memory).toLowerCase();
|
|
179
|
+
const memoryEntities = extractMemoryEntities(memory);
|
|
180
|
+
const queryEntityNames = extractMemoryEntities({ content: query }).map((entity) => entity.name.toLowerCase());
|
|
181
|
+
|
|
182
|
+
let lexicalMatches = 0;
|
|
183
|
+
for (const token of queryTokens) {
|
|
184
|
+
if (memoryTokens.has(token)) lexicalMatches++;
|
|
185
|
+
}
|
|
186
|
+
const lexicalScore = queryTokens.size > 0 ? lexicalMatches / queryTokens.size : 0;
|
|
187
|
+
const phraseScore = queryText && memoryText.includes(queryText) ? 0.35 : 0;
|
|
188
|
+
const entityMatches = memoryEntities.filter((entity) => queryEntityNames.includes(entity.name.toLowerCase()));
|
|
189
|
+
const entityScore = queryEntityNames.length > 0 ? entityMatches.length / queryEntityNames.length : 0;
|
|
190
|
+
const decay = scoreMemoryDecay(memory, options);
|
|
191
|
+
const lifecycleScore = decay.state === 'archive_candidate' ? -0.15 : decay.state === 'sticky' ? 0.12 : 0;
|
|
192
|
+
const score = lexicalScore + phraseScore + (entityScore * 0.45) + lifecycleScore;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
score: Number(Math.max(0, score).toFixed(4)),
|
|
196
|
+
lexicalScore: Number(lexicalScore.toFixed(4)),
|
|
197
|
+
entityScore: Number(entityScore.toFixed(4)),
|
|
198
|
+
matchedEntities: entityMatches,
|
|
199
|
+
decayState: decay.state,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function buildMemoryLifecycleView(memory = {}, options = {}) {
|
|
204
|
+
const scope = inferMemoryScope(memory);
|
|
205
|
+
const entities = extractMemoryEntities(memory);
|
|
206
|
+
const decay = scoreMemoryDecay(memory, options);
|
|
207
|
+
const retrieval = scoreHybridMemoryMatch(options.query || '', memory, options);
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
scope,
|
|
211
|
+
entities,
|
|
212
|
+
decay,
|
|
213
|
+
retrievalHints: {
|
|
214
|
+
hybridScore: retrieval.score,
|
|
215
|
+
lexicalScore: retrieval.lexicalScore,
|
|
216
|
+
entityScore: retrieval.entityScore,
|
|
217
|
+
matchedEntities: retrieval.matchedEntities,
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
16
222
|
function buildMemoryLifecyclePolicy(input = {}) {
|
|
17
223
|
return {
|
|
18
224
|
generatedAt: normalizeText(input.generatedAt) || new Date().toISOString(),
|
|
@@ -91,6 +297,11 @@ function evaluateMemoryPromotion(memory = {}, policy = buildMemoryLifecyclePolic
|
|
|
91
297
|
|
|
92
298
|
module.exports = {
|
|
93
299
|
buildMemoryLifecyclePolicy,
|
|
300
|
+
buildMemoryLifecycleView,
|
|
94
301
|
evaluateMemoryPromotion,
|
|
302
|
+
extractMemoryEntities,
|
|
303
|
+
inferMemoryScope,
|
|
95
304
|
normalizeMemoryType,
|
|
305
|
+
scoreHybridMemoryMatch,
|
|
306
|
+
scoreMemoryDecay,
|
|
96
307
|
};
|