slashvibe-mcp 0.2.2 → 0.2.4

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 (162) hide show
  1. package/README.md +1 -0
  2. package/analytics.js +107 -0
  3. package/config.js +174 -3
  4. package/index.js +163 -34
  5. package/intelligence/index.js +45 -0
  6. package/intelligence/infer.js +316 -0
  7. package/intelligence/interests.js +369 -0
  8. package/intelligence/patterns.js +651 -0
  9. package/intelligence/proactive.js +358 -0
  10. package/intelligence/serendipity.js +306 -0
  11. package/notification-emitter.js +77 -0
  12. package/notify.js +141 -18
  13. package/package.json +14 -6
  14. package/presence.js +5 -1
  15. package/protocol/index.js +88 -1
  16. package/protocol/telegram-commands.js +199 -0
  17. package/store/api.js +469 -29
  18. package/store/index.js +7 -7
  19. package/store/local.js +67 -11
  20. package/store/profiles.js +435 -0
  21. package/store/reservations.js +321 -0
  22. package/store/skills.js +378 -0
  23. package/tools/_actions.js +491 -22
  24. package/tools/_connection-queue.js +257 -0
  25. package/tools/_discovery-enhanced.js +290 -0
  26. package/tools/_discovery.js +439 -0
  27. package/tools/_proactive-discovery.js +301 -0
  28. package/tools/_shared/index.js +64 -0
  29. package/tools/_work-context.js +338 -0
  30. package/tools/_work-context.manual-test.js +199 -0
  31. package/tools/_work-context.test.js +260 -0
  32. package/tools/admin-inbox.js +218 -0
  33. package/tools/agent-treasury.js +288 -0
  34. package/tools/agents.js +122 -0
  35. package/tools/analytics.js +191 -0
  36. package/tools/approve.js +197 -0
  37. package/tools/arcade.js +173 -0
  38. package/tools/artifact-create.js +247 -0
  39. package/tools/artifact-view.js +174 -0
  40. package/tools/artifacts-price.js +107 -0
  41. package/tools/ask-expert.js +160 -0
  42. package/tools/auto-suggest-connections.js +304 -0
  43. package/tools/away.js +68 -0
  44. package/tools/back.js +51 -0
  45. package/tools/become-expert.js +150 -0
  46. package/tools/bootstrap-skills.js +231 -0
  47. package/tools/bridge-dashboard.js +342 -0
  48. package/tools/bridge-health.js +400 -0
  49. package/tools/bridge-live.js +384 -0
  50. package/tools/bridges.js +383 -0
  51. package/tools/broadcast.js +286 -0
  52. package/tools/bye.js +4 -0
  53. package/tools/chat.js +202 -0
  54. package/tools/collaborative-drawing.js +286 -0
  55. package/tools/colorguess.js +281 -0
  56. package/tools/crossword.js +369 -0
  57. package/tools/discover-insights.js +379 -0
  58. package/tools/discover-momentum.js +256 -0
  59. package/tools/discover.js +675 -0
  60. package/tools/discovery-analytics.js +345 -0
  61. package/tools/discovery-auto-suggest.js +275 -0
  62. package/tools/discovery-bootstrap.js +267 -0
  63. package/tools/discovery-daily.js +375 -0
  64. package/tools/discovery-dashboard.js +385 -0
  65. package/tools/discovery-digest.js +314 -0
  66. package/tools/discovery-hub.js +357 -0
  67. package/tools/discovery-insights.js +384 -0
  68. package/tools/discovery-momentum.js +281 -0
  69. package/tools/discovery-monitor.js +319 -0
  70. package/tools/discovery-proactive.js +300 -0
  71. package/tools/dm.js +84 -14
  72. package/tools/draw.js +317 -0
  73. package/tools/drawing.js +310 -0
  74. package/tools/earnings.js +126 -0
  75. package/tools/echo.js +16 -0
  76. package/tools/farcaster.js +307 -0
  77. package/tools/feed.js +215 -0
  78. package/tools/follow.js +224 -0
  79. package/tools/friends.js +192 -0
  80. package/tools/game.js +218 -110
  81. package/tools/games-catalog.js +376 -0
  82. package/tools/games.js +313 -0
  83. package/tools/genesis.js +233 -0
  84. package/tools/gig-browse.js +206 -0
  85. package/tools/gig-complete.js +139 -0
  86. package/tools/guessnumber.js +194 -0
  87. package/tools/hangman.js +129 -0
  88. package/tools/help.js +269 -0
  89. package/tools/idea.js +217 -0
  90. package/tools/inbox.js +291 -25
  91. package/tools/init.js +657 -33
  92. package/tools/insights.js +123 -0
  93. package/tools/invite.js +142 -21
  94. package/tools/l2-bridge.js +272 -0
  95. package/tools/l2-status.js +217 -0
  96. package/tools/l2.js +206 -0
  97. package/tools/migrate.js +156 -0
  98. package/tools/mint.js +377 -0
  99. package/tools/multiplayer-game.js +275 -0
  100. package/tools/multiplayer-tictactoe.js +303 -0
  101. package/tools/mute.js +97 -0
  102. package/tools/notifications.js +415 -0
  103. package/tools/observe.js +200 -0
  104. package/tools/onboarding.js +147 -0
  105. package/tools/open.js +52 -3
  106. package/tools/party-game.js +314 -0
  107. package/tools/plan.js +225 -0
  108. package/tools/presence-agent.js +167 -0
  109. package/tools/profile.js +219 -0
  110. package/tools/proof-of-work.js +139 -0
  111. package/tools/pulse.js +218 -0
  112. package/tools/react.js +4 -0
  113. package/tools/release.js +83 -0
  114. package/tools/report.js +109 -0
  115. package/tools/reputation.js +175 -0
  116. package/tools/request.js +231 -0
  117. package/tools/reservations.js +116 -0
  118. package/tools/reserve.js +111 -0
  119. package/tools/riddle.js +240 -0
  120. package/tools/run-bootstrap.js +69 -0
  121. package/tools/schedule.js +367 -0
  122. package/tools/session.js +420 -0
  123. package/tools/session_price.js +128 -0
  124. package/tools/settings.js +200 -0
  125. package/tools/ship.js +188 -0
  126. package/tools/shipback.js +326 -0
  127. package/tools/skills-analytics.js +349 -0
  128. package/tools/skills-bootstrap.js +301 -0
  129. package/tools/skills-dashboard.js +268 -0
  130. package/tools/skills-exchange.js +342 -0
  131. package/tools/skills.js +380 -0
  132. package/tools/smart-intro.js +353 -0
  133. package/tools/social-inbox.js +326 -69
  134. package/tools/social-post.js +251 -66
  135. package/tools/social-processor.js +445 -0
  136. package/tools/solo-game.js +390 -0
  137. package/tools/start.js +296 -81
  138. package/tools/status.js +53 -6
  139. package/tools/storybuilder.js +331 -0
  140. package/tools/stuck.js +297 -0
  141. package/tools/subscribe.js +148 -0
  142. package/tools/subscriptions.js +134 -0
  143. package/tools/suggest-tags.js +184 -0
  144. package/tools/tag-suggestions.js +257 -0
  145. package/tools/telegram-bot.js +183 -0
  146. package/tools/telegram-setup.js +214 -0
  147. package/tools/tictactoe.js +155 -0
  148. package/tools/tip.js +120 -0
  149. package/tools/token.js +103 -0
  150. package/tools/twentyquestions.js +143 -0
  151. package/tools/update.js +1 -1
  152. package/tools/wallet.js +127 -0
  153. package/tools/watch.js +157 -0
  154. package/tools/webhook-test.js +388 -0
  155. package/tools/who.js +118 -25
  156. package/tools/withdraw.js +145 -0
  157. package/tools/wordassociation.js +247 -0
  158. package/tools/work-summary.js +96 -0
  159. package/tools/workshop-buddy.js +394 -0
  160. package/tools/workshop.js +327 -0
  161. package/version.json +12 -3
  162. package/tools/board.js +0 -130
@@ -0,0 +1,96 @@
1
+ /**
2
+ * vibe_work_summary — Standalone tool for explicit context gathering
3
+ *
4
+ * Use this when you need to:
5
+ * - Draft a message about what you're working on
6
+ * - Share your progress with someone
7
+ * - Get context for composing a "ship" post
8
+ *
9
+ * This tool returns structured data about:
10
+ * - Git state (branch, recent commits, changed files)
11
+ * - Project info (name, type)
12
+ * - Pre-formatted suggestions ready for messages/presence
13
+ */
14
+
15
+ const { gatherWorkContext } = require('./_work-context');
16
+
17
+ const definition = {
18
+ name: 'vibe_work_summary',
19
+ description: 'Get a summary of what you\'re working on (git state, project info). Use before composing messages about your work.',
20
+ inputSchema: {
21
+ type: 'object',
22
+ properties: {
23
+ detail_level: {
24
+ type: 'string',
25
+ enum: ['brief', 'detailed'],
26
+ description: 'brief = one-liner, detailed = include commits/files'
27
+ }
28
+ }
29
+ }
30
+ };
31
+
32
+ async function handler(args) {
33
+ const { detail_level = 'brief' } = args;
34
+
35
+ // Gather all context
36
+ const context = gatherWorkContext();
37
+
38
+ // Build display based on detail level
39
+ let display = '## Work Context\n\n';
40
+
41
+ // Project info
42
+ display += `**Project:** ${context.project.name}`;
43
+ if (context.project.type !== 'unknown') {
44
+ display += ` (${context.project.type})`;
45
+ }
46
+ display += '\n';
47
+
48
+ // Git info
49
+ if (context.git) {
50
+ display += `**Branch:** ${context.git.branch}\n`;
51
+
52
+ if (detail_level === 'detailed') {
53
+ // Show recent commits
54
+ if (context.git.recentCommits.length > 0) {
55
+ display += '\n**Recent commits:**\n';
56
+ context.git.recentCommits.forEach(c => {
57
+ display += `- \`${c.hash}\` ${c.message}\n`;
58
+ });
59
+ }
60
+
61
+ // Show changed files
62
+ if (context.git.changedFiles.length > 0) {
63
+ display += '\n**Changed files:**\n';
64
+ context.git.changedFiles.forEach(f => {
65
+ display += `- ${f}\n`;
66
+ });
67
+ }
68
+
69
+ // Uncommitted changes indicator
70
+ if (context.git.hasUncommitted) {
71
+ display += '\n⚠️ _Uncommitted changes_\n';
72
+ }
73
+ }
74
+ } else {
75
+ display += '_Not in a git repository_\n';
76
+ }
77
+
78
+ // Suggestions
79
+ display += '\n---\n\n';
80
+ display += '**Ready to use:**\n';
81
+ display += `- Brief: "${context.suggestions.brief}"\n`;
82
+ if (detail_level === 'detailed' && context.suggestions.detailed !== context.suggestions.brief) {
83
+ display += `- Detailed: "${context.suggestions.detailed}"\n`;
84
+ }
85
+
86
+ display += '\n_Use these in messages, status updates, or ship posts._';
87
+
88
+ return {
89
+ display,
90
+ // Structured data for Claude to use programmatically
91
+ ...context,
92
+ usage_hint: 'Use suggestions.brief for messages, suggestions.detailed for updates.'
93
+ };
94
+ }
95
+
96
+ module.exports = { definition, handler };
@@ -0,0 +1,394 @@
1
+ /**
2
+ * vibe workshop-buddy — Find Your Perfect Workshop Partner
3
+ *
4
+ * Pairs users based on complementary skills and interests to form
5
+ * productive workshop partnerships. Unlike general discovery,
6
+ * this focuses on active collaboration potential.
7
+ *
8
+ * Commands:
9
+ * - workshop-buddy find — Find your ideal workshop partner
10
+ * - workshop-buddy offer <skills> — Offer skills to the community
11
+ * - workshop-buddy seeking <skills> — What you're looking for
12
+ * - workshop-buddy matches — See current skill exchange opportunities
13
+ */
14
+
15
+ const config = require('../config');
16
+ const store = require('../store');
17
+ const userProfiles = require('../store/profiles');
18
+ const { formatTimeAgo, requireInit } = require('./_shared');
19
+
20
+ const definition = {
21
+ name: 'vibe_workshop_buddy',
22
+ description: 'Find workshop partners with complementary skills for collaboration.',
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {
26
+ command: {
27
+ type: 'string',
28
+ enum: ['find', 'offer', 'seeking', 'matches'],
29
+ description: 'Workshop buddy command to run'
30
+ },
31
+ skills: {
32
+ type: 'string',
33
+ description: 'Skills you offer or seek (comma-separated)'
34
+ }
35
+ }
36
+ }
37
+ };
38
+
39
+ // Skill complementarity matrix
40
+ const complementarySkills = {
41
+ 'frontend': ['backend', 'design', 'ux'],
42
+ 'backend': ['frontend', 'devops', 'database'],
43
+ 'design': ['frontend', 'user-research', 'engineering'],
44
+ 'ux': ['design', 'frontend', 'user-research'],
45
+ 'ai': ['data', 'backend', 'research'],
46
+ 'data': ['ai', 'backend', 'analytics'],
47
+ 'mobile': ['backend', 'design', 'ux'],
48
+ 'devops': ['backend', 'security', 'infrastructure'],
49
+ 'product': ['engineering', 'design', 'marketing'],
50
+ 'engineering': ['product', 'design', 'backend'],
51
+ 'research': ['ai', 'data', 'implementation'],
52
+ 'marketing': ['product', 'design', 'content'],
53
+ 'content': ['marketing', 'design', 'writing'],
54
+ 'security': ['devops', 'backend', 'infrastructure'],
55
+ 'infrastructure': ['devops', 'backend', 'security'],
56
+ 'analytics': ['data', 'product', 'research'],
57
+ 'user-research': ['ux', 'product', 'design'],
58
+ 'writing': ['content', 'marketing', 'editing'],
59
+ 'business': ['product', 'marketing', 'strategy'],
60
+ 'strategy': ['business', 'product', 'leadership']
61
+ };
62
+
63
+ // Calculate workshop collaboration potential
64
+ function calculateBuddyScore(user1, user2) {
65
+ let score = 0;
66
+ const reasons = [];
67
+ const collaborationPotential = [];
68
+
69
+ const user1Skills = (user1.tags || []).concat(user1.interests || []);
70
+ const user2Skills = (user2.tags || []).concat(user2.interests || []);
71
+
72
+ // High-value complementary skills
73
+ for (const skill1 of user1Skills) {
74
+ const complementaries = complementarySkills[skill1.toLowerCase()] || [];
75
+ for (const skill2 of user2Skills) {
76
+ if (complementaries.includes(skill2.toLowerCase())) {
77
+ score += 30;
78
+ collaborationPotential.push(`${skill1} + ${skill2}`);
79
+ }
80
+ }
81
+ }
82
+
83
+ // Project collaboration potential
84
+ if (user1.building && user2.building) {
85
+ const building1 = user1.building.toLowerCase();
86
+ const building2 = user2.building.toLowerCase();
87
+
88
+ // Different but related domains
89
+ const domains = ['ai', 'web', 'mobile', 'fintech', 'healthcare', 'gaming', 'productivity'];
90
+ const user1Domains = domains.filter(d => building1.includes(d));
91
+ const user2Domains = domains.filter(d => building2.includes(d));
92
+
93
+ if (user1Domains.length > 0 && user2Domains.length > 0) {
94
+ const sharedDomains = user1Domains.filter(d => user2Domains.includes(d));
95
+ if (sharedDomains.length > 0) {
96
+ score += 25;
97
+ reasons.push(`Both working in ${sharedDomains.join(', ')}`);
98
+ }
99
+ }
100
+ }
101
+
102
+ // Experience level balance
103
+ const user1Level = getExperienceLevel(user1);
104
+ const user2Level = getExperienceLevel(user2);
105
+
106
+ if (Math.abs(user1Level - user2Level) <= 1) {
107
+ score += 15;
108
+ reasons.push('Compatible experience levels');
109
+ }
110
+
111
+ // Activity synchronization
112
+ if (user1.lastSeen && user2.lastSeen) {
113
+ const timeDiff = Math.abs(user1.lastSeen - user2.lastSeen);
114
+ const hours = timeDiff / (1000 * 60 * 60);
115
+ if (hours < 6) {
116
+ score += 20;
117
+ reasons.push('Active at similar times');
118
+ }
119
+ }
120
+
121
+ // Add collaboration potential to reasons
122
+ if (collaborationPotential.length > 0) {
123
+ reasons.unshift(`Perfect skill combo: ${collaborationPotential.slice(0, 2).join(', ')}`);
124
+ }
125
+
126
+ return { score, reasons: reasons.slice(0, 3), collaborationPotential };
127
+ }
128
+
129
+ // Estimate experience level from profile
130
+ function getExperienceLevel(user) {
131
+ const skills = (user.tags || []).length;
132
+ const interests = (user.interests || []).length;
133
+ const hasBuilding = user.building ? 1 : 0;
134
+
135
+ return Math.min(5, skills + interests + hasBuilding);
136
+ }
137
+
138
+ // Find workshop buddies
139
+ async function findWorkshopBuddies(myHandle) {
140
+ const myProfile = await userProfiles.getProfile(myHandle);
141
+ const allProfiles = await userProfiles.getAllProfiles();
142
+
143
+ const candidates = allProfiles.filter(p => p.handle !== myHandle);
144
+ const matches = [];
145
+
146
+ for (const candidate of candidates) {
147
+ const match = calculateBuddyScore(myProfile, candidate);
148
+ if (match.score > 20) { // Higher threshold for workshop partnerships
149
+ matches.push({
150
+ handle: candidate.handle,
151
+ score: match.score,
152
+ reasons: match.reasons,
153
+ collaborationPotential: match.collaborationPotential,
154
+ building: candidate.building,
155
+ tags: candidate.tags || [],
156
+ interests: candidate.interests || [],
157
+ lastSeen: candidate.lastSeen,
158
+ experienceLevel: getExperienceLevel(candidate)
159
+ });
160
+ }
161
+ }
162
+
163
+ return matches.sort((a, b) => b.score - a.score).slice(0, 3);
164
+ }
165
+
166
+ // Get skill offering/seeking data
167
+ async function getSkillExchange() {
168
+ // This would integrate with a persistent skills marketplace
169
+ // For now, analyze profiles to suggest exchanges
170
+ const allProfiles = await userProfiles.getAllProfiles();
171
+ const exchanges = [];
172
+
173
+ for (const profile of allProfiles) {
174
+ if (profile.tags && profile.tags.length > 0) {
175
+ for (const skill of profile.tags) {
176
+ const seeking = complementarySkills[skill.toLowerCase()] || [];
177
+ if (seeking.length > 0) {
178
+ exchanges.push({
179
+ handle: profile.handle,
180
+ offering: skill,
181
+ seeking: seeking,
182
+ building: profile.building
183
+ });
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+ return exchanges.slice(0, 10);
190
+ }
191
+
192
+ async function handler(args) {
193
+ const initCheck = requireInit();
194
+ if (initCheck) return initCheck;
195
+
196
+ const myHandle = config.getHandle();
197
+ const command = args.command || 'find';
198
+
199
+ let display = '';
200
+
201
+ try {
202
+ switch (command) {
203
+ case 'find': {
204
+ const buddies = await findWorkshopBuddies(myHandle);
205
+
206
+ if (buddies.length === 0) {
207
+ display = `## No Workshop Buddies Found
208
+
209
+ _Need more profiles to find great partnerships._
210
+
211
+ **To find your perfect workshop buddy:**
212
+ 1. \`vibe update tags "your-skills"\` (e.g., "frontend, react, typescript")
213
+ 2. \`vibe update building "your current project"\`
214
+ 3. \`vibe update interests "what excites you"\`
215
+
216
+ **What makes a great workshop buddy:**
217
+ - Complementary skills (frontend + backend)
218
+ - Similar availability/timezone
219
+ - Compatible experience level
220
+ - Shared domain interest`;
221
+ } else {
222
+ display = `## Your Workshop Buddy Matches 🤝\n\n`;
223
+
224
+ for (const buddy of buddies) {
225
+ display += `### **@${buddy.handle}** _(${buddy.score}% match)_\n`;
226
+ display += `${buddy.building || 'Available for collaboration'}\n\n`;
227
+
228
+ display += `**Why you'd work great together:**\n`;
229
+ for (const reason of buddy.reasons) {
230
+ display += `• ${reason}\n`;
231
+ }
232
+
233
+ if (buddy.collaborationPotential.length > 0) {
234
+ display += `\n**Skill synergy:** ${buddy.collaborationPotential.slice(0, 2).join(', ')}\n`;
235
+ }
236
+
237
+ display += `**Their skills:** ${buddy.tags.join(', ')}\n`;
238
+ display += `**Experience level:** ${'⭐'.repeat(buddy.experienceLevel)}\n`;
239
+ display += `_Last seen: ${formatTimeAgo(buddy.lastSeen)}_\n\n`;
240
+ display += `**Reach out:** \`message @${buddy.handle} "Hey! We seem like a great workshop match..."\`\n\n`;
241
+ display += '---\n\n';
242
+ }
243
+
244
+ display += `**Next steps:**\n`;
245
+ display += `• Message your top match to start collaborating\n`;
246
+ display += `• Use \`workshop-buddy matches\` to see community skill exchanges\n`;
247
+ display += `• Try \`workshop-buddy seeking "skill"\` to find specific expertise`;
248
+ }
249
+ break;
250
+ }
251
+
252
+ case 'offer': {
253
+ if (!args.skills) {
254
+ return { error: 'Specify skills you offer: workshop-buddy offer "frontend, react"' };
255
+ }
256
+
257
+ // Update user tags with offered skills
258
+ const skills = args.skills.split(',').map(s => s.trim().toLowerCase());
259
+ const currentProfile = await userProfiles.getProfile(myHandle);
260
+ const updatedTags = [...new Set([...(currentProfile.tags || []), ...skills])];
261
+
262
+ await userProfiles.updateProfile(myHandle, { tags: updatedTags });
263
+
264
+ display = `## Skills Offered! 🎯
265
+
266
+ **You're now offering:** ${skills.join(', ')}
267
+
268
+ People looking for these skills can find you via:
269
+ - \`discover search "${skills[0]}"\`
270
+ - \`workshop-buddy matches\`
271
+
272
+ **Want to find collaboration opportunities?**
273
+ \`workshop-buddy find\` — Find your ideal workshop partner`;
274
+ break;
275
+ }
276
+
277
+ case 'seeking': {
278
+ if (!args.skills) {
279
+ return { error: 'Specify skills you need: workshop-buddy seeking "backend, devops"' };
280
+ }
281
+
282
+ const seekingSkills = args.skills.split(',').map(s => s.trim().toLowerCase());
283
+ const allProfiles = await userProfiles.getAllProfiles();
284
+
285
+ const matches = allProfiles.filter(profile => {
286
+ const theirSkills = (profile.tags || []).map(t => t.toLowerCase());
287
+ return seekingSkills.some(skill => theirSkills.includes(skill)) && profile.handle !== myHandle;
288
+ });
289
+
290
+ if (matches.length === 0) {
291
+ display = `## No One Found with: ${args.skills}
292
+
293
+ **Try:**
294
+ - \`discover search "${seekingSkills[0]}"\` for broader search
295
+ - \`workshop-buddy matches\` to browse all skill exchanges
296
+ - Post what you're seeking: \`ship "Looking for ${args.skills} expertise"\``;
297
+ } else {
298
+ display = `## People with: ${args.skills}\n\n`;
299
+
300
+ for (const match of matches) {
301
+ const theirMatchingSkills = (match.tags || []).filter(t =>
302
+ seekingSkills.includes(t.toLowerCase())
303
+ );
304
+
305
+ display += `**@${match.handle}**\n`;
306
+ display += `${match.building || 'Available to help'}\n`;
307
+ display += `**Has:** ${theirMatchingSkills.join(', ')}\n`;
308
+ display += `**All skills:** ${(match.tags || []).join(', ')}\n`;
309
+ display += `_Last seen: ${formatTimeAgo(match.lastSeen)}_\n\n`;
310
+ }
311
+
312
+ display += `**Ready to collaborate?**\n`;
313
+ display += `\`workshop-buddy find\` — See your best overall matches`;
314
+ }
315
+ break;
316
+ }
317
+
318
+ case 'matches': {
319
+ const exchanges = await getSkillExchange();
320
+
321
+ if (exchanges.length === 0) {
322
+ display = `## No Skill Exchanges Yet
323
+
324
+ _The skill marketplace is empty._
325
+
326
+ **Start the exchange:**
327
+ 1. \`workshop-buddy offer "your-skills"\`
328
+ 2. Others can find you via \`workshop-buddy seeking "your-skills"\`
329
+
330
+ **Example skills to offer/seek:**
331
+ - Technical: frontend, backend, mobile, ai, data
332
+ - Design: ui, ux, illustration, branding
333
+ - Business: product, marketing, strategy, writing`;
334
+ } else {
335
+ display = `## Community Skill Exchange 🔄\n\n`;
336
+
337
+ const groupedByOffering = {};
338
+ for (const exchange of exchanges) {
339
+ if (!groupedByOffering[exchange.offering]) {
340
+ groupedByOffering[exchange.offering] = [];
341
+ }
342
+ groupedByOffering[exchange.offering].push(exchange);
343
+ }
344
+
345
+ for (const [skill, providers] of Object.entries(groupedByOffering)) {
346
+ display += `### ${skill.toUpperCase()}\n`;
347
+
348
+ for (const provider of providers.slice(0, 3)) {
349
+ display += `**@${provider.handle}** offers ${skill}, seeks: ${provider.seeking.join(', ')}\n`;
350
+ if (provider.building) {
351
+ display += `_Building: ${provider.building}_\n`;
352
+ }
353
+ }
354
+
355
+ display += '\n';
356
+ }
357
+
358
+ display += `**Find your perfect exchange:**\n`;
359
+ display += `- \`workshop-buddy seeking "skill"\` to find specific expertise\n`;
360
+ display += `- \`workshop-buddy find\` for AI-matched partners`;
361
+ }
362
+ break;
363
+ }
364
+
365
+ default:
366
+ display = `## Workshop Buddy Commands
367
+
368
+ **\`workshop-buddy find\`** — Find your ideal workshop partner
369
+ **\`workshop-buddy offer <skills>\`** — Offer skills to the community
370
+ **\`workshop-buddy seeking <skills>\`** — Find people with specific skills
371
+ **\`workshop-buddy matches\`** — Browse community skill exchanges
372
+
373
+ **Perfect for:**
374
+ - Finding a coding partner with complementary skills
375
+ - Pairing designers with developers
376
+ - Connecting product people with engineers
377
+ - Building cross-functional teams
378
+
379
+ **Examples:**
380
+ \`workshop-buddy offer "frontend, react, typescript"\`
381
+ \`workshop-buddy seeking "backend, python"\``;
382
+ }
383
+ } catch (error) {
384
+ display = `## Workshop Buddy Error
385
+
386
+ ${error.message}
387
+
388
+ Try: \`workshop-buddy\` for available commands`;
389
+ }
390
+
391
+ return { display };
392
+ }
393
+
394
+ module.exports = { definition, handler };