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
|
@@ -84,6 +84,11 @@ const {
|
|
|
84
84
|
const {
|
|
85
85
|
searchThumbgate,
|
|
86
86
|
} = require('../../scripts/thumbgate-search');
|
|
87
|
+
const {
|
|
88
|
+
importDocument,
|
|
89
|
+
listImportedDocuments,
|
|
90
|
+
readImportedDocument,
|
|
91
|
+
} = require('../../scripts/document-intake');
|
|
87
92
|
const { checkLimit, UPGRADE_MESSAGE } = require('../../scripts/rate-limiter');
|
|
88
93
|
const { generateOrgDashboard } = require('../../scripts/org-dashboard');
|
|
89
94
|
const {
|
|
@@ -119,7 +124,7 @@ const {
|
|
|
119
124
|
finalizeSession: finalizeFeedbackSession,
|
|
120
125
|
} = require('../../scripts/feedback-session');
|
|
121
126
|
|
|
122
|
-
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.
|
|
127
|
+
const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.4.0' };
|
|
123
128
|
const COMMERCE_CATEGORIES = [
|
|
124
129
|
'product_recommendation',
|
|
125
130
|
'brand_compliance',
|
|
@@ -145,6 +150,28 @@ function resolveSafePath(targetPath, { mustExist = false } = {}) {
|
|
|
145
150
|
return resolved;
|
|
146
151
|
}
|
|
147
152
|
|
|
153
|
+
function resolveImportDocumentPath(targetPath) {
|
|
154
|
+
const workspaceRoot = path.resolve(process.cwd());
|
|
155
|
+
const resolved = path.resolve(workspaceRoot, String(targetPath || ''));
|
|
156
|
+
const allowedRoots = [workspaceRoot, SAFE_DATA_DIR]
|
|
157
|
+
.filter(Boolean)
|
|
158
|
+
.map((root) => path.resolve(root));
|
|
159
|
+
const allowed = allowedRoots.some((root) => {
|
|
160
|
+
const relative = path.relative(root, resolved);
|
|
161
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (!allowed) {
|
|
165
|
+
throw new Error(`Path must stay within ${workspaceRoot} or ${SAFE_DATA_DIR}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!fs.existsSync(resolved)) {
|
|
169
|
+
throw new Error(`Path does not exist: ${resolved}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return resolved;
|
|
173
|
+
}
|
|
174
|
+
|
|
148
175
|
function toTextResult(payload) {
|
|
149
176
|
const text = typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2);
|
|
150
177
|
return {
|
|
@@ -421,6 +448,29 @@ async function callToolInner(name, args) {
|
|
|
421
448
|
source: args.source,
|
|
422
449
|
signal: args.signal,
|
|
423
450
|
}));
|
|
451
|
+
case 'import_document':
|
|
452
|
+
return toTextResult(importDocument({
|
|
453
|
+
filePath: args.filePath ? resolveImportDocumentPath(args.filePath) : null,
|
|
454
|
+
content: typeof args.content === 'string' ? args.content : null,
|
|
455
|
+
title: args.title,
|
|
456
|
+
sourceFormat: args.sourceFormat,
|
|
457
|
+
sourceUrl: args.sourceUrl,
|
|
458
|
+
tags: Array.isArray(args.tags) ? args.tags : [],
|
|
459
|
+
proposeGates: args.proposeGates !== false,
|
|
460
|
+
}));
|
|
461
|
+
case 'list_imported_documents':
|
|
462
|
+
return toTextResult(listImportedDocuments({
|
|
463
|
+
query: args.query || '',
|
|
464
|
+
tag: args.tag || null,
|
|
465
|
+
limit: Number(args.limit || 20),
|
|
466
|
+
}));
|
|
467
|
+
case 'get_imported_document': {
|
|
468
|
+
const document = readImportedDocument(args.documentId);
|
|
469
|
+
if (!document) {
|
|
470
|
+
throw new Error(`Imported document not found: ${args.documentId}`);
|
|
471
|
+
}
|
|
472
|
+
return toTextResult(document);
|
|
473
|
+
}
|
|
424
474
|
case 'feedback_stats':
|
|
425
475
|
return toTextResult(analyzeFeedback());
|
|
426
476
|
case 'diagnose_failure':
|
|
@@ -489,6 +539,19 @@ async function callToolInner(name, args) {
|
|
|
489
539
|
}));
|
|
490
540
|
case 'enforcement_matrix':
|
|
491
541
|
return toTextResult(listEnforcementMatrix());
|
|
542
|
+
case 'security_scan': {
|
|
543
|
+
const { scanCode, scanDependencyChange, scanGitDiff } = require('../../scripts/security-scanner');
|
|
544
|
+
if (args.diffMode) {
|
|
545
|
+
return toTextResult(scanGitDiff(args.content));
|
|
546
|
+
}
|
|
547
|
+
const codeResult = scanCode(args.content, args.filePath || '');
|
|
548
|
+
if (args.filePath && args.filePath.endsWith('package.json')) {
|
|
549
|
+
const supplyResult = scanDependencyChange('', args.content);
|
|
550
|
+
codeResult.findings = (codeResult.findings || []).concat(supplyResult.findings || []);
|
|
551
|
+
codeResult.detected = codeResult.detected || supplyResult.detected;
|
|
552
|
+
}
|
|
553
|
+
return toTextResult(codeResult);
|
|
554
|
+
}
|
|
492
555
|
case 'prevention_rules': {
|
|
493
556
|
const outputPath = args.outputPath ? resolveSafePath(args.outputPath) : undefined;
|
|
494
557
|
return toTextResult(writePreventionRules(outputPath, Number(args.minOccurrences || 2)));
|
|
@@ -680,6 +743,26 @@ async function callToolInner(name, args) {
|
|
|
680
743
|
return toTextResult(appendFeedbackContext(args.sessionId, args.message, args.role));
|
|
681
744
|
case 'finalize_feedback_session':
|
|
682
745
|
return toTextResult(finalizeFeedbackSession(args.sessionId));
|
|
746
|
+
case 'run_managed_lesson_agent': {
|
|
747
|
+
const { runManagedAgent } = require('../../scripts/managed-lesson-agent');
|
|
748
|
+
return toTextResult(await runManagedAgent({ dryRun: args.dryRun, limit: args.limit, model: args.model }));
|
|
749
|
+
}
|
|
750
|
+
case 'managed_agent_status': {
|
|
751
|
+
const { getManagedAgentStatus } = require('../../scripts/managed-lesson-agent');
|
|
752
|
+
return toTextResult(getManagedAgentStatus() || { message: 'No managed agent runs recorded yet.' });
|
|
753
|
+
}
|
|
754
|
+
case 'run_self_distill': {
|
|
755
|
+
const { runSelfDistill } = require('../../scripts/self-distill-agent');
|
|
756
|
+
return toTextResult(await runSelfDistill({ dryRun: args.dryRun, limit: args.limit, model: args.model }));
|
|
757
|
+
}
|
|
758
|
+
case 'self_distill_status': {
|
|
759
|
+
const { getSelfDistillStatus } = require('../../scripts/self-distill-agent');
|
|
760
|
+
return toTextResult(getSelfDistillStatus() || { message: 'No self-distill runs found.' });
|
|
761
|
+
}
|
|
762
|
+
case 'context_stuff_lessons': {
|
|
763
|
+
const { getAllLessonsForContext } = require('../../scripts/lesson-inference');
|
|
764
|
+
return toTextResult(getAllLessonsForContext({ maxTokenBudget: args.maxTokenBudget, signal: args.signal, format: args.format }));
|
|
765
|
+
}
|
|
683
766
|
default:
|
|
684
767
|
throw new Error(`Unsupported tool: ${name}`);
|
|
685
768
|
}
|
package/bin/cli.js
CHANGED
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
* npx thumbgate init --agent claude-code # scaffold + wire hooks for specific agent
|
|
9
9
|
* npx thumbgate gate-check # PreToolUse hook: pipe tool JSON via stdin, get verdict
|
|
10
10
|
* npx thumbgate capture # capture feedback
|
|
11
|
+
* npx thumbgate import-doc # import a local policy/runbook document and propose gates
|
|
11
12
|
* npx thumbgate export-dpo # export DPO training pairs
|
|
12
13
|
* npx thumbgate export-databricks # export Databricks-ready analytics bundle
|
|
13
14
|
* npx thumbgate stats # feedback analytics + Revenue-at-Risk
|
|
14
15
|
* npx thumbgate cfo # local operational billing summary
|
|
15
|
-
* npx thumbgate pro #
|
|
16
|
+
* npx thumbgate pro # solo dashboard + exports side lane
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
'use strict';
|
|
@@ -49,7 +50,9 @@ function upgradeNudge() {
|
|
|
49
50
|
if (isProTier()) return;
|
|
50
51
|
} catch (_) { return; }
|
|
51
52
|
process.stderr.write(
|
|
52
|
-
|
|
53
|
+
'\n Team rollout: start with the Workflow Hardening Sprint\n' +
|
|
54
|
+
' https://thumbgate-production.up.railway.app/#workflow-sprint-intake\n' +
|
|
55
|
+
`\n Solo side lane: Pro — ${PRO_PRICE_LABEL}\n` +
|
|
53
56
|
` ${PRO_CHECKOUT_URL}\n\n`
|
|
54
57
|
);
|
|
55
58
|
}
|
|
@@ -456,8 +459,78 @@ function setupForge() {
|
|
|
456
459
|
return true;
|
|
457
460
|
}
|
|
458
461
|
|
|
459
|
-
function
|
|
460
|
-
|
|
462
|
+
function detectAgent(projectDir) {
|
|
463
|
+
if (fs.existsSync(path.join(projectDir, '.claude'))) return 'claude-code';
|
|
464
|
+
if (fs.existsSync(path.join(projectDir, '.cursorrules'))) return 'cursor';
|
|
465
|
+
if (fs.existsSync(path.join(projectDir, '.cursor'))) return 'cursor';
|
|
466
|
+
if (fs.existsSync(path.join(projectDir, '.codex'))) return 'codex';
|
|
467
|
+
if (fs.existsSync(path.join(projectDir, '.gemini'))) return 'gemini';
|
|
468
|
+
if (fs.existsSync(path.join(projectDir, '.amp'))) return 'amp';
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function quickStart() {
|
|
473
|
+
const qsArgs = parseArgs(process.argv.slice(3));
|
|
474
|
+
const projectDir = process.cwd();
|
|
475
|
+
const detectedAgent = detectAgent(projectDir);
|
|
476
|
+
const agent = qsArgs.agent || detectedAgent || 'claude-code';
|
|
477
|
+
const thumbgateDir = path.join(projectDir, '.thumbgate');
|
|
478
|
+
const configPath = path.join(thumbgateDir, 'config.json');
|
|
479
|
+
const agentSource = qsArgs.agent ? 'specified' : (detectedAgent ? 'auto-detected' : 'default');
|
|
480
|
+
|
|
481
|
+
console.log(`\nthumbgate quick-start v${pkgVersion()}`);
|
|
482
|
+
console.log(`Agent: ${agent} (${agentSource})`);
|
|
483
|
+
console.log('');
|
|
484
|
+
|
|
485
|
+
// 1. Run init with the resolved agent so hook wiring uses the same target.
|
|
486
|
+
init({ ...qsArgs, agent });
|
|
487
|
+
|
|
488
|
+
// 2. Copy default gates
|
|
489
|
+
const defaultGates = path.join(PKG_ROOT, 'config', 'gates', 'default.json');
|
|
490
|
+
const targetGates = path.join(thumbgateDir, 'gates.json');
|
|
491
|
+
if (fs.existsSync(defaultGates)) {
|
|
492
|
+
fs.mkdirSync(thumbgateDir, { recursive: true });
|
|
493
|
+
fs.copyFileSync(defaultGates, targetGates);
|
|
494
|
+
console.log(' Copied default gates to .thumbgate/gates.json');
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// 3. Write config
|
|
498
|
+
let baseConfig = {};
|
|
499
|
+
if (fs.existsSync(configPath)) {
|
|
500
|
+
try {
|
|
501
|
+
baseConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
502
|
+
} catch (_) {
|
|
503
|
+
baseConfig = {};
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const config = {
|
|
507
|
+
...baseConfig,
|
|
508
|
+
selfDistillation: true,
|
|
509
|
+
contextStuffing: true,
|
|
510
|
+
maxTokenBudget: 10000,
|
|
511
|
+
autoGatePromotion: true,
|
|
512
|
+
agent,
|
|
513
|
+
version: pkgVersion(),
|
|
514
|
+
installId: baseConfig.installId || require('crypto').randomBytes(8).toString('hex'),
|
|
515
|
+
quickStart: true,
|
|
516
|
+
createdAt: baseConfig.createdAt || new Date().toISOString(),
|
|
517
|
+
};
|
|
518
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
519
|
+
console.log(' Created .thumbgate/config.json');
|
|
520
|
+
|
|
521
|
+
console.log('\n Enforcement setup complete:');
|
|
522
|
+
console.log(' Self-distillation: ON (agent auto-learns from outcomes)');
|
|
523
|
+
console.log(' Context-stuffing: ON (all lessons injected at session start)');
|
|
524
|
+
console.log(' Auto-gate promotion: ON (recurring failures become hard blocks)');
|
|
525
|
+
console.log(' Default gates: ' + (fs.existsSync(targetGates) ? 'loaded' : 'not found'));
|
|
526
|
+
console.log('\n Next steps:');
|
|
527
|
+
console.log(' npx thumbgate capture --feedback=down --context="what failed"');
|
|
528
|
+
console.log(' npx thumbgate stats');
|
|
529
|
+
console.log('');
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function init(cliArgs = parseArgs(process.argv.slice(3))) {
|
|
533
|
+
const args = { ...cliArgs };
|
|
461
534
|
|
|
462
535
|
// --wire-hooks only mode: skip scaffolding, just wire hooks
|
|
463
536
|
if (args['wire-hooks']) {
|
|
@@ -582,11 +655,11 @@ function init() {
|
|
|
582
655
|
trackEvent('cli_init', { command: 'init' });
|
|
583
656
|
proNudge();
|
|
584
657
|
console.log('');
|
|
585
|
-
console.log('
|
|
586
|
-
console.log(' │
|
|
587
|
-
console.log(' │
|
|
588
|
-
console.log(' │
|
|
589
|
-
console.log('
|
|
658
|
+
console.log(' ┌──────────────────────────────────────────────────────────┐');
|
|
659
|
+
console.log(' │ Teams: shared enforcement, CI gates, audit trails │');
|
|
660
|
+
console.log(' │ One correction protects every agent on your team. │');
|
|
661
|
+
console.log(' │ https://thumbgate-production.up.railway.app/pro │');
|
|
662
|
+
console.log(' └──────────────────────────────────────────────────────────┘');
|
|
590
663
|
|
|
591
664
|
try {
|
|
592
665
|
const { appendFunnelEvent } = require(path.join(PKG_ROOT, 'scripts', 'billing'));
|
|
@@ -696,8 +769,9 @@ function stats() {
|
|
|
696
769
|
console.log(` Repeated Failures detected: ${data.totalNegative}`);
|
|
697
770
|
console.log(` Estimated Operational Loss: $${revenueAtRisk}`);
|
|
698
771
|
console.log(' Action Required: Run "npx thumbgate rules" to generate guardrails.');
|
|
699
|
-
console.log(' Strategic Recommendation:
|
|
700
|
-
console.log('
|
|
772
|
+
console.log(' Strategic Recommendation: if this is a shared workflow problem, start the Workflow Hardening Sprint.');
|
|
773
|
+
console.log(' Team intake: https://thumbgate-production.up.railway.app/#workflow-sprint-intake');
|
|
774
|
+
console.log(' Solo side lane: npx thumbgate pro');
|
|
701
775
|
} else {
|
|
702
776
|
console.log('\n✅ System is currently high-reliability. No immediate revenue loss detected.');
|
|
703
777
|
}
|
|
@@ -804,11 +878,11 @@ function pro() {
|
|
|
804
878
|
const truthUrl = 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/docs/COMMERCIAL_TRUTH.md';
|
|
805
879
|
console.log('\nThumbGate Pro — Local Dashboard');
|
|
806
880
|
console.log('─'.repeat(50));
|
|
807
|
-
console.log('Self-serve
|
|
881
|
+
console.log('Self-serve side lane today: Pro ($19/mo or $149/yr).');
|
|
808
882
|
console.log('Every licensed Pro user gets a personal local dashboard on localhost.');
|
|
809
883
|
console.log('\nWhat is available:');
|
|
810
884
|
console.log(' - Local Pro dashboard: your own browser dashboard for search, gates, and DPO export');
|
|
811
|
-
console.log(' -
|
|
885
|
+
console.log(' - Team rollout path: shared hosted lessons, org visibility, and workflow proof');
|
|
812
886
|
console.log(' - Commercial truth doc: source of truth for traction, pricing, and proof claims');
|
|
813
887
|
console.log('\nLinks:');
|
|
814
888
|
console.log(` Buy Pro : ${PRO_CHECKOUT_URL}`);
|
|
@@ -1038,6 +1112,67 @@ function exportDatabricks() {
|
|
|
1038
1112
|
}
|
|
1039
1113
|
}
|
|
1040
1114
|
|
|
1115
|
+
function importDoc() {
|
|
1116
|
+
syncActiveProjectContext();
|
|
1117
|
+
const args = parseArgs(process.argv.slice(3));
|
|
1118
|
+
const positionalFilePath = process.argv.slice(3).find((arg) => !arg.startsWith('--'));
|
|
1119
|
+
const filePath = positionalFilePath || args.file || args.path || null;
|
|
1120
|
+
const inlineContent = typeof args.content === 'string' && args.content.trim()
|
|
1121
|
+
? args.content
|
|
1122
|
+
: (!filePath ? readStdinText().trim() : '');
|
|
1123
|
+
const tags = String(args.tags || args.tag || '')
|
|
1124
|
+
.split(',')
|
|
1125
|
+
.map((tag) => tag.trim())
|
|
1126
|
+
.filter(Boolean);
|
|
1127
|
+
|
|
1128
|
+
if (!filePath && !inlineContent) {
|
|
1129
|
+
console.error('Error: import-doc requires a file path, --content, or stdin text');
|
|
1130
|
+
process.exit(1);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
try {
|
|
1134
|
+
const { importDocument: importDocumentLocal } = require(path.join(PKG_ROOT, 'scripts', 'document-intake'));
|
|
1135
|
+
const document = importDocumentLocal({
|
|
1136
|
+
filePath,
|
|
1137
|
+
content: inlineContent || null,
|
|
1138
|
+
title: args.title || null,
|
|
1139
|
+
sourceFormat: args.format || args['source-format'] || null,
|
|
1140
|
+
sourceUrl: args.url || args['source-url'] || null,
|
|
1141
|
+
tags,
|
|
1142
|
+
proposeGates: args['no-proposals'] ? false : args.proposeGates !== 'false',
|
|
1143
|
+
});
|
|
1144
|
+
trackEvent('cli_import_doc', {
|
|
1145
|
+
command: 'import-doc',
|
|
1146
|
+
documentId: document.documentId,
|
|
1147
|
+
sourceFormat: document.sourceFormat,
|
|
1148
|
+
proposalCount: Array.isArray(document.proposals) ? document.proposals.length : 0,
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
const payload = {
|
|
1152
|
+
ok: true,
|
|
1153
|
+
document,
|
|
1154
|
+
};
|
|
1155
|
+
if (args.json) {
|
|
1156
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
console.log(`Imported document: ${document.title}`);
|
|
1161
|
+
console.log(` ID: ${document.documentId}`);
|
|
1162
|
+
console.log(` Format: ${document.sourceFormat}`);
|
|
1163
|
+
console.log(` Proposals: ${Array.isArray(document.proposals) ? document.proposals.length : 0}`);
|
|
1164
|
+
if (Array.isArray(document.proposals) && document.proposals.length > 0) {
|
|
1165
|
+
console.log('\nProposed gates:');
|
|
1166
|
+
for (const proposal of document.proposals.slice(0, 6)) {
|
|
1167
|
+
console.log(` - [${proposal.type}] ${proposal.title} (${proposal.action}/${proposal.severity})`);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
} catch (err) {
|
|
1171
|
+
console.error(err && err.message ? err.message : err);
|
|
1172
|
+
process.exit(1);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1041
1176
|
function obsidianExport() {
|
|
1042
1177
|
const args = parseArgs(process.argv.slice(3));
|
|
1043
1178
|
const { exportAll } = require(path.join(PKG_ROOT, 'scripts', 'obsidian-export'));
|
|
@@ -1295,6 +1430,20 @@ function sessionStart() {
|
|
|
1295
1430
|
const { analyzeFeedback } = require(path.join(PKG_ROOT, 'scripts', 'feedback-loop'));
|
|
1296
1431
|
const { refreshStatuslineCache } = require(path.join(PKG_ROOT, 'scripts', 'hook-thumbgate-cache-updater'));
|
|
1297
1432
|
refreshStatuslineCache(analyzeFeedback());
|
|
1433
|
+
|
|
1434
|
+
// Surface gate-program.md active rules so the agent starts aware of what is blocked.
|
|
1435
|
+
try {
|
|
1436
|
+
const { readGateProgram, extractBlockPatterns } = require(path.join(PKG_ROOT, 'scripts', 'meta-agent-loop'));
|
|
1437
|
+
const gateProgram = readGateProgram();
|
|
1438
|
+
if (gateProgram) {
|
|
1439
|
+
const blockPatterns = extractBlockPatterns(gateProgram);
|
|
1440
|
+
if (blockPatterns.length > 0) {
|
|
1441
|
+
process.stderr.write('\n[ThumbGate] Active hard-block rules from gate-program.md:\n');
|
|
1442
|
+
blockPatterns.forEach((p, i) => process.stderr.write(` ${i + 1}. ${p}\n`));
|
|
1443
|
+
process.stderr.write('\n');
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
} catch (_) { /* gate-program awareness is best-effort */ }
|
|
1298
1447
|
}
|
|
1299
1448
|
|
|
1300
1449
|
function installMcp() {
|
|
@@ -1365,6 +1514,7 @@ function help() {
|
|
|
1365
1514
|
console.log(' risk [flags] Train or query the boosted local risk scorer');
|
|
1366
1515
|
console.log(' doctor Audit runtime isolation, bootstrap context, and permission tier');
|
|
1367
1516
|
console.log(' dispatch Print a Dispatch-safe remote ops brief for phone-driven review sessions');
|
|
1517
|
+
console.log(' import-doc Import a local policy/runbook and propose reviewable gate candidates');
|
|
1368
1518
|
console.log(' export-dpo Export DPO training pairs (prompt/chosen/rejected JSONL)');
|
|
1369
1519
|
console.log(' export-databricks Export feedback logs + proof artifacts as a Databricks-ready analytics bundle');
|
|
1370
1520
|
console.log(' obsidian-export Export all feedback data as interlinked Obsidian markdown notes');
|
|
@@ -1373,6 +1523,9 @@ function help() {
|
|
|
1373
1523
|
console.log(' rules Generate prevention rules from repeated failures');
|
|
1374
1524
|
console.log(' optimize [PRO] Prune CLAUDE.md and migrate manual rules to Pre-Action Gates');
|
|
1375
1525
|
console.log(' force-gate <PATTERN> Immediately create a blocking gate from a pattern');
|
|
1526
|
+
console.log(' meta-agent Run meta-agent loop: generate + evaluate + promote prevention rules');
|
|
1527
|
+
console.log(' --dry-run Preview rules without writing');
|
|
1528
|
+
console.log(' --status Show last run summary');
|
|
1376
1529
|
console.log(' self-heal Run self-healing check and auto-fix');
|
|
1377
1530
|
console.log(' activate <KEY> Activate a Pro license key (from Stripe checkout)');
|
|
1378
1531
|
console.log(' pro Show Pro plan ($19/mo) + hosted pilot info');
|
|
@@ -1394,6 +1547,7 @@ function help() {
|
|
|
1394
1547
|
console.log(' npx thumbgate init');
|
|
1395
1548
|
console.log(' npx thumbgate stats');
|
|
1396
1549
|
console.log(' npx thumbgate cfo');
|
|
1550
|
+
console.log(' npx thumbgate import-doc docs/release-policy.md --json');
|
|
1397
1551
|
console.log(' npx thumbgate repair-github-marketplace --write');
|
|
1398
1552
|
console.log(' npx thumbgate lessons --query="verification" --limit=5');
|
|
1399
1553
|
console.log(' npx thumbgate model-fit');
|
|
@@ -1414,6 +1568,9 @@ switch (COMMAND) {
|
|
|
1414
1568
|
init();
|
|
1415
1569
|
upgradeNudge();
|
|
1416
1570
|
break;
|
|
1571
|
+
case 'quick-start':
|
|
1572
|
+
quickStart();
|
|
1573
|
+
break;
|
|
1417
1574
|
case 'install':
|
|
1418
1575
|
install();
|
|
1419
1576
|
break;
|
|
@@ -1559,6 +1716,10 @@ switch (COMMAND) {
|
|
|
1559
1716
|
case 'obsidian-export':
|
|
1560
1717
|
obsidianExport();
|
|
1561
1718
|
break;
|
|
1719
|
+
case 'import-doc':
|
|
1720
|
+
case 'import-document':
|
|
1721
|
+
importDoc();
|
|
1722
|
+
break;
|
|
1562
1723
|
case 'rules':
|
|
1563
1724
|
rules();
|
|
1564
1725
|
break;
|
|
@@ -1577,6 +1738,32 @@ switch (COMMAND) {
|
|
|
1577
1738
|
console.log(`Total auto-promoted gates: ${result.totalGates}`);
|
|
1578
1739
|
break;
|
|
1579
1740
|
}
|
|
1741
|
+
case 'meta-agent': {
|
|
1742
|
+
const metaArgs = parseArgs(process.argv.slice(3));
|
|
1743
|
+
if (metaArgs.status) {
|
|
1744
|
+
const { getMetaAgentStatus } = require(path.join(PKG_ROOT, 'scripts', 'meta-agent-loop'));
|
|
1745
|
+
const status = getMetaAgentStatus();
|
|
1746
|
+
if (!status) {
|
|
1747
|
+
console.log('No meta-agent runs recorded yet. Run: npx thumbgate meta-agent');
|
|
1748
|
+
} else {
|
|
1749
|
+
console.log(JSON.stringify(status, null, 2));
|
|
1750
|
+
}
|
|
1751
|
+
} else {
|
|
1752
|
+
const { runMetaAgentLoop } = require(path.join(PKG_ROOT, 'scripts', 'meta-agent-loop'));
|
|
1753
|
+
runMetaAgentLoop({ dryRun: Boolean(metaArgs['dry-run']), verbose: true })
|
|
1754
|
+
.then((manifest) => {
|
|
1755
|
+
console.log(`\nMeta-agent run complete.`);
|
|
1756
|
+
console.log(` Promoted : ${manifest.promotedCount} rule(s)`);
|
|
1757
|
+
console.log(` Reverted : ${manifest.revertedCount} candidate(s)`);
|
|
1758
|
+
if (manifest.dryRun) console.log(' [DRY RUN] No rules written.');
|
|
1759
|
+
})
|
|
1760
|
+
.catch((err) => {
|
|
1761
|
+
console.error('Meta-agent failed:', err.message);
|
|
1762
|
+
process.exit(1);
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
break;
|
|
1766
|
+
}
|
|
1580
1767
|
case 'self-heal':
|
|
1581
1768
|
selfHeal();
|
|
1582
1769
|
break;
|
package/bin/postinstall.js
CHANGED
|
@@ -15,7 +15,9 @@ if (isCI || isQuiet) process.exit(0);
|
|
|
15
15
|
const {
|
|
16
16
|
PRO_MONTHLY_PAYMENT_LINK,
|
|
17
17
|
PRO_PRICE_LABEL,
|
|
18
|
+
TEAM_PRICE_LABEL,
|
|
18
19
|
} = require('../scripts/commercial-offer');
|
|
20
|
+
const WORKFLOW_SPRINT_URL = 'https://thumbgate-production.up.railway.app/#workflow-sprint-intake';
|
|
19
21
|
|
|
20
22
|
process.stderr.write(`
|
|
21
23
|
┌─────────────────────────────────────────────────────┐
|
|
@@ -26,9 +28,13 @@ process.stderr.write(`
|
|
|
26
28
|
│ npx thumbgate init │
|
|
27
29
|
│ npx thumbgate stats │
|
|
28
30
|
│ │
|
|
29
|
-
│
|
|
30
|
-
│
|
|
31
|
+
│ Team rollout starts with the Workflow Hardening │
|
|
32
|
+
│ Sprint: ${WORKFLOW_SPRINT_URL} │
|
|
33
|
+
│ │
|
|
34
|
+
│ Solo side lane: Pro (personal local dashboard, │
|
|
35
|
+
│ DPO export) — ${PRO_PRICE_LABEL}: │
|
|
31
36
|
│ ${PRO_MONTHLY_PAYMENT_LINK} │
|
|
37
|
+
│ Team: ${TEAM_PRICE_LABEL} after intake. │
|
|
32
38
|
│ │
|
|
33
39
|
│ Or run: npx thumbgate pro │
|
|
34
40
|
│ │
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"max_actions": 2000,
|
|
3
|
+
"max_time_minutes": 600,
|
|
4
|
+
"profiles": {
|
|
5
|
+
"strict": {
|
|
6
|
+
"max_actions": 500,
|
|
7
|
+
"max_time_minutes": 150
|
|
8
|
+
},
|
|
9
|
+
"guided": {
|
|
10
|
+
"max_actions": 2000,
|
|
11
|
+
"max_time_minutes": 600
|
|
12
|
+
},
|
|
13
|
+
"autonomous": {
|
|
14
|
+
"max_actions": 5000,
|
|
15
|
+
"max_time_minutes": 1200
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"harness": "code-edit",
|
|
4
|
+
"description": "Specialized gates for code editing operations. Loaded when tool context involves Edit, Write, or MultiEdit tools.",
|
|
5
|
+
"gates": [
|
|
6
|
+
{
|
|
7
|
+
"id": "edit-env-direct",
|
|
8
|
+
"layer": "Execution",
|
|
9
|
+
"toolNames": ["Edit", "Write", "MultiEdit"],
|
|
10
|
+
"pattern": "\\.env$|\\.env\\.local$|\\.env\\.production$",
|
|
11
|
+
"action": "warn",
|
|
12
|
+
"severity": "high",
|
|
13
|
+
"message": "Editing a .env file directly. Ensure you are editing .env.example instead, and that no real secrets are committed."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "edit-lockfile-manual",
|
|
17
|
+
"layer": "Execution",
|
|
18
|
+
"toolNames": ["Edit", "Write"],
|
|
19
|
+
"pattern": "package-lock\\.json$|yarn\\.lock$|pnpm-lock\\.yaml$",
|
|
20
|
+
"action": "warn",
|
|
21
|
+
"severity": "medium",
|
|
22
|
+
"message": "Manually editing a lockfile is not recommended. Run npm install / yarn / pnpm install to regenerate it."
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "edit-generated-file",
|
|
26
|
+
"layer": "Execution",
|
|
27
|
+
"toolNames": ["Edit", "Write"],
|
|
28
|
+
"pattern": "dist/|build/|\\.min\\.js$|\\.min\\.css$",
|
|
29
|
+
"action": "warn",
|
|
30
|
+
"severity": "medium",
|
|
31
|
+
"message": "Editing a generated/built file. Edit the source instead and rebuild."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "edit-test-skip",
|
|
35
|
+
"layer": "Execution",
|
|
36
|
+
"toolNames": ["Edit", "Write", "MultiEdit"],
|
|
37
|
+
"pattern": "\\.skip\\(|test\\.skip|describe\\.skip|it\\.skip|xit\\(|xdescribe\\(",
|
|
38
|
+
"action": "warn",
|
|
39
|
+
"severity": "high",
|
|
40
|
+
"message": "Skipping a test. Only skip tests intentionally and document why — never skip to pass CI."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "edit-console-log-commit",
|
|
44
|
+
"layer": "Execution",
|
|
45
|
+
"toolNames": ["Edit", "Write"],
|
|
46
|
+
"pattern": "console\\.log\\(.*password|console\\.log\\(.*secret|console\\.log\\(.*token|console\\.log\\(.*api.?key",
|
|
47
|
+
"action": "block",
|
|
48
|
+
"severity": "critical",
|
|
49
|
+
"message": "Logging a secret value to console is blocked. Remove the log or redact the value."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "edit-version-file-without-sync",
|
|
53
|
+
"layer": "Execution",
|
|
54
|
+
"toolNames": ["Edit", "Write"],
|
|
55
|
+
"pattern": "\"version\"\\s*:\\s*\"",
|
|
56
|
+
"action": "warn",
|
|
57
|
+
"severity": "medium",
|
|
58
|
+
"message": "Editing a version field. Run node scripts/sync-version.js after changing package.json version to propagate to all targets."
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"harness": "db-write",
|
|
4
|
+
"description": "Specialized gates for database write operations. Loaded when tool context involves SQL mutations, SQLite writes, or ORM model changes.",
|
|
5
|
+
"gates": [
|
|
6
|
+
{
|
|
7
|
+
"id": "db-drop-table-production",
|
|
8
|
+
"layer": "Execution",
|
|
9
|
+
"pattern": "DROP\\s+TABLE(?!.*test|.*tmp|.*temp|.*_test|.*staging)",
|
|
10
|
+
"toolNames": ["Bash"],
|
|
11
|
+
"action": "block",
|
|
12
|
+
"severity": "critical",
|
|
13
|
+
"message": "DROP TABLE on a non-test table is blocked. Use a migration with a rollback path or confirm this is against a test/staging database."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "db-delete-without-where",
|
|
17
|
+
"layer": "Execution",
|
|
18
|
+
"pattern": "DELETE\\s+FROM\\s+\\w+\\s*;|DELETE\\s+FROM\\s+\\w+\\s*$",
|
|
19
|
+
"toolNames": ["Bash"],
|
|
20
|
+
"action": "block",
|
|
21
|
+
"severity": "critical",
|
|
22
|
+
"message": "DELETE without a WHERE clause deletes all rows. Add a WHERE clause or use TRUNCATE deliberately."
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "db-truncate-production",
|
|
26
|
+
"layer": "Execution",
|
|
27
|
+
"pattern": "TRUNCATE\\s+(?!.*test|.*tmp|.*temp)",
|
|
28
|
+
"toolNames": ["Bash"],
|
|
29
|
+
"action": "warn",
|
|
30
|
+
"severity": "critical",
|
|
31
|
+
"message": "TRUNCATE detected. Confirm this is against a test or staging table, not production data."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "db-raw-sql-no-migration",
|
|
35
|
+
"layer": "Execution",
|
|
36
|
+
"pattern": "ALTER\\s+TABLE|ADD\\s+COLUMN|DROP\\s+COLUMN|RENAME\\s+COLUMN",
|
|
37
|
+
"toolNames": ["Bash"],
|
|
38
|
+
"action": "warn",
|
|
39
|
+
"severity": "high",
|
|
40
|
+
"message": "Schema change detected outside a migration file. Create a versioned migration instead of running raw DDL."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "db-sqlite-delete-runtime",
|
|
44
|
+
"layer": "Execution",
|
|
45
|
+
"pattern": "rm\\s+.*\\.sqlite|unlink\\s+.*\\.sqlite|fs\\.rmSync.*\\.sqlite",
|
|
46
|
+
"toolNames": ["Bash"],
|
|
47
|
+
"action": "warn",
|
|
48
|
+
"severity": "high",
|
|
49
|
+
"message": "Deleting a SQLite database file. Confirm this is not the production lesson DB (.claude/memory/lessons.sqlite)."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "db-lancedb-wipe",
|
|
53
|
+
"layer": "Execution",
|
|
54
|
+
"pattern": "rm\\s+-rf\\s+.*lancedb|rmSync.*lancedb",
|
|
55
|
+
"toolNames": ["Bash"],
|
|
56
|
+
"action": "warn",
|
|
57
|
+
"severity": "high",
|
|
58
|
+
"message": "Wiping the LanceDB vector store. This deletes all embedded feedback memories. Confirm intent."
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|