thumbgate 1.3.0 → 1.4.0
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 +32 -13
- package/.claude-plugin/plugin.json +15 -2
- package/.well-known/llms.txt +60 -0
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +109 -20
- package/adapters/README.md +1 -1
- package/adapters/chatgpt/openapi.yaml +168 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/mcp/server-stdio.js +84 -1
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +200 -13
- package/bin/postinstall.js +8 -2
- package/config/budget.json +18 -0
- package/config/gates/code-edit.json +61 -0
- package/config/gates/db-write.json +61 -0
- package/config/gates/default.json +154 -3
- package/config/gates/deploy.json +61 -0
- package/config/github-about.json +2 -1
- package/config/merge-quality-checks.json +23 -0
- package/openapi/openapi.yaml +168 -0
- package/package.json +42 -10
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-codex-bridge/.mcp.json +1 -1
- package/plugins/claude-codex-bridge/scripts/codex-bridge.js +1 -3
- package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
- package/plugins/codex-profile/.mcp.json +1 -1
- package/plugins/codex-profile/INSTALL.md +27 -4
- package/plugins/codex-profile/README.md +33 -9
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
- package/plugins/opencode-profile/INSTALL.md +1 -1
- package/public/blog.html +73 -0
- package/public/compare/mem0.html +189 -0
- package/public/compare/speclock.html +180 -0
- package/public/compare.html +10 -2
- package/public/guide.html +2 -2
- package/public/guides/claude-code-prevent-repeated-mistakes.html +161 -0
- package/public/guides/codex-cli-guardrails.html +158 -0
- package/public/guides/cursor-prevent-repeated-mistakes.html +161 -0
- package/public/guides/pre-action-gates.html +162 -0
- package/public/guides/stop-repeated-ai-agent-mistakes.html +159 -0
- package/public/index.html +136 -50
- package/public/lessons.html +33 -24
- package/public/llm-context.md +140 -0
- package/public/pro.html +24 -22
- package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
- package/scripts/access-anomaly-detector.js +1 -1
- package/scripts/adk-consolidator.js +1 -5
- package/scripts/agent-security-hardening.js +4 -6
- package/scripts/agentic-data-pipeline.js +1 -3
- package/scripts/async-job-runner.js +1 -5
- package/scripts/audit-trail.js +1 -5
- package/scripts/background-agent-governance.js +2 -10
- package/scripts/billing.js +2 -16
- package/scripts/budget-enforcer.js +173 -0
- package/scripts/build-codex-plugin.js +152 -0
- package/scripts/check-congruence.js +132 -14
- package/scripts/commercial-offer.js +5 -7
- package/scripts/content-engine/linkedin-content-generator.js +154 -0
- package/scripts/content-engine/output/linkedin-memento-validation.md +17 -0
- package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +175 -0
- package/scripts/content-engine/reddit-thread-finder.js +154 -0
- package/scripts/context-engine.js +21 -6
- package/scripts/contextfs.js +1 -21
- package/scripts/dashboard.js +20 -0
- package/scripts/decision-journal.js +341 -0
- package/scripts/delegation-runtime.js +1 -5
- package/scripts/distribution-surfaces.js +26 -0
- package/scripts/document-intake.js +927 -0
- package/scripts/ephemeral-agent-store.js +1 -8
- package/scripts/evolution-state.js +1 -5
- package/scripts/experiment-tracker.js +1 -5
- package/scripts/export-databricks-bundle.js +1 -5
- package/scripts/export-hf-dataset.js +1 -5
- package/scripts/export-training.js +1 -5
- package/scripts/feedback-attribution.js +1 -16
- package/scripts/feedback-history-distiller.js +1 -16
- package/scripts/feedback-loop.js +1 -5
- package/scripts/feedback-root-consolidator.js +2 -21
- package/scripts/feedback-session.js +49 -0
- package/scripts/feedback-to-rules.js +188 -28
- package/scripts/filesystem-search.js +1 -9
- package/scripts/fs-utils.js +104 -0
- package/scripts/gates-engine.js +149 -4
- package/scripts/github-about.js +32 -8
- package/scripts/gtm-revenue-loop.js +1 -5
- package/scripts/harness-selector.js +148 -0
- package/scripts/hosted-job-launcher.js +1 -5
- package/scripts/hybrid-feedback-context.js +7 -33
- package/scripts/intervention-policy.js +58 -1
- package/scripts/lesson-db.js +3 -18
- package/scripts/lesson-inference.js +194 -16
- package/scripts/lesson-retrieval.js +60 -24
- package/scripts/llm-client.js +59 -0
- package/scripts/managed-lesson-agent.js +183 -0
- package/scripts/marketing-experiment.js +8 -22
- package/scripts/meta-agent-loop.js +624 -0
- package/scripts/metered-billing.js +1 -1
- package/scripts/money-watcher.js +1 -4
- package/scripts/obsidian-export.js +1 -5
- package/scripts/operational-integrity.js +15 -3
- package/scripts/org-dashboard.js +6 -1
- package/scripts/per-step-scoring.js +2 -4
- package/scripts/pr-manager.js +201 -19
- package/scripts/pro-features.js +3 -2
- package/scripts/prompt-dlp.js +3 -3
- package/scripts/prove-adapters.js +1 -5
- package/scripts/prove-attribution.js +1 -5
- package/scripts/prove-automation.js +1 -3
- package/scripts/prove-cloudflare-sandbox.js +1 -3
- package/scripts/prove-data-pipeline.js +1 -3
- package/scripts/prove-intelligence.js +1 -3
- package/scripts/prove-lancedb.js +1 -5
- package/scripts/prove-local-intelligence.js +1 -3
- package/scripts/prove-packaged-runtime.js +75 -9
- package/scripts/prove-predictive-insights.js +1 -3
- package/scripts/prove-training-export.js +1 -3
- package/scripts/prove-workflow-contract.js +1 -5
- package/scripts/rate-limiter.js +3 -1
- package/scripts/reddit-dm-outreach.js +14 -4
- package/scripts/schedule-manager.js +3 -5
- package/scripts/security-scanner.js +448 -0
- package/scripts/self-distill-agent.js +579 -0
- package/scripts/semantic-dedup.js +115 -0
- package/scripts/skill-exporter.js +1 -3
- package/scripts/skill-generator.js +1 -5
- package/scripts/social-analytics/engagement-audit.js +1 -18
- package/scripts/social-analytics/pollers/linkedin.js +26 -16
- package/scripts/social-analytics/publishers/linkedin.js +1 -1
- package/scripts/social-analytics/publishers/zernio.js +51 -0
- package/scripts/social-pipeline.js +1 -3
- package/scripts/social-post-hourly.js +47 -4
- package/scripts/statusline-links.js +6 -5
- package/scripts/statusline.sh +29 -153
- package/scripts/sync-branch-protection.js +340 -0
- package/scripts/tessl-export.js +1 -3
- package/scripts/thumbgate-search.js +32 -1
- package/scripts/tool-kpi-tracker.js +1 -1
- package/scripts/tool-registry.js +106 -2
- package/scripts/vector-store.js +1 -5
- package/scripts/weekly-auto-post.js +1 -1
- package/scripts/workflow-sentinel.js +91 -0
- package/skills/thumbgate/SKILL.md +1 -1
- package/src/api/server.js +273 -4
- package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
- /package/scripts/social-analytics/db/{social-analytics.db-wal → analytics.sqlite} +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const { resolveFeedbackDir } = require('./feedback-paths');
|
|
8
|
+
const { parseFeedbackFile, classifySignal, analyzeWithLLM, analyze, promoteToGates } = require('./feedback-to-rules');
|
|
9
|
+
const { inferStructuredLessonLLM, inferStructuredLesson, createLesson } = require('./lesson-inference');
|
|
10
|
+
const { isAvailable } = require('./llm-client');
|
|
11
|
+
|
|
12
|
+
const MAX_ENTRIES_PER_RUN = 20;
|
|
13
|
+
const DELAY_BETWEEN_CALLS_MS = 500;
|
|
14
|
+
const MANIFEST_DIR = path.join(os.homedir(), '.thumbgate');
|
|
15
|
+
const MANIFEST_PATH = path.join(MANIFEST_DIR, 'managed-agent-runs.jsonl');
|
|
16
|
+
|
|
17
|
+
function sleep(ms) {
|
|
18
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getProcessedIds() {
|
|
22
|
+
if (!fs.existsSync(MANIFEST_PATH)) return new Set();
|
|
23
|
+
const ids = new Set();
|
|
24
|
+
for (const line of fs.readFileSync(MANIFEST_PATH, 'utf8').split('\n')) {
|
|
25
|
+
const trimmed = line.trim();
|
|
26
|
+
if (!trimmed) continue;
|
|
27
|
+
try {
|
|
28
|
+
const run = JSON.parse(trimmed);
|
|
29
|
+
if (Array.isArray(run.processedIds)) {
|
|
30
|
+
for (const id of run.processedIds) ids.add(id);
|
|
31
|
+
}
|
|
32
|
+
} catch { /* skip */ }
|
|
33
|
+
}
|
|
34
|
+
return ids;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function writeManifest(manifest) {
|
|
38
|
+
fs.mkdirSync(MANIFEST_DIR, { recursive: true });
|
|
39
|
+
fs.appendFileSync(MANIFEST_PATH, JSON.stringify(manifest) + '\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getManagedAgentStatus() {
|
|
43
|
+
if (!fs.existsSync(MANIFEST_PATH)) return null;
|
|
44
|
+
const lines = fs.readFileSync(MANIFEST_PATH, 'utf8').split('\n').filter(Boolean);
|
|
45
|
+
if (lines.length === 0) return null;
|
|
46
|
+
try {
|
|
47
|
+
const last = JSON.parse(lines[lines.length - 1]);
|
|
48
|
+
return {
|
|
49
|
+
lastRun: last.runAt,
|
|
50
|
+
entriesProcessed: last.entriesProcessed,
|
|
51
|
+
lessonsCreated: last.lessonsCreated,
|
|
52
|
+
gatesPromoted: last.gatesPromoted,
|
|
53
|
+
model: last.model,
|
|
54
|
+
durationMs: last.durationMs,
|
|
55
|
+
totalRuns: lines.length,
|
|
56
|
+
};
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function runManagedAgent({ dryRun = false, limit, model } = {}) {
|
|
63
|
+
const startTime = Date.now();
|
|
64
|
+
const feedbackDir = resolveFeedbackDir();
|
|
65
|
+
const logPath = path.join(feedbackDir, 'feedback-log.jsonl');
|
|
66
|
+
const entries = parseFeedbackFile(logPath);
|
|
67
|
+
|
|
68
|
+
if (entries.length === 0) {
|
|
69
|
+
return { entriesProcessed: 0, lessonsCreated: 0, gatesPromoted: 0, model: 'none', durationMs: 0, message: 'No feedback entries found' };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const processedIds = getProcessedIds();
|
|
73
|
+
const pending = entries
|
|
74
|
+
.filter((e) => {
|
|
75
|
+
const id = e.id || e.feedbackId || e.timestamp;
|
|
76
|
+
return id && !processedIds.has(id);
|
|
77
|
+
})
|
|
78
|
+
.slice(0, limit || MAX_ENTRIES_PER_RUN);
|
|
79
|
+
|
|
80
|
+
if (pending.length === 0) {
|
|
81
|
+
return { entriesProcessed: 0, lessonsCreated: 0, gatesPromoted: 0, model: 'none', durationMs: Date.now() - startTime, message: 'All entries already processed' };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const useLLM = isAvailable();
|
|
85
|
+
const modelUsed = useLLM ? 'claude-haiku-4-5' : 'heuristic';
|
|
86
|
+
let lessonsCreated = 0;
|
|
87
|
+
const newProcessedIds = [];
|
|
88
|
+
|
|
89
|
+
for (const entry of pending) {
|
|
90
|
+
const id = entry.id || entry.feedbackId || entry.timestamp;
|
|
91
|
+
const signal = classifySignal(entry);
|
|
92
|
+
if (!signal) {
|
|
93
|
+
newProcessedIds.push(id);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const window = Array.isArray(entry.conversationWindow) ? entry.conversationWindow : [];
|
|
98
|
+
const context = entry.context || '';
|
|
99
|
+
|
|
100
|
+
let structuredLesson = null;
|
|
101
|
+
if (useLLM) {
|
|
102
|
+
structuredLesson = await inferStructuredLessonLLM(window, signal, context);
|
|
103
|
+
if (structuredLesson && !dryRun) {
|
|
104
|
+
await sleep(DELAY_BETWEEN_CALLS_MS);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!structuredLesson) {
|
|
109
|
+
structuredLesson = inferStructuredLesson(window, signal, context);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!dryRun && structuredLesson) {
|
|
113
|
+
try {
|
|
114
|
+
createLesson({
|
|
115
|
+
feedbackId: id,
|
|
116
|
+
signal,
|
|
117
|
+
inferredLesson: structuredLesson.action?.description || '',
|
|
118
|
+
triggerMessage: structuredLesson.examples?.[0]?.assistantAction || '',
|
|
119
|
+
priorSummary: '',
|
|
120
|
+
confidence: structuredLesson.confidence || 0.5,
|
|
121
|
+
tags: structuredLesson.tags || entry.tags || [],
|
|
122
|
+
metadata: { ...structuredLesson.metadata, managedAgent: true, format: structuredLesson.format },
|
|
123
|
+
});
|
|
124
|
+
lessonsCreated++;
|
|
125
|
+
} catch { /* lesson creation is best-effort */ }
|
|
126
|
+
} else if (dryRun && structuredLesson) {
|
|
127
|
+
lessonsCreated++;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
newProcessedIds.push(id);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Rule generation pass
|
|
134
|
+
let gatesPromoted = 0;
|
|
135
|
+
if (useLLM) {
|
|
136
|
+
const llmIssues = await analyzeWithLLM(entries);
|
|
137
|
+
if (llmIssues && llmIssues.length > 0) {
|
|
138
|
+
if (!dryRun) {
|
|
139
|
+
promoteToGates(llmIssues);
|
|
140
|
+
}
|
|
141
|
+
gatesPromoted = llmIssues.filter((i) => i.severity === 'critical').length;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
const report = analyze(entries);
|
|
145
|
+
gatesPromoted = report.recurringIssues.filter((i) => i.severity === 'critical').length;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const manifest = {
|
|
149
|
+
runAt: new Date().toISOString(),
|
|
150
|
+
entriesProcessed: pending.length,
|
|
151
|
+
lessonsCreated,
|
|
152
|
+
gatesPromoted,
|
|
153
|
+
model: modelUsed,
|
|
154
|
+
dryRun,
|
|
155
|
+
durationMs: Date.now() - startTime,
|
|
156
|
+
processedIds: newProcessedIds,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
if (!dryRun) {
|
|
160
|
+
writeManifest(manifest);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return manifest;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (require.main === module) {
|
|
167
|
+
const args = process.argv.slice(2);
|
|
168
|
+
const dryRun = args.includes('--dry-run');
|
|
169
|
+
const limitFlag = args.find((a) => a.startsWith('--limit'));
|
|
170
|
+
const limit = limitFlag ? Number(args[args.indexOf(limitFlag) + 1]) || MAX_ENTRIES_PER_RUN : undefined;
|
|
171
|
+
|
|
172
|
+
runManagedAgent({ dryRun, limit })
|
|
173
|
+
.then((result) => {
|
|
174
|
+
console.log(JSON.stringify(result, null, 2));
|
|
175
|
+
process.exit(0);
|
|
176
|
+
})
|
|
177
|
+
.catch((err) => {
|
|
178
|
+
console.error('Managed agent error:', err.message);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = { runManagedAgent, getManagedAgentStatus };
|
|
@@ -23,6 +23,7 @@ const path = require('path');
|
|
|
23
23
|
const { getFeedbackPaths, readJSONL } = require('./feedback-loop');
|
|
24
24
|
const { loadModel, saveModel, updateModel, samplePosteriors, getReliability } = require('./thompson-sampling');
|
|
25
25
|
const { buildResearchBrief } = require('./hf-papers');
|
|
26
|
+
const { ensureDir, readJsonl } = require('./fs-utils');
|
|
26
27
|
|
|
27
28
|
// ---------------------------------------------------------------------------
|
|
28
29
|
// Constants
|
|
@@ -80,27 +81,12 @@ function getMarketingPaths() {
|
|
|
80
81
|
};
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
function ensureDir(dirPath) {
|
|
84
|
-
if (!fs.existsSync(dirPath)) {
|
|
85
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
84
|
|
|
89
85
|
function appendJSONL(filePath, record) {
|
|
90
86
|
ensureDir(path.dirname(filePath));
|
|
91
87
|
fs.appendFileSync(filePath, `${JSON.stringify(record)}\n`);
|
|
92
88
|
}
|
|
93
89
|
|
|
94
|
-
function readJSONLFile(filePath) {
|
|
95
|
-
if (!fs.existsSync(filePath)) return [];
|
|
96
|
-
const lines = fs.readFileSync(filePath, 'utf-8').trim().split('\n').filter(Boolean);
|
|
97
|
-
const records = [];
|
|
98
|
-
for (const line of lines) {
|
|
99
|
-
try { records.push(JSON.parse(line)); } catch { /* skip bad lines */ }
|
|
100
|
-
}
|
|
101
|
-
return records;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
90
|
// ---------------------------------------------------------------------------
|
|
105
91
|
// Variant Generation
|
|
106
92
|
// ---------------------------------------------------------------------------
|
|
@@ -300,7 +286,7 @@ function recordVariantMetrics(params) {
|
|
|
300
286
|
}
|
|
301
287
|
|
|
302
288
|
const paths = getMarketingPaths();
|
|
303
|
-
const variants =
|
|
289
|
+
const variants = readJsonl(paths.variantsPath);
|
|
304
290
|
const variant = variants.find(v => v.id === params.variantId);
|
|
305
291
|
|
|
306
292
|
if (!variant) {
|
|
@@ -333,7 +319,7 @@ function selectWinners(params) {
|
|
|
333
319
|
}
|
|
334
320
|
|
|
335
321
|
const paths = getMarketingPaths();
|
|
336
|
-
const allVariants =
|
|
322
|
+
const allVariants = readJsonl(paths.variantsPath);
|
|
337
323
|
|
|
338
324
|
// Get latest state of each variant in this batch (last write wins)
|
|
339
325
|
const batchMap = new Map();
|
|
@@ -479,7 +465,7 @@ function extractPattern(variant) {
|
|
|
479
465
|
*/
|
|
480
466
|
function getWinningPatterns(channel, limit = 5) {
|
|
481
467
|
const paths = getMarketingPaths();
|
|
482
|
-
const winners =
|
|
468
|
+
const winners = readJsonl(paths.winnersPath);
|
|
483
469
|
return winners
|
|
484
470
|
.filter(w => w.channel === channel)
|
|
485
471
|
.slice(-limit)
|
|
@@ -496,7 +482,7 @@ function getWinningPatterns(channel, limit = 5) {
|
|
|
496
482
|
*/
|
|
497
483
|
function getKnowledgeBase(opts = {}) {
|
|
498
484
|
const paths = getMarketingPaths();
|
|
499
|
-
let entries =
|
|
485
|
+
let entries = readJsonl(paths.knowledgePath);
|
|
500
486
|
if (opts.channel) {
|
|
501
487
|
entries = entries.filter(e => e.channel === opts.channel);
|
|
502
488
|
}
|
|
@@ -509,9 +495,9 @@ function getKnowledgeBase(opts = {}) {
|
|
|
509
495
|
|
|
510
496
|
function updateMarketingProgress() {
|
|
511
497
|
const paths = getMarketingPaths();
|
|
512
|
-
const experiments =
|
|
513
|
-
const knowledge =
|
|
514
|
-
const winners =
|
|
498
|
+
const experiments = readJsonl(paths.experimentsPath);
|
|
499
|
+
const knowledge = readJsonl(paths.knowledgePath);
|
|
500
|
+
const winners = readJsonl(paths.winnersPath);
|
|
515
501
|
|
|
516
502
|
const channelStats = {};
|
|
517
503
|
for (const ch of MARKETING_CHANNELS) {
|