thumbgate 1.15.0 → 1.16.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 (129) hide show
  1. package/.claude-plugin/marketplace.json +6 -6
  2. package/.claude-plugin/plugin.json +3 -3
  3. package/.well-known/llms.txt +5 -5
  4. package/.well-known/mcp/server-card.json +1 -1
  5. package/README.md +59 -35
  6. package/adapters/chatgpt/openapi.yaml +118 -2
  7. package/adapters/claude/.mcp.json +2 -2
  8. package/adapters/mcp/server-stdio.js +210 -84
  9. package/adapters/opencode/opencode.json +1 -1
  10. package/bench/prompt-eval-suite.json +5 -1
  11. package/bin/cli.js +157 -8
  12. package/config/evals/agent-safety-eval.json +338 -22
  13. package/config/gates/routine.json +43 -0
  14. package/config/github-about.json +3 -3
  15. package/config/model-candidates.json +131 -0
  16. package/openapi/openapi.yaml +118 -2
  17. package/package.json +55 -48
  18. package/public/blog.html +7 -7
  19. package/public/codex-plugin.html +6 -6
  20. package/public/compare.html +29 -23
  21. package/public/dashboard.html +82 -10
  22. package/public/guide.html +28 -28
  23. package/public/index.html +216 -98
  24. package/public/learn.html +50 -22
  25. package/public/lessons.html +1 -1
  26. package/public/numbers.html +17 -17
  27. package/public/pro.html +82 -18
  28. package/scripts/agent-audit-trace.js +55 -0
  29. package/scripts/agent-memory-lifecycle.js +96 -0
  30. package/scripts/agent-readiness-plan.js +118 -0
  31. package/scripts/agentic-data-pipeline.js +21 -1
  32. package/scripts/agents-sdk-sandbox-plan.js +57 -0
  33. package/scripts/ai-org-governance.js +98 -0
  34. package/scripts/ai-search-distribution.js +43 -0
  35. package/scripts/artifact-agent-plan.js +81 -0
  36. package/scripts/billing.js +27 -8
  37. package/scripts/cli-schema.js +18 -2
  38. package/scripts/code-mode-mcp-plan.js +71 -0
  39. package/scripts/context-engine.js +1 -2
  40. package/scripts/context-manager.js +4 -1
  41. package/scripts/dashboard-render-spec.js +1 -1
  42. package/scripts/dashboard.js +275 -9
  43. package/scripts/decision-journal.js +13 -3
  44. package/scripts/document-workflow-governance.js +62 -0
  45. package/scripts/enterprise-agent-rollout.js +34 -0
  46. package/scripts/experience-replay-governance.js +69 -0
  47. package/scripts/export-hf-dataset.js +1 -1
  48. package/scripts/feedback-loop.js +92 -4
  49. package/scripts/feedback-to-rules.js +17 -23
  50. package/scripts/gates-engine.js +4 -6
  51. package/scripts/growth-campaigns.js +49 -0
  52. package/scripts/harness-selector.js +16 -4
  53. package/scripts/hybrid-supervisor-agent.js +64 -0
  54. package/scripts/inference-cache-policy.js +72 -0
  55. package/scripts/inference-economics.js +53 -0
  56. package/scripts/internal-agent-bootstrap.js +12 -2
  57. package/scripts/knowledge-layer-plan.js +108 -0
  58. package/scripts/lesson-inference.js +183 -44
  59. package/scripts/lesson-search.js +4 -1
  60. package/scripts/llm-client.js +157 -26
  61. package/scripts/mailer/resend-mailer.js +112 -1
  62. package/scripts/mcp-transport-strategy.js +66 -0
  63. package/scripts/memory-store-governance.js +60 -0
  64. package/scripts/meta-agent-loop.js +7 -13
  65. package/scripts/model-access-eligibility.js +38 -0
  66. package/scripts/model-migration-readiness.js +55 -0
  67. package/scripts/operational-integrity.js +96 -3
  68. package/scripts/otel-declarative-config.js +56 -0
  69. package/scripts/perplexity-client.js +1 -1
  70. package/scripts/post-training-governance.js +34 -0
  71. package/scripts/private-core-boundary.js +72 -0
  72. package/scripts/production-agent-readiness.js +40 -0
  73. package/scripts/prompt-eval.js +564 -32
  74. package/scripts/prompt-programs.js +93 -0
  75. package/scripts/provider-action-normalizer.js +585 -0
  76. package/scripts/scaling-law-claims.js +60 -0
  77. package/scripts/security-scanner.js +1 -1
  78. package/scripts/self-distill-agent.js +7 -32
  79. package/scripts/seo-gsd.js +232 -55
  80. package/scripts/skill-rag-router.js +53 -0
  81. package/scripts/spec-gate.js +1 -1
  82. package/scripts/student-consistent-training.js +73 -0
  83. package/scripts/synthetic-data-provenance.js +98 -0
  84. package/scripts/task-context-result.js +81 -0
  85. package/scripts/telemetry-analytics.js +149 -0
  86. package/scripts/thompson-sampling.js +2 -2
  87. package/scripts/token-savings.js +7 -6
  88. package/scripts/token-tco.js +46 -0
  89. package/scripts/tool-registry.js +63 -3
  90. package/scripts/verification-loop.js +10 -1
  91. package/scripts/verifier-scoring.js +71 -0
  92. package/scripts/workflow-sentinel.js +284 -28
  93. package/scripts/workspace-agent-routines.js +118 -0
  94. package/src/api/server.js +381 -120
  95. package/scripts/analytics-report.js +0 -328
  96. package/scripts/autonomous-workflow.js +0 -377
  97. package/scripts/billing-setup.js +0 -109
  98. package/scripts/creator-campaigns.js +0 -239
  99. package/scripts/cross-encoder-reranker.js +0 -235
  100. package/scripts/daemon-manager.js +0 -108
  101. package/scripts/decision-trace.js +0 -354
  102. package/scripts/delegation-runtime.js +0 -896
  103. package/scripts/dispatch-brief.js +0 -159
  104. package/scripts/distribution-surfaces.js +0 -110
  105. package/scripts/feedback-history-distiller.js +0 -382
  106. package/scripts/funnel-analytics.js +0 -35
  107. package/scripts/history-distiller.js +0 -200
  108. package/scripts/hosted-job-launcher.js +0 -256
  109. package/scripts/intent-router.js +0 -392
  110. package/scripts/lesson-reranker.js +0 -263
  111. package/scripts/lesson-retrieval.js +0 -148
  112. package/scripts/managed-lesson-agent.js +0 -183
  113. package/scripts/operational-dashboard.js +0 -103
  114. package/scripts/operational-summary.js +0 -129
  115. package/scripts/operator-artifacts.js +0 -608
  116. package/scripts/optimize-context.js +0 -17
  117. package/scripts/org-dashboard.js +0 -206
  118. package/scripts/partner-orchestration.js +0 -146
  119. package/scripts/predictive-insights.js +0 -356
  120. package/scripts/pulse.js +0 -80
  121. package/scripts/reflector-agent.js +0 -221
  122. package/scripts/sales-pipeline.js +0 -681
  123. package/scripts/session-episode-store.js +0 -329
  124. package/scripts/session-health-sensor.js +0 -242
  125. package/scripts/session-report.js +0 -120
  126. package/scripts/swarm-coordinator.js +0 -81
  127. package/scripts/tool-kpi-tracker.js +0 -12
  128. package/scripts/webhook-delivery.js +0 -62
  129. package/scripts/workflow-sprint-intake.js +0 -475
package/bin/cli.js CHANGED
@@ -11,6 +11,7 @@
11
11
  * npx thumbgate import-doc # import a local policy/runbook document and propose gates
12
12
  * npx thumbgate export-dpo # export DPO training pairs
13
13
  * npx thumbgate export-databricks # export Databricks-ready analytics bundle
14
+ * npx thumbgate eval --from-feedback # turn feedback into reusable prompt evals
14
15
  * npx thumbgate stats # feedback analytics + Revenue-at-Risk
15
16
  * npx thumbgate cfo # local operational billing summary
16
17
  * npx thumbgate pro # solo dashboard + exports side lane
@@ -528,8 +529,54 @@ function setupForge() {
528
529
  return true;
529
530
  }
530
531
 
532
+ function setupCline() {
533
+ let changed = false;
534
+
535
+ // 1. Copy .clinerules into project root (Cline auto-loads this at session start).
536
+ const rulesDest = path.join(CWD, '.clinerules');
537
+ const rulesSrc = path.join(PKG_ROOT, 'adapters', 'cline', '.clinerules');
538
+ if (!fs.existsSync(rulesDest) && fs.existsSync(rulesSrc)) {
539
+ fs.copyFileSync(rulesSrc, rulesDest);
540
+ console.log(' Cline: installed .clinerules with ThumbGate gating rules');
541
+ changed = true;
542
+ }
543
+
544
+ // 2. Merge MCP server block into Cline's VS Code globalStorage settings.
545
+ // Extension id: saoudrizwan.claude-dev
546
+ const platform = process.platform;
547
+ let clineSettingsPath = null;
548
+ if (platform === 'darwin') {
549
+ clineSettingsPath = path.join(HOME, 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json');
550
+ } else if (platform === 'linux') {
551
+ clineSettingsPath = path.join(HOME, '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json');
552
+ } else if (platform === 'win32' && process.env.APPDATA) {
553
+ clineSettingsPath = path.join(process.env.APPDATA, 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json');
554
+ }
555
+
556
+ if (clineSettingsPath) {
557
+ let settings = { mcpServers: {} };
558
+ if (fs.existsSync(clineSettingsPath)) {
559
+ try { settings = JSON.parse(fs.readFileSync(clineSettingsPath, 'utf8')); } catch (_) { settings = { mcpServers: {} }; }
560
+ }
561
+ settings.mcpServers = settings.mcpServers || {};
562
+ const canonicalEntry = canonicalMcpEntry('home');
563
+ if (!mcpEntriesMatch(settings.mcpServers[MCP_SERVER_NAME], canonicalEntry)) {
564
+ settings.mcpServers[MCP_SERVER_NAME] = canonicalEntry;
565
+ fs.mkdirSync(path.dirname(clineSettingsPath), { recursive: true });
566
+ fs.writeFileSync(clineSettingsPath, JSON.stringify(settings, null, 2) + '\n');
567
+ console.log(` Cline: registered thumbgate MCP server in ${clineSettingsPath}`);
568
+ changed = true;
569
+ }
570
+ } else {
571
+ console.log(' Cline: unsupported platform for auto-wiring MCP settings; see adapters/cline/INSTALL.md');
572
+ }
573
+
574
+ return changed;
575
+ }
576
+
531
577
  function detectAgent(projectDir) {
532
578
  if (fs.existsSync(path.join(projectDir, '.claude'))) return 'claude-code';
579
+ if (fs.existsSync(path.join(projectDir, '.clinerules'))) return 'cline';
533
580
  if (fs.existsSync(path.join(projectDir, '.cursorrules'))) return 'cursor';
534
581
  if (fs.existsSync(path.join(projectDir, '.cursor'))) return 'cursor';
535
582
  if (fs.existsSync(path.join(projectDir, '.codex'))) return 'codex';
@@ -670,6 +717,12 @@ function init(cliArgs = parseArgs(process.argv.slice(3))) {
670
717
  { name: 'Amp', detect: [() => whichExists('amp'), () => fs.existsSync(path.join(HOME, '.amp'))], setup: setupAmp },
671
718
  { name: 'Cursor', detect: [() => fs.existsSync(path.join(HOME, '.cursor', 'mcp.json')), () => fs.existsSync(path.join(CWD, '.cursor'))], setup: setupCursor },
672
719
  { name: 'ForgeCode', detect: [() => whichExists('forge'), () => fs.existsSync(path.join(CWD, 'forge.yaml'))], setup: setupForge },
720
+ { name: 'Cline', detect: [
721
+ () => fs.existsSync(path.join(CWD, '.clinerules')),
722
+ () => process.platform === 'darwin' && fs.existsSync(path.join(HOME, 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev')),
723
+ () => process.platform === 'linux' && fs.existsSync(path.join(HOME, '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev')),
724
+ () => process.platform === 'win32' && process.env.APPDATA && fs.existsSync(path.join(process.env.APPDATA, 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev')),
725
+ ], setup: setupCline },
673
726
  ];
674
727
 
675
728
  for (const p of platforms) {
@@ -690,8 +743,11 @@ function init(cliArgs = parseArgs(process.argv.slice(3))) {
690
743
 
691
744
  if (configured === 0) console.log(' All detected platforms already configured.');
692
745
 
693
- // Auto-wire hooks if --agent flag is provided (or auto-detect)
694
- if (args.agent || args['wire-hooks']) {
746
+ // Cline uses .clinerules (no native hook surface). Run setupCline directly
747
+ // and skip wireHooks, which does not support cline.
748
+ if (args.agent === 'cline') {
749
+ setupCline();
750
+ } else if (args.agent || args['wire-hooks']) {
695
751
  const { wireHooks } = require(path.join(PKG_ROOT, 'scripts', 'auto-wire-hooks'));
696
752
  const hookResult = wireHooks({ agent: args.agent, dryRun: args['dry-run'] });
697
753
  if (hookResult.error) {
@@ -999,8 +1055,8 @@ function pro() {
999
1055
  console.log(' Launch dashboard: npx thumbgate pro');
1000
1056
  console.log(' Activate + run : npx thumbgate pro --activate --key=YOUR_KEY');
1001
1057
  console.log(' Install configs : npx thumbgate pro --upgrade');
1002
- console.log(' Legacy launcher : npx thumbgate-pro (separate package)');
1003
- console.log(' Pro repo : https://github.com/IgorGanapolsky/thumbgate-pro\n');
1058
+ console.log(' Private core : ThumbGate-Core (private repo)');
1059
+ console.log(' Core repo : https://github.com/IgorGanapolsky/ThumbGate-Core\n');
1004
1060
  }
1005
1061
 
1006
1062
  function launchDashboard(key, eventType) {
@@ -1164,6 +1220,27 @@ function modelFit() {
1164
1220
  console.log(JSON.stringify({ reportPath, report }, null, 2));
1165
1221
  }
1166
1222
 
1223
+ function modelCandidatesCmd() {
1224
+ const args = parseArgs(process.argv.slice(3));
1225
+ const { writeModelCandidatesReport, renderModelCandidatesReport } = require(path.join(PKG_ROOT, 'scripts', 'model-candidates'));
1226
+ const maxCandidates = args.max ? Number(args.max) : undefined;
1227
+ const { reportPath, report } = writeModelCandidatesReport(undefined, {
1228
+ workload: args.workload,
1229
+ provider: args.provider,
1230
+ family: args.family,
1231
+ gateway: args.gateway,
1232
+ maxCandidates: Number.isFinite(maxCandidates) ? maxCandidates : undefined,
1233
+ });
1234
+
1235
+ if (args.json) {
1236
+ console.log(JSON.stringify({ reportPath, report }, null, 2));
1237
+ return;
1238
+ }
1239
+
1240
+ process.stdout.write(renderModelCandidatesReport(report));
1241
+ process.stdout.write(`\nReport path: ${reportPath}\n`);
1242
+ }
1243
+
1167
1244
  function risk() {
1168
1245
  const args = parseArgs(process.argv.slice(3));
1169
1246
  const riskScorer = require(path.join(PKG_ROOT, 'scripts', 'risk-scorer'));
@@ -1596,7 +1673,14 @@ function hookAutoCapture() {
1596
1673
  const prompt = process.env.CLAUDE_USER_PROMPT || process.env.THUMBGATE_USER_PROMPT || readStdinText().trim();
1597
1674
  const { evaluatePromptGuard } = require(path.join(PKG_ROOT, 'scripts', 'prompt-guard'));
1598
1675
  const { processInlineFeedback, formatCliOutput } = require(path.join(PKG_ROOT, 'scripts', 'cli-feedback'));
1599
- const { recordConversationEntry, readRecentConversationWindow } = require(path.join(PKG_ROOT, 'scripts', 'feedback-history-distiller'));
1676
+ const { loadOptionalModule } = require(path.join(PKG_ROOT, 'scripts', 'private-core-boundary'));
1677
+ const { recordConversationEntry, readRecentConversationWindow } = loadOptionalModule(
1678
+ path.join(PKG_ROOT, 'scripts', 'feedback-history-distiller'),
1679
+ () => ({
1680
+ recordConversationEntry: () => ({ recorded: false, reason: 'thumbgate_core_required' }),
1681
+ readRecentConversationWindow: () => [],
1682
+ })
1683
+ );
1600
1684
 
1601
1685
  recordConversationEntry({
1602
1686
  author: 'user',
@@ -1754,6 +1838,60 @@ function gateStats() {
1754
1838
  console.log('\n' + formatStats(stats) + '\n');
1755
1839
  }
1756
1840
 
1841
+ function evalCmd() {
1842
+ syncActiveProjectContext();
1843
+ const args = parseArgs(process.argv.slice(3));
1844
+ const {
1845
+ formatProofReport,
1846
+ runFeedbackEvalSuite,
1847
+ runSuite,
1848
+ loadSuite,
1849
+ } = require(path.join(PKG_ROOT, 'scripts', 'prompt-eval'));
1850
+ const minScore = args['min-score'] === undefined ? 80 : Number(args['min-score']);
1851
+ const maxCases = args['max-cases'] === undefined ? 25 : Number(args['max-cases']);
1852
+ const suitePath = args.suite ? path.resolve(CWD, args.suite) : null;
1853
+ const fromFeedback = Boolean(args['from-feedback'] || !suitePath);
1854
+ const evalRun = fromFeedback
1855
+ ? runFeedbackEvalSuite({
1856
+ feedbackDir: args['feedback-dir'] ? path.resolve(CWD, args['feedback-dir']) : undefined,
1857
+ feedbackLog: args['feedback-log'] ? path.resolve(CWD, args['feedback-log']) : undefined,
1858
+ maxCases,
1859
+ minScore,
1860
+ })
1861
+ : {
1862
+ suite: loadSuite(suitePath),
1863
+ report: runSuite(suitePath, { minScore }),
1864
+ };
1865
+ const { suite, report } = evalRun;
1866
+
1867
+ if (args['write-suite']) {
1868
+ const outputPath = path.resolve(CWD, args['write-suite']);
1869
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
1870
+ fs.writeFileSync(outputPath, `${JSON.stringify(suite, null, 2)}\n`, 'utf8');
1871
+ }
1872
+
1873
+ if (args['write-report']) {
1874
+ const outputPath = path.resolve(CWD, args['write-report']);
1875
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
1876
+ fs.writeFileSync(outputPath, `${formatProofReport(report, suite)}\n`, 'utf8');
1877
+ }
1878
+
1879
+ if (args.json) {
1880
+ console.log(JSON.stringify({ ...report, suiteDefinition: fromFeedback ? suite : undefined }, null, 2));
1881
+ process.exit(report.pass ? 0 : 1);
1882
+ }
1883
+
1884
+ console.log(`\nPrompt Evaluation: ${report.suite}`);
1885
+ console.log('─'.repeat(50));
1886
+ console.log(` Score : ${report.score}% (min ${report.minScore}%)`);
1887
+ console.log(` Cases : ${report.passed}/${report.total} passing`);
1888
+ console.log(` Failures : ${report.failed}`);
1889
+ console.log(` Errors : ${report.errors}`);
1890
+ console.log(` Source : ${fromFeedback ? 'feedback-derived' : suitePath}`);
1891
+ console.log(report.pass ? '\n✅ PASS\n' : '\n❌ FAIL\n');
1892
+ process.exit(report.pass ? 0 : 1);
1893
+ }
1894
+
1757
1895
  function startApi() {
1758
1896
  const serverPath = path.join(PKG_ROOT, 'src', 'api', 'server.js');
1759
1897
  try {
@@ -1770,13 +1908,13 @@ function help() {
1770
1908
  const GROUP_LABELS = {
1771
1909
  capture: 'Feedback capture',
1772
1910
  discovery: 'Discovery & inspection',
1773
- gates: 'Gates & rules',
1911
+ gates: 'Checks & rules',
1774
1912
  export: 'Export',
1775
1913
  ops: 'Operations',
1776
1914
  advanced: 'Advanced',
1777
1915
  };
1778
1916
 
1779
- console.log(`thumbgate v${v} — pre-action gates for AI coding agents`);
1917
+ console.log(`thumbgate v${v} — pre-action checks for AI coding agents`);
1780
1918
  console.log('');
1781
1919
 
1782
1920
  for (const [groupKey, label] of Object.entries(GROUP_LABELS)) {
@@ -1806,8 +1944,10 @@ function help() {
1806
1944
  console.log(' repair-github-marketplace Repair legacy GitHub Marketplace amount mappings');
1807
1945
  console.log(' north-star Show proof-backed workflow-run progress toward the North Star');
1808
1946
  console.log(' model-fit Detect local embedding profile and write evidence report');
1947
+ console.log(' model-candidates Rank managed model candidates and emit a benchmark plan');
1809
1948
  console.log(' risk Train or query the boosted local risk scorer');
1810
- console.log(' optimize [PRO] Prune CLAUDE.md and migrate rules to Pre-Action Gates');
1949
+ console.log(' eval Turn feedback into reusable prompt/workflow eval proof');
1950
+ console.log(' optimize [PRO] Prune CLAUDE.md and migrate rules to Pre-Action Checks');
1811
1951
  console.log(' prove [--target=X] Run proof harness (adapters|automation|...)');
1812
1952
  console.log(' watch Watch .thumbgate/ for external signals');
1813
1953
  console.log(' status Approval trend + failure domain dashboard');
@@ -1838,6 +1978,7 @@ function help() {
1838
1978
  console.log(' npx thumbgate explore gates --json');
1839
1979
  console.log(' npx thumbgate demo');
1840
1980
  console.log(' npx thumbgate stats --json');
1981
+ console.log(' npx thumbgate eval --from-feedback --json');
1841
1982
  console.log(' npx thumbgate lessons "force push" --json');
1842
1983
  console.log(' npx thumbgate lessons --query="deploy" --remote');
1843
1984
  console.log(' npx thumbgate gate-stats --json');
@@ -1979,6 +2120,10 @@ switch (COMMAND) {
1979
2120
  case 'model-fit':
1980
2121
  modelFit();
1981
2122
  break;
2123
+ case 'model-candidates':
2124
+ case 'managed-models':
2125
+ modelCandidatesCmd();
2126
+ break;
1982
2127
  case 'risk':
1983
2128
  risk();
1984
2129
  break;
@@ -2118,6 +2263,10 @@ switch (COMMAND) {
2118
2263
  case 'gate-stats':
2119
2264
  gateStats();
2120
2265
  break;
2266
+ case 'eval':
2267
+ case 'prompt-eval':
2268
+ evalCmd();
2269
+ break;
2121
2270
  case 'explore': {
2122
2271
  const subCmd = process.argv[3];
2123
2272
  const exploreArgs = parseArgs(process.argv.slice(3));