thumbgate 0.9.9

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 (369) hide show
  1. package/.claude-plugin/README.md +134 -0
  2. package/.claude-plugin/bundle/icon.png +0 -0
  3. package/.claude-plugin/bundle/icon.svg +18 -0
  4. package/.claude-plugin/bundle/server/index.js +24 -0
  5. package/.claude-plugin/marketplace.json +36 -0
  6. package/.claude-plugin/plugin.json +21 -0
  7. package/.well-known/mcp/server-card.json +231 -0
  8. package/LICENSE +21 -0
  9. package/README.md +375 -0
  10. package/adapters/README.md +9 -0
  11. package/adapters/amp/skills/rlhf-feedback/SKILL.md +22 -0
  12. package/adapters/chatgpt/INSTALL.md +83 -0
  13. package/adapters/chatgpt/openapi.yaml +1281 -0
  14. package/adapters/claude/.mcp.json +14 -0
  15. package/adapters/codex/config.toml +9 -0
  16. package/adapters/gemini/function-declarations.json +224 -0
  17. package/adapters/mcp/server-stdio.js +788 -0
  18. package/adapters/opencode/opencode.json +15 -0
  19. package/bin/cli.js +1483 -0
  20. package/bin/memory.sh +64 -0
  21. package/bin/obsidian-sync.sh +20 -0
  22. package/bin/postinstall.js +37 -0
  23. package/config/build-metadata.json +4 -0
  24. package/config/e2e-critical-flows.json +45 -0
  25. package/config/gate-templates.json +77 -0
  26. package/config/gates/claim-verification.json +29 -0
  27. package/config/gates/computer-use.json +39 -0
  28. package/config/gates/default.json +117 -0
  29. package/config/github-about.json +25 -0
  30. package/config/mcp-allowlists.json +135 -0
  31. package/config/model-tiers.json +33 -0
  32. package/config/partner-routing.json +132 -0
  33. package/config/policy-bundles/constrained-v1.json +64 -0
  34. package/config/policy-bundles/default-v1.json +91 -0
  35. package/config/rubrics/default-v1.json +52 -0
  36. package/config/skill-packs/react-testing.json +23 -0
  37. package/config/skill-packs/stripe-integration/references/api-spec.json +1 -0
  38. package/config/skill-packs/stripe-integration/references/webhook-guide.md +3 -0
  39. package/config/skill-specs/pr-reviewer.json +9 -0
  40. package/config/skill-specs/release-status.json +9 -0
  41. package/config/skill-specs/ticket-triage.json +9 -0
  42. package/config/subagent-profiles.json +32 -0
  43. package/config/tessl-tiles.json +29 -0
  44. package/config/thumbgate-settings.managed.json +12 -0
  45. package/openapi/openapi.yaml +1281 -0
  46. package/package.json +286 -0
  47. package/plugins/amp-skill/INSTALL.md +52 -0
  48. package/plugins/amp-skill/SKILL.md +64 -0
  49. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +22 -0
  50. package/plugins/claude-codex-bridge/.mcp.json +12 -0
  51. package/plugins/claude-codex-bridge/INSTALL.md +43 -0
  52. package/plugins/claude-codex-bridge/README.md +46 -0
  53. package/plugins/claude-codex-bridge/scripts/codex-bridge.js +288 -0
  54. package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +24 -0
  55. package/plugins/claude-codex-bridge/skills/result/SKILL.md +22 -0
  56. package/plugins/claude-codex-bridge/skills/review/SKILL.md +28 -0
  57. package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +27 -0
  58. package/plugins/claude-codex-bridge/skills/setup/SKILL.md +21 -0
  59. package/plugins/claude-codex-bridge/skills/status/SKILL.md +19 -0
  60. package/plugins/claude-skill/INSTALL.md +55 -0
  61. package/plugins/claude-skill/SKILL.md +46 -0
  62. package/plugins/codex-profile/.codex-plugin/plugin.json +43 -0
  63. package/plugins/codex-profile/.mcp.json +12 -0
  64. package/plugins/codex-profile/AGENTS.md +20 -0
  65. package/plugins/codex-profile/INSTALL.md +66 -0
  66. package/plugins/codex-profile/README.md +37 -0
  67. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +23 -0
  68. package/plugins/cursor-marketplace/CHANGELOG.md +30 -0
  69. package/plugins/cursor-marketplace/LICENSE +21 -0
  70. package/plugins/cursor-marketplace/README.md +124 -0
  71. package/plugins/cursor-marketplace/agents/reliability-reviewer.md +31 -0
  72. package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
  73. package/plugins/cursor-marketplace/commands/capture-feedback.md +33 -0
  74. package/plugins/cursor-marketplace/commands/check-gates.md +25 -0
  75. package/plugins/cursor-marketplace/commands/show-lessons.md +27 -0
  76. package/plugins/cursor-marketplace/hooks/hooks.json +10 -0
  77. package/plugins/cursor-marketplace/mcp.json +12 -0
  78. package/plugins/cursor-marketplace/rules/feedback-capture.mdc +34 -0
  79. package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +30 -0
  80. package/plugins/cursor-marketplace/rules/session-continuity.mdc +28 -0
  81. package/plugins/cursor-marketplace/scripts/gate-check.sh +11 -0
  82. package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +47 -0
  83. package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +31 -0
  84. package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +30 -0
  85. package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +33 -0
  86. package/plugins/gemini-extension/INSTALL.md +92 -0
  87. package/plugins/gemini-extension/gemini_prompt.txt +14 -0
  88. package/plugins/gemini-extension/tool_contract.json +45 -0
  89. package/plugins/opencode-profile/INSTALL.md +57 -0
  90. package/public/assets/instagram-card.png +0 -0
  91. package/public/assets/tiktok-agent-memory.mp4 +0 -0
  92. package/public/blog.html +400 -0
  93. package/public/dashboard.html +1093 -0
  94. package/public/guide.html +317 -0
  95. package/public/index.html +1195 -0
  96. package/public/learn/agent-harness-pattern.html +180 -0
  97. package/public/learn/ai-agent-persistent-memory.html +202 -0
  98. package/public/learn/learn.css +45 -0
  99. package/public/learn/mcp-pre-action-gates-explained.html +172 -0
  100. package/public/learn/stop-ai-agent-force-push.html +134 -0
  101. package/public/learn/vibe-coding-safety-net.html +142 -0
  102. package/public/learn.html +213 -0
  103. package/public/lessons.html +650 -0
  104. package/public/vercel.json +8 -0
  105. package/scripts/__pycache__/train_from_feedback.cpython-314.pyc +0 -0
  106. package/scripts/a2ui-engine.js +73 -0
  107. package/scripts/access-anomaly-detector.js +12 -0
  108. package/scripts/adk-consolidator.js +266 -0
  109. package/scripts/agent-readiness.js +220 -0
  110. package/scripts/agent-security-hardening.js +227 -0
  111. package/scripts/agentic-data-pipeline.js +847 -0
  112. package/scripts/analytics-report.js +328 -0
  113. package/scripts/analytics-window.js +158 -0
  114. package/scripts/async-job-runner.js +1001 -0
  115. package/scripts/audit-trail.js +398 -0
  116. package/scripts/auto-promote-gates.js +293 -0
  117. package/scripts/auto-wire-hooks.js +316 -0
  118. package/scripts/autonomous-sales-agent.js +39 -0
  119. package/scripts/autoresearch-runner.js +216 -0
  120. package/scripts/background-agent-governance.js +237 -0
  121. package/scripts/behavioral-extraction.js +93 -0
  122. package/scripts/belief-update.js +84 -0
  123. package/scripts/billing.js +2438 -0
  124. package/scripts/bot-detector.js +50 -0
  125. package/scripts/budget-guard.js +173 -0
  126. package/scripts/build-claude-mcpb.js +189 -0
  127. package/scripts/build-metadata.js +97 -0
  128. package/scripts/check-congruence.js +322 -0
  129. package/scripts/cli-feedback.js +135 -0
  130. package/scripts/cli-telemetry.js +87 -0
  131. package/scripts/cloudflare-dynamic-sandbox.js +315 -0
  132. package/scripts/code-reasoning.js +350 -0
  133. package/scripts/codegraph-context.js +466 -0
  134. package/scripts/commercial-offer.js +56 -0
  135. package/scripts/computer-use-firewall.js +250 -0
  136. package/scripts/context-engine.js +694 -0
  137. package/scripts/contextfs.js +1287 -0
  138. package/scripts/conversation-context.js +119 -0
  139. package/scripts/creator-campaigns.js +239 -0
  140. package/scripts/daemon-manager.js +108 -0
  141. package/scripts/daily-digest.js +11 -0
  142. package/scripts/dashboard-render-spec.js +395 -0
  143. package/scripts/dashboard.js +1058 -0
  144. package/scripts/data-governance.js +173 -0
  145. package/scripts/delegation-runtime.js +900 -0
  146. package/scripts/deploy-gcp.sh +44 -0
  147. package/scripts/deploy-policy.js +231 -0
  148. package/scripts/disagreement-mining.js +315 -0
  149. package/scripts/dispatch-brief.js +159 -0
  150. package/scripts/distribution-surfaces.js +44 -0
  151. package/scripts/dpo-optimizer.js +206 -0
  152. package/scripts/ensure-repo-bootstrap.js +129 -0
  153. package/scripts/ephemeral-agent-store.js +219 -0
  154. package/scripts/eval-harness.js +56 -0
  155. package/scripts/evolution-state.js +241 -0
  156. package/scripts/experiment-tracker.js +267 -0
  157. package/scripts/export-databricks-bundle.js +242 -0
  158. package/scripts/export-dpo-pairs.js +344 -0
  159. package/scripts/export-kto-pairs.js +309 -0
  160. package/scripts/export-training.js +450 -0
  161. package/scripts/failure-diagnostics.js +558 -0
  162. package/scripts/feedback-attribution.js +313 -0
  163. package/scripts/feedback-fallback.js +110 -0
  164. package/scripts/feedback-history-distiller.js +391 -0
  165. package/scripts/feedback-inbox-read.js +162 -0
  166. package/scripts/feedback-loop.js +1887 -0
  167. package/scripts/feedback-paths.js +145 -0
  168. package/scripts/feedback-quality.js +139 -0
  169. package/scripts/feedback-root-consolidator.js +238 -0
  170. package/scripts/feedback-schema.js +426 -0
  171. package/scripts/feedback-session.js +286 -0
  172. package/scripts/feedback-to-memory.js +185 -0
  173. package/scripts/feedback-to-rules.js +164 -0
  174. package/scripts/filesystem-search.js +405 -0
  175. package/scripts/funnel-analytics.js +35 -0
  176. package/scripts/gate-satisfy.js +42 -0
  177. package/scripts/gate-stats.js +116 -0
  178. package/scripts/gate-templates.js +70 -0
  179. package/scripts/gates-engine.js +816 -0
  180. package/scripts/generate-paperbanana-diagrams.sh +99 -0
  181. package/scripts/generate-pretool-hook.sh +40 -0
  182. package/scripts/github-about.js +350 -0
  183. package/scripts/github-outreach.js +65 -0
  184. package/scripts/gtm-revenue-loop.js +520 -0
  185. package/scripts/hallucination-detector.js +226 -0
  186. package/scripts/hf-papers.js +317 -0
  187. package/scripts/history-distiller.js +200 -0
  188. package/scripts/hook-auto-capture.sh +100 -0
  189. package/scripts/hook-stop-pr-thread-check.sh +68 -0
  190. package/scripts/hook-stop-self-score.sh +51 -0
  191. package/scripts/hook-stop-verify-deploy.sh +31 -0
  192. package/scripts/hook-thumbgate-cache-updater.js +48 -0
  193. package/scripts/hook-verify-before-done.sh +20 -0
  194. package/scripts/hosted-config.js +156 -0
  195. package/scripts/hybrid-feedback-context.js +675 -0
  196. package/scripts/install-mcp.js +159 -0
  197. package/scripts/intent-router.js +392 -0
  198. package/scripts/internal-agent-bootstrap.js +490 -0
  199. package/scripts/jsonl-watcher.js +155 -0
  200. package/scripts/lesson-db.js +613 -0
  201. package/scripts/lesson-inference.js +310 -0
  202. package/scripts/lesson-retrieval.js +95 -0
  203. package/scripts/lesson-rotation.js +137 -0
  204. package/scripts/lesson-search.js +644 -0
  205. package/scripts/lesson-synthesis.js +196 -0
  206. package/scripts/license.js +50 -0
  207. package/scripts/local-model-profile.js +384 -0
  208. package/scripts/markdown-escape.js +12 -0
  209. package/scripts/marketing-experiment.js +671 -0
  210. package/scripts/mcp-config.js +149 -0
  211. package/scripts/mcp-policy.js +99 -0
  212. package/scripts/memalign-recall.js +111 -0
  213. package/scripts/memory-firewall.js +222 -0
  214. package/scripts/memory-migration.js +296 -0
  215. package/scripts/meta-policy.js +190 -0
  216. package/scripts/metered-billing.js +16 -0
  217. package/scripts/model-tier-router.js +301 -0
  218. package/scripts/money-watcher.js +71 -0
  219. package/scripts/multi-hop-recall.js +240 -0
  220. package/scripts/natural-language-harness.js +330 -0
  221. package/scripts/obsidian-export.js +713 -0
  222. package/scripts/operational-dashboard.js +103 -0
  223. package/scripts/operational-summary.js +93 -0
  224. package/scripts/optimize-context.js +17 -0
  225. package/scripts/org-dashboard.js +201 -0
  226. package/scripts/partner-orchestration.js +146 -0
  227. package/scripts/per-step-scoring.js +165 -0
  228. package/scripts/perplexity-marketing.js +466 -0
  229. package/scripts/pii-scanner.js +153 -0
  230. package/scripts/plan-gate.js +154 -0
  231. package/scripts/post-everywhere.js +308 -0
  232. package/scripts/post-to-x-retry.sh +22 -0
  233. package/scripts/post-to-x.js +369 -0
  234. package/scripts/pr-manager.js +236 -0
  235. package/scripts/predictive-insights.js +356 -0
  236. package/scripts/principle-extractor.js +162 -0
  237. package/scripts/pro-features.js +40 -0
  238. package/scripts/pro-local-dashboard.js +174 -0
  239. package/scripts/problem-detail.js +53 -0
  240. package/scripts/product-feedback.js +134 -0
  241. package/scripts/profile-router.js +245 -0
  242. package/scripts/prompt-dlp.js +221 -0
  243. package/scripts/prompt-guard.js +83 -0
  244. package/scripts/prove-adapters.js +863 -0
  245. package/scripts/prove-attribution.js +365 -0
  246. package/scripts/prove-automation.js +653 -0
  247. package/scripts/prove-autoresearch.js +304 -0
  248. package/scripts/prove-claim-verification.js +277 -0
  249. package/scripts/prove-cloudflare-sandbox.js +163 -0
  250. package/scripts/prove-data-pipeline.js +410 -0
  251. package/scripts/prove-data-quality.js +227 -0
  252. package/scripts/prove-evolution.js +352 -0
  253. package/scripts/prove-harnesses.js +287 -0
  254. package/scripts/prove-intelligence.js +259 -0
  255. package/scripts/prove-lancedb.js +371 -0
  256. package/scripts/prove-local-intelligence.js +342 -0
  257. package/scripts/prove-loop-closure.js +263 -0
  258. package/scripts/prove-predictive-insights.js +357 -0
  259. package/scripts/prove-runtime.js +350 -0
  260. package/scripts/prove-seo-gsd.js +234 -0
  261. package/scripts/prove-settings.js +279 -0
  262. package/scripts/prove-subway-upgrades.js +277 -0
  263. package/scripts/prove-tessl.js +229 -0
  264. package/scripts/prove-training-export.js +327 -0
  265. package/scripts/prove-workflow-contract.js +116 -0
  266. package/scripts/prove-xmemory.js +332 -0
  267. package/scripts/publish-decision.js +133 -0
  268. package/scripts/pulse.js +80 -0
  269. package/scripts/rate-limiter.js +125 -0
  270. package/scripts/reddit-dm-outreach.js +182 -0
  271. package/scripts/reddit-monitor-cron.sh +26 -0
  272. package/scripts/reflector-agent.js +221 -0
  273. package/scripts/reminder-engine.js +132 -0
  274. package/scripts/revenue-status.js +472 -0
  275. package/scripts/risk-scorer.js +459 -0
  276. package/scripts/rlaif-self-audit.js +129 -0
  277. package/scripts/rlhf_session_start.sh +32 -0
  278. package/scripts/rubric-engine.js +230 -0
  279. package/scripts/schedule-manager.js +251 -0
  280. package/scripts/secret-scanner.js +414 -0
  281. package/scripts/self-heal.js +147 -0
  282. package/scripts/self-healing-check.js +188 -0
  283. package/scripts/semantic-layer.js +98 -0
  284. package/scripts/seo-gsd.js +1153 -0
  285. package/scripts/settings-hierarchy.js +214 -0
  286. package/scripts/shieldcortex-memory-firewall-runner.mjs +53 -0
  287. package/scripts/skill-exporter.js +262 -0
  288. package/scripts/skill-generator.js +446 -0
  289. package/scripts/skill-materializer.js +134 -0
  290. package/scripts/skill-packs.js +136 -0
  291. package/scripts/skill-proposer.js +99 -0
  292. package/scripts/skill-quality-tracker.js +282 -0
  293. package/scripts/slo-alert-engine.js +14 -0
  294. package/scripts/slow-loop.js +72 -0
  295. package/scripts/social-analytics/db/schema.sql +32 -0
  296. package/scripts/social-analytics/db/social-analytics.db +0 -0
  297. package/scripts/social-analytics/digest.js +256 -0
  298. package/scripts/social-analytics/generate-instagram-card.js +97 -0
  299. package/scripts/social-analytics/instagram-thumbgate-post.js +107 -0
  300. package/scripts/social-analytics/load-env.js +46 -0
  301. package/scripts/social-analytics/mcp-server.js +289 -0
  302. package/scripts/social-analytics/normalizer.js +580 -0
  303. package/scripts/social-analytics/notify.js +162 -0
  304. package/scripts/social-analytics/poll-all.js +92 -0
  305. package/scripts/social-analytics/pollers/github.js +195 -0
  306. package/scripts/social-analytics/pollers/instagram.js +253 -0
  307. package/scripts/social-analytics/pollers/linkedin.js +330 -0
  308. package/scripts/social-analytics/pollers/plausible.js +247 -0
  309. package/scripts/social-analytics/pollers/reddit.js +306 -0
  310. package/scripts/social-analytics/pollers/threads.js +233 -0
  311. package/scripts/social-analytics/pollers/tiktok.js +203 -0
  312. package/scripts/social-analytics/pollers/x.js +227 -0
  313. package/scripts/social-analytics/pollers/youtube.js +304 -0
  314. package/scripts/social-analytics/pollers/zernio.js +183 -0
  315. package/scripts/social-analytics/publish-instagram-thumbgate.js +98 -0
  316. package/scripts/social-analytics/publish-thumbgate-launch.js +316 -0
  317. package/scripts/social-analytics/publishers/devto.js +122 -0
  318. package/scripts/social-analytics/publishers/instagram.js +317 -0
  319. package/scripts/social-analytics/publishers/linkedin.js +294 -0
  320. package/scripts/social-analytics/publishers/reddit.js +390 -0
  321. package/scripts/social-analytics/publishers/threads.js +275 -0
  322. package/scripts/social-analytics/publishers/tiktok.js +217 -0
  323. package/scripts/social-analytics/publishers/x.js +259 -0
  324. package/scripts/social-analytics/publishers/youtube.js +223 -0
  325. package/scripts/social-analytics/publishers/zernio.js +378 -0
  326. package/scripts/social-analytics/run-digest.js +34 -0
  327. package/scripts/social-analytics/store.js +257 -0
  328. package/scripts/social-analytics/utm.js +143 -0
  329. package/scripts/social-pipeline.js +2628 -0
  330. package/scripts/social-quality-gate.js +18 -0
  331. package/scripts/social-reply-monitor.js +445 -0
  332. package/scripts/status-dashboard.js +155 -0
  333. package/scripts/statusline-lesson.js +16 -0
  334. package/scripts/statusline-tower.js +8 -0
  335. package/scripts/statusline.sh +116 -0
  336. package/scripts/stripe-live-status.js +115 -0
  337. package/scripts/subagent-profiles.js +79 -0
  338. package/scripts/sync-gh-secrets-from-env.sh +70 -0
  339. package/scripts/sync-github-about.js +52 -0
  340. package/scripts/sync-version.js +447 -0
  341. package/scripts/synthetic-dpo.js +234 -0
  342. package/scripts/telemetry-analytics.js +821 -0
  343. package/scripts/tessl-export.js +371 -0
  344. package/scripts/test-coverage.js +120 -0
  345. package/scripts/thompson-sampling.js +417 -0
  346. package/scripts/thumbgate-search.js +189 -0
  347. package/scripts/tool-kpi-tracker.js +12 -0
  348. package/scripts/tool-registry.js +811 -0
  349. package/scripts/train_from_feedback.py +933 -0
  350. package/scripts/user-profile.js +78 -0
  351. package/scripts/validate-feedback.js +581 -0
  352. package/scripts/validate-workflow-contract.js +287 -0
  353. package/scripts/vector-store.js +197 -0
  354. package/scripts/verification-loop.js +291 -0
  355. package/scripts/verify-obsidian-setup.sh +269 -0
  356. package/scripts/verify-run.js +269 -0
  357. package/scripts/webhook-delivery.js +62 -0
  358. package/scripts/weekly-auto-post.js +124 -0
  359. package/scripts/workflow-runs.js +154 -0
  360. package/scripts/workflow-sprint-intake.js +475 -0
  361. package/scripts/workspace-evolver.js +374 -0
  362. package/scripts/x-autonomous-marketing.js +139 -0
  363. package/scripts/xmemory-lite.js +405 -0
  364. package/skills/agent-memory/SKILL.md +97 -0
  365. package/skills/rlhf-feedback/SKILL.md +49 -0
  366. package/skills/solve-architecture-autonomy/SKILL.md +17 -0
  367. package/skills/solve-architecture-autonomy/tool.js +33 -0
  368. package/skills/thumbgate/SKILL.md +114 -0
  369. package/src/api/server.js +4206 -0
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+
3
+ const { resolveAnalyticsWindow } = require('./analytics-window');
4
+ const { getBillingSummaryLive } = require('./billing');
5
+ const { generateDashboard } = require('./dashboard');
6
+ const { getFeedbackPaths } = require('./feedback-loop');
7
+ const { resolveHostedBillingConfig } = require('./hosted-config');
8
+
9
+ function normalizeText(value) {
10
+ if (value === undefined || value === null) return null;
11
+ const text = String(value).trim();
12
+ return text || null;
13
+ }
14
+
15
+ function shouldPreferHostedDashboard() {
16
+ return String(process.env.THUMBGATE_METRICS_SOURCE || '').trim().toLowerCase() !== 'local';
17
+ }
18
+
19
+ function resolveHostedDashboardConfig() {
20
+ const runtimeConfig = resolveHostedBillingConfig();
21
+ const apiBaseUrl = normalizeText(process.env.THUMBGATE_BILLING_API_BASE_URL) || runtimeConfig.billingApiBaseUrl;
22
+ const apiKey = normalizeText(process.env.THUMBGATE_API_KEY);
23
+ return {
24
+ apiBaseUrl,
25
+ apiKey,
26
+ };
27
+ }
28
+
29
+ async function buildOperationalDashboard(options = {}) {
30
+ const analyticsWindow = resolveAnalyticsWindow(options);
31
+ const feedbackDir = options.feedbackDir || getFeedbackPaths().FEEDBACK_DIR;
32
+ const billingSummary = await getBillingSummaryLive(analyticsWindow);
33
+
34
+ return generateDashboard(feedbackDir, {
35
+ analyticsWindow,
36
+ billingSummary,
37
+ billingSource: 'live',
38
+ billingFallbackReason: null,
39
+ });
40
+ }
41
+
42
+ async function fetchHostedDashboard(options = {}, config = resolveHostedDashboardConfig()) {
43
+ const analyticsWindow = resolveAnalyticsWindow(options);
44
+ if (!shouldPreferHostedDashboard()) {
45
+ const err = new Error('Hosted operational dashboard is disabled.');
46
+ err.code = 'hosted_dashboard_disabled';
47
+ throw err;
48
+ }
49
+ if (!config.apiBaseUrl || !config.apiKey) {
50
+ const err = new Error('Hosted operational dashboard is not configured.');
51
+ err.code = 'hosted_dashboard_unconfigured';
52
+ throw err;
53
+ }
54
+
55
+ const requestUrl = new URL('/v1/dashboard', config.apiBaseUrl);
56
+ requestUrl.searchParams.set('window', analyticsWindow.window);
57
+ requestUrl.searchParams.set('timezone', analyticsWindow.timeZone);
58
+ requestUrl.searchParams.set('now', analyticsWindow.now);
59
+
60
+ const response = await fetch(requestUrl, {
61
+ method: 'GET',
62
+ headers: {
63
+ authorization: `Bearer ${config.apiKey}`,
64
+ accept: 'application/json',
65
+ },
66
+ });
67
+
68
+ if (!response.ok) {
69
+ const detail = await response.text().catch(() => '');
70
+ const err = new Error(`Hosted operational dashboard request failed (${response.status}): ${detail || 'unknown error'}`);
71
+ err.code = 'hosted_dashboard_http_error';
72
+ err.status = response.status;
73
+ throw err;
74
+ }
75
+
76
+ return response.json();
77
+ }
78
+
79
+ async function getOperationalDashboard(options = {}) {
80
+ const analyticsWindow = resolveAnalyticsWindow(options);
81
+ try {
82
+ const data = await fetchHostedDashboard(analyticsWindow);
83
+ return {
84
+ source: 'hosted',
85
+ data,
86
+ fallbackReason: null,
87
+ };
88
+ } catch (err) {
89
+ return {
90
+ source: 'local',
91
+ data: await buildOperationalDashboard(analyticsWindow),
92
+ fallbackReason: err && err.message ? err.message : 'hosted_dashboard_unavailable',
93
+ };
94
+ }
95
+ }
96
+
97
+ module.exports = {
98
+ buildOperationalDashboard,
99
+ fetchHostedDashboard,
100
+ getOperationalDashboard,
101
+ resolveHostedDashboardConfig,
102
+ shouldPreferHostedDashboard,
103
+ };
@@ -0,0 +1,93 @@
1
+ 'use strict';
2
+
3
+ const { getBillingSummaryLive } = require('./billing');
4
+ const { resolveAnalyticsWindow } = require('./analytics-window');
5
+ const { resolveHostedBillingConfig } = require('./hosted-config');
6
+
7
+ function normalizeText(value) {
8
+ if (value === undefined || value === null) return null;
9
+ const text = String(value).trim();
10
+ return text || null;
11
+ }
12
+
13
+ function shouldPreferHostedSummary() {
14
+ return String(process.env.THUMBGATE_METRICS_SOURCE || '').trim().toLowerCase() !== 'local';
15
+ }
16
+
17
+ function resolveHostedSummaryConfig() {
18
+ const runtimeConfig = resolveHostedBillingConfig();
19
+ const apiBaseUrl = normalizeText(process.env.THUMBGATE_BILLING_API_BASE_URL) || runtimeConfig.billingApiBaseUrl;
20
+ const apiKey = normalizeText(process.env.THUMBGATE_API_KEY);
21
+ return {
22
+ apiBaseUrl,
23
+ apiKey,
24
+ };
25
+ }
26
+
27
+ async function fetchHostedBillingSummary(options = {}, config = resolveHostedSummaryConfig()) {
28
+ const analyticsWindow = resolveAnalyticsWindow(options);
29
+ if (!shouldPreferHostedSummary()) {
30
+ const err = new Error('Hosted operational summary is disabled.');
31
+ err.code = 'hosted_summary_disabled';
32
+ throw err;
33
+ }
34
+ if (!config.apiBaseUrl || !config.apiKey) {
35
+ const err = new Error('Hosted operational summary is not configured.');
36
+ err.code = 'hosted_summary_unconfigured';
37
+ throw err;
38
+ }
39
+
40
+ const requestUrl = new URL('/v1/billing/summary', config.apiBaseUrl);
41
+ requestUrl.searchParams.set('window', analyticsWindow.window);
42
+ requestUrl.searchParams.set('timezone', analyticsWindow.timeZone);
43
+ if (options.now !== undefined && options.now !== null && options.now !== '') {
44
+ requestUrl.searchParams.set('now', analyticsWindow.now);
45
+ }
46
+
47
+ const response = await fetch(requestUrl, {
48
+ method: 'GET',
49
+ headers: {
50
+ authorization: `Bearer ${config.apiKey}`,
51
+ accept: 'application/json',
52
+ },
53
+ });
54
+
55
+ if (!response.ok) {
56
+ const detail = await response.text().catch(() => '');
57
+ const err = new Error(`Hosted operational summary request failed (${response.status}): ${detail || 'unknown error'}`);
58
+ err.code = 'hosted_summary_http_error';
59
+ err.status = response.status;
60
+ throw err;
61
+ }
62
+
63
+ return response.json();
64
+ }
65
+
66
+ async function getOperationalBillingSummary(options = {}) {
67
+ const analyticsWindow = resolveAnalyticsWindow(options);
68
+ try {
69
+ const summary = await fetchHostedBillingSummary(analyticsWindow);
70
+ return {
71
+ source: 'hosted',
72
+ summary,
73
+ fallbackReason: null,
74
+ };
75
+ } catch (err) {
76
+ const reason = err && err.message ? err.message : 'hosted_summary_unavailable';
77
+ // TODO: Configure hosted billing via THUMBGATE_BILLING_API_BASE_URL and THUMBGATE_API_KEY
78
+ // to avoid falling back to local state. See docs/PRICING_RESEARCH_2026-03-10.md
79
+ console.warn(`[operational-summary] Hosted billing not configured — falling back to local state. Reason: ${reason}`);
80
+ return {
81
+ source: 'local',
82
+ summary: await getBillingSummaryLive(analyticsWindow),
83
+ fallbackReason: reason,
84
+ };
85
+ }
86
+ }
87
+
88
+ module.exports = {
89
+ fetchHostedBillingSummary,
90
+ getOperationalBillingSummary,
91
+ resolveHostedSummaryConfig,
92
+ shouldPreferHostedSummary,
93
+ };
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const CLAUDE_MD_PATH = path.join(process.cwd(), 'CLAUDE.md');
5
+ const THUMBGATE_DIR = path.join(process.cwd(), '.rlhf');
6
+ const RULES_PATH = path.join(THUMBGATE_DIR, 'prevention-rules.md');
7
+ function optimize() {
8
+ console.log('🚀 [Context Optimizer] Starting CLAUDE.md migration...');
9
+ if (!fs.existsSync(CLAUDE_MD_PATH)) return;
10
+ const content = fs.readFileSync(CLAUDE_MD_PATH, 'utf8');
11
+ if (!fs.existsSync(THUMBGATE_DIR)) fs.mkdirSync(THUMBGATE_DIR, { recursive: true });
12
+ const migrationHeader = '\n### [MIGRATED] Rules from CLAUDE.md\n';
13
+ fs.appendFileSync(RULES_PATH, migrationHeader + content.slice(0, 500) + '\n');
14
+ console.log('✅ Migrated rules to the Pre-Action Gates.');
15
+ }
16
+ if (require.main === module) optimize();
17
+ module.exports = { optimize };
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Org Dashboard — Multi-Agent Orchestration Visibility
6
+ *
7
+ * Aggregates gate decisions, audit trails, and session data across
8
+ * multiple agent sessions into a single org-wide view. CIOs want to
9
+ * see what ALL their agents are doing, not just one at a time.
10
+ *
11
+ * "I'm not going to have 10,000 agents running in the environment
12
+ * that I don't know what they're doing" — CIO.com, March 2026
13
+ *
14
+ * Pro feature: free tier gets single-agent dashboard only.
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const { resolveFeedbackDir } = require('./feedback-paths');
20
+ const { readAuditLog, auditStats, skillAdherence } = require('./audit-trail');
21
+ const { isProTier } = require('./rate-limiter');
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Agent Registry
25
+ // ---------------------------------------------------------------------------
26
+
27
+ const REGISTRY_FILENAME = 'agent-registry.jsonl';
28
+
29
+ function getRegistryPath() {
30
+ return path.join(resolveFeedbackDir(), REGISTRY_FILENAME);
31
+ }
32
+
33
+ /**
34
+ * Register an agent session. Called on MCP server startup or agent bootstrap.
35
+ *
36
+ * @param {object} params
37
+ * @param {string} params.agentId - Unique agent identifier
38
+ * @param {string} [params.source] - Where the agent was spawned from (cli, mcp, github, slack)
39
+ * @param {string} [params.project] - Project/repo name
40
+ * @param {string} [params.branch] - Git branch
41
+ * @param {object} [params.metadata] - Arbitrary metadata
42
+ * @returns {object} The registered agent record
43
+ */
44
+ function registerAgent({ agentId, source, project, branch, metadata } = {}) {
45
+ const id = agentId || `agent_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
46
+ const record = {
47
+ id,
48
+ registeredAt: new Date().toISOString(),
49
+ lastSeenAt: new Date().toISOString(),
50
+ source: source || 'unknown',
51
+ project: project || path.basename(process.cwd()),
52
+ branch: branch || null,
53
+ toolCalls: 0,
54
+ gateBlocks: 0,
55
+ gateWarns: 0,
56
+ metadata: metadata || {},
57
+ };
58
+
59
+ const registryPath = getRegistryPath();
60
+ const dir = path.dirname(registryPath);
61
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
62
+ fs.appendFileSync(registryPath, JSON.stringify(record) + '\n');
63
+ return record;
64
+ }
65
+
66
+ /**
67
+ * Record agent activity — called after each tool call evaluation.
68
+ *
69
+ * @param {string} agentId
70
+ * @param {string} decision - 'allow' | 'deny' | 'warn'
71
+ */
72
+ function recordAgentActivity(agentId, decision) {
73
+ const registryPath = getRegistryPath();
74
+ if (!fs.existsSync(registryPath)) return;
75
+
76
+ const lines = fs.readFileSync(registryPath, 'utf-8').trim().split('\n');
77
+ const updated = [];
78
+ let found = false;
79
+
80
+ for (const line of lines) {
81
+ try {
82
+ const record = JSON.parse(line);
83
+ if (record.id === agentId && !found) {
84
+ record.lastSeenAt = new Date().toISOString();
85
+ record.toolCalls = (record.toolCalls || 0) + 1;
86
+ if (decision === 'deny') record.gateBlocks = (record.gateBlocks || 0) + 1;
87
+ if (decision === 'warn') record.gateWarns = (record.gateWarns || 0) + 1;
88
+ found = true;
89
+ }
90
+ updated.push(JSON.stringify(record));
91
+ } catch {
92
+ updated.push(line);
93
+ }
94
+ }
95
+
96
+ fs.writeFileSync(registryPath, updated.join('\n') + '\n');
97
+ }
98
+
99
+ /**
100
+ * Load all registered agent sessions.
101
+ */
102
+ function loadAgentRegistry() {
103
+ const registryPath = getRegistryPath();
104
+ if (!fs.existsSync(registryPath)) return [];
105
+ const raw = fs.readFileSync(registryPath, 'utf-8').trim();
106
+ if (!raw) return [];
107
+ return raw.split('\n').map(line => {
108
+ try { return JSON.parse(line); }
109
+ catch { return null; }
110
+ }).filter(Boolean);
111
+ }
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // Org Dashboard Aggregation
115
+ // ---------------------------------------------------------------------------
116
+
117
+ /**
118
+ * Generate org-wide dashboard aggregating all agent sessions.
119
+ * Pro feature — returns limited data on free tier.
120
+ *
121
+ * @param {object} [opts]
122
+ * @param {number} [opts.windowHours=24] - Lookback window in hours
123
+ * @returns {object} Org dashboard data
124
+ */
125
+ function generateOrgDashboard(opts = {}) {
126
+ const windowHours = opts.windowHours || 24;
127
+ const cutoff = Date.now() - windowHours * 60 * 60 * 1000;
128
+ const pro = typeof opts.proOverride === 'boolean'
129
+ ? opts.proOverride
130
+ : isProTier(opts.authContext);
131
+
132
+ // Load all agents
133
+ const allAgents = loadAgentRegistry();
134
+ const activeAgents = allAgents.filter(a => new Date(a.lastSeenAt).getTime() > cutoff);
135
+
136
+ // Aggregate audit trail
137
+ const audit = auditStats();
138
+ const adherence = skillAdherence();
139
+
140
+ // Per-agent summary
141
+ const agentSummaries = activeAgents.map(a => ({
142
+ id: a.id,
143
+ source: a.source,
144
+ project: a.project,
145
+ branch: a.branch,
146
+ registeredAt: a.registeredAt,
147
+ lastSeenAt: a.lastSeenAt,
148
+ toolCalls: a.toolCalls || 0,
149
+ gateBlocks: a.gateBlocks || 0,
150
+ gateWarns: a.gateWarns || 0,
151
+ adherenceRate: a.toolCalls > 0
152
+ ? Math.round(((a.toolCalls - (a.gateBlocks || 0) - (a.gateWarns || 0)) / a.toolCalls) * 10000) / 100
153
+ : 100,
154
+ }));
155
+
156
+ // Top blocked gates across all agents
157
+ const topBlockedGates = Object.entries(audit.byGate || {})
158
+ .map(([gateId, counts]) => ({ gateId, blocked: counts.deny || 0, warned: counts.warn || 0 }))
159
+ .sort((a, b) => b.blocked - a.blocked)
160
+ .slice(0, 10);
161
+
162
+ // Risk agents — those with lowest adherence
163
+ const riskAgents = agentSummaries
164
+ .filter(a => a.toolCalls >= 3)
165
+ .sort((a, b) => a.adherenceRate - b.adherenceRate)
166
+ .slice(0, 5);
167
+
168
+ const summary = {
169
+ windowHours,
170
+ totalAgents: allAgents.length,
171
+ activeAgents: activeAgents.length,
172
+ totalToolCalls: audit.total,
173
+ totalBlocked: audit.deny,
174
+ totalWarned: audit.warn,
175
+ totalAllowed: audit.allow,
176
+ orgAdherenceRate: adherence.overall,
177
+ topBlockedGates,
178
+ riskAgents: pro ? riskAgents : riskAgents.slice(0, 1),
179
+ agents: pro ? agentSummaries : agentSummaries.slice(0, 3),
180
+ proRequired: !pro,
181
+ };
182
+
183
+ if (!pro) {
184
+ summary.upgradeMessage = 'Upgrade to Pro for full org visibility — all agents, all gates, all history. https://thumbgate-production.up.railway.app/checkout/pro';
185
+ }
186
+
187
+ return summary;
188
+ }
189
+
190
+ // ---------------------------------------------------------------------------
191
+ // Exports
192
+ // ---------------------------------------------------------------------------
193
+
194
+ module.exports = {
195
+ registerAgent,
196
+ recordAgentActivity,
197
+ loadAgentRegistry,
198
+ generateOrgDashboard,
199
+ getRegistryPath,
200
+ REGISTRY_FILENAME,
201
+ };
@@ -0,0 +1,146 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const PROJECT_ROOT = path.join(__dirname, '..');
7
+ const DEFAULT_CONFIG_PATH = path.join(PROJECT_ROOT, 'config', 'partner-routing.json');
8
+
9
+ function clamp(value, min, max) {
10
+ return Math.min(max, Math.max(min, value));
11
+ }
12
+
13
+ function loadPartnerRoutingConfig(configPath = DEFAULT_CONFIG_PATH) {
14
+ const raw = fs.readFileSync(configPath, 'utf-8');
15
+ const parsed = JSON.parse(raw);
16
+
17
+ if (!parsed || typeof parsed !== 'object') {
18
+ throw new Error('Invalid partner routing config: expected object');
19
+ }
20
+ if (!parsed.defaultProfile || typeof parsed.defaultProfile !== 'string') {
21
+ throw new Error('Invalid partner routing config: missing defaultProfile');
22
+ }
23
+ if (!parsed.profiles || typeof parsed.profiles !== 'object') {
24
+ throw new Error('Invalid partner routing config: missing profiles');
25
+ }
26
+
27
+ return parsed;
28
+ }
29
+
30
+ function normalizePartnerProfile(partnerProfile, config = loadPartnerRoutingConfig()) {
31
+ if (!partnerProfile) {
32
+ return config.defaultProfile;
33
+ }
34
+
35
+ const raw = String(partnerProfile).trim().toLowerCase();
36
+ const alias = config.aliases && config.aliases[raw];
37
+ const resolved = alias || raw;
38
+
39
+ if (!config.profiles[resolved]) {
40
+ throw new Error(`Unknown partner profile: ${partnerProfile}`);
41
+ }
42
+
43
+ return resolved;
44
+ }
45
+
46
+ function getPartnerCategory(partnerProfile) {
47
+ return `partner_${partnerProfile}`;
48
+ }
49
+
50
+ function scaleBudgetValue(value, multiplier) {
51
+ if (!Number.isFinite(value) || value <= 0) {
52
+ return value;
53
+ }
54
+ const effectiveMultiplier = Number.isFinite(multiplier) && multiplier > 0 ? multiplier : 1;
55
+ return Math.max(1, Math.round(value * effectiveMultiplier));
56
+ }
57
+
58
+ function scaleTokenBudget(tokenBudget, multipliers = {}) {
59
+ if (!tokenBudget || typeof tokenBudget !== 'object') {
60
+ return null;
61
+ }
62
+
63
+ return {
64
+ total: scaleBudgetValue(tokenBudget.total, multipliers.total),
65
+ perAction: scaleBudgetValue(tokenBudget.perAction, multipliers.perAction),
66
+ contextPack: scaleBudgetValue(tokenBudget.contextPack, multipliers.contextPack),
67
+ };
68
+ }
69
+
70
+ function buildPartnerStrategy(options = {}) {
71
+ const config = loadPartnerRoutingConfig(options.configPath);
72
+ const profile = normalizePartnerProfile(options.partnerProfile, config);
73
+ const profileConfig = config.profiles[profile] || {};
74
+
75
+ return {
76
+ profile,
77
+ label: profileConfig.label || profile,
78
+ description: profileConfig.description || '',
79
+ verificationMode: profileConfig.verificationMode || 'standard',
80
+ maxRetryDelta: Number.isFinite(profileConfig.maxRetryDelta) ? profileConfig.maxRetryDelta : 0,
81
+ rewardBias: Number.isFinite(profileConfig.rewardBias) ? profileConfig.rewardBias : 0,
82
+ partnerCategory: getPartnerCategory(profile),
83
+ actionBiases: profileConfig.actionBiases || {},
84
+ recommendedChecks: Array.isArray(profileConfig.recommendedChecks) ? profileConfig.recommendedChecks.slice() : [],
85
+ tokenBudget: scaleTokenBudget(options.tokenBudget, profileConfig.tokenBudgetMultiplier || {}),
86
+ };
87
+ }
88
+
89
+ function getPartnerActionBias(action, partnerStrategy) {
90
+ if (!action || !partnerStrategy || !partnerStrategy.actionBiases) {
91
+ return 0;
92
+ }
93
+ return Number(partnerStrategy.actionBiases[action.name] || 0);
94
+ }
95
+
96
+ function resolveVerificationRetries(baseMaxRetries, partnerStrategy) {
97
+ const requested = Number.isFinite(baseMaxRetries) ? baseMaxRetries : 3;
98
+ const delta = partnerStrategy && Number.isFinite(partnerStrategy.maxRetryDelta)
99
+ ? partnerStrategy.maxRetryDelta
100
+ : 0;
101
+ return Math.max(1, requested + delta);
102
+ }
103
+
104
+ function computePartnerReward(params = {}) {
105
+ const config = loadPartnerRoutingConfig(params.configPath);
106
+ const rewardModel = config.rewardModel || {};
107
+ const accepted = params.accepted === true;
108
+ const attempts = Number.isFinite(params.attempts) ? params.attempts : 1;
109
+ const violationCount = Number.isFinite(params.violationCount) ? params.violationCount : 0;
110
+ const partnerStrategy = params.partnerStrategy || buildPartnerStrategy({
111
+ partnerProfile: params.partnerProfile,
112
+ });
113
+
114
+ const baseReward = accepted ? Number(rewardModel.accepted || 1) : Number(rewardModel.rejected || -1);
115
+ const attemptPenalty = Math.max(0, attempts - 1) * Number(rewardModel.attemptPenalty || 0);
116
+ const violationPenalty = Math.min(
117
+ violationCount * Number(rewardModel.violationPenalty || 0),
118
+ Number(rewardModel.maxViolationPenalty || 0),
119
+ );
120
+ const rawReward = baseReward - attemptPenalty - violationPenalty + Number(partnerStrategy.rewardBias || 0);
121
+ const reward = Math.round(clamp(rawReward, -1, 1) * 1000) / 1000;
122
+
123
+ return {
124
+ profile: partnerStrategy.profile,
125
+ reward,
126
+ weightMultiplier: 1 + Math.abs(reward),
127
+ components: {
128
+ baseReward,
129
+ attemptPenalty,
130
+ violationPenalty,
131
+ rewardBias: Number(partnerStrategy.rewardBias || 0),
132
+ },
133
+ };
134
+ }
135
+
136
+ module.exports = {
137
+ DEFAULT_CONFIG_PATH,
138
+ loadPartnerRoutingConfig,
139
+ normalizePartnerProfile,
140
+ getPartnerCategory,
141
+ scaleTokenBudget,
142
+ buildPartnerStrategy,
143
+ getPartnerActionBias,
144
+ resolveVerificationRetries,
145
+ computePartnerReward,
146
+ };