@timmeck/marketing-brain 0.2.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 (294) hide show
  1. package/.mcp.json +9 -0
  2. package/README.md +342 -0
  3. package/dashboard.html +666 -0
  4. package/dist/api/server.d.ts +15 -0
  5. package/dist/api/server.js +73 -0
  6. package/dist/api/server.js.map +1 -0
  7. package/dist/cli/colors.d.ts +43 -0
  8. package/dist/cli/colors.js +54 -0
  9. package/dist/cli/colors.js.map +1 -0
  10. package/dist/cli/commands/campaign.d.ts +2 -0
  11. package/dist/cli/commands/campaign.js +62 -0
  12. package/dist/cli/commands/campaign.js.map +1 -0
  13. package/dist/cli/commands/config.d.ts +2 -0
  14. package/dist/cli/commands/config.js +164 -0
  15. package/dist/cli/commands/config.js.map +1 -0
  16. package/dist/cli/commands/dashboard.d.ts +2 -0
  17. package/dist/cli/commands/dashboard.js +147 -0
  18. package/dist/cli/commands/dashboard.js.map +1 -0
  19. package/dist/cli/commands/doctor.d.ts +2 -0
  20. package/dist/cli/commands/doctor.js +111 -0
  21. package/dist/cli/commands/doctor.js.map +1 -0
  22. package/dist/cli/commands/export.d.ts +2 -0
  23. package/dist/cli/commands/export.js +37 -0
  24. package/dist/cli/commands/export.js.map +1 -0
  25. package/dist/cli/commands/import.d.ts +2 -0
  26. package/dist/cli/commands/import.js +76 -0
  27. package/dist/cli/commands/import.js.map +1 -0
  28. package/dist/cli/commands/insights.d.ts +2 -0
  29. package/dist/cli/commands/insights.js +41 -0
  30. package/dist/cli/commands/insights.js.map +1 -0
  31. package/dist/cli/commands/learn.d.ts +2 -0
  32. package/dist/cli/commands/learn.js +22 -0
  33. package/dist/cli/commands/learn.js.map +1 -0
  34. package/dist/cli/commands/network.d.ts +2 -0
  35. package/dist/cli/commands/network.js +66 -0
  36. package/dist/cli/commands/network.js.map +1 -0
  37. package/dist/cli/commands/post.d.ts +2 -0
  38. package/dist/cli/commands/post.js +45 -0
  39. package/dist/cli/commands/post.js.map +1 -0
  40. package/dist/cli/commands/query.d.ts +2 -0
  41. package/dist/cli/commands/query.js +96 -0
  42. package/dist/cli/commands/query.js.map +1 -0
  43. package/dist/cli/commands/rules.d.ts +2 -0
  44. package/dist/cli/commands/rules.js +25 -0
  45. package/dist/cli/commands/rules.js.map +1 -0
  46. package/dist/cli/commands/start.d.ts +2 -0
  47. package/dist/cli/commands/start.js +91 -0
  48. package/dist/cli/commands/start.js.map +1 -0
  49. package/dist/cli/commands/status.d.ts +2 -0
  50. package/dist/cli/commands/status.js +63 -0
  51. package/dist/cli/commands/status.js.map +1 -0
  52. package/dist/cli/commands/stop.d.ts +2 -0
  53. package/dist/cli/commands/stop.js +34 -0
  54. package/dist/cli/commands/stop.js.map +1 -0
  55. package/dist/cli/commands/suggest.d.ts +2 -0
  56. package/dist/cli/commands/suggest.js +57 -0
  57. package/dist/cli/commands/suggest.js.map +1 -0
  58. package/dist/cli/ipc-helper.d.ts +2 -0
  59. package/dist/cli/ipc-helper.js +26 -0
  60. package/dist/cli/ipc-helper.js.map +1 -0
  61. package/dist/cli/update-check.d.ts +2 -0
  62. package/dist/cli/update-check.js +58 -0
  63. package/dist/cli/update-check.js.map +1 -0
  64. package/dist/config.d.ts +2 -0
  65. package/dist/config.js +111 -0
  66. package/dist/config.js.map +1 -0
  67. package/dist/dashboard/renderer.d.ts +11 -0
  68. package/dist/dashboard/renderer.js +112 -0
  69. package/dist/dashboard/renderer.js.map +1 -0
  70. package/dist/dashboard/server.d.ts +15 -0
  71. package/dist/dashboard/server.js +122 -0
  72. package/dist/dashboard/server.js.map +1 -0
  73. package/dist/db/connection.d.ts +2 -0
  74. package/dist/db/connection.js +19 -0
  75. package/dist/db/connection.js.map +1 -0
  76. package/dist/db/migrations/001_core_schema.d.ts +2 -0
  77. package/dist/db/migrations/001_core_schema.js +62 -0
  78. package/dist/db/migrations/001_core_schema.js.map +1 -0
  79. package/dist/db/migrations/002_learning_schema.d.ts +2 -0
  80. package/dist/db/migrations/002_learning_schema.js +45 -0
  81. package/dist/db/migrations/002_learning_schema.js.map +1 -0
  82. package/dist/db/migrations/003_synapse_schema.d.ts +2 -0
  83. package/dist/db/migrations/003_synapse_schema.js +26 -0
  84. package/dist/db/migrations/003_synapse_schema.js.map +1 -0
  85. package/dist/db/migrations/004_insights_schema.d.ts +2 -0
  86. package/dist/db/migrations/004_insights_schema.js +37 -0
  87. package/dist/db/migrations/004_insights_schema.js.map +1 -0
  88. package/dist/db/migrations/005_fts_indexes.d.ts +2 -0
  89. package/dist/db/migrations/005_fts_indexes.js +76 -0
  90. package/dist/db/migrations/005_fts_indexes.js.map +1 -0
  91. package/dist/db/migrations/index.d.ts +2 -0
  92. package/dist/db/migrations/index.js +47 -0
  93. package/dist/db/migrations/index.js.map +1 -0
  94. package/dist/db/repositories/audience.repository.d.ts +18 -0
  95. package/dist/db/repositories/audience.repository.js +45 -0
  96. package/dist/db/repositories/audience.repository.js.map +1 -0
  97. package/dist/db/repositories/campaign.repository.d.ts +15 -0
  98. package/dist/db/repositories/campaign.repository.js +58 -0
  99. package/dist/db/repositories/campaign.repository.js.map +1 -0
  100. package/dist/db/repositories/engagement.repository.d.ts +26 -0
  101. package/dist/db/repositories/engagement.repository.js +83 -0
  102. package/dist/db/repositories/engagement.repository.js.map +1 -0
  103. package/dist/db/repositories/insight.repository.d.ts +18 -0
  104. package/dist/db/repositories/insight.repository.js +87 -0
  105. package/dist/db/repositories/insight.repository.js.map +1 -0
  106. package/dist/db/repositories/post.repository.d.ts +21 -0
  107. package/dist/db/repositories/post.repository.js +105 -0
  108. package/dist/db/repositories/post.repository.js.map +1 -0
  109. package/dist/db/repositories/rule.repository.d.ts +16 -0
  110. package/dist/db/repositories/rule.repository.js +71 -0
  111. package/dist/db/repositories/rule.repository.js.map +1 -0
  112. package/dist/db/repositories/strategy.repository.d.ts +16 -0
  113. package/dist/db/repositories/strategy.repository.js +69 -0
  114. package/dist/db/repositories/strategy.repository.js.map +1 -0
  115. package/dist/db/repositories/synapse.repository.d.ts +25 -0
  116. package/dist/db/repositories/synapse.repository.js +115 -0
  117. package/dist/db/repositories/synapse.repository.js.map +1 -0
  118. package/dist/db/repositories/template.repository.d.ts +16 -0
  119. package/dist/db/repositories/template.repository.js +61 -0
  120. package/dist/db/repositories/template.repository.js.map +1 -0
  121. package/dist/index.d.ts +2 -0
  122. package/dist/index.js +62 -0
  123. package/dist/index.js.map +1 -0
  124. package/dist/ipc/client.d.ts +13 -0
  125. package/dist/ipc/client.js +93 -0
  126. package/dist/ipc/client.js.map +1 -0
  127. package/dist/ipc/protocol.d.ts +8 -0
  128. package/dist/ipc/protocol.js +29 -0
  129. package/dist/ipc/protocol.js.map +1 -0
  130. package/dist/ipc/router.d.ts +30 -0
  131. package/dist/ipc/router.js +88 -0
  132. package/dist/ipc/router.js.map +1 -0
  133. package/dist/ipc/server.d.ts +14 -0
  134. package/dist/ipc/server.js +130 -0
  135. package/dist/ipc/server.js.map +1 -0
  136. package/dist/learning/confidence-scorer.d.ts +17 -0
  137. package/dist/learning/confidence-scorer.js +26 -0
  138. package/dist/learning/confidence-scorer.js.map +1 -0
  139. package/dist/learning/learning-engine.d.ts +33 -0
  140. package/dist/learning/learning-engine.js +211 -0
  141. package/dist/learning/learning-engine.js.map +1 -0
  142. package/dist/marketing-core.d.ts +17 -0
  143. package/dist/marketing-core.js +233 -0
  144. package/dist/marketing-core.js.map +1 -0
  145. package/dist/mcp/server.d.ts +1 -0
  146. package/dist/mcp/server.js +67 -0
  147. package/dist/mcp/server.js.map +1 -0
  148. package/dist/mcp/tools.d.ts +3 -0
  149. package/dist/mcp/tools.js +138 -0
  150. package/dist/mcp/tools.js.map +1 -0
  151. package/dist/research/research-engine.d.ts +28 -0
  152. package/dist/research/research-engine.js +211 -0
  153. package/dist/research/research-engine.js.map +1 -0
  154. package/dist/services/analytics.service.d.ts +116 -0
  155. package/dist/services/analytics.service.js +69 -0
  156. package/dist/services/analytics.service.js.map +1 -0
  157. package/dist/services/audience.service.d.ts +20 -0
  158. package/dist/services/audience.service.js +30 -0
  159. package/dist/services/audience.service.js.map +1 -0
  160. package/dist/services/campaign.service.d.ts +27 -0
  161. package/dist/services/campaign.service.js +65 -0
  162. package/dist/services/campaign.service.js.map +1 -0
  163. package/dist/services/insight.service.d.ts +18 -0
  164. package/dist/services/insight.service.js +40 -0
  165. package/dist/services/insight.service.js.map +1 -0
  166. package/dist/services/post.service.d.ts +48 -0
  167. package/dist/services/post.service.js +93 -0
  168. package/dist/services/post.service.js.map +1 -0
  169. package/dist/services/rule.service.d.ts +29 -0
  170. package/dist/services/rule.service.js +67 -0
  171. package/dist/services/rule.service.js.map +1 -0
  172. package/dist/services/strategy.service.d.ts +17 -0
  173. package/dist/services/strategy.service.js +39 -0
  174. package/dist/services/strategy.service.js.map +1 -0
  175. package/dist/services/synapse.service.d.ts +22 -0
  176. package/dist/services/synapse.service.js +22 -0
  177. package/dist/services/synapse.service.js.map +1 -0
  178. package/dist/services/template.service.d.ts +17 -0
  179. package/dist/services/template.service.js +37 -0
  180. package/dist/services/template.service.js.map +1 -0
  181. package/dist/synapses/activation.d.ts +13 -0
  182. package/dist/synapses/activation.js +50 -0
  183. package/dist/synapses/activation.js.map +1 -0
  184. package/dist/synapses/decay.d.ts +11 -0
  185. package/dist/synapses/decay.js +27 -0
  186. package/dist/synapses/decay.js.map +1 -0
  187. package/dist/synapses/hebbian.d.ts +13 -0
  188. package/dist/synapses/hebbian.js +35 -0
  189. package/dist/synapses/hebbian.js.map +1 -0
  190. package/dist/synapses/pathfinder.d.ts +14 -0
  191. package/dist/synapses/pathfinder.js +50 -0
  192. package/dist/synapses/pathfinder.js.map +1 -0
  193. package/dist/synapses/synapse-manager.d.ts +32 -0
  194. package/dist/synapses/synapse-manager.js +76 -0
  195. package/dist/synapses/synapse-manager.js.map +1 -0
  196. package/dist/types/config.types.d.ts +69 -0
  197. package/dist/types/config.types.js +2 -0
  198. package/dist/types/config.types.js.map +1 -0
  199. package/dist/types/ipc.types.d.ts +11 -0
  200. package/dist/types/ipc.types.js +2 -0
  201. package/dist/types/ipc.types.js.map +1 -0
  202. package/dist/types/post.types.d.ts +141 -0
  203. package/dist/types/post.types.js +2 -0
  204. package/dist/types/post.types.js.map +1 -0
  205. package/dist/types/synapse.types.d.ts +23 -0
  206. package/dist/types/synapse.types.js +2 -0
  207. package/dist/types/synapse.types.js.map +1 -0
  208. package/dist/utils/events.d.ts +57 -0
  209. package/dist/utils/events.js +23 -0
  210. package/dist/utils/events.js.map +1 -0
  211. package/dist/utils/hash.d.ts +1 -0
  212. package/dist/utils/hash.js +5 -0
  213. package/dist/utils/hash.js.map +1 -0
  214. package/dist/utils/logger.d.ts +8 -0
  215. package/dist/utils/logger.js +39 -0
  216. package/dist/utils/logger.js.map +1 -0
  217. package/dist/utils/paths.d.ts +3 -0
  218. package/dist/utils/paths.js +18 -0
  219. package/dist/utils/paths.js.map +1 -0
  220. package/package.json +40 -0
  221. package/seed-data.json +78 -0
  222. package/src/api/server.ts +86 -0
  223. package/src/cli/colors.ts +59 -0
  224. package/src/cli/commands/campaign.ts +66 -0
  225. package/src/cli/commands/config.ts +168 -0
  226. package/src/cli/commands/dashboard.ts +165 -0
  227. package/src/cli/commands/doctor.ts +110 -0
  228. package/src/cli/commands/export.ts +40 -0
  229. package/src/cli/commands/import.ts +84 -0
  230. package/src/cli/commands/insights.ts +44 -0
  231. package/src/cli/commands/learn.ts +24 -0
  232. package/src/cli/commands/network.ts +71 -0
  233. package/src/cli/commands/post.ts +47 -0
  234. package/src/cli/commands/query.ts +108 -0
  235. package/src/cli/commands/rules.ts +27 -0
  236. package/src/cli/commands/start.ts +100 -0
  237. package/src/cli/commands/status.ts +73 -0
  238. package/src/cli/commands/stop.ts +33 -0
  239. package/src/cli/commands/suggest.ts +64 -0
  240. package/src/cli/ipc-helper.ts +22 -0
  241. package/src/cli/update-check.ts +63 -0
  242. package/src/config.ts +110 -0
  243. package/src/dashboard/renderer.ts +136 -0
  244. package/src/dashboard/server.ts +140 -0
  245. package/src/db/connection.ts +22 -0
  246. package/src/db/migrations/001_core_schema.ts +63 -0
  247. package/src/db/migrations/002_learning_schema.ts +46 -0
  248. package/src/db/migrations/003_synapse_schema.ts +27 -0
  249. package/src/db/migrations/004_insights_schema.ts +38 -0
  250. package/src/db/migrations/005_fts_indexes.ts +77 -0
  251. package/src/db/migrations/index.ts +62 -0
  252. package/src/db/repositories/audience.repository.ts +53 -0
  253. package/src/db/repositories/campaign.repository.ts +72 -0
  254. package/src/db/repositories/engagement.repository.ts +108 -0
  255. package/src/db/repositories/insight.repository.ts +100 -0
  256. package/src/db/repositories/post.repository.ts +123 -0
  257. package/src/db/repositories/rule.repository.ts +87 -0
  258. package/src/db/repositories/strategy.repository.ts +82 -0
  259. package/src/db/repositories/synapse.repository.ts +148 -0
  260. package/src/db/repositories/template.repository.ts +76 -0
  261. package/src/index.ts +69 -0
  262. package/src/ipc/client.ts +110 -0
  263. package/src/ipc/protocol.ts +35 -0
  264. package/src/ipc/router.ts +126 -0
  265. package/src/ipc/server.ts +140 -0
  266. package/src/learning/confidence-scorer.ts +36 -0
  267. package/src/learning/learning-engine.ts +254 -0
  268. package/src/marketing-core.ts +285 -0
  269. package/src/mcp/server.ts +72 -0
  270. package/src/mcp/tools.ts +216 -0
  271. package/src/research/research-engine.ts +226 -0
  272. package/src/services/analytics.service.ts +73 -0
  273. package/src/services/audience.service.ts +40 -0
  274. package/src/services/campaign.service.ts +80 -0
  275. package/src/services/insight.service.ts +54 -0
  276. package/src/services/post.service.ts +116 -0
  277. package/src/services/rule.service.ts +90 -0
  278. package/src/services/strategy.service.ts +53 -0
  279. package/src/services/synapse.service.ts +32 -0
  280. package/src/services/template.service.ts +50 -0
  281. package/src/synapses/activation.ts +80 -0
  282. package/src/synapses/decay.ts +38 -0
  283. package/src/synapses/hebbian.ts +68 -0
  284. package/src/synapses/pathfinder.ts +81 -0
  285. package/src/synapses/synapse-manager.ts +115 -0
  286. package/src/types/config.types.ts +79 -0
  287. package/src/types/ipc.types.ts +8 -0
  288. package/src/types/post.types.ts +156 -0
  289. package/src/types/synapse.types.ts +43 -0
  290. package/src/utils/events.ts +44 -0
  291. package/src/utils/hash.ts +5 -0
  292. package/src/utils/logger.ts +48 -0
  293. package/src/utils/paths.ts +19 -0
  294. package/tsconfig.json +18 -0
@@ -0,0 +1,211 @@
1
+ import { engagementScore } from '../learning/confidence-scorer.js';
2
+ import { getLogger } from '../utils/logger.js';
3
+ export class ResearchEngine {
4
+ config;
5
+ postRepo;
6
+ engagementRepo;
7
+ campaignRepo;
8
+ templateRepo;
9
+ insightRepo;
10
+ synapseManager;
11
+ timer = null;
12
+ logger = getLogger();
13
+ constructor(config, postRepo, engagementRepo, campaignRepo, templateRepo, insightRepo, synapseManager) {
14
+ this.config = config;
15
+ this.postRepo = postRepo;
16
+ this.engagementRepo = engagementRepo;
17
+ this.campaignRepo = campaignRepo;
18
+ this.templateRepo = templateRepo;
19
+ this.insightRepo = insightRepo;
20
+ this.synapseManager = synapseManager;
21
+ }
22
+ start() {
23
+ // Initial delay before first run
24
+ setTimeout(() => {
25
+ this.runCycle();
26
+ this.timer = setInterval(() => {
27
+ try {
28
+ this.runCycle();
29
+ }
30
+ catch (err) {
31
+ this.logger.error('Research cycle error:', err);
32
+ }
33
+ }, this.config.intervalMs);
34
+ }, this.config.initialDelayMs);
35
+ }
36
+ stop() {
37
+ if (this.timer) {
38
+ clearInterval(this.timer);
39
+ this.timer = null;
40
+ }
41
+ }
42
+ runCycle() {
43
+ this.logger.info('Starting research cycle');
44
+ // Expire old insights
45
+ const expired = this.insightRepo.expireOld();
46
+ if (expired > 0)
47
+ this.logger.info(`Expired ${expired} old insights`);
48
+ // Generate new insights
49
+ this.detectTrends();
50
+ this.detectGaps();
51
+ this.detectSynergies();
52
+ this.suggestTemplates();
53
+ this.suggestOptimizations();
54
+ this.logger.info('Research cycle complete');
55
+ }
56
+ detectTrends() {
57
+ const cutoff = new Date();
58
+ cutoff.setDate(cutoff.getDate() - this.config.trendWindowDays);
59
+ const recentPosts = this.postRepo.recentPublished(cutoff.toISOString());
60
+ if (recentPosts.length < this.config.minDataPoints)
61
+ return;
62
+ // Detect platform engagement trends
63
+ const platformScores = {};
64
+ for (const post of recentPosts) {
65
+ const eng = this.engagementRepo.getLatestByPost(post.id);
66
+ if (!eng)
67
+ continue;
68
+ const score = engagementScore(eng);
69
+ if (!platformScores[post.platform])
70
+ platformScores[post.platform] = [];
71
+ platformScores[post.platform].push(score);
72
+ }
73
+ for (const [platform, scores] of Object.entries(platformScores)) {
74
+ if (scores.length < 3)
75
+ continue;
76
+ const avg = scores.reduce((a, b) => a + b, 0) / scores.length;
77
+ const recentAvg = scores.slice(0, Math.ceil(scores.length / 2)).reduce((a, b) => a + b, 0) / Math.ceil(scores.length / 2);
78
+ const olderAvg = scores.slice(Math.ceil(scores.length / 2)).reduce((a, b) => a + b, 0) / Math.floor(scores.length / 2);
79
+ if (olderAvg > 0 && Math.abs(recentAvg - olderAvg) / olderAvg > 0.2) {
80
+ const direction = recentAvg > olderAvg ? 'up' : 'down';
81
+ const pct = Math.round(Math.abs(recentAvg - olderAvg) / olderAvg * 100);
82
+ this.insightRepo.create({
83
+ type: 'trend',
84
+ title: `${platform} engagement trending ${direction}`,
85
+ description: `Engagement on ${platform} is ${direction} ${pct}% over the last ${this.config.trendWindowDays} days (avg score: ${avg.toFixed(0)})`,
86
+ confidence: Math.min(0.9, scores.length / 20),
87
+ priority: pct > 30 ? 8 : 5,
88
+ expires_at: this.expiresAt(),
89
+ });
90
+ }
91
+ }
92
+ }
93
+ detectGaps() {
94
+ const platforms = ['x', 'reddit', 'linkedin', 'bluesky'];
95
+ const postsByPlatform = this.postRepo.countByPlatform();
96
+ for (const platform of platforms) {
97
+ if (!postsByPlatform[platform] || postsByPlatform[platform] === 0) {
98
+ this.insightRepo.create({
99
+ type: 'gap',
100
+ title: `No posts on ${platform}`,
101
+ description: `You haven't posted on ${platform} yet. Consider expanding your reach to this platform.`,
102
+ confidence: 0.8,
103
+ priority: 4,
104
+ expires_at: this.expiresAt(),
105
+ });
106
+ }
107
+ else if (postsByPlatform[platform] < 3) {
108
+ this.insightRepo.create({
109
+ type: 'gap',
110
+ title: `Low activity on ${platform}`,
111
+ description: `Only ${postsByPlatform[platform]} posts on ${platform}. Increasing frequency could improve visibility.`,
112
+ confidence: 0.6,
113
+ priority: 3,
114
+ expires_at: this.expiresAt(),
115
+ });
116
+ }
117
+ }
118
+ }
119
+ detectSynergies() {
120
+ const topPosts = this.engagementRepo.topPosts(20);
121
+ // Look for patterns in top posts
122
+ const platformFormat = {};
123
+ for (const post of topPosts) {
124
+ const fullPost = this.postRepo.getById(post.post_id);
125
+ if (!fullPost)
126
+ continue;
127
+ const key = fullPost.platform;
128
+ if (!platformFormat[key])
129
+ platformFormat[key] = {};
130
+ const format = fullPost.format;
131
+ platformFormat[key][format] = (platformFormat[key][format] ?? 0) + 1;
132
+ }
133
+ for (const [platform, formats] of Object.entries(platformFormat)) {
134
+ const sorted = Object.entries(formats).sort(([, a], [, b]) => b - a);
135
+ if (sorted[0] && sorted[0][1] >= 3) {
136
+ this.insightRepo.create({
137
+ type: 'synergy',
138
+ title: `${sorted[0][0]} works best on ${platform}`,
139
+ description: `${sorted[0][1]} of your top posts on ${platform} use the ${sorted[0][0]} format. This combination consistently performs well.`,
140
+ confidence: sorted[0][1] / topPosts.length,
141
+ priority: 6,
142
+ expires_at: this.expiresAt(),
143
+ });
144
+ }
145
+ }
146
+ }
147
+ suggestTemplates() {
148
+ const topPosts = this.engagementRepo.topPosts(10);
149
+ for (const post of topPosts) {
150
+ const fullPost = this.postRepo.getById(post.post_id);
151
+ if (!fullPost)
152
+ continue;
153
+ // Check if a template already exists for similar structure
154
+ const existing = this.templateRepo.search(fullPost.format, 1);
155
+ if (existing.length > 0)
156
+ continue;
157
+ // If top post has no matching template, suggest creating one
158
+ this.insightRepo.create({
159
+ type: 'template',
160
+ title: `Create template from top ${fullPost.platform} post`,
161
+ description: `Post #${fullPost.id} (${fullPost.format}) has high engagement. Consider extracting its structure as a reusable template.`,
162
+ confidence: 0.7,
163
+ priority: 5,
164
+ expires_at: this.expiresAt(),
165
+ });
166
+ }
167
+ }
168
+ suggestOptimizations() {
169
+ const campaigns = this.campaignRepo.listActive();
170
+ for (const campaign of campaigns) {
171
+ const posts = this.postRepo.listByCampaign(campaign.id, 50);
172
+ if (posts.length < 3)
173
+ continue;
174
+ let totalScore = 0;
175
+ let postCount = 0;
176
+ for (const post of posts) {
177
+ const eng = this.engagementRepo.getLatestByPost(post.id);
178
+ if (!eng)
179
+ continue;
180
+ totalScore += engagementScore(eng);
181
+ postCount++;
182
+ }
183
+ if (postCount === 0)
184
+ continue;
185
+ const avgScore = totalScore / postCount;
186
+ // Suggest cross-posting top content
187
+ const topPost = this.engagementRepo.topPosts(1);
188
+ if (topPost.length > 0 && topPost[0]) {
189
+ const top = topPost[0];
190
+ const topFullPost = this.postRepo.getById(top.post_id);
191
+ if (topFullPost && topFullPost.campaign_id === campaign.id) {
192
+ this.insightRepo.create({
193
+ type: 'optimization',
194
+ title: `Cross-post top content from "${campaign.name}"`,
195
+ description: `Your top post in "${campaign.name}" (score: ${engagementScore(top).toFixed(0)}) could be adapted for other platforms. Campaign avg: ${avgScore.toFixed(0)}.`,
196
+ confidence: 0.6,
197
+ priority: 4,
198
+ campaign_id: campaign.id,
199
+ expires_at: this.expiresAt(),
200
+ });
201
+ }
202
+ }
203
+ }
204
+ }
205
+ expiresAt() {
206
+ const d = new Date();
207
+ d.setDate(d.getDate() + this.config.insightExpiryDays);
208
+ return d.toISOString();
209
+ }
210
+ }
211
+ //# sourceMappingURL=research-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"research-engine.js","sourceRoot":"","sources":["../../src/research/research-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ import type { PostRepository } from '../db/repositories/post.repository.js';
2
+ import type { EngagementRepository } from '../db/repositories/engagement.repository.js';
3
+ import type { CampaignRepository } from '../db/repositories/campaign.repository.js';
4
+ import type { StrategyRepository } from '../db/repositories/strategy.repository.js';
5
+ import type { RuleRepository } from '../db/repositories/rule.repository.js';
6
+ import type { TemplateRepository } from '../db/repositories/template.repository.js';
7
+ import type { InsightRepository } from '../db/repositories/insight.repository.js';
8
+ import type { SynapseManager } from '../synapses/synapse-manager.js';
9
+ export declare class AnalyticsService {
10
+ private postRepo;
11
+ private engagementRepo;
12
+ private campaignRepo;
13
+ private strategyRepo;
14
+ private ruleRepo;
15
+ private templateRepo;
16
+ private insightRepo;
17
+ private synapseManager;
18
+ constructor(postRepo: PostRepository, engagementRepo: EngagementRepository, campaignRepo: CampaignRepository, strategyRepo: StrategyRepository, ruleRepo: RuleRepository, templateRepo: TemplateRepository, insightRepo: InsightRepository, synapseManager: SynapseManager);
19
+ getSummary(): {
20
+ posts: {
21
+ total: number;
22
+ byPlatform: Record<string, number>;
23
+ byStatus: Record<string, number>;
24
+ };
25
+ campaigns: {
26
+ total: number;
27
+ };
28
+ strategies: {
29
+ total: number;
30
+ };
31
+ rules: {
32
+ total: number;
33
+ active: number;
34
+ };
35
+ templates: {
36
+ total: number;
37
+ };
38
+ insights: {
39
+ active: number;
40
+ total: number;
41
+ };
42
+ network: {
43
+ synapses: number;
44
+ nodes: number;
45
+ avgWeight: number;
46
+ };
47
+ };
48
+ getTopPerformers(limit?: number): {
49
+ topPosts: (import("../types/post.types.js").Engagement & {
50
+ platform: string;
51
+ content: string;
52
+ published_at: string;
53
+ })[];
54
+ platformStats: {
55
+ platform: string;
56
+ avg_likes: number;
57
+ avg_comments: number;
58
+ avg_shares: number;
59
+ avg_impressions: number;
60
+ avg_clicks: number;
61
+ post_count: number;
62
+ }[];
63
+ topStrategies: import("../types/post.types.js").Strategy[];
64
+ };
65
+ getDashboardData(): {
66
+ summary: {
67
+ posts: {
68
+ total: number;
69
+ byPlatform: Record<string, number>;
70
+ byStatus: Record<string, number>;
71
+ };
72
+ campaigns: {
73
+ total: number;
74
+ };
75
+ strategies: {
76
+ total: number;
77
+ };
78
+ rules: {
79
+ total: number;
80
+ active: number;
81
+ };
82
+ templates: {
83
+ total: number;
84
+ };
85
+ insights: {
86
+ active: number;
87
+ total: number;
88
+ };
89
+ network: {
90
+ synapses: number;
91
+ nodes: number;
92
+ avgWeight: number;
93
+ };
94
+ };
95
+ topPerformers: {
96
+ topPosts: (import("../types/post.types.js").Engagement & {
97
+ platform: string;
98
+ content: string;
99
+ published_at: string;
100
+ })[];
101
+ platformStats: {
102
+ platform: string;
103
+ avg_likes: number;
104
+ avg_comments: number;
105
+ avg_shares: number;
106
+ avg_impressions: number;
107
+ avg_clicks: number;
108
+ post_count: number;
109
+ }[];
110
+ topStrategies: import("../types/post.types.js").Strategy[];
111
+ };
112
+ recentInsights: import("../types/post.types.js").Insight[];
113
+ activeRules: import("../types/post.types.js").MarketingRule[];
114
+ strongestConnections: import("../types/synapse.types.js").SynapseRecord[];
115
+ };
116
+ }
@@ -0,0 +1,69 @@
1
+ export class AnalyticsService {
2
+ postRepo;
3
+ engagementRepo;
4
+ campaignRepo;
5
+ strategyRepo;
6
+ ruleRepo;
7
+ templateRepo;
8
+ insightRepo;
9
+ synapseManager;
10
+ constructor(postRepo, engagementRepo, campaignRepo, strategyRepo, ruleRepo, templateRepo, insightRepo, synapseManager) {
11
+ this.postRepo = postRepo;
12
+ this.engagementRepo = engagementRepo;
13
+ this.campaignRepo = campaignRepo;
14
+ this.strategyRepo = strategyRepo;
15
+ this.ruleRepo = ruleRepo;
16
+ this.templateRepo = templateRepo;
17
+ this.insightRepo = insightRepo;
18
+ this.synapseManager = synapseManager;
19
+ }
20
+ getSummary() {
21
+ const network = this.synapseManager.getNetworkStats();
22
+ return {
23
+ posts: {
24
+ total: this.postRepo.countAll(),
25
+ byPlatform: this.postRepo.countByPlatform(),
26
+ byStatus: this.postRepo.countByStatus(),
27
+ },
28
+ campaigns: {
29
+ total: this.campaignRepo.countAll(),
30
+ },
31
+ strategies: {
32
+ total: this.strategyRepo.countAll(),
33
+ },
34
+ rules: {
35
+ total: this.ruleRepo.countAll(),
36
+ active: this.ruleRepo.countActive(),
37
+ },
38
+ templates: {
39
+ total: this.templateRepo.countAll(),
40
+ },
41
+ insights: {
42
+ active: this.insightRepo.countActive(),
43
+ total: this.insightRepo.countAll(),
44
+ },
45
+ network: {
46
+ synapses: network.totalSynapses,
47
+ nodes: network.totalNodes,
48
+ avgWeight: network.avgWeight,
49
+ },
50
+ };
51
+ }
52
+ getTopPerformers(limit = 10) {
53
+ return {
54
+ topPosts: this.engagementRepo.topPosts(limit),
55
+ platformStats: this.engagementRepo.avgByPlatform(),
56
+ topStrategies: this.strategyRepo.topByConfidence(0.6, limit),
57
+ };
58
+ }
59
+ getDashboardData() {
60
+ return {
61
+ summary: this.getSummary(),
62
+ topPerformers: this.getTopPerformers(5),
63
+ recentInsights: this.insightRepo.listActive(5),
64
+ activeRules: this.ruleRepo.listActive(),
65
+ strongestConnections: this.synapseManager.getStrongestSynapses(10),
66
+ };
67
+ }
68
+ }
69
+ //# sourceMappingURL=analytics.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.service.js","sourceRoot":"","sources":["../../src/services/analytics.service.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,gBAAgB;IAEjB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IARV,YACU,QAAwB,EACxB,cAAoC,EACpC,YAAgC,EAChC,YAAgC,EAChC,QAAwB,EACxB,YAAgC,EAChC,WAA8B,EAC9B,cAA8B;QAP9B,aAAQ,GAAR,QAAQ,CAAgB;QACxB,mBAAc,GAAd,cAAc,CAAsB;QACpC,iBAAY,GAAZ,YAAY,CAAoB;QAChC,iBAAY,GAAZ,YAAY,CAAoB;QAChC,aAAQ,GAAR,QAAQ,CAAgB;QACxB,iBAAY,GAAZ,YAAY,CAAoB;QAChC,gBAAW,GAAX,WAAW,CAAmB;QAC9B,mBAAc,GAAd,cAAc,CAAgB;IACrC,CAAC;IAEJ,UAAU;QACR,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;QAEtD,OAAO;YACL,KAAK,EAAE;gBACL,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;gBAC/B,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE;gBAC3C,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE;aACxC;YACD,SAAS,EAAE;gBACT,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE;aACpC;YACD,UAAU,EAAE;gBACV,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE;aACpC;YACD,KAAK,EAAE;gBACL,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;gBAC/B,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE;aACpC;YACD,SAAS,EAAE;gBACT,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE;aACpC;YACD,QAAQ,EAAE;gBACR,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE;gBACtC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE;aACnC;YACD,OAAO,EAAE;gBACP,QAAQ,EAAE,OAAO,CAAC,aAAa;gBAC/B,KAAK,EAAE,OAAO,CAAC,UAAU;gBACzB,SAAS,EAAE,OAAO,CAAC,SAAS;aAC7B;SACF,CAAC;IACJ,CAAC;IAED,gBAAgB,CAAC,QAAgB,EAAE;QACjC,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC7C,aAAa,EAAE,IAAI,CAAC,cAAc,CAAC,aAAa,EAAE;YAClD,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC;SAC7D,CAAC;IACJ,CAAC;IAED,gBAAgB;QACd,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE;YAC1B,aAAa,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;YACvC,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;YAC9C,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE;YACvC,oBAAoB,EAAE,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAAC,EAAE,CAAC;SACnE,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import type { AudienceRepository } from '../db/repositories/audience.repository.js';
2
+ import type { SynapseManager } from '../synapses/synapse-manager.js';
3
+ import type { Audience } from '../types/post.types.js';
4
+ export declare class AudienceService {
5
+ private audienceRepo;
6
+ private synapseManager;
7
+ constructor(audienceRepo: AudienceRepository, synapseManager: SynapseManager);
8
+ create(data: {
9
+ name: string;
10
+ platform?: string;
11
+ demographics?: string;
12
+ interests?: string;
13
+ }): Audience;
14
+ linkToPost(audienceId: number, postId: number): void;
15
+ getById(id: number): Audience | undefined;
16
+ listAll(): Audience[];
17
+ getStats(): {
18
+ total: number;
19
+ };
20
+ }
@@ -0,0 +1,30 @@
1
+ export class AudienceService {
2
+ audienceRepo;
3
+ synapseManager;
4
+ constructor(audienceRepo, synapseManager) {
5
+ this.audienceRepo = audienceRepo;
6
+ this.synapseManager = synapseManager;
7
+ }
8
+ create(data) {
9
+ const existing = this.audienceRepo.getByName(data.name);
10
+ if (existing)
11
+ return existing;
12
+ const id = this.audienceRepo.create(data);
13
+ return this.audienceRepo.getById(id);
14
+ }
15
+ linkToPost(audienceId, postId) {
16
+ this.synapseManager.strengthen({ type: 'post', id: postId }, { type: 'audience', id: audienceId }, 'engages_with');
17
+ }
18
+ getById(id) {
19
+ return this.audienceRepo.getById(id);
20
+ }
21
+ listAll() {
22
+ return this.audienceRepo.listAll();
23
+ }
24
+ getStats() {
25
+ return {
26
+ total: this.audienceRepo.countAll(),
27
+ };
28
+ }
29
+ }
30
+ //# sourceMappingURL=audience.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audience.service.js","sourceRoot":"","sources":["../../src/services/audience.service.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,eAAe;IAEhB;IACA;IAFV,YACU,YAAgC,EAChC,cAA8B;QAD9B,iBAAY,GAAZ,YAAY,CAAoB;QAChC,mBAAc,GAAd,cAAc,CAAgB;IACrC,CAAC;IAEJ,MAAM,CAAC,IAAoF;QACzF,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAE,CAAC;IACxC,CAAC;IAED,UAAU,CAAC,UAAkB,EAAE,MAAc;QAC3C,IAAI,CAAC,cAAc,CAAC,UAAU,CAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAC5B,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,EACpC,cAAc,CACf,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,EAAU;QAChB,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC;IAED,QAAQ;QACN,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE;SACpC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,27 @@
1
+ import type { CampaignRepository } from '../db/repositories/campaign.repository.js';
2
+ import type { PostRepository } from '../db/repositories/post.repository.js';
3
+ import type { EngagementRepository } from '../db/repositories/engagement.repository.js';
4
+ import type { SynapseManager } from '../synapses/synapse-manager.js';
5
+ import type { Campaign, CampaignCreate } from '../types/post.types.js';
6
+ export declare class CampaignService {
7
+ private campaignRepo;
8
+ private postRepo;
9
+ private engagementRepo;
10
+ private synapseManager;
11
+ constructor(campaignRepo: CampaignRepository, postRepo: PostRepository, engagementRepo: EngagementRepository, synapseManager: SynapseManager);
12
+ create(data: CampaignCreate): Campaign;
13
+ getById(id: number): Campaign | undefined;
14
+ getByName(name: string): Campaign | undefined;
15
+ listCampaigns(): Campaign[];
16
+ getStats(campaignId: number): {
17
+ campaign: Campaign;
18
+ postCount: number;
19
+ totalLikes: number;
20
+ totalComments: number;
21
+ totalShares: number;
22
+ totalImpressions: number;
23
+ avgEngagement: number;
24
+ } | null;
25
+ update(id: number, data: Partial<Campaign>): boolean;
26
+ crossPromote(campaignA: number, campaignB: number): void;
27
+ }
@@ -0,0 +1,65 @@
1
+ import { getEventBus } from '../utils/events.js';
2
+ export class CampaignService {
3
+ campaignRepo;
4
+ postRepo;
5
+ engagementRepo;
6
+ synapseManager;
7
+ constructor(campaignRepo, postRepo, engagementRepo, synapseManager) {
8
+ this.campaignRepo = campaignRepo;
9
+ this.postRepo = postRepo;
10
+ this.engagementRepo = engagementRepo;
11
+ this.synapseManager = synapseManager;
12
+ }
13
+ create(data) {
14
+ const existing = this.campaignRepo.getByName(data.name);
15
+ if (existing)
16
+ return existing;
17
+ const id = this.campaignRepo.create(data);
18
+ const campaign = this.campaignRepo.getById(id);
19
+ getEventBus().emit('campaign:created', { campaignId: id, name: data.name });
20
+ return campaign;
21
+ }
22
+ getById(id) {
23
+ return this.campaignRepo.getById(id);
24
+ }
25
+ getByName(name) {
26
+ return this.campaignRepo.getByName(name);
27
+ }
28
+ listCampaigns() {
29
+ return this.campaignRepo.listAll();
30
+ }
31
+ getStats(campaignId) {
32
+ const campaign = this.campaignRepo.getById(campaignId);
33
+ if (!campaign)
34
+ return null;
35
+ const posts = this.postRepo.listByCampaign(campaignId, 1000);
36
+ let totalLikes = 0, totalComments = 0, totalShares = 0, totalImpressions = 0;
37
+ for (const post of posts) {
38
+ const eng = this.engagementRepo.getLatestByPost(post.id);
39
+ if (eng) {
40
+ totalLikes += eng.likes;
41
+ totalComments += eng.comments;
42
+ totalShares += eng.shares;
43
+ totalImpressions += eng.impressions;
44
+ }
45
+ }
46
+ return {
47
+ campaign,
48
+ postCount: posts.length,
49
+ totalLikes,
50
+ totalComments,
51
+ totalShares,
52
+ totalImpressions,
53
+ avgEngagement: posts.length > 0
54
+ ? (totalLikes + totalComments * 3 + totalShares * 5) / posts.length
55
+ : 0,
56
+ };
57
+ }
58
+ update(id, data) {
59
+ return this.campaignRepo.update(id, data);
60
+ }
61
+ crossPromote(campaignA, campaignB) {
62
+ this.synapseManager.strengthen({ type: 'campaign', id: campaignA }, { type: 'campaign', id: campaignB }, 'cross_promotes');
63
+ }
64
+ }
65
+ //# sourceMappingURL=campaign.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"campaign.service.js","sourceRoot":"","sources":["../../src/services/campaign.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { InsightRepository } from '../db/repositories/insight.repository.js';
2
+ import type { SynapseManager } from '../synapses/synapse-manager.js';
3
+ import type { Insight, InsightCreate } from '../types/post.types.js';
4
+ export declare class InsightService {
5
+ private insightRepo;
6
+ private synapseManager;
7
+ constructor(insightRepo: InsightRepository, synapseManager: SynapseManager);
8
+ create(data: InsightCreate): Insight;
9
+ listActive(limit?: number): Insight[];
10
+ listByType(type: string, limit?: number): Insight[];
11
+ listByCampaign(campaignId: number): Insight[];
12
+ deactivate(id: number): void;
13
+ expireOld(): number;
14
+ getStats(): {
15
+ active: number;
16
+ total: number;
17
+ };
18
+ }
@@ -0,0 +1,40 @@
1
+ import { getEventBus } from '../utils/events.js';
2
+ export class InsightService {
3
+ insightRepo;
4
+ synapseManager;
5
+ constructor(insightRepo, synapseManager) {
6
+ this.insightRepo = insightRepo;
7
+ this.synapseManager = synapseManager;
8
+ }
9
+ create(data) {
10
+ const id = this.insightRepo.create(data);
11
+ const insight = this.insightRepo.getById(id);
12
+ if (data.campaign_id) {
13
+ this.synapseManager.strengthen({ type: 'insight', id }, { type: 'campaign', id: data.campaign_id }, 'informs');
14
+ }
15
+ getEventBus().emit('insight:created', { insightId: id, type: data.type });
16
+ return insight;
17
+ }
18
+ listActive(limit) {
19
+ return this.insightRepo.listActive(limit);
20
+ }
21
+ listByType(type, limit) {
22
+ return this.insightRepo.listByType(type, limit);
23
+ }
24
+ listByCampaign(campaignId) {
25
+ return this.insightRepo.listByCampaign(campaignId);
26
+ }
27
+ deactivate(id) {
28
+ this.insightRepo.deactivate(id);
29
+ }
30
+ expireOld() {
31
+ return this.insightRepo.expireOld();
32
+ }
33
+ getStats() {
34
+ return {
35
+ active: this.insightRepo.countActive(),
36
+ total: this.insightRepo.countAll(),
37
+ };
38
+ }
39
+ }
40
+ //# sourceMappingURL=insight.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insight.service.js","sourceRoot":"","sources":["../../src/services/insight.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,OAAO,cAAc;IAEf;IACA;IAFV,YACU,WAA8B,EAC9B,cAA8B;QAD9B,gBAAW,GAAX,WAAW,CAAmB;QAC9B,mBAAc,GAAd,cAAc,CAAgB;IACrC,CAAC;IAEJ,MAAM,CAAC,IAAmB;QACxB,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAE,CAAC;QAE9C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,cAAc,CAAC,UAAU,CAC5B,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EACvB,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,EAC1C,SAAS,CACV,CAAC;QACJ,CAAC;QAED,WAAW,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1E,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,UAAU,CAAC,KAAc;QACvB,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,UAAU,CAAC,IAAY,EAAE,KAAc;QACrC,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,cAAc,CAAC,UAAkB;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC;IAED,UAAU,CAAC,EAAU;QACnB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;IACtC,CAAC;IAED,QAAQ;QACN,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE;YACtC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE;SACnC,CAAC;IACJ,CAAC;CACF"}