slashvibe-mcp 0.2.9 → 0.3.13

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 (205) hide show
  1. package/README.md +1 -0
  2. package/analytics.js +107 -0
  3. package/auth-store.js +148 -0
  4. package/auto-update.js +130 -0
  5. package/bridges/bridge-monitor.js +388 -0
  6. package/bridges/discord-bot.js +431 -0
  7. package/bridges/farcaster.js +299 -0
  8. package/bridges/telegram.js +261 -0
  9. package/bridges/webhook-health.js +420 -0
  10. package/bridges/webhook-server.js +437 -0
  11. package/bridges/whatsapp.js +441 -0
  12. package/bridges/x-webhook.js +423 -0
  13. package/config.js +154 -5
  14. package/crypto.js +3 -8
  15. package/games/arcade.js +406 -0
  16. package/games/chess.js +451 -0
  17. package/games/colorguess.js +343 -0
  18. package/games/crossword-words.js +171 -0
  19. package/games/crossword.js +461 -0
  20. package/games/drawing.js +347 -0
  21. package/games/gameroulette.js +300 -0
  22. package/games/gamerouter.js +336 -0
  23. package/games/gamestatus.js +337 -0
  24. package/games/guessnumber.js +209 -0
  25. package/games/hangman.js +279 -0
  26. package/games/memory.js +338 -0
  27. package/games/multiplayer-tictactoe.js +389 -0
  28. package/games/pixelart.js +399 -0
  29. package/games/quickduel.js +354 -0
  30. package/games/riddle.js +371 -0
  31. package/games/rockpaperscissors.js +291 -0
  32. package/games/snake.js +406 -0
  33. package/games/storybuilder.js +343 -0
  34. package/games/tictactoe.js +345 -0
  35. package/games/twentyquestions.js +286 -0
  36. package/games/twotruths.js +207 -0
  37. package/games/werewolf.js +508 -0
  38. package/games/wordassociation.js +247 -0
  39. package/games/wordchain.js +135 -0
  40. package/index.js +105 -216
  41. package/intelligence/index.js +45 -0
  42. package/intelligence/infer.js +316 -0
  43. package/intelligence/interests.js +369 -0
  44. package/intelligence/patterns.js +651 -0
  45. package/intelligence/proactive.js +358 -0
  46. package/intelligence/serendipity.js +306 -0
  47. package/memory.js +166 -0
  48. package/notification-emitter.js +77 -0
  49. package/notify.js +102 -1
  50. package/package.json +21 -7
  51. package/prompts.js +1 -1
  52. package/protocol/index.js +161 -1
  53. package/setup.js +402 -0
  54. package/store/api.js +528 -82
  55. package/store/profiles.js +160 -12
  56. package/tools/_actions.js +463 -16
  57. package/tools/_deprecated/auto-suggest-connections.js +304 -0
  58. package/tools/_deprecated/bootstrap-skills.js +231 -0
  59. package/tools/_deprecated/bridge-dashboard.js +342 -0
  60. package/tools/_deprecated/bridge-health.js +400 -0
  61. package/tools/_deprecated/bridge-live.js +384 -0
  62. package/tools/_deprecated/bridges.js +383 -0
  63. package/tools/_deprecated/colorguess.js +281 -0
  64. package/tools/_deprecated/discover-insights.js +379 -0
  65. package/tools/_deprecated/discover-momentum.js +256 -0
  66. package/tools/_deprecated/discovery-analytics.js +345 -0
  67. package/tools/_deprecated/discovery-auto-suggest.js +275 -0
  68. package/tools/_deprecated/discovery-bootstrap.js +267 -0
  69. package/tools/_deprecated/discovery-daily.js +375 -0
  70. package/tools/_deprecated/discovery-dashboard.js +385 -0
  71. package/tools/_deprecated/discovery-digest.js +314 -0
  72. package/tools/_deprecated/discovery-hub.js +357 -0
  73. package/tools/_deprecated/discovery-insights.js +384 -0
  74. package/tools/_deprecated/discovery-momentum.js +281 -0
  75. package/tools/_deprecated/discovery-monitor.js +319 -0
  76. package/tools/_deprecated/discovery-proactive.js +300 -0
  77. package/tools/_deprecated/draw.js +317 -0
  78. package/tools/_deprecated/farcaster.js +307 -0
  79. package/tools/_deprecated/forget.js +119 -0
  80. package/tools/_deprecated/games-catalog.js +376 -0
  81. package/tools/_deprecated/games.js +313 -0
  82. package/tools/_deprecated/guessnumber.js +194 -0
  83. package/tools/_deprecated/hangman.js +129 -0
  84. package/tools/_deprecated/multiplayer-tictactoe.js +303 -0
  85. package/tools/_deprecated/recall.js +147 -0
  86. package/tools/_deprecated/remember.js +86 -0
  87. package/tools/_deprecated/riddle.js +240 -0
  88. package/tools/_deprecated/run-bootstrap.js +69 -0
  89. package/tools/_deprecated/skills-analytics.js +349 -0
  90. package/tools/_deprecated/skills-bootstrap.js +301 -0
  91. package/tools/_deprecated/skills-dashboard.js +268 -0
  92. package/tools/_deprecated/skills.js +380 -0
  93. package/tools/_deprecated/smart-intro.js +353 -0
  94. package/tools/_deprecated/storybuilder.js +331 -0
  95. package/tools/_deprecated/telegram-bot.js +183 -0
  96. package/tools/_deprecated/telegram-setup.js +214 -0
  97. package/tools/_deprecated/twentyquestions.js +143 -0
  98. package/tools/_discovery-enhanced.js +290 -0
  99. package/tools/_discovery.js +439 -0
  100. package/tools/_proactive-discovery.js +301 -0
  101. package/tools/_shared/index.js +64 -0
  102. package/tools/_shared.js +234 -0
  103. package/tools/_work-context.js +338 -0
  104. package/tools/_work-context.manual-test.js +199 -0
  105. package/tools/_work-context.test.js +260 -0
  106. package/tools/activity.js +220 -0
  107. package/tools/admin-inbox.js +218 -0
  108. package/tools/agent-treasury.js +288 -0
  109. package/tools/analytics.js +191 -0
  110. package/tools/approve.js +197 -0
  111. package/tools/arcade.js +173 -0
  112. package/tools/artifact-create.js +17 -11
  113. package/tools/artifact-view.js +31 -1
  114. package/tools/artifacts-price.js +47 -43
  115. package/tools/ask-expert.js +160 -0
  116. package/tools/available.js +120 -0
  117. package/tools/become-expert.js +150 -0
  118. package/tools/broadcast.js +286 -0
  119. package/tools/chat.js +202 -0
  120. package/tools/collaborative-drawing.js +286 -0
  121. package/tools/connection-status.js +178 -0
  122. package/tools/crossword.js +17 -1
  123. package/tools/discover.js +350 -34
  124. package/tools/dm.js +115 -73
  125. package/tools/drawing.js +1 -1
  126. package/tools/earnings.js +126 -0
  127. package/tools/echo.js +16 -0
  128. package/tools/feed.js +51 -7
  129. package/tools/follow.js +224 -0
  130. package/tools/friends.js +207 -0
  131. package/tools/game.js +2 -2
  132. package/tools/genesis.js +233 -0
  133. package/tools/gig-browse.js +206 -0
  134. package/tools/gig-complete.js +144 -0
  135. package/tools/handoff.js +7 -1
  136. package/tools/help.js +4 -4
  137. package/tools/idea.js +9 -2
  138. package/tools/inbox.js +334 -28
  139. package/tools/init.js +727 -36
  140. package/tools/invite.js +15 -4
  141. package/tools/l2-bridge.js +272 -0
  142. package/tools/l2-status.js +217 -0
  143. package/tools/l2.js +206 -0
  144. package/tools/migrate.js +156 -0
  145. package/tools/mint.js +377 -0
  146. package/tools/multiplayer-game.js +1 -1
  147. package/tools/notifications.js +415 -0
  148. package/tools/observe.js +200 -0
  149. package/tools/onboarding.js +147 -0
  150. package/tools/open.js +143 -12
  151. package/tools/party-game.js +2 -2
  152. package/tools/plan.js +225 -0
  153. package/tools/presence-agent.js +7 -0
  154. package/tools/proof-of-work.js +100 -104
  155. package/tools/pulse.js +218 -0
  156. package/tools/reply.js +166 -0
  157. package/tools/report.js +2 -2
  158. package/tools/reputation.js +175 -0
  159. package/tools/request.js +17 -3
  160. package/tools/schedule.js +367 -0
  161. package/tools/search-messages.js +123 -0
  162. package/tools/session.js +420 -0
  163. package/tools/session_price.js +128 -0
  164. package/tools/settings.js +126 -3
  165. package/tools/ship.js +31 -8
  166. package/tools/shipback.js +326 -0
  167. package/tools/smart-check.js +201 -0
  168. package/tools/social-processor.js +445 -0
  169. package/tools/solo-game.js +1 -1
  170. package/tools/start.js +335 -93
  171. package/tools/status.js +53 -6
  172. package/tools/stuck.js +297 -0
  173. package/tools/subscribe.js +148 -0
  174. package/tools/subscriptions.js +134 -0
  175. package/tools/suggest-tags.js +6 -8
  176. package/tools/tag-suggestions.js +257 -0
  177. package/tools/tip.js +193 -0
  178. package/tools/token.js +103 -0
  179. package/tools/update.js +1 -1
  180. package/tools/wallet.js +239 -186
  181. package/tools/watch.js +157 -0
  182. package/tools/webhook-test.js +388 -0
  183. package/tools/who.js +54 -3
  184. package/tools/withdraw.js +145 -0
  185. package/tools/work-summary.js +96 -0
  186. package/tools/workshop.js +327 -0
  187. package/tools/x-mentions.js +1 -1
  188. package/version.json +14 -3
  189. package/tools/artifacts-buy.js +0 -111
  190. package/tools/connect.js +0 -284
  191. package/tools/gigs-apply.js +0 -99
  192. package/tools/gigs-browse.js +0 -114
  193. package/tools/gigs-complete.js +0 -128
  194. package/tools/gigs-post.js +0 -140
  195. package/tools/live-off.js +0 -109
  196. package/tools/live-watch.js +0 -176
  197. package/tools/live.js +0 -128
  198. package/tools/sessions-browse.js +0 -105
  199. package/tools/whats-happening.js +0 -125
  200. /package/tools/{away.js → _deprecated/away.js} +0 -0
  201. /package/tools/{back.js → _deprecated/back.js} +0 -0
  202. /package/tools/{mute.js → _deprecated/mute.js} +0 -0
  203. /package/tools/{skills-exchange.js → _deprecated/skills-exchange.js} +0 -0
  204. /package/tools/{tictactoe.js → _deprecated/tictactoe.js} +0 -0
  205. /package/tools/{wordassociation.js → _deprecated/wordassociation.js} +0 -0
@@ -0,0 +1,379 @@
1
+ /**
2
+ * Discovery Insights — Analytics and improvement suggestions for the discovery system
3
+ *
4
+ * Features:
5
+ * - Connection success tracking
6
+ * - Match quality analysis
7
+ * - Community growth insights
8
+ * - Recommendation algorithm tuning
9
+ */
10
+
11
+ const config = require('../config');
12
+ const userProfiles = require('../store/profiles');
13
+ const { formatTimeAgo, requireInit } = require('./_shared');
14
+
15
+ const definition = {
16
+ name: 'vibe_discover_insights',
17
+ description: 'Analyze discovery patterns and suggest improvements to matchmaking.',
18
+ inputSchema: {
19
+ type: 'object',
20
+ properties: {
21
+ command: {
22
+ type: 'string',
23
+ enum: ['quality', 'growth', 'gaps', 'tune'],
24
+ description: 'Type of insight analysis to run'
25
+ }
26
+ }
27
+ }
28
+ };
29
+
30
+ // Analyze connection quality patterns
31
+ async function analyzeConnectionQuality() {
32
+ const profiles = await userProfiles.getAllProfiles();
33
+ const analysis = {
34
+ totalConnections: 0,
35
+ avgConnectionsPerUser: 0,
36
+ connectionsByReason: {},
37
+ mostSuccessfulTags: {},
38
+ interestClusterSizes: {},
39
+ timingPatterns: {}
40
+ };
41
+
42
+ let totalConnectionCount = 0;
43
+
44
+ for (const profile of profiles) {
45
+ if (profile.connections) {
46
+ totalConnectionCount += profile.connections.length;
47
+
48
+ // Analyze reasons for connections
49
+ for (const conn of profile.connections) {
50
+ const reason = conn.reason || 'unknown';
51
+ analysis.connectionsByReason[reason] = (analysis.connectionsByReason[reason] || 0) + 1;
52
+ }
53
+ }
54
+
55
+ // Track tag success (users with more connections)
56
+ if (profile.tags && profile.connections) {
57
+ for (const tag of profile.tags) {
58
+ if (!analysis.mostSuccessfulTags[tag]) {
59
+ analysis.mostSuccessfulTags[tag] = { connections: 0, users: 0 };
60
+ }
61
+ analysis.mostSuccessfulTags[tag].connections += profile.connections.length;
62
+ analysis.mostSuccessfulTags[tag].users += 1;
63
+ }
64
+ }
65
+ }
66
+
67
+ analysis.totalConnections = totalConnectionCount / 2; // Each connection is counted twice
68
+ analysis.avgConnectionsPerUser = profiles.length > 0 ? totalConnectionCount / profiles.length : 0;
69
+
70
+ // Calculate tag success rates
71
+ const tagSuccessRates = Object.entries(analysis.mostSuccessfulTags)
72
+ .map(([tag, data]) => ({
73
+ tag,
74
+ avgConnectionsPerUser: data.connections / data.users,
75
+ userCount: data.users
76
+ }))
77
+ .filter(item => item.userCount >= 2) // Only tags with multiple users
78
+ .sort((a, b) => b.avgConnectionsPerUser - a.avgConnectionsPerUser)
79
+ .slice(0, 10);
80
+
81
+ return { analysis, tagSuccessRates };
82
+ }
83
+
84
+ // Analyze community growth patterns
85
+ async function analyzeCommunityGrowth() {
86
+ const profiles = await userProfiles.getAllProfiles();
87
+
88
+ if (profiles.length === 0) {
89
+ return {
90
+ growth: 'No user data available',
91
+ trends: [],
92
+ recommendations: ['Encourage users to set up profiles with vibe update commands']
93
+ };
94
+ }
95
+
96
+ // Sort by first seen date
97
+ const sortedProfiles = profiles
98
+ .filter(p => p.firstSeen)
99
+ .sort((a, b) => a.firstSeen - b.firstSeen);
100
+
101
+ const now = Date.now();
102
+ const oneWeekAgo = now - (7 * 24 * 60 * 60 * 1000);
103
+ const oneMonthAgo = now - (30 * 24 * 60 * 60 * 1000);
104
+
105
+ const recentUsers = sortedProfiles.filter(p => p.firstSeen > oneWeekAgo).length;
106
+ const monthlyUsers = sortedProfiles.filter(p => p.firstSeen > oneMonthAgo).length;
107
+
108
+ // Interest evolution
109
+ const interestTrends = await userProfiles.getTrendingInterests();
110
+ const tagTrends = await userProfiles.getTrendingTags();
111
+
112
+ // Activity patterns
113
+ const activeUsers = profiles.filter(p => p.lastSeen && p.lastSeen > oneWeekAgo).length;
114
+ const profileCompleteness = profiles.filter(p =>
115
+ p.building && p.interests?.length > 0 && p.tags?.length > 0
116
+ ).length;
117
+
118
+ return {
119
+ totalUsers: profiles.length,
120
+ recentGrowth: recentUsers,
121
+ monthlyGrowth: monthlyUsers,
122
+ activeUsers,
123
+ profileCompleteness: `${Math.round((profileCompleteness / profiles.length) * 100)}%`,
124
+ topInterests: interestTrends.slice(0, 5),
125
+ topTags: tagTrends.slice(0, 8),
126
+ recommendations: generateGrowthRecommendations(profiles, recentUsers, profileCompleteness)
127
+ };
128
+ }
129
+
130
+ // Identify gaps in the community
131
+ async function identifyGaps() {
132
+ const profiles = await userProfiles.getAllProfiles();
133
+
134
+ if (profiles.length < 5) {
135
+ return {
136
+ message: 'Community too small for gap analysis',
137
+ recommendations: ['Focus on user acquisition and profile setup']
138
+ };
139
+ }
140
+
141
+ const gaps = {
142
+ underrepresentedSkills: [],
143
+ missingComplementaryPairs: [],
144
+ isolatedUsers: [],
145
+ timezoneGaps: []
146
+ };
147
+
148
+ // Find isolated users (few connections)
149
+ gaps.isolatedUsers = profiles
150
+ .filter(p => !p.connections || p.connections.length < 2)
151
+ .map(p => ({
152
+ handle: p.handle,
153
+ building: p.building,
154
+ interests: p.interests || [],
155
+ connectionCount: p.connections?.length || 0
156
+ }))
157
+ .slice(0, 8);
158
+
159
+ // Skill gaps - common complementary pairs
160
+ const skillPairs = [
161
+ ['frontend', 'backend'],
162
+ ['design', 'engineering'],
163
+ ['ai', 'data'],
164
+ ['product', 'engineering'],
165
+ ['marketing', 'engineering']
166
+ ];
167
+
168
+ for (const [skill1, skill2] of skillPairs) {
169
+ const skill1Users = profiles.filter(p => p.tags?.some(t => t.toLowerCase().includes(skill1))).length;
170
+ const skill2Users = profiles.filter(p => p.tags?.some(t => t.toLowerCase().includes(skill2))).length;
171
+
172
+ if (Math.abs(skill1Users - skill2Users) > 3) {
173
+ gaps.missingComplementaryPairs.push({
174
+ overpopulated: skill1Users > skill2Users ? skill1 : skill2,
175
+ underpopulated: skill1Users > skill2Users ? skill2 : skill1,
176
+ ratio: `${Math.max(skill1Users, skill2Users)}:${Math.min(skill1Users, skill2Users)}`
177
+ });
178
+ }
179
+ }
180
+
181
+ return gaps;
182
+ }
183
+
184
+ // Suggest algorithm tuning
185
+ async function suggestTuning() {
186
+ const { analysis } = await analyzeConnectionQuality();
187
+ const suggestions = [];
188
+
189
+ if (analysis.avgConnectionsPerUser < 2) {
190
+ suggestions.push({
191
+ metric: 'Low connection rate',
192
+ issue: `Avg ${analysis.avgConnectionsPerUser.toFixed(1)} connections per user`,
193
+ suggestion: 'Lower match score threshold or improve onboarding'
194
+ });
195
+ }
196
+
197
+ // Analyze most successful connection reasons
198
+ const topReasons = Object.entries(analysis.connectionsByReason)
199
+ .sort(([,a], [,b]) => b - a)
200
+ .slice(0, 3);
201
+
202
+ if (topReasons.length > 0) {
203
+ suggestions.push({
204
+ metric: 'Top connection drivers',
205
+ issue: `Most connections from: ${topReasons.map(([r]) => r).join(', ')}`,
206
+ suggestion: 'Weight these factors higher in scoring algorithm'
207
+ });
208
+ }
209
+
210
+ suggestions.push({
211
+ metric: 'Algorithm recommendations',
212
+ issue: 'Based on current patterns',
213
+ suggestion: 'Consider time-based matching boost for users online simultaneously'
214
+ });
215
+
216
+ return suggestions;
217
+ }
218
+
219
+ // Generate growth recommendations
220
+ function generateGrowthRecommendations(profiles, recentUsers, completeProfiles) {
221
+ const recommendations = [];
222
+
223
+ if (recentUsers < 2) {
224
+ recommendations.push('Focus on user acquisition - invite more builders');
225
+ }
226
+
227
+ if (completeProfiles < profiles.length * 0.5) {
228
+ recommendations.push('Improve onboarding - guide users through profile setup');
229
+ }
230
+
231
+ if (profiles.length > 10 && recentUsers > 5) {
232
+ recommendations.push('Community is growing! Consider specialized interest groups');
233
+ }
234
+
235
+ recommendations.push('Encourage users to ship and announce their work');
236
+ recommendations.push('Host virtual coworking sessions for active builders');
237
+
238
+ return recommendations;
239
+ }
240
+
241
+ async function handler(args) {
242
+ const initCheck = requireInit();
243
+ if (initCheck) return initCheck;
244
+
245
+ const command = args.command || 'quality';
246
+ let display = '';
247
+
248
+ try {
249
+ switch (command) {
250
+ case 'quality': {
251
+ const { analysis, tagSuccessRates } = await analyzeConnectionQuality();
252
+
253
+ display = `## Connection Quality Analysis\n\n`;
254
+ display += `**Overall Stats:**\n`;
255
+ display += `• Total connections made: ${analysis.totalConnections}\n`;
256
+ display += `• Avg connections per user: ${analysis.avgConnectionsPerUser.toFixed(1)}\n\n`;
257
+
258
+ if (tagSuccessRates.length > 0) {
259
+ display += `**Most Connected Skills:**\n`;
260
+ for (const item of tagSuccessRates) {
261
+ display += `• ${item.tag}: ${item.avgConnectionsPerUser.toFixed(1)} avg connections (${item.userCount} users)\n`;
262
+ }
263
+ display += `\n`;
264
+ }
265
+
266
+ if (Object.keys(analysis.connectionsByReason).length > 0) {
267
+ display += `**Connection Reasons:**\n`;
268
+ const sortedReasons = Object.entries(analysis.connectionsByReason)
269
+ .sort(([,a], [,b]) => b - a)
270
+ .slice(0, 5);
271
+
272
+ for (const [reason, count] of sortedReasons) {
273
+ display += `• ${reason}: ${count} connections\n`;
274
+ }
275
+ }
276
+
277
+ break;
278
+ }
279
+
280
+ case 'growth': {
281
+ const growth = await analyzeCommunityGrowth();
282
+
283
+ display = `## Community Growth Analysis\n\n`;
284
+ display += `**Community Size:**\n`;
285
+ display += `• Total users: ${growth.totalUsers}\n`;
286
+ display += `• New this week: ${growth.recentGrowth}\n`;
287
+ display += `• New this month: ${growth.monthlyGrowth}\n`;
288
+ display += `• Currently active: ${growth.activeUsers}\n`;
289
+ display += `• Complete profiles: ${growth.profileCompleteness}\n\n`;
290
+
291
+ if (growth.topInterests?.length > 0) {
292
+ display += `**Trending Interests:**\n`;
293
+ for (const item of growth.topInterests) {
294
+ display += `• ${item.interest} (${item.count} users)\n`;
295
+ }
296
+ display += `\n`;
297
+ }
298
+
299
+ if (growth.topTags?.length > 0) {
300
+ display += `**Popular Skills:**\n`;
301
+ for (const item of growth.topTags) {
302
+ display += `• ${item.tag} (${item.count})\n`;
303
+ }
304
+ display += `\n`;
305
+ }
306
+
307
+ display += `**Growth Recommendations:**\n`;
308
+ for (const rec of growth.recommendations) {
309
+ display += `• ${rec}\n`;
310
+ }
311
+
312
+ break;
313
+ }
314
+
315
+ case 'gaps': {
316
+ const gaps = await identifyGaps();
317
+
318
+ display = `## Community Gap Analysis\n\n`;
319
+
320
+ if (gaps.isolatedUsers?.length > 0) {
321
+ display += `**Users Needing Connections:**\n`;
322
+ for (const user of gaps.isolatedUsers) {
323
+ display += `• @${user.handle} (${user.connectionCount} connections)\n`;
324
+ if (user.building) display += ` Building: ${user.building}\n`;
325
+ }
326
+ display += `\n`;
327
+ }
328
+
329
+ if (gaps.missingComplementaryPairs?.length > 0) {
330
+ display += `**Skill Imbalances:**\n`;
331
+ for (const gap of gaps.missingComplementaryPairs) {
332
+ display += `• Need more ${gap.underpopulated} (${gap.ratio} ratio)\n`;
333
+ }
334
+ display += `\n`;
335
+ }
336
+
337
+ display += `**Suggestions:**\n`;
338
+ display += `• Target recruitment for underrepresented skills\n`;
339
+ display += `• Create interest groups for isolated users\n`;
340
+ display += `• Host skill-exchange sessions\n`;
341
+
342
+ break;
343
+ }
344
+
345
+ case 'tune': {
346
+ const suggestions = await suggestTuning();
347
+
348
+ display = `## Algorithm Tuning Suggestions\n\n`;
349
+
350
+ for (const suggestion of suggestions) {
351
+ display += `**${suggestion.metric}**\n`;
352
+ display += `Issue: ${suggestion.issue}\n`;
353
+ display += `Recommendation: ${suggestion.suggestion}\n\n`;
354
+ }
355
+
356
+ break;
357
+ }
358
+
359
+ default:
360
+ display = `## Discovery Insights Commands
361
+
362
+ **\`insights quality\`** — Analyze connection success patterns
363
+ **\`insights growth\`** — Review community growth metrics
364
+ **\`insights gaps\`** — Identify underserved users and skills
365
+ **\`insights tune\`** — Get algorithm improvement suggestions`;
366
+ }
367
+ } catch (error) {
368
+ display = `## Insights Error
369
+
370
+ ${error.message}
371
+
372
+ The discovery insights system needs user profile data to work.
373
+ Try: \`discover insights\` for available commands`;
374
+ }
375
+
376
+ return { display };
377
+ }
378
+
379
+ module.exports = { definition, handler };
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Momentum-Enhanced Discovery Command — Find people based on shipping velocity and collaboration signals
3
+ *
4
+ * This provides users with discovery options that consider:
5
+ * - Recent shipping activity
6
+ * - Collaboration intent signals
7
+ * - Building momentum patterns
8
+ * - Project complementarity
9
+ */
10
+
11
+ const config = require('../config');
12
+ const userProfiles = require('../store/profiles');
13
+ const { formatTimeAgo, requireInit } = require('./_shared');
14
+ const momentum = require('./discovery-momentum');
15
+
16
+ const definition = {
17
+ name: 'vibe_discover_momentum',
18
+ description: 'Find connections based on shipping patterns and collaboration signals.',
19
+ inputSchema: {
20
+ type: 'object',
21
+ properties: {
22
+ mode: {
23
+ type: 'string',
24
+ enum: ['matches', 'collaborate', 'momentum', 'opportunities'],
25
+ description: 'Discovery mode: matches (general), collaborate (seeking partners), momentum (activity-based), opportunities (all collaboration matches)'
26
+ }
27
+ },
28
+ required: []
29
+ }
30
+ };
31
+
32
+ async function handler(args) {
33
+ const initCheck = requireInit();
34
+ if (initCheck) return initCheck;
35
+
36
+ const myHandle = config.getHandle();
37
+ const mode = args.mode || 'matches';
38
+
39
+ let display = '';
40
+
41
+ try {
42
+ switch (mode) {
43
+ case 'matches': {
44
+ const recommendations = await momentum.generateShippingRecommendations(myHandle);
45
+
46
+ if (recommendations.momentumMatches.length === 0) {
47
+ display = `## No Momentum Matches Found
48
+
49
+ _Looking for people with recent shipping activity..._
50
+
51
+ ${recommendations.targetMomentum.recentShips > 0
52
+ ? `**Your momentum:** ${recommendations.targetMomentum.score} (${recommendations.targetMomentum.recentShips} recent ships)`
53
+ : '**Tip:** Ship something recently to improve matching with active builders'
54
+ }
55
+
56
+ **Try:**
57
+ - \`discover momentum collaborate\` — Find collaboration opportunities
58
+ - \`discover momentum opportunities\` — See all seeking partnerships
59
+ - \`vibe ship "what you built"\` — Update your activity`;
60
+
61
+ } else {
62
+ display = `## Momentum-Based Matches\n\n`;
63
+ display += `**Your building momentum:** ${recommendations.targetMomentum.score}\n`;
64
+ display += `_${recommendations.targetMomentum.recentShips} ships this week • ${recommendations.targetMomentum.totalShips} total_\n\n`;
65
+
66
+ for (const match of recommendations.momentumMatches) {
67
+ display += `### @${match.handle} _(${match.score} match • ${Math.round(match.confidence * 100)}% confidence)_\n\n`;
68
+ display += `**Building:** ${match.building || 'Active project'}\n`;
69
+
70
+ if (match.lastShip) {
71
+ display += `**Latest ship:** ${match.lastShip.what}\n`;
72
+ display += `_${formatTimeAgo(match.lastShip.timestamp)}_\n`;
73
+ }
74
+
75
+ display += `**Why connect:**\n`;
76
+ for (const reason of match.reasons) {
77
+ display += `• ${reason}\n`;
78
+ }
79
+
80
+ display += `**Activity:** ${match.momentum.recentShips} recent ships`;
81
+ if (match.momentum.seekingCollaboration) {
82
+ display += ` • 🤝 **Seeking collaboration**`;
83
+ }
84
+ display += '\n\n';
85
+ }
86
+
87
+ display += `**Quick actions:**\n`;
88
+ display += `- \`message @handle\` to connect\n`;
89
+ display += `- \`discover momentum collaborate\` for partnership opportunities`;
90
+ }
91
+ break;
92
+ }
93
+
94
+ case 'collaborate': {
95
+ const recommendations = await momentum.generateShippingRecommendations(myHandle);
96
+ const collabOpps = recommendations.collaborationOpportunities;
97
+
98
+ if (collabOpps.length === 0) {
99
+ const myMomentum = recommendations.targetMomentum;
100
+
101
+ display = `## No Direct Collaboration Matches
102
+
103
+ ${myMomentum.seekingCollaboration
104
+ ? '**You\'re seeking collaboration** — here are active builders:'
105
+ : '**Tip:** Signal collaboration intent in your ships with phrases like "looking for help" or "seeking feedback"'
106
+ }
107
+
108
+ **Alternative matches:**`;
109
+
110
+ const topMatches = recommendations.momentumMatches.slice(0, 2);
111
+ for (const match of topMatches) {
112
+ display += `\n\n**@${match.handle}** _(${match.score} match)_`;
113
+ display += `\nBuilding: ${match.building}`;
114
+ display += `\nActive: ${match.momentum.recentShips} recent ships`;
115
+ if (match.reasons.length > 0) {
116
+ display += `\nWhy: ${match.reasons[0]}`;
117
+ }
118
+ }
119
+
120
+ if (topMatches.length === 0) {
121
+ display += `\n\n_No matches found. Try shipping something or updating your profile._`;
122
+ }
123
+
124
+ } else {
125
+ display = `## Collaboration Opportunities\n\n`;
126
+
127
+ for (const opp of collabOpps) {
128
+ const isSeeker = opp.seeker === myHandle;
129
+ const partnerHandle = isSeeker ? opp.builder : opp.seeker;
130
+ const partnerProject = isSeeker ? opp.builderProject : opp.seekerProject;
131
+
132
+ display += `### @${partnerHandle} _(${opp.score} match)_\n`;
133
+ display += `**Their project:** ${partnerProject}\n`;
134
+ display += `**Match reasons:**\n`;
135
+ for (const reason of opp.reasons) {
136
+ display += `• ${reason}\n`;
137
+ }
138
+ display += '\n';
139
+ }
140
+
141
+ display += `**Next steps:**\n`;
142
+ display += `- Reach out with \`message @handle\`\n`;
143
+ display += `- Reference their recent ship to show genuine interest\n`;
144
+ display += `- Be specific about how you could collaborate`;
145
+ }
146
+ break;
147
+ }
148
+
149
+ case 'momentum': {
150
+ const myProfile = await userProfiles.getProfile(myHandle);
151
+ const myMomentum = momentum.analyzeShippingMomentum(myProfile);
152
+
153
+ display = `## Your Building Momentum\n\n`;
154
+ display += `**Momentum Score:** ${myMomentum.score}\n`;
155
+ display += `**Recent ships:** ${myMomentum.recentShips} (past week)\n`;
156
+ display += `**Total ships:** ${myMomentum.totalShips}\n`;
157
+
158
+ if (myMomentum.seekingCollaboration) {
159
+ display += `**Status:** 🤝 Seeking collaboration\n`;
160
+ }
161
+
162
+ if (myMomentum.projectTypes.length > 0) {
163
+ display += `**Project types:** ${myMomentum.projectTypes.join(', ')}\n`;
164
+ }
165
+
166
+ display += '\n';
167
+
168
+ // Momentum insights
169
+ if (myMomentum.score >= 50) {
170
+ display += `🚀 **High momentum!** Great time to find collaboration partners.\n\n`;
171
+ } else if (myMomentum.score >= 25) {
172
+ display += `⚡ **Good momentum.** Consider shipping more to increase visibility.\n\n`;
173
+ } else {
174
+ display += `📈 **Building momentum.** Ship something recent to improve matching.\n\n`;
175
+ }
176
+
177
+ // Show recent ships
178
+ if (myProfile.ships && myProfile.ships.length > 0) {
179
+ display += `**Recent ships:**\n`;
180
+ for (const ship of myProfile.ships.slice(0, 3)) {
181
+ display += `• ${ship.what} _(${formatTimeAgo(ship.timestamp)})_\n`;
182
+ }
183
+ } else {
184
+ display += `**No ships recorded.** Use \`vibe ship "what you built"\` to get started.`;
185
+ }
186
+
187
+ display += `\n\n**Improve your momentum:**\n`;
188
+ display += `- Ship regularly (\`vibe ship\`)\n`;
189
+ display += `- Signal collaboration intent ("seeking feedback", "looking for help")\n`;
190
+ display += `- Update your profile with current project (\`vibe update building\`)`;
191
+ break;
192
+ }
193
+
194
+ case 'opportunities': {
195
+ const opportunities = await momentum.findCollaborationOpportunities();
196
+
197
+ if (opportunities.opportunities.length === 0) {
198
+ display = `## No Collaboration Opportunities Found
199
+
200
+ **Current activity:**
201
+ - ${opportunities.totalSeekers} people seeking collaboration
202
+ - ${opportunities.totalActiveBuilders} active builders
203
+
204
+ _Not enough overlap for quality matches yet._
205
+
206
+ **Help grow the community:**
207
+ - Ship with collaboration signals ("looking for", "need help")
208
+ - Update your profile and interests
209
+ - Connect with \`discover momentum matches\``;
210
+
211
+ } else {
212
+ display = `## All Collaboration Opportunities\n\n`;
213
+ display += `**Found ${opportunities.opportunities.length} potential matches**\n`;
214
+ display += `_${opportunities.totalSeekers} seeking • ${opportunities.totalActiveBuilders} building_\n\n`;
215
+
216
+ for (const opp of opportunities.opportunities) {
217
+ display += `**@${opp.seeker} 🤝 @${opp.builder}** _(${opp.score} match)_\n`;
218
+ display += `Seeker: ${opp.seekerProject || 'Seeking collaboration'}\n`;
219
+ display += `Builder: ${opp.builderProject || 'Active project'}\n`;
220
+ display += `Match: ${opp.reasons[0] || 'Good fit'}\n\n`;
221
+ }
222
+
223
+ display += `**As a community member, you could:**\n`;
224
+ display += `- Suggest these connections to the people involved\n`;
225
+ display += `- Join \`discover momentum collaborate\` to find your own matches`;
226
+ }
227
+ break;
228
+ }
229
+
230
+ default:
231
+ display = `## Momentum Discovery Commands
232
+
233
+ **\`discover momentum matches\`** — Find matches based on shipping patterns
234
+ **\`discover momentum collaborate\`** — Find collaboration opportunities
235
+ **\`discover momentum momentum\`** — Analyze your building momentum
236
+ **\`discover momentum opportunities\`** — See all collaboration matches
237
+
238
+ **Key features:**
239
+ - Matches based on recent shipping activity
240
+ - Detects collaboration intent in ships
241
+ - Considers project complementarity
242
+ - Analyzes building momentum patterns`;
243
+ }
244
+
245
+ } catch (error) {
246
+ display = `## Momentum Discovery Error
247
+
248
+ ${error.message}
249
+
250
+ Try: \`discover momentum\` for available commands`;
251
+ }
252
+
253
+ return { display };
254
+ }
255
+
256
+ module.exports = { definition, handler };