thumbgate 1.2.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.
Files changed (160) hide show
  1. package/.claude-plugin/README.md +4 -4
  2. package/.claude-plugin/marketplace.json +32 -13
  3. package/.claude-plugin/plugin.json +15 -2
  4. package/.well-known/llms.txt +60 -0
  5. package/.well-known/mcp/server-card.json +1 -1
  6. package/README.md +133 -23
  7. package/adapters/README.md +1 -1
  8. package/adapters/chatgpt/openapi.yaml +168 -0
  9. package/adapters/claude/.mcp.json +2 -2
  10. package/adapters/codex/config.toml +2 -2
  11. package/adapters/mcp/server-stdio.js +85 -2
  12. package/adapters/opencode/opencode.json +1 -1
  13. package/bin/cli.js +215 -19
  14. package/bin/postinstall.js +8 -2
  15. package/config/budget.json +18 -0
  16. package/config/gates/code-edit.json +61 -0
  17. package/config/gates/db-write.json +61 -0
  18. package/config/gates/default.json +154 -3
  19. package/config/gates/deploy.json +61 -0
  20. package/config/github-about.json +2 -1
  21. package/config/merge-quality-checks.json +23 -0
  22. package/config/model-tiers.json +11 -0
  23. package/openapi/openapi.yaml +168 -0
  24. package/package.json +47 -13
  25. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
  26. package/plugins/claude-codex-bridge/.mcp.json +1 -1
  27. package/plugins/claude-codex-bridge/scripts/codex-bridge.js +1 -3
  28. package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
  29. package/plugins/codex-profile/.mcp.json +1 -1
  30. package/plugins/codex-profile/INSTALL.md +27 -4
  31. package/plugins/codex-profile/README.md +33 -9
  32. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
  33. package/plugins/cursor-marketplace/README.md +2 -2
  34. package/plugins/cursor-marketplace/commands/capture-feedback.md +2 -2
  35. package/plugins/cursor-marketplace/rules/feedback-capture.mdc +3 -3
  36. package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +3 -2
  37. package/plugins/opencode-profile/INSTALL.md +1 -1
  38. package/public/blog.html +73 -0
  39. package/public/compare/mem0.html +189 -0
  40. package/public/compare/speclock.html +180 -0
  41. package/public/compare.html +12 -4
  42. package/public/guide.html +5 -5
  43. package/public/guides/claude-code-prevent-repeated-mistakes.html +161 -0
  44. package/public/guides/codex-cli-guardrails.html +158 -0
  45. package/public/guides/cursor-prevent-repeated-mistakes.html +161 -0
  46. package/public/guides/pre-action-gates.html +162 -0
  47. package/public/guides/stop-repeated-ai-agent-mistakes.html +159 -0
  48. package/public/index.html +169 -70
  49. package/public/learn/ai-agent-persistent-memory.html +1 -0
  50. package/public/lessons.html +334 -17
  51. package/public/llm-context.md +140 -0
  52. package/public/pro.html +24 -22
  53. package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
  54. package/scripts/access-anomaly-detector.js +1 -1
  55. package/scripts/adk-consolidator.js +1 -5
  56. package/scripts/agent-security-hardening.js +4 -6
  57. package/scripts/agentic-data-pipeline.js +1 -3
  58. package/scripts/async-job-runner.js +1 -5
  59. package/scripts/audit-trail.js +7 -5
  60. package/scripts/background-agent-governance.js +2 -10
  61. package/scripts/billing.js +2 -16
  62. package/scripts/budget-enforcer.js +173 -0
  63. package/scripts/build-codex-plugin.js +152 -0
  64. package/scripts/capture-railway-diagnostics.sh +97 -0
  65. package/scripts/check-congruence.js +133 -15
  66. package/scripts/claude-feedback-sync.js +320 -0
  67. package/scripts/cli-telemetry.js +4 -1
  68. package/scripts/commercial-offer.js +5 -7
  69. package/scripts/content-engine/linkedin-content-generator.js +154 -0
  70. package/scripts/content-engine/output/linkedin-memento-validation.md +17 -0
  71. package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +175 -0
  72. package/scripts/content-engine/reddit-thread-finder.js +154 -0
  73. package/scripts/context-engine.js +21 -6
  74. package/scripts/contextfs.js +33 -44
  75. package/scripts/dashboard.js +104 -0
  76. package/scripts/decision-journal.js +341 -0
  77. package/scripts/delegation-runtime.js +1 -5
  78. package/scripts/distribution-surfaces.js +26 -0
  79. package/scripts/document-intake.js +927 -0
  80. package/scripts/ephemeral-agent-store.js +1 -8
  81. package/scripts/evolution-state.js +1 -5
  82. package/scripts/experiment-tracker.js +1 -5
  83. package/scripts/export-databricks-bundle.js +1 -5
  84. package/scripts/export-hf-dataset.js +1 -5
  85. package/scripts/export-training.js +1 -5
  86. package/scripts/feedback-attribution.js +1 -16
  87. package/scripts/feedback-history-distiller.js +1 -16
  88. package/scripts/feedback-loop.js +17 -5
  89. package/scripts/feedback-root-consolidator.js +2 -21
  90. package/scripts/feedback-session.js +49 -0
  91. package/scripts/feedback-to-rules.js +188 -28
  92. package/scripts/filesystem-search.js +1 -9
  93. package/scripts/fs-utils.js +104 -0
  94. package/scripts/gates-engine.js +149 -4
  95. package/scripts/github-about.js +32 -8
  96. package/scripts/gtm-revenue-loop.js +1 -5
  97. package/scripts/harness-selector.js +148 -0
  98. package/scripts/hosted-job-launcher.js +1 -5
  99. package/scripts/hybrid-feedback-context.js +7 -33
  100. package/scripts/intervention-policy.js +753 -0
  101. package/scripts/lesson-db.js +3 -18
  102. package/scripts/lesson-inference.js +194 -16
  103. package/scripts/lesson-retrieval.js +60 -24
  104. package/scripts/llm-client.js +59 -0
  105. package/scripts/local-model-profile.js +18 -2
  106. package/scripts/managed-lesson-agent.js +183 -0
  107. package/scripts/marketing-experiment.js +8 -22
  108. package/scripts/meta-agent-loop.js +624 -0
  109. package/scripts/metered-billing.js +1 -1
  110. package/scripts/model-tier-router.js +10 -1
  111. package/scripts/money-watcher.js +1 -4
  112. package/scripts/obsidian-export.js +1 -5
  113. package/scripts/operational-integrity.js +369 -34
  114. package/scripts/org-dashboard.js +6 -1
  115. package/scripts/per-step-scoring.js +2 -4
  116. package/scripts/pr-manager.js +201 -19
  117. package/scripts/pro-features.js +3 -2
  118. package/scripts/prompt-dlp.js +3 -3
  119. package/scripts/prove-adapters.js +2 -5
  120. package/scripts/prove-attribution.js +1 -5
  121. package/scripts/prove-automation.js +3 -5
  122. package/scripts/prove-cloudflare-sandbox.js +1 -3
  123. package/scripts/prove-data-pipeline.js +1 -3
  124. package/scripts/prove-intelligence.js +1 -3
  125. package/scripts/prove-lancedb.js +1 -5
  126. package/scripts/prove-local-intelligence.js +1 -3
  127. package/scripts/prove-packaged-runtime.js +326 -0
  128. package/scripts/prove-predictive-insights.js +1 -3
  129. package/scripts/prove-runtime.js +13 -0
  130. package/scripts/prove-training-export.js +1 -3
  131. package/scripts/prove-workflow-contract.js +1 -5
  132. package/scripts/rate-limiter.js +6 -4
  133. package/scripts/reddit-dm-outreach.js +14 -4
  134. package/scripts/schedule-manager.js +3 -5
  135. package/scripts/security-scanner.js +448 -0
  136. package/scripts/self-distill-agent.js +579 -0
  137. package/scripts/semantic-dedup.js +115 -0
  138. package/scripts/skill-exporter.js +1 -3
  139. package/scripts/skill-generator.js +1 -5
  140. package/scripts/social-analytics/engagement-audit.js +1 -18
  141. package/scripts/social-analytics/pollers/linkedin.js +26 -16
  142. package/scripts/social-analytics/publishers/linkedin.js +1 -1
  143. package/scripts/social-analytics/publishers/zernio.js +51 -0
  144. package/scripts/social-pipeline.js +1 -3
  145. package/scripts/social-post-hourly.js +47 -4
  146. package/scripts/statusline-links.js +6 -5
  147. package/scripts/statusline-local-stats.js +2 -0
  148. package/scripts/statusline.sh +38 -7
  149. package/scripts/sync-branch-protection.js +340 -0
  150. package/scripts/tessl-export.js +1 -3
  151. package/scripts/thumbgate-search.js +32 -1
  152. package/scripts/tool-kpi-tracker.js +1 -1
  153. package/scripts/tool-registry.js +108 -4
  154. package/scripts/vector-store.js +1 -5
  155. package/scripts/weekly-auto-post.js +1 -1
  156. package/scripts/workflow-sentinel.js +205 -4
  157. package/skills/thumbgate/SKILL.md +2 -2
  158. package/src/api/server.js +273 -4
  159. package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
  160. /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 {
@@ -105,7 +110,7 @@ function enforceLimit(action) {
105
110
  const limit = checkLimit(action);
106
111
  if (!limit.allowed) {
107
112
  const err = new Error(
108
- `Free tier daily limit reached for "${action}". ${UPGRADE_MESSAGE}\nUpgrade now: ${PRO_CHECKOUT_URL}`
113
+ `Free tier limit reached. Upgrade to Pro for unlimited: https://thumbgate-production.up.railway.app/pro\n${UPGRADE_MESSAGE}\nUpgrade now: ${PRO_CHECKOUT_URL}`
109
114
  );
110
115
  err.errorCategory = 'rate_limit';
111
116
  err.isRetryable = false;
@@ -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.2.0' };
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
  }
@@ -7,7 +7,7 @@
7
7
  "npx",
8
8
  "--yes",
9
9
  "--package",
10
- "thumbgate@1.2.0",
10
+ "thumbgate@1.4.0",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],
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 # upgrade to Context Gateway
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
- `\n Unlock Pro: unlimited gates, DPO export, searchable dashboard — ${PRO_PRICE_LABEL}\n` +
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
  }
@@ -115,6 +118,7 @@ function telemetryPing(installId) {
115
118
  const req = mod.request(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }, timeout: 3000 }, () => {});
116
119
  req.on('error', () => {});
117
120
  req.on('timeout', () => { req.destroy(); });
121
+ req.on('socket', (s) => s.unref()); // fire-and-forget: never block process exit
118
122
  req.end(payload);
119
123
  } catch (_) { /* telemetry is best-effort */ }
120
124
  }
@@ -134,8 +138,8 @@ function proNudge(context) {
134
138
  function limitNudge(action) {
135
139
  if (process.env.THUMBGATE_NO_NUDGE === '1') return;
136
140
  process.stderr.write(
137
- `\n ⚠️ Free tier: ${action} daily limit reached.\n` +
138
- ` Upgrade to Pro for unlimited usage — ${PRO_PRICE_LABEL}:\n` +
141
+ `\n ⚠️ Free tier limit reached. Upgrade to Pro for unlimited: https://thumbgate-production.up.railway.app/pro\n` +
142
+ ` ${action} daily limit reached. Upgrade to Pro for unlimited usage — ${PRO_PRICE_LABEL}:\n` +
139
143
  ` ${PRO_CHECKOUT_URL}\n\n`
140
144
  );
141
145
  }
@@ -455,8 +459,78 @@ function setupForge() {
455
459
  return true;
456
460
  }
457
461
 
458
- function init() {
459
- const args = parseArgs(process.argv.slice(3));
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 };
460
534
 
461
535
  // --wire-hooks only mode: skip scaffolding, just wire hooks
462
536
  if (args['wire-hooks']) {
@@ -580,13 +654,12 @@ function init() {
580
654
  console.log('Run: npx thumbgate help');
581
655
  trackEvent('cli_init', { command: 'init' });
582
656
  proNudge();
583
- process.stderr.write(
584
- '\n ┌──────────────────────────────────────────────────┐\n' +
585
- ' │ Free: unlimited 👍👎 · 5 searches · 5 gates │\n' +
586
- ' │ Pro: + dashboard + DPO export + full search │\n' +
587
- ' │ $19/mo → npx thumbgate pro │\n' +
588
- ' └──────────────────────────────────────────────────┘\n\n'
589
- );
657
+ 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'));
@@ -663,7 +736,7 @@ function capture() {
663
736
  const pct = Math.round((capLimit.used / capLimit.limit) * 100);
664
737
  console.log(` Usage : ${capLimit.used}/${capLimit.limit} captures today (${pct}%)`);
665
738
  if (capLimit.remaining <= 1) {
666
- console.log(` ⚠️ Last capture for today. Upgrade to Pro for unlimited.`);
739
+ console.log(` ⚠️ Free tier limit reached. Upgrade to Pro for unlimited: https://thumbgate-production.up.railway.app/pro`);
667
740
  }
668
741
  }
669
742
  console.log('');
@@ -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: Upgrade to Context Gateway to sync these rules across your team.');
700
- console.log(' Run: npx thumbgate pro');
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 offer today: Pro ($19/mo or $149/yr).');
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(' - Optional hosted API key: shared lesson DB for teams and multi-agent workflows');
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}`);
@@ -892,7 +966,7 @@ function pro() {
892
966
 
893
967
  if (args.info) {
894
968
  printProInfo();
895
- return;
969
+ process.exit(0);
896
970
  }
897
971
 
898
972
  const resolvedKey = resolveProKey();
@@ -901,6 +975,7 @@ function pro() {
901
975
  }
902
976
 
903
977
  printProInfo();
978
+ process.exit(0);
904
979
  }
905
980
 
906
981
  function summary() {
@@ -1037,6 +1112,67 @@ function exportDatabricks() {
1037
1112
  }
1038
1113
  }
1039
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
+
1040
1176
  function obsidianExport() {
1041
1177
  const args = parseArgs(process.argv.slice(3));
1042
1178
  const { exportAll } = require(path.join(PKG_ROOT, 'scripts', 'obsidian-export'));
@@ -1232,6 +1368,10 @@ function cacheUpdate() {
1232
1368
 
1233
1369
  function statuslineRender() {
1234
1370
  syncActiveProjectContext();
1371
+ try {
1372
+ const { syncClaudeHistoryFeedback } = require(path.join(PKG_ROOT, 'scripts', 'claude-feedback-sync'));
1373
+ syncClaudeHistoryFeedback();
1374
+ } catch (_) { /* best-effort fallback sync */ }
1235
1375
  const payload = readStdinText();
1236
1376
  const output = execFileSync('bash', [path.join(PKG_ROOT, 'scripts', 'statusline.sh')], {
1237
1377
  encoding: 'utf8',
@@ -1283,9 +1423,27 @@ function hookAutoCapture() {
1283
1423
 
1284
1424
  function sessionStart() {
1285
1425
  syncActiveProjectContext();
1426
+ try {
1427
+ const { syncClaudeHistoryFeedback } = require(path.join(PKG_ROOT, 'scripts', 'claude-feedback-sync'));
1428
+ syncClaudeHistoryFeedback();
1429
+ } catch (_) { /* best-effort fallback sync */ }
1286
1430
  const { analyzeFeedback } = require(path.join(PKG_ROOT, 'scripts', 'feedback-loop'));
1287
1431
  const { refreshStatuslineCache } = require(path.join(PKG_ROOT, 'scripts', 'hook-thumbgate-cache-updater'));
1288
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 */ }
1289
1447
  }
1290
1448
 
1291
1449
  function installMcp() {
@@ -1356,6 +1514,7 @@ function help() {
1356
1514
  console.log(' risk [flags] Train or query the boosted local risk scorer');
1357
1515
  console.log(' doctor Audit runtime isolation, bootstrap context, and permission tier');
1358
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');
1359
1518
  console.log(' export-dpo Export DPO training pairs (prompt/chosen/rejected JSONL)');
1360
1519
  console.log(' export-databricks Export feedback logs + proof artifacts as a Databricks-ready analytics bundle');
1361
1520
  console.log(' obsidian-export Export all feedback data as interlinked Obsidian markdown notes');
@@ -1364,6 +1523,9 @@ function help() {
1364
1523
  console.log(' rules Generate prevention rules from repeated failures');
1365
1524
  console.log(' optimize [PRO] Prune CLAUDE.md and migrate manual rules to Pre-Action Gates');
1366
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');
1367
1529
  console.log(' self-heal Run self-healing check and auto-fix');
1368
1530
  console.log(' activate <KEY> Activate a Pro license key (from Stripe checkout)');
1369
1531
  console.log(' pro Show Pro plan ($19/mo) + hosted pilot info');
@@ -1385,6 +1547,7 @@ function help() {
1385
1547
  console.log(' npx thumbgate init');
1386
1548
  console.log(' npx thumbgate stats');
1387
1549
  console.log(' npx thumbgate cfo');
1550
+ console.log(' npx thumbgate import-doc docs/release-policy.md --json');
1388
1551
  console.log(' npx thumbgate repair-github-marketplace --write');
1389
1552
  console.log(' npx thumbgate lessons --query="verification" --limit=5');
1390
1553
  console.log(' npx thumbgate model-fit');
@@ -1405,6 +1568,9 @@ switch (COMMAND) {
1405
1568
  init();
1406
1569
  upgradeNudge();
1407
1570
  break;
1571
+ case 'quick-start':
1572
+ quickStart();
1573
+ break;
1408
1574
  case 'install':
1409
1575
  install();
1410
1576
  break;
@@ -1550,6 +1716,10 @@ switch (COMMAND) {
1550
1716
  case 'obsidian-export':
1551
1717
  obsidianExport();
1552
1718
  break;
1719
+ case 'import-doc':
1720
+ case 'import-document':
1721
+ importDoc();
1722
+ break;
1553
1723
  case 'rules':
1554
1724
  rules();
1555
1725
  break;
@@ -1568,6 +1738,32 @@ switch (COMMAND) {
1568
1738
  console.log(`Total auto-promoted gates: ${result.totalGates}`);
1569
1739
  break;
1570
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
+ }
1571
1767
  case 'self-heal':
1572
1768
  selfHeal();
1573
1769
  break;
@@ -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
- Unlock Pro (personal local dashboard, DPO export,
30
- optional hosted API key) — ${PRO_PRICE_LABEL}:
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
+ }