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
@@ -1,356 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- function toNumber(value) {
5
- const numeric = Number(value || 0);
6
- return Number.isFinite(numeric) ? numeric : 0;
7
- }
8
-
9
- function safeRate(numerator, denominator, precision = 4) {
10
- if (!denominator) return 0;
11
- return Number((toNumber(numerator) / toNumber(denominator)).toFixed(precision));
12
- }
13
-
14
- function clamp01(value) {
15
- return Math.max(0, Math.min(1, toNumber(value)));
16
- }
17
-
18
- function normalizeCapped(value, cap) {
19
- const capped = toNumber(cap);
20
- if (!capped || capped <= 0) return 0;
21
- return clamp01(toNumber(value) / capped);
22
- }
23
-
24
- function sumCounter(counter = {}) {
25
- return Object.values(counter).reduce((sum, value) => sum + toNumber(value), 0);
26
- }
27
-
28
- function summarizeSeverity(anomalies = []) {
29
- if (anomalies.some((entry) => entry.severity === 'critical')) return 'critical';
30
- if (anomalies.some((entry) => entry.severity === 'warning')) return 'warning';
31
- return 'healthy';
32
- }
33
-
34
- function toBand(score) {
35
- if (score >= 0.8) return 'very_high';
36
- if (score >= 0.6) return 'high';
37
- if (score >= 0.4) return 'medium';
38
- if (score >= 0.2) return 'low';
39
- return 'very_low';
40
- }
41
-
42
- function weightedAverage(entries = []) {
43
- const active = entries.filter((entry) => entry && Number.isFinite(entry.value) && entry.weight > 0);
44
- const totalWeight = active.reduce((sum, entry) => sum + entry.weight, 0);
45
- if (!totalWeight) return 0;
46
- return active.reduce((sum, entry) => sum + (entry.value * entry.weight), 0) / totalWeight;
47
- }
48
-
49
- function smoothedRate(successes, trials, priorRate = 0, priorWeight = 8) {
50
- const trialCount = Math.max(0, toNumber(trials));
51
- const successCount = Math.max(0, toNumber(successes));
52
- const boundedPrior = clamp01(priorRate);
53
- return safeRate(successCount + (boundedPrior * priorWeight), trialCount + priorWeight, 6);
54
- }
55
-
56
- function countQualifiedCreators(rows = []) {
57
- return rows.filter((row) => {
58
- return toNumber(row.workflowSprintLeads) > 0
59
- || toNumber(row.qualifiedWorkflowSprintLeads) > 0
60
- || toNumber(row.bookedRevenueCents) > 0
61
- || toNumber(row.checkoutStarts) > 0;
62
- }).length;
63
- }
64
-
65
- function buildBenchmarks({ telemetryAnalytics = {}, billingSummary = {}, stagingModel = {} } = {}) {
66
- const uniqueVisitors = toNumber(telemetryAnalytics.visitors && telemetryAnalytics.visitors.uniqueVisitors);
67
- const checkoutStarts = toNumber(telemetryAnalytics.ctas && telemetryAnalytics.ctas.checkoutStarts);
68
- const acquisitionLeads = toNumber(billingSummary.signups && billingSummary.signups.uniqueLeads);
69
- const paidCustomers = toNumber(billingSummary.revenue && billingSummary.revenue.paidCustomers);
70
- const bookedRevenueCents = toNumber(billingSummary.revenue && billingSummary.revenue.bookedRevenueCents);
71
- const revenuePerPaidCents = paidCustomers > 0
72
- ? Math.max(1, Math.round(bookedRevenueCents / paidCustomers))
73
- : 1900;
74
- const creatorRows = Array.isArray(stagingModel.dims && stagingModel.dims.creators)
75
- ? stagingModel.dims.creators
76
- : [];
77
-
78
- return {
79
- uniqueVisitors,
80
- checkoutStarts,
81
- acquisitionLeads,
82
- paidCustomers,
83
- bookedRevenueCents,
84
- revenuePerPaidCents,
85
- visitorToCheckoutRate: safeRate(checkoutStarts, uniqueVisitors, 6),
86
- visitorToLeadRate: safeRate(acquisitionLeads, uniqueVisitors, 6),
87
- visitorToPaidRate: safeRate(paidCustomers, uniqueVisitors, 6),
88
- checkoutToLeadRate: safeRate(acquisitionLeads, checkoutStarts, 6),
89
- checkoutToPaidRate: safeRate(paidCustomers, checkoutStarts, 6),
90
- leadToPaidRate: safeRate(paidCustomers, acquisitionLeads, 6),
91
- creatorCount: creatorRows.length,
92
- qualifiedCreatorCount: countQualifiedCreators(creatorRows),
93
- };
94
- }
95
-
96
- function buildOpportunityForecast(row, benchmarks, labelKey) {
97
- const pageViews = toNumber(row.pageViews);
98
- const checkoutStarts = toNumber(row.checkoutStarts);
99
- const acquisitionLeads = toNumber(row.acquisitionLeads);
100
- const paidCustomers = toNumber(row.paidCustomers);
101
- const bookedRevenueCents = toNumber(row.bookedRevenueCents);
102
- const workflowSprintLeads = toNumber(row.workflowSprintLeads);
103
- const qualifiedWorkflowSprintLeads = toNumber(row.qualifiedWorkflowSprintLeads);
104
-
105
- const visitorToPaid = smoothedRate(
106
- paidCustomers,
107
- pageViews,
108
- benchmarks.visitorToPaidRate,
109
- 12
110
- );
111
- const checkoutToPaid = smoothedRate(
112
- paidCustomers,
113
- checkoutStarts,
114
- benchmarks.checkoutToPaidRate,
115
- 8
116
- );
117
- const leadToPaid = smoothedRate(
118
- paidCustomers,
119
- acquisitionLeads,
120
- benchmarks.leadToPaidRate,
121
- 6
122
- );
123
-
124
- const predictedPaidCustomers = Math.max(
125
- paidCustomers,
126
- weightedAverage([
127
- { value: pageViews * visitorToPaid, weight: pageViews > 0 ? 0.2 : 0 },
128
- { value: checkoutStarts * checkoutToPaid, weight: checkoutStarts > 0 ? 0.45 : 0 },
129
- { value: acquisitionLeads * leadToPaid, weight: acquisitionLeads > 0 ? 0.35 : 0 },
130
- ])
131
- );
132
- const predictedBookedRevenueCents = Math.round(predictedPaidCustomers * benchmarks.revenuePerPaidCents);
133
- const opportunityRevenueCents = Math.max(0, predictedBookedRevenueCents - bookedRevenueCents);
134
- const sampleVolume = pageViews + checkoutStarts + (acquisitionLeads * 2) + (workflowSprintLeads * 3);
135
- const confidence = clamp01(Math.log1p(sampleVolume) / Math.log1p(40));
136
- const momentumScore = clamp01(weightedAverage([
137
- { value: normalizeCapped(pageViews, 50), weight: 0.2 },
138
- { value: normalizeCapped(checkoutStarts, 12), weight: 0.35 },
139
- { value: normalizeCapped(acquisitionLeads, 6), weight: 0.25 },
140
- { value: normalizeCapped(qualifiedWorkflowSprintLeads, 3), weight: 0.2 },
141
- ]));
142
-
143
- return {
144
- key: row.key || 'unknown',
145
- label: row[labelKey] || row.key || 'unknown',
146
- pageViews,
147
- checkoutStarts,
148
- acquisitionLeads,
149
- paidCustomers,
150
- bookedRevenueCents,
151
- workflowSprintLeads,
152
- qualifiedWorkflowSprintLeads,
153
- predictedPaidCustomers: Number(predictedPaidCustomers.toFixed(2)),
154
- predictedBookedRevenueCents,
155
- opportunityRevenueCents,
156
- confidence: Number(confidence.toFixed(4)),
157
- momentumScore: Number(momentumScore.toFixed(4)),
158
- band: toBand(clamp01((confidence * 0.45) + (momentumScore * 0.55))),
159
- };
160
- }
161
-
162
- function scoreDimensionForecasts(rows = [], benchmarks = {}, labelKey = 'key') {
163
- return rows
164
- .map((row) => buildOpportunityForecast(row, benchmarks, labelKey))
165
- .filter((row) => row.pageViews > 0 || row.checkoutStarts > 0 || row.acquisitionLeads > 0 || row.bookedRevenueCents > 0)
166
- .sort((left, right) => {
167
- if (right.opportunityRevenueCents !== left.opportunityRevenueCents) {
168
- return right.opportunityRevenueCents - left.opportunityRevenueCents;
169
- }
170
- if (right.predictedBookedRevenueCents !== left.predictedBookedRevenueCents) {
171
- return right.predictedBookedRevenueCents - left.predictedBookedRevenueCents;
172
- }
173
- return String(left.key).localeCompare(String(right.key));
174
- });
175
- }
176
-
177
- function summarizeDrivers(drivers = []) {
178
- return drivers
179
- .sort((left, right) => right.impact - left.impact)
180
- .filter((driver) => driver.impact > 0)
181
- .slice(0, 3)
182
- .map((driver) => ({
183
- key: driver.key,
184
- label: driver.label,
185
- impact: Number(driver.impact.toFixed(4)),
186
- rawValue: driver.rawValue,
187
- }));
188
- }
189
-
190
- function scoreUpgradePropensity({ telemetryAnalytics = {}, billingSummary = {}, stagingModel = {}, gateStats = {}, team = {} } = {}) {
191
- const benchmarks = buildBenchmarks({ telemetryAnalytics, billingSummary, stagingModel });
192
- const pricingSignals = toNumber(telemetryAnalytics.pricing && telemetryAnalytics.pricing.pricingInterestEvents);
193
- const tooExpensiveSignals = toNumber(telemetryAnalytics.buyerLoss && telemetryAnalytics.buyerLoss.reasonsByCode && telemetryAnalytics.buyerLoss.reasonsByCode.too_expensive);
194
- const workflowSprintLeads = toNumber(billingSummary.pipeline && billingSummary.pipeline.workflowSprintLeads && billingSummary.pipeline.workflowSprintLeads.total);
195
- const qualifiedWorkflowSprintLeads = toNumber(billingSummary.pipeline && billingSummary.pipeline.qualifiedWorkflowSprintLeads && billingSummary.pipeline.qualifiedWorkflowSprintLeads.total);
196
- const activeProKeys = toNumber(billingSummary.keys && billingSummary.keys.active);
197
- const totalUsage = toNumber(billingSummary.keys && billingSummary.keys.totalUsage);
198
- const blockedActions = toNumber(gateStats.blocked);
199
- const activeAgents = toNumber(team.activeAgents);
200
-
201
- const proDrivers = [
202
- { key: 'checkoutStarts', label: 'checkout starts', impact: normalizeCapped(benchmarks.checkoutStarts, 12) * 0.28, rawValue: benchmarks.checkoutStarts },
203
- { key: 'acquisitionLeads', label: 'captured leads', impact: normalizeCapped(benchmarks.acquisitionLeads, 6) * 0.2, rawValue: benchmarks.acquisitionLeads },
204
- { key: 'visitorToCheckoutRate', label: 'visitor → checkout rate', impact: normalizeCapped(benchmarks.visitorToCheckoutRate, 0.08) * 0.18, rawValue: benchmarks.visitorToCheckoutRate },
205
- { key: 'pricingInterest', label: 'pricing intent', impact: normalizeCapped(pricingSignals, 8) * 0.14, rawValue: pricingSignals },
206
- { key: 'totalUsage', label: 'usage depth', impact: normalizeCapped(totalUsage, 300) * 0.12, rawValue: totalUsage },
207
- { key: 'blockedActions', label: 'blocked mistakes', impact: normalizeCapped(blockedActions, 30) * 0.08, rawValue: blockedActions },
208
- ];
209
- const proPenalty = normalizeCapped(tooExpensiveSignals, 6) * 0.12;
210
- const proScore = clamp01(proDrivers.reduce((sum, driver) => sum + driver.impact, 0) - proPenalty);
211
-
212
- const teamDrivers = [
213
- { key: 'qualifiedWorkflowSprintLeads', label: 'qualified workflow sprint leads', impact: normalizeCapped(qualifiedWorkflowSprintLeads, 3) * 0.3, rawValue: qualifiedWorkflowSprintLeads },
214
- { key: 'workflowSprintLeads', label: 'workflow sprint leads', impact: normalizeCapped(workflowSprintLeads, 5) * 0.22, rawValue: workflowSprintLeads },
215
- { key: 'activeProKeys', label: 'active Pro keys', impact: normalizeCapped(activeProKeys, 5) * 0.16, rawValue: activeProKeys },
216
- { key: 'qualifiedCreators', label: 'qualified creators/channels', impact: normalizeCapped(benchmarks.qualifiedCreatorCount, 4) * 0.12, rawValue: benchmarks.qualifiedCreatorCount },
217
- { key: 'activeAgents', label: 'active agents', impact: normalizeCapped(activeAgents, 6) * 0.12, rawValue: activeAgents },
218
- { key: 'leadToPaidRate', label: 'lead → paid rate', impact: normalizeCapped(benchmarks.leadToPaidRate, 0.5) * 0.08, rawValue: benchmarks.leadToPaidRate },
219
- ];
220
- const teamScore = clamp01(teamDrivers.reduce((sum, driver) => sum + driver.impact, 0));
221
-
222
- return {
223
- pro: {
224
- score: Number(proScore.toFixed(4)),
225
- band: toBand(proScore),
226
- confidence: Number(clamp01(Math.log1p(benchmarks.uniqueVisitors + benchmarks.checkoutStarts + pricingSignals) / Math.log1p(80)).toFixed(4)),
227
- drivers: summarizeDrivers(proDrivers),
228
- pricingResistanceSignals: tooExpensiveSignals,
229
- },
230
- team: {
231
- score: Number(teamScore.toFixed(4)),
232
- band: toBand(teamScore),
233
- confidence: Number(clamp01(Math.log1p(workflowSprintLeads + qualifiedWorkflowSprintLeads + activeProKeys + activeAgents) / Math.log1p(24)).toFixed(4)),
234
- drivers: summarizeDrivers(teamDrivers),
235
- },
236
- };
237
- }
238
-
239
- function detectPredictiveAnomalies({ telemetryAnalytics = {}, billingSummary = {}, creatorForecasts = [], sourceForecasts = [] } = {}) {
240
- const anomalies = [];
241
- const uniqueVisitors = toNumber(telemetryAnalytics.visitors && telemetryAnalytics.visitors.uniqueVisitors);
242
- const checkoutStarts = toNumber(telemetryAnalytics.ctas && telemetryAnalytics.ctas.checkoutStarts);
243
- const paidCustomers = toNumber(billingSummary.revenue && billingSummary.revenue.paidCustomers);
244
- const attributionCoverageRate = toNumber(telemetryAnalytics.visitors && telemetryAnalytics.visitors.attributionCoverageRate);
245
- const unreconciledPaidEvents = toNumber(billingSummary.dataQuality && billingSummary.dataQuality.unreconciledPaidEvents);
246
- const tooExpensiveSignals = toNumber(telemetryAnalytics.buyerLoss && telemetryAnalytics.buyerLoss.reasonsByCode && telemetryAnalytics.buyerLoss.reasonsByCode.too_expensive);
247
- const buyerLossSignals = toNumber(telemetryAnalytics.buyerLoss && telemetryAnalytics.buyerLoss.totalSignals);
248
-
249
- if (checkoutStarts >= 3 && paidCustomers === 0) {
250
- anomalies.push({
251
- type: 'conversion_stall',
252
- severity: checkoutStarts >= 8 ? 'critical' : 'warning',
253
- message: 'Checkout starts are arriving without paid conversions.',
254
- evidence: `checkoutStarts=${checkoutStarts}, paidCustomers=${paidCustomers}`,
255
- });
256
- }
257
-
258
- if (uniqueVisitors >= 10 && attributionCoverageRate < 0.6) {
259
- anomalies.push({
260
- type: 'attribution_blindspot',
261
- severity: attributionCoverageRate < 0.35 ? 'critical' : 'warning',
262
- message: 'Attribution coverage is too low for reliable predictive routing.',
263
- evidence: `uniqueVisitors=${uniqueVisitors}, attributionCoverageRate=${attributionCoverageRate}`,
264
- });
265
- }
266
-
267
- if (unreconciledPaidEvents > 0) {
268
- anomalies.push({
269
- type: 'billing_reconciliation',
270
- severity: unreconciledPaidEvents >= 3 ? 'critical' : 'warning',
271
- message: 'Paid events are waiting on reconciliation, which weakens revenue forecasts.',
272
- evidence: `unreconciledPaidEvents=${unreconciledPaidEvents}`,
273
- });
274
- }
275
-
276
- if (buyerLossSignals >= 3 && safeRate(tooExpensiveSignals, buyerLossSignals, 4) >= 0.5) {
277
- anomalies.push({
278
- type: 'pricing_resistance',
279
- severity: 'warning',
280
- message: 'Price sensitivity dominates current loss reasons.',
281
- evidence: `tooExpensiveSignals=${tooExpensiveSignals}, buyerLossSignals=${buyerLossSignals}`,
282
- });
283
- }
284
-
285
- const underperformingCreator = creatorForecasts.find((row) => row.checkoutStarts >= 2 && row.bookedRevenueCents === 0 && row.opportunityRevenueCents >= 1500);
286
- if (underperformingCreator) {
287
- anomalies.push({
288
- type: 'creator_underperformance',
289
- severity: 'warning',
290
- message: `Creator ${underperformingCreator.key} is generating intent without revenue conversion.`,
291
- evidence: `checkouts=${underperformingCreator.checkoutStarts}, opportunityRevenueCents=${underperformingCreator.opportunityRevenueCents}`,
292
- });
293
- }
294
-
295
- const underperformingSource = sourceForecasts.find((row) => row.checkoutStarts >= 3 && row.bookedRevenueCents === 0 && row.opportunityRevenueCents >= 1900);
296
- if (underperformingSource) {
297
- anomalies.push({
298
- type: 'channel_underperformance',
299
- severity: 'warning',
300
- message: `Channel ${underperformingSource.key} is leaking revenue between checkout and paid.`,
301
- evidence: `checkouts=${underperformingSource.checkoutStarts}, opportunityRevenueCents=${underperformingSource.opportunityRevenueCents}`,
302
- });
303
- }
304
-
305
- return anomalies;
306
- }
307
-
308
- function buildPredictiveInsights({ telemetryAnalytics = {}, billingSummary = {}, stagingModel = {}, gateStats = {}, team = {} } = {}) {
309
- const benchmarks = buildBenchmarks({ telemetryAnalytics, billingSummary, stagingModel });
310
- const creators = scoreDimensionForecasts(stagingModel.dims && stagingModel.dims.creators ? stagingModel.dims.creators : [], benchmarks);
311
- const sources = scoreDimensionForecasts(stagingModel.dims && stagingModel.dims.sources ? stagingModel.dims.sources : [], benchmarks);
312
- const upgradePropensity = scoreUpgradePropensity({ telemetryAnalytics, billingSummary, stagingModel, gateStats, team });
313
- const anomalies = detectPredictiveAnomalies({
314
- telemetryAnalytics,
315
- billingSummary,
316
- creatorForecasts: creators,
317
- sourceForecasts: sources,
318
- });
319
-
320
- const aggregatePredictedBookedRevenueCents = Math.max(
321
- benchmarks.bookedRevenueCents,
322
- Math.round(weightedAverage([
323
- { value: benchmarks.uniqueVisitors * smoothedRate(benchmarks.paidCustomers, benchmarks.uniqueVisitors, benchmarks.visitorToPaidRate, 12) * benchmarks.revenuePerPaidCents, weight: benchmarks.uniqueVisitors > 0 ? 0.2 : 0 },
324
- { value: benchmarks.checkoutStarts * smoothedRate(benchmarks.paidCustomers, benchmarks.checkoutStarts, benchmarks.checkoutToPaidRate, 8) * benchmarks.revenuePerPaidCents, weight: benchmarks.checkoutStarts > 0 ? 0.45 : 0 },
325
- { value: benchmarks.acquisitionLeads * smoothedRate(benchmarks.paidCustomers, benchmarks.acquisitionLeads, benchmarks.leadToPaidRate, 6) * benchmarks.revenuePerPaidCents, weight: benchmarks.acquisitionLeads > 0 ? 0.35 : 0 },
326
- ]))
327
- );
328
-
329
- return {
330
- generatedAt: new Date().toISOString(),
331
- modelVersion: 'predictive-insights-v1',
332
- benchmarks,
333
- upgradePropensity,
334
- revenueForecast: {
335
- predictedBookedRevenueCents: aggregatePredictedBookedRevenueCents,
336
- incrementalOpportunityCents: Math.max(0, aggregatePredictedBookedRevenueCents - benchmarks.bookedRevenueCents),
337
- confidence: Number(clamp01((upgradePropensity.pro.confidence + upgradePropensity.team.confidence) / 2).toFixed(4)),
338
- band: toBand(clamp01((upgradePropensity.pro.score * 0.55) + (upgradePropensity.team.score * 0.45))),
339
- },
340
- topCreators: creators.slice(0, 5),
341
- topSources: sources.slice(0, 5),
342
- anomalies,
343
- anomalySummary: {
344
- count: anomalies.length,
345
- severity: summarizeSeverity(anomalies),
346
- },
347
- };
348
- }
349
-
350
- module.exports = {
351
- buildBenchmarks,
352
- buildPredictiveInsights,
353
- detectPredictiveAnomalies,
354
- scoreDimensionForecasts,
355
- scoreUpgradePropensity,
356
- };
package/scripts/pulse.js DELETED
@@ -1,80 +0,0 @@
1
- #!/usr/bin/env node
2
- const { getOperationalBillingSummary } = require('./operational-summary');
3
-
4
- function getPulseSnapshot(summary, now = new Date()) {
5
- const funnel = summary.funnel || {};
6
- const revenue = summary.revenue || {};
7
- const signups = summary.signups || {};
8
- const trafficMetrics = summary.trafficMetrics || {};
9
- const pipeline = summary.pipeline || {};
10
- const operatorGeneratedAcquisition = summary.operatorGeneratedAcquisition || {};
11
- const dataQuality = summary.dataQuality || {};
12
- const leadCount = signups.uniqueLeads || 0;
13
- const activeCount = funnel.stageCounts ? funnel.stageCounts.activation || 0 : 0;
14
- const sprintLeads = pipeline.workflowSprintLeads ? pipeline.workflowSprintLeads.total || 0 : 0;
15
- const qualifiedSprintLeads = pipeline.qualifiedWorkflowSprintLeads ? pipeline.qualifiedWorkflowSprintLeads.total || 0 : 0;
16
- const paidProviderEvents = revenue.paidProviderEvents || 0;
17
- const paidOrders = revenue.paidOrders || 0;
18
- const bookedRevenueCents = revenue.bookedRevenueCents || 0;
19
- const conversionRate = leadCount > 0 ? ((paidOrders / leadCount) * 100).toFixed(2) : '0.00';
20
- const health = bookedRevenueCents > 0
21
- ? '🟢 BOOKED REVENUE ACTIVE'
22
- : ((leadCount > 0 || sprintLeads > 0) ? '🟡 PIPELINE ACTIVE' : '🔴 BLIND / COLD');
23
-
24
- let eta = 'N/A';
25
- if (bookedRevenueCents === 0 && (leadCount > 0 || sprintLeads > 0)) {
26
- const hoursRemaining = 4;
27
- const etaDate = new Date(now.getTime() + hoursRemaining * 60 * 60 * 1000);
28
- eta = `${etaDate.toLocaleTimeString()} (Decision Window)`;
29
- } else if (bookedRevenueCents > 0) {
30
- eta = 'SUCCESS';
31
- }
32
-
33
- return {
34
- leadCount,
35
- activeCount,
36
- visitors: trafficMetrics.visitors || 0,
37
- ctaClicks: trafficMetrics.ctaClicks || 0,
38
- checkoutStarts: trafficMetrics.checkoutStarts || 0,
39
- sprintLeads,
40
- qualifiedSprintLeads,
41
- paidProviderEvents,
42
- paidOrders,
43
- bookedRevenueCents,
44
- conversionRate,
45
- health,
46
- eta,
47
- operatorGeneratedAcquisitionEvents: operatorGeneratedAcquisition.totalEvents || 0,
48
- operatorGeneratedUniqueLeads: operatorGeneratedAcquisition.uniqueLeads || 0,
49
- unreconciledPaidEvents: dataQuality.unreconciledPaidEvents || 0,
50
- topAcquisitionChannels: Object.entries(funnel.eventCounts || {})
51
- .filter(([key]) => key.startsWith('acquisition:'))
52
- .sort((a, b) => b[1] - a[1])
53
- .slice(0, 3),
54
- };
55
- }
56
-
57
- async function showPulse() {
58
- const now = new Date();
59
- const { source, summary, fallbackReason } = await getOperationalBillingSummary();
60
- const snapshot = getPulseSnapshot(summary, now);
61
- console.log('📡 [MISSION CONTROL] MISSION PULSE — ' + now.toLocaleTimeString());
62
- console.log('─'.repeat(60));
63
- console.log(`🛰️ SOURCE: ${source.toUpperCase()}${fallbackReason ? ` (${fallbackReason})` : ''}`);
64
- console.log(`🚀 TRAFFIC: ${snapshot.visitors} Visitors | ${snapshot.ctaClicks} CTA Clicks | ${snapshot.checkoutStarts} Checkout Starts | ${snapshot.leadCount} Unique Leads`);
65
- console.log(`🧪 PIPELINE: ${snapshot.sprintLeads} Sprint Leads | ${snapshot.qualifiedSprintLeads} Qualified Sprint Leads | ${snapshot.activeCount} Activations`);
66
- console.log(`🤖 OPERATOR ACQ: ${snapshot.operatorGeneratedAcquisitionEvents} Events | ${snapshot.operatorGeneratedUniqueLeads} Unique Leads`);
67
- console.log(`💳 REVENUE FLOW: ${snapshot.paidProviderEvents} Paid Provider Events | ${snapshot.paidOrders} Paid Orders`);
68
- console.log(`💵 BOOKED REVENUE: $${(snapshot.bookedRevenueCents / 100).toFixed(2)}`);
69
- console.log(`📈 HEALTH: ${snapshot.health} (${snapshot.conversionRate}% lead-to-paid conversion)`);
70
- console.log(`⏱️ FIRST DOLLAR ETA: ${snapshot.eta}`);
71
- console.log(`🧹 DATA QUALITY: ${snapshot.unreconciledPaidEvents} unreconciled paid event(s)`);
72
- console.log('─'.repeat(60));
73
- console.log('📊 TOP ACQUISITION CHANNELS:');
74
- snapshot.topAcquisitionChannels.forEach(([key, count]) => {
75
- const name = key.split(':')[1];
76
- console.log(` - ${name.padEnd(25)} : ${count} events`);
77
- });
78
- }
79
- if (require.main === module) showPulse().catch(console.error);
80
- module.exports = { showPulse, getPulseSnapshot };
@@ -1,221 +0,0 @@
1
- /**
2
- * Reflector Agent — Self-Healing Brain
3
- *
4
- * On negative feedback, analyzes the conversation window to:
5
- * 1. Identify what the assistant did wrong
6
- * 2. Check if this is a recurring mistake
7
- * 3. Propose a specific, actionable rule
8
- * 4. Return the proposal for user confirmation
9
- *
10
- * This transforms ThumbGate from "Manual Guardrail" to "Self-Healing Brain"
11
- */
12
-
13
- 'use strict';
14
-
15
- const { retrieveWithRerankingSync } = require('./cross-encoder-reranker');
16
- const {
17
- extractFilePaths,
18
- extractToolCalls,
19
- extractErrors,
20
- normalizeConversationWindow,
21
- } = require('./conversation-context');
22
-
23
- /**
24
- * Run a post-mortem analysis on a negative feedback event.
25
- * @param {object} params
26
- * @param {Array} params.conversationWindow - Last N conversation turns
27
- * @param {string} params.context - One-line context from the caller
28
- * @param {string} params.whatWentWrong - What the caller said went wrong
29
- * @param {object} params.structuredRule - IF/THEN rule from lesson-inference
30
- * @param {object} params.feedbackEvent - The stored feedback event
31
- * @returns {object} Reflection result with proposed rule and recurrence info
32
- */
33
- function reflect(params) {
34
- const { conversationWindow, context, whatWentWrong, structuredRule, feedbackEvent } = params;
35
-
36
- // 1. Extract what happened from the conversation
37
- const analysis = analyzeConversation(conversationWindow || []);
38
-
39
- // 2. Check for recurrence — has this mistake happened before?
40
- const recurrence = checkRecurrence(analysis, feedbackEvent);
41
-
42
- // 3. Generate a human-readable proposed rule
43
- const proposedRule = generateProposedRule(analysis, structuredRule, recurrence, whatWentWrong);
44
-
45
- // 4. Determine severity based on recurrence
46
- const severity = recurrence.count >= 3 ? 'critical' : recurrence.count >= 1 ? 'warning' : 'info';
47
-
48
- return {
49
- status: 'reflection_complete',
50
- analysis: {
51
- userIntent: analysis.userIntent,
52
- assistantAction: analysis.assistantAction,
53
- errorDetected: analysis.errorDetected,
54
- toolsUsed: analysis.toolsUsed,
55
- filesInvolved: analysis.filesInvolved,
56
- },
57
- recurrence: {
58
- isRecurring: recurrence.count > 0,
59
- count: recurrence.count,
60
- previousLessons: recurrence.previousLessons.map(l => ({
61
- id: l.id,
62
- title: l.title,
63
- timestamp: l.timestamp,
64
- })),
65
- },
66
- proposedRule: proposedRule,
67
- severity: severity,
68
- message: formatReflectionMessage(proposedRule, recurrence, analysis),
69
- };
70
- }
71
-
72
- function analyzeConversation(window) {
73
- const normalizedWindow = normalizeConversationWindow(window);
74
- const userMsgs = normalizedWindow.filter(m => m.role === 'user');
75
- const assistantMsgs = normalizedWindow.filter(m => m.role === 'assistant');
76
-
77
- const lastUser = userMsgs[userMsgs.length - 1]?.content || '';
78
- const lastAssistant = assistantMsgs[assistantMsgs.length - 1]?.content || '';
79
- const corrections = extractCorrections(userMsgs);
80
- const toolsUsed = extractToolCalls(normalizedWindow);
81
- const filesInvolved = extractFilePaths(normalizedWindow).slice(0, 10);
82
- const errors = extractErrors(normalizedWindow).slice(0, 5);
83
-
84
- return {
85
- userIntent: lastUser.slice(0, 300),
86
- assistantAction: lastAssistant.slice(0, 300),
87
- corrections,
88
- errorDetected: errors.length > 0,
89
- errors,
90
- toolsUsed,
91
- filesInvolved,
92
- messageCount: normalizedWindow.length,
93
- };
94
- }
95
-
96
- function checkRecurrence(analysis, feedbackEvent) {
97
- // Search existing lessons for similar mistakes
98
- let previousLessons = [];
99
- try {
100
- const context = `${analysis.userIntent} ${analysis.assistantAction} ${analysis.corrections.join(' ')}`;
101
- const toolName = analysis.toolsUsed[0] || 'unknown';
102
- previousLessons = retrieveWithRerankingSync(toolName, context, { candidateCount: 20, maxResults: 5 });
103
- // Filter to only negative lessons
104
- previousLessons = previousLessons.filter(l => l.signal === 'negative');
105
- } catch (_err) {
106
- // Non-critical — recurrence check is best-effort
107
- }
108
-
109
- return {
110
- count: previousLessons.length,
111
- previousLessons,
112
- };
113
- }
114
-
115
- function generateProposedRule(analysis, structuredRule, recurrence, whatWentWrong) {
116
- // Build the most specific rule we can from available data
117
- const parts = [];
118
-
119
- // Use corrections from conversation as the strongest signal
120
- if (analysis.corrections.length > 0) {
121
- const correction = analysis.corrections[0];
122
- parts.push({
123
- type: 'constraint',
124
- rule: `NEVER ${correction}`,
125
- source: 'user-correction',
126
- confidence: 0.95,
127
- });
128
- }
129
-
130
- // Use structured rule if available
131
- if (structuredRule?.trigger && structuredRule?.action) {
132
- parts.push({
133
- type: structuredRule.action.type === 'avoid' ? 'constraint' : 'preference',
134
- rule: `IF ${structuredRule.trigger.condition} THEN ${structuredRule.action.description}`,
135
- source: 'inferred',
136
- confidence: structuredRule.confidence || 0.7,
137
- });
138
- }
139
-
140
- // Use whatWentWrong as fallback
141
- if (parts.length === 0 && whatWentWrong) {
142
- parts.push({
143
- type: 'lesson',
144
- rule: `AVOID: ${whatWentWrong}`,
145
- source: 'user-provided',
146
- confidence: 0.8,
147
- });
148
- }
149
-
150
- // Use analysis as last resort
151
- if (parts.length === 0) {
152
- parts.push({
153
- type: 'observation',
154
- rule: `Review approach when: ${analysis.userIntent.slice(0, 80)}`,
155
- source: 'conversation-analysis',
156
- confidence: 0.5,
157
- });
158
- }
159
-
160
- // Pick highest confidence rule
161
- const best = parts.sort((a, b) => b.confidence - a.confidence)[0];
162
-
163
- return {
164
- ...best,
165
- isRecurring: recurrence.count > 0,
166
- recurrenceCount: recurrence.count,
167
- scope: analysis.filesInvolved.length > 0 ? 'project' : 'global',
168
- };
169
- }
170
-
171
- function formatReflectionMessage(proposedRule, recurrence, analysis) {
172
- const prefix = recurrence.count > 0
173
- ? `I've made this mistake ${recurrence.count + 1} time(s) now. `
174
- : '';
175
-
176
- const ruleText = proposedRule.rule;
177
-
178
- const correction = analysis.corrections.length > 0
179
- ? ` I noticed you corrected me: "${analysis.corrections[0].slice(0, 80)}".`
180
- : '';
181
-
182
- const fileContext = analysis.filesInvolved.length > 0
183
- ? ` (in ${analysis.filesInvolved.slice(0, 3).join(', ')})`
184
- : '';
185
-
186
- return `${prefix}${correction} I've recorded a rule${fileContext}: "${ruleText}". Correct?`;
187
- }
188
-
189
- function extractCorrections(userMessages) {
190
- const results = [];
191
- const phraseSets = [
192
- ['don\'t ', 'do not ', 'never ', 'stop '],
193
- ['wrong ', 'incorrect ', 'that\'s not ', 'no, '],
194
- ['i said ', 'i told you ', 'i already '],
195
- ['use ', 'switch to ', 'change to '],
196
- ];
197
-
198
- for (const message of userMessages) {
199
- const content = String(message.content || '').trim();
200
- const lower = content.toLowerCase();
201
- if (!lower) continue;
202
-
203
- for (const phrases of phraseSets) {
204
- for (const phrase of phrases) {
205
- const index = lower.indexOf(phrase);
206
- if (index === -1) continue;
207
- let detail = content.slice(index + phrase.length).trim();
208
- const insteadIndex = detail.toLowerCase().indexOf(' instead');
209
- if (insteadIndex >= 0) {
210
- detail = detail.slice(0, insteadIndex).trim();
211
- }
212
- if (detail) results.push(detail.slice(0, 100));
213
- break;
214
- }
215
- }
216
- }
217
-
218
- return results;
219
- }
220
-
221
- module.exports = { reflect, analyzeConversation, checkRecurrence, generateProposedRule, formatReflectionMessage };