thumbgate 1.3.0 → 1.4.1

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 (156) hide show
  1. package/.claude-plugin/README.md +25 -0
  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 +242 -126
  7. package/adapters/README.md +1 -1
  8. package/adapters/chatgpt/INSTALL.md +59 -4
  9. package/adapters/chatgpt/openapi.yaml +168 -0
  10. package/adapters/claude/.mcp.json +2 -2
  11. package/adapters/codex/config.toml +2 -2
  12. package/adapters/mcp/server-stdio.js +84 -1
  13. package/adapters/opencode/opencode.json +1 -1
  14. package/bin/cli.js +204 -13
  15. package/bin/postinstall.js +8 -2
  16. package/config/budget.json +18 -0
  17. package/config/gates/code-edit.json +61 -0
  18. package/config/gates/db-write.json +61 -0
  19. package/config/gates/default.json +154 -3
  20. package/config/gates/deploy.json +61 -0
  21. package/config/github-about.json +2 -1
  22. package/config/merge-quality-checks.json +23 -0
  23. package/openapi/openapi.yaml +168 -0
  24. package/package.json +47 -11
  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/opencode-profile/INSTALL.md +1 -1
  34. package/public/blog.html +73 -0
  35. package/public/compare/mem0.html +189 -0
  36. package/public/compare/speclock.html +180 -0
  37. package/public/compare.html +10 -2
  38. package/public/guide.html +2 -2
  39. package/public/guides/claude-code-prevent-repeated-mistakes.html +161 -0
  40. package/public/guides/codex-cli-guardrails.html +158 -0
  41. package/public/guides/cursor-prevent-repeated-mistakes.html +161 -0
  42. package/public/guides/pre-action-gates.html +162 -0
  43. package/public/guides/stop-repeated-ai-agent-mistakes.html +159 -0
  44. package/public/index.html +172 -65
  45. package/public/lessons.html +33 -24
  46. package/public/llm-context.md +140 -0
  47. package/public/pro.html +24 -22
  48. package/scripts/access-anomaly-detector.js +1 -1
  49. package/scripts/adk-consolidator.js +1 -5
  50. package/scripts/agent-security-hardening.js +4 -6
  51. package/scripts/agentic-data-pipeline.js +1 -3
  52. package/scripts/async-job-runner.js +1 -5
  53. package/scripts/audit-trail.js +1 -5
  54. package/scripts/auto-promote-gates.js +5 -3
  55. package/scripts/background-agent-governance.js +2 -10
  56. package/scripts/billing-setup.js +109 -0
  57. package/scripts/billing.js +2 -16
  58. package/scripts/budget-enforcer.js +173 -0
  59. package/scripts/build-claude-mcpb.js +71 -5
  60. package/scripts/build-codex-plugin.js +152 -0
  61. package/scripts/check-congruence.js +132 -14
  62. package/scripts/commercial-offer.js +5 -7
  63. package/scripts/content-engine/linkedin-content-generator.js +154 -0
  64. package/scripts/content-engine/output/linkedin-memento-validation.md +17 -0
  65. package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +175 -0
  66. package/scripts/content-engine/reddit-thread-finder.js +154 -0
  67. package/scripts/context-engine.js +21 -6
  68. package/scripts/contextfs.js +1 -21
  69. package/scripts/dashboard.js +20 -0
  70. package/scripts/decision-journal.js +341 -0
  71. package/scripts/delegation-runtime.js +1 -5
  72. package/scripts/distribution-surfaces.js +54 -0
  73. package/scripts/document-intake.js +927 -0
  74. package/scripts/ephemeral-agent-store.js +1 -8
  75. package/scripts/evolution-state.js +1 -5
  76. package/scripts/experiment-tracker.js +1 -5
  77. package/scripts/export-databricks-bundle.js +1 -5
  78. package/scripts/export-hf-dataset.js +1 -5
  79. package/scripts/export-training.js +1 -5
  80. package/scripts/feedback-attribution.js +1 -16
  81. package/scripts/feedback-history-distiller.js +1 -16
  82. package/scripts/feedback-loop.js +1 -5
  83. package/scripts/feedback-root-consolidator.js +2 -21
  84. package/scripts/feedback-session.js +49 -0
  85. package/scripts/feedback-to-rules.js +215 -36
  86. package/scripts/filesystem-search.js +1 -9
  87. package/scripts/fs-utils.js +104 -0
  88. package/scripts/gates-engine.js +200 -11
  89. package/scripts/github-about.js +32 -8
  90. package/scripts/gtm-revenue-loop.js +1 -5
  91. package/scripts/harness-selector.js +148 -0
  92. package/scripts/hosted-config.js +2 -0
  93. package/scripts/hosted-job-launcher.js +1 -5
  94. package/scripts/hybrid-feedback-context.js +33 -49
  95. package/scripts/intervention-policy.js +58 -1
  96. package/scripts/lesson-db.js +3 -18
  97. package/scripts/lesson-inference.js +194 -16
  98. package/scripts/lesson-retrieval.js +60 -24
  99. package/scripts/llm-client.js +59 -0
  100. package/scripts/managed-lesson-agent.js +183 -0
  101. package/scripts/marketing-experiment.js +8 -22
  102. package/scripts/meta-agent-loop.js +624 -0
  103. package/scripts/metered-billing.js +1 -1
  104. package/scripts/money-watcher.js +1 -4
  105. package/scripts/obsidian-export.js +1 -5
  106. package/scripts/operational-integrity.js +15 -3
  107. package/scripts/operational-summary.js +41 -5
  108. package/scripts/org-dashboard.js +6 -1
  109. package/scripts/per-step-scoring.js +2 -4
  110. package/scripts/pr-manager.js +201 -19
  111. package/scripts/pro-features.js +3 -2
  112. package/scripts/prompt-dlp.js +3 -3
  113. package/scripts/prove-adapters.js +1 -5
  114. package/scripts/prove-attribution.js +1 -5
  115. package/scripts/prove-automation.js +1 -3
  116. package/scripts/prove-cloudflare-sandbox.js +1 -3
  117. package/scripts/prove-data-pipeline.js +1 -3
  118. package/scripts/prove-intelligence.js +1 -3
  119. package/scripts/prove-lancedb.js +1 -5
  120. package/scripts/prove-local-intelligence.js +1 -3
  121. package/scripts/prove-packaged-runtime.js +75 -9
  122. package/scripts/prove-predictive-insights.js +1 -3
  123. package/scripts/prove-training-export.js +1 -3
  124. package/scripts/prove-workflow-contract.js +1 -5
  125. package/scripts/ralph-loop.js +376 -0
  126. package/scripts/ralph-mode-ci.js +331 -0
  127. package/scripts/rate-limiter.js +3 -1
  128. package/scripts/reddit-dm-outreach.js +14 -4
  129. package/scripts/rotate-stripe-webhook-secret.js +314 -0
  130. package/scripts/schedule-manager.js +3 -5
  131. package/scripts/security-scanner.js +448 -0
  132. package/scripts/self-distill-agent.js +579 -0
  133. package/scripts/semantic-dedup.js +115 -0
  134. package/scripts/skill-exporter.js +1 -3
  135. package/scripts/skill-generator.js +1 -5
  136. package/scripts/social-analytics/engagement-audit.js +1 -18
  137. package/scripts/social-analytics/pollers/linkedin.js +26 -16
  138. package/scripts/social-analytics/publishers/linkedin.js +1 -1
  139. package/scripts/social-analytics/publishers/zernio.js +51 -0
  140. package/scripts/social-pipeline.js +1 -3
  141. package/scripts/social-post-hourly.js +47 -4
  142. package/scripts/statusline-links.js +6 -5
  143. package/scripts/statusline.sh +29 -153
  144. package/scripts/sync-branch-protection.js +340 -0
  145. package/scripts/tessl-export.js +1 -3
  146. package/scripts/thumbgate-search.js +32 -1
  147. package/scripts/tool-kpi-tracker.js +1 -1
  148. package/scripts/tool-registry.js +106 -2
  149. package/scripts/vector-store.js +1 -5
  150. package/scripts/weekly-auto-post.js +1 -1
  151. package/scripts/workflow-sentinel.js +91 -0
  152. package/skills/thumbgate/SKILL.md +1 -1
  153. package/src/api/server.js +296 -7
  154. package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
  155. package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
  156. /package/scripts/social-analytics/db/{social-analytics.db-wal → analytics.sqlite} +0 -0
@@ -814,6 +814,98 @@ paths:
814
814
  description: Invalid dashboard render view or query
815
815
  '401':
816
816
  description: Unauthorized
817
+ /v1/decisions/evaluate:
818
+ post:
819
+ operationId: evaluateDecision
820
+ requestBody:
821
+ required: true
822
+ content:
823
+ application/json:
824
+ schema:
825
+ type: object
826
+ required: [toolName]
827
+ properties:
828
+ toolName:
829
+ type: string
830
+ command:
831
+ type: string
832
+ filePath:
833
+ type: string
834
+ changedFiles:
835
+ type: array
836
+ items:
837
+ type: string
838
+ repoPath:
839
+ type: string
840
+ baseBranch:
841
+ type: string
842
+ requirePrForReleaseSensitive:
843
+ type: boolean
844
+ requireVersionNotBehindBase:
845
+ type: boolean
846
+ responses:
847
+ '200':
848
+ description: Persisted workflow-sentinel recommendation with decision-control metadata and actionId
849
+ content:
850
+ application/json:
851
+ schema:
852
+ type: object
853
+ additionalProperties: true
854
+ '400':
855
+ description: Invalid decision evaluation request
856
+ '401':
857
+ description: Unauthorized
858
+ /v1/decisions/outcome:
859
+ post:
860
+ operationId: recordDecisionOutcome
861
+ requestBody:
862
+ required: true
863
+ content:
864
+ application/json:
865
+ schema:
866
+ type: object
867
+ required: [actionId, outcome]
868
+ properties:
869
+ actionId:
870
+ type: string
871
+ outcome:
872
+ type: string
873
+ actualDecision:
874
+ type: string
875
+ actor:
876
+ type: string
877
+ notes:
878
+ type: string
879
+ latencyMs:
880
+ type: number
881
+ metadata:
882
+ type: object
883
+ additionalProperties: true
884
+ responses:
885
+ '200':
886
+ description: Recorded a decision override, rollback, completion, or block outcome
887
+ content:
888
+ application/json:
889
+ schema:
890
+ type: object
891
+ additionalProperties: true
892
+ '400':
893
+ description: Invalid decision outcome request
894
+ '401':
895
+ description: Unauthorized
896
+ /v1/decisions/metrics:
897
+ get:
898
+ operationId: getDecisionMetrics
899
+ responses:
900
+ '200':
901
+ description: Decision-loop metrics derived from recorded evaluations and outcomes
902
+ content:
903
+ application/json:
904
+ schema:
905
+ type: object
906
+ additionalProperties: true
907
+ '401':
908
+ description: Unauthorized
817
909
  /v1/settings/status:
818
910
  get:
819
911
  operationId: getSettingsStatus
@@ -1115,6 +1207,82 @@ paths:
1115
1207
  description: DPO export accepted as a hosted background job
1116
1208
  '401':
1117
1209
  description: Unauthorized
1210
+ /v1/documents:
1211
+ get:
1212
+ operationId: listImportedDocuments
1213
+ parameters:
1214
+ - in: query
1215
+ name: query
1216
+ schema:
1217
+ type: string
1218
+ - in: query
1219
+ name: q
1220
+ schema:
1221
+ type: string
1222
+ - in: query
1223
+ name: tag
1224
+ schema:
1225
+ type: string
1226
+ - in: query
1227
+ name: limit
1228
+ schema:
1229
+ type: integer
1230
+ default: 20
1231
+ responses:
1232
+ '200':
1233
+ description: Imported policy and runbook documents
1234
+ '401':
1235
+ description: Unauthorized
1236
+ /v1/documents/import:
1237
+ post:
1238
+ operationId: importDocument
1239
+ requestBody:
1240
+ required: true
1241
+ content:
1242
+ application/json:
1243
+ schema:
1244
+ type: object
1245
+ properties:
1246
+ filePath:
1247
+ type: string
1248
+ content:
1249
+ type: string
1250
+ title:
1251
+ type: string
1252
+ sourceFormat:
1253
+ type: string
1254
+ enum: [markdown, text, yaml, json, html]
1255
+ sourceUrl:
1256
+ type: string
1257
+ tags:
1258
+ type: array
1259
+ items:
1260
+ type: string
1261
+ proposeGates:
1262
+ type: boolean
1263
+ responses:
1264
+ '201':
1265
+ description: Document imported
1266
+ '400':
1267
+ description: Invalid document import request
1268
+ '401':
1269
+ description: Unauthorized
1270
+ /v1/documents/{documentId}:
1271
+ get:
1272
+ operationId: getImportedDocument
1273
+ parameters:
1274
+ - in: path
1275
+ name: documentId
1276
+ required: true
1277
+ schema:
1278
+ type: string
1279
+ responses:
1280
+ '200':
1281
+ description: Imported document with proposed gates
1282
+ '401':
1283
+ description: Unauthorized
1284
+ '404':
1285
+ description: Imported document not found
1118
1286
  /v1/jobs:
1119
1287
  get:
1120
1288
  operationId: listHostedJobs
@@ -2,13 +2,13 @@
2
2
  "mcpServers": {
3
3
  "thumbgate": {
4
4
  "command": "npx",
5
- "args": ["--yes", "--package", "thumbgate@1.3.0", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.4.0", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.3.0", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.4.0", "thumbgate", "gate-check"]
12
12
  }
13
13
  }
14
14
  }
@@ -1,9 +1,9 @@
1
1
  # Codex MCP profile (copy into ~/.codex/config.toml or merge section)
2
2
  [mcp_servers.thumbgate]
3
3
  command = "npx"
4
- args = ["--yes", "--package", "thumbgate@1.3.0", "thumbgate", "serve"]
4
+ args = ["--yes", "--package", "thumbgate@1.4.0", "thumbgate", "serve"]
5
5
 
6
6
  # Hard PreToolUse hook for Codex
7
7
  [hooks.pre_tool_use]
8
8
  command = "npx"
9
- args = ["--yes", "--package", "thumbgate@1.3.0", "thumbgate", "gate-check"]
9
+ args = ["--yes", "--package", "thumbgate@1.4.0", "thumbgate", "gate-check"]
@@ -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.3.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.3.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
  }
@@ -456,8 +459,78 @@ function setupForge() {
456
459
  return true;
457
460
  }
458
461
 
459
- function init() {
460
- 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 };
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(' │ Unlock unlimited captures, searches & dashboard: │');
587
- console.log(' │ https://thumbgate-production.up.railway.app/pro │');
588
- console.log(' │ Pro starts at $19/mo — 7-day free trial included │');
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: 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}`);
@@ -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() {
@@ -1357,6 +1506,7 @@ function help() {
1357
1506
  console.log(' capture [flags] Capture feedback (--feedback=up|down --context="..." --tags="...")');
1358
1507
  console.log(' stats Show feedback analytics + Revenue-at-Risk');
1359
1508
  console.log(' cfo Show hosted billing summary when configured, else local fallback JSON');
1509
+ console.log(' billing:setup Generate operator key + print Railway setup instructions');
1360
1510
  console.log(' repair-github-marketplace Dry-run or apply legacy GitHub Marketplace amount repairs (--write)');
1361
1511
  console.log(' north-star Show proof-backed workflow-run progress toward the North Star');
1362
1512
  console.log(' summary Human-readable feedback summary');
@@ -1365,6 +1515,7 @@ function help() {
1365
1515
  console.log(' risk [flags] Train or query the boosted local risk scorer');
1366
1516
  console.log(' doctor Audit runtime isolation, bootstrap context, and permission tier');
1367
1517
  console.log(' dispatch Print a Dispatch-safe remote ops brief for phone-driven review sessions');
1518
+ console.log(' import-doc Import a local policy/runbook and propose reviewable gate candidates');
1368
1519
  console.log(' export-dpo Export DPO training pairs (prompt/chosen/rejected JSONL)');
1369
1520
  console.log(' export-databricks Export feedback logs + proof artifacts as a Databricks-ready analytics bundle');
1370
1521
  console.log(' obsidian-export Export all feedback data as interlinked Obsidian markdown notes');
@@ -1373,6 +1524,9 @@ function help() {
1373
1524
  console.log(' rules Generate prevention rules from repeated failures');
1374
1525
  console.log(' optimize [PRO] Prune CLAUDE.md and migrate manual rules to Pre-Action Gates');
1375
1526
  console.log(' force-gate <PATTERN> Immediately create a blocking gate from a pattern');
1527
+ console.log(' meta-agent Run meta-agent loop: generate + evaluate + promote prevention rules');
1528
+ console.log(' --dry-run Preview rules without writing');
1529
+ console.log(' --status Show last run summary');
1376
1530
  console.log(' self-heal Run self-healing check and auto-fix');
1377
1531
  console.log(' activate <KEY> Activate a Pro license key (from Stripe checkout)');
1378
1532
  console.log(' pro Show Pro plan ($19/mo) + hosted pilot info');
@@ -1394,6 +1548,7 @@ function help() {
1394
1548
  console.log(' npx thumbgate init');
1395
1549
  console.log(' npx thumbgate stats');
1396
1550
  console.log(' npx thumbgate cfo');
1551
+ console.log(' npx thumbgate import-doc docs/release-policy.md --json');
1397
1552
  console.log(' npx thumbgate repair-github-marketplace --write');
1398
1553
  console.log(' npx thumbgate lessons --query="verification" --limit=5');
1399
1554
  console.log(' npx thumbgate model-fit');
@@ -1414,6 +1569,9 @@ switch (COMMAND) {
1414
1569
  init();
1415
1570
  upgradeNudge();
1416
1571
  break;
1572
+ case 'quick-start':
1573
+ quickStart();
1574
+ break;
1417
1575
  case 'install':
1418
1576
  install();
1419
1577
  break;
@@ -1455,6 +1613,9 @@ switch (COMMAND) {
1455
1613
  case 'revenue':
1456
1614
  cfo();
1457
1615
  break;
1616
+ case 'billing:setup':
1617
+ require(path.join(PKG_ROOT, 'scripts', 'billing-setup'));
1618
+ break;
1458
1619
  case 'repair-github-marketplace':
1459
1620
  repairGithubMarketplace();
1460
1621
  break;
@@ -1559,6 +1720,10 @@ switch (COMMAND) {
1559
1720
  case 'obsidian-export':
1560
1721
  obsidianExport();
1561
1722
  break;
1723
+ case 'import-doc':
1724
+ case 'import-document':
1725
+ importDoc();
1726
+ break;
1562
1727
  case 'rules':
1563
1728
  rules();
1564
1729
  break;
@@ -1577,6 +1742,32 @@ switch (COMMAND) {
1577
1742
  console.log(`Total auto-promoted gates: ${result.totalGates}`);
1578
1743
  break;
1579
1744
  }
1745
+ case 'meta-agent': {
1746
+ const metaArgs = parseArgs(process.argv.slice(3));
1747
+ if (metaArgs.status) {
1748
+ const { getMetaAgentStatus } = require(path.join(PKG_ROOT, 'scripts', 'meta-agent-loop'));
1749
+ const status = getMetaAgentStatus();
1750
+ if (!status) {
1751
+ console.log('No meta-agent runs recorded yet. Run: npx thumbgate meta-agent');
1752
+ } else {
1753
+ console.log(JSON.stringify(status, null, 2));
1754
+ }
1755
+ } else {
1756
+ const { runMetaAgentLoop } = require(path.join(PKG_ROOT, 'scripts', 'meta-agent-loop'));
1757
+ runMetaAgentLoop({ dryRun: Boolean(metaArgs['dry-run']), verbose: true })
1758
+ .then((manifest) => {
1759
+ console.log(`\nMeta-agent run complete.`);
1760
+ console.log(` Promoted : ${manifest.promotedCount} rule(s)`);
1761
+ console.log(` Reverted : ${manifest.revertedCount} candidate(s)`);
1762
+ if (manifest.dryRun) console.log(' [DRY RUN] No rules written.');
1763
+ })
1764
+ .catch((err) => {
1765
+ console.error('Meta-agent failed:', err.message);
1766
+ process.exit(1);
1767
+ });
1768
+ }
1769
+ break;
1770
+ }
1580
1771
  case 'self-heal':
1581
1772
  selfHeal();
1582
1773
  break;