slashvibe-mcp 0.3.21 → 0.3.22

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 (229) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -47
  3. package/config.js +36 -31
  4. package/crypto.js +1 -6
  5. package/discord.js +19 -19
  6. package/index.js +217 -207
  7. package/intelligence/index.js +2 -9
  8. package/intelligence/infer.js +10 -16
  9. package/intelligence/patterns.js +23 -18
  10. package/intelligence/proactive.js +16 -15
  11. package/intelligence/serendipity.js +57 -20
  12. package/memory.js +13 -8
  13. package/notify.js +39 -14
  14. package/package.json +27 -20
  15. package/presence.js +2 -2
  16. package/prompts.js +5 -9
  17. package/protocol/index.js +123 -87
  18. package/protocol/telegram-commands.js +36 -37
  19. package/store/api.js +358 -529
  20. package/store/local.js +9 -10
  21. package/store/profiles.js +48 -192
  22. package/store/reservations.js +2 -9
  23. package/store/skills.js +69 -71
  24. package/store/sqlite.js +355 -0
  25. package/tools/_actions.js +48 -387
  26. package/tools/_connection-queue.js +45 -56
  27. package/tools/_discovery-enhanced.js +52 -57
  28. package/tools/_discovery.js +87 -185
  29. package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
  30. package/tools/{shipback.js → _experimental/shipback.js} +4 -3
  31. package/tools/_proactive-discovery.js +60 -73
  32. package/tools/_shared/index.js +41 -64
  33. package/tools/admin-inbox.js +10 -15
  34. package/tools/agents.js +1 -1
  35. package/tools/artifact-create.js +13 -23
  36. package/tools/artifact-view.js +4 -4
  37. package/tools/{_deprecated/back.js → back.js} +1 -1
  38. package/tools/bye.js +3 -5
  39. package/tools/consent.js +2 -2
  40. package/tools/context.js +9 -10
  41. package/tools/crossword.js +3 -2
  42. package/tools/discover.js +94 -356
  43. package/tools/dm.js +27 -86
  44. package/tools/doctor.js +12 -41
  45. package/tools/drawing.js +34 -20
  46. package/tools/echo.js +11 -11
  47. package/tools/feed.js +30 -58
  48. package/tools/follow.js +64 -187
  49. package/tools/{_deprecated/forget.js → forget.js} +4 -7
  50. package/tools/game.js +144 -48
  51. package/tools/handoff.js +6 -8
  52. package/tools/help.js +3 -3
  53. package/tools/idea.js +15 -27
  54. package/tools/inbox.js +121 -293
  55. package/tools/init.js +54 -151
  56. package/tools/invite.js +8 -21
  57. package/tools/migrate.js +27 -24
  58. package/tools/multiplayer-game.js +50 -40
  59. package/tools/{_deprecated/mute.js → mute.js} +4 -3
  60. package/tools/notifications.js +58 -48
  61. package/tools/observe.js +12 -15
  62. package/tools/onboarding.js +8 -11
  63. package/tools/open.js +13 -144
  64. package/tools/party-game.js +23 -12
  65. package/tools/patterns.js +2 -1
  66. package/tools/ping.js +5 -7
  67. package/tools/react.js +28 -30
  68. package/tools/{_deprecated/recall.js → recall.js} +5 -10
  69. package/tools/release.js +4 -2
  70. package/tools/{_deprecated/remember.js → remember.js} +4 -6
  71. package/tools/report.js +2 -2
  72. package/tools/request.js +6 -26
  73. package/tools/reserve.js +1 -1
  74. package/tools/session-fork.js +97 -0
  75. package/tools/session-save.js +109 -0
  76. package/tools/settings.js +30 -99
  77. package/tools/ship.js +74 -56
  78. package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
  79. package/tools/social-inbox.js +22 -28
  80. package/tools/social-post.js +24 -27
  81. package/tools/solo-game.js +54 -46
  82. package/tools/start.js +14 -148
  83. package/tools/status.js +21 -68
  84. package/tools/submit.js +4 -2
  85. package/tools/suggest-tags.js +36 -33
  86. package/tools/summarize.js +19 -16
  87. package/tools/tag-suggestions.js +72 -73
  88. package/tools/test.js +1 -1
  89. package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
  90. package/tools/token.js +4 -4
  91. package/tools/update.js +1 -2
  92. package/tools/watch.js +132 -112
  93. package/tools/who.js +20 -40
  94. package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
  95. package/tools/workshop-buddy.js +52 -53
  96. package/tools/x-mentions.js +0 -1
  97. package/tools/x-reply.js +0 -1
  98. package/twitter.js +14 -20
  99. package/version.json +8 -10
  100. package/analytics.js +0 -107
  101. package/auth-store.js +0 -148
  102. package/auto-update.js +0 -130
  103. package/bridges/bridge-monitor.js +0 -388
  104. package/bridges/discord-bot.js +0 -431
  105. package/bridges/farcaster.js +0 -299
  106. package/bridges/telegram.js +0 -261
  107. package/bridges/webhook-health.js +0 -420
  108. package/bridges/webhook-server.js +0 -437
  109. package/bridges/whatsapp.js +0 -441
  110. package/bridges/x-webhook.js +0 -423
  111. package/games/arcade.js +0 -406
  112. package/games/chess.js +0 -451
  113. package/games/colorguess.js +0 -343
  114. package/games/crossword-words.js +0 -171
  115. package/games/crossword.js +0 -461
  116. package/games/drawing.js +0 -347
  117. package/games/gameroulette.js +0 -300
  118. package/games/gamerouter.js +0 -336
  119. package/games/gamestatus.js +0 -337
  120. package/games/guessnumber.js +0 -209
  121. package/games/hangman.js +0 -279
  122. package/games/memory.js +0 -338
  123. package/games/multiplayer-tictactoe.js +0 -389
  124. package/games/pixelart.js +0 -399
  125. package/games/quickduel.js +0 -354
  126. package/games/riddle.js +0 -371
  127. package/games/rockpaperscissors.js +0 -291
  128. package/games/snake.js +0 -406
  129. package/games/storybuilder.js +0 -343
  130. package/games/tictactoe.js +0 -345
  131. package/games/twentyquestions.js +0 -286
  132. package/games/twotruths.js +0 -207
  133. package/games/werewolf.js +0 -508
  134. package/games/wordassociation.js +0 -247
  135. package/games/wordchain.js +0 -135
  136. package/intelligence/interests.js +0 -369
  137. package/notification-emitter.js +0 -77
  138. package/setup.js +0 -480
  139. package/smart-inbox.js +0 -276
  140. package/tools/_deprecated/auto-suggest-connections.js +0 -304
  141. package/tools/_deprecated/bootstrap-skills.js +0 -231
  142. package/tools/_deprecated/bridge-dashboard.js +0 -342
  143. package/tools/_deprecated/bridge-health.js +0 -400
  144. package/tools/_deprecated/bridge-live.js +0 -384
  145. package/tools/_deprecated/bridges.js +0 -383
  146. package/tools/_deprecated/colorguess.js +0 -281
  147. package/tools/_deprecated/discover-insights.js +0 -379
  148. package/tools/_deprecated/discover-momentum.js +0 -256
  149. package/tools/_deprecated/discovery-analytics.js +0 -345
  150. package/tools/_deprecated/discovery-auto-suggest.js +0 -275
  151. package/tools/_deprecated/discovery-bootstrap.js +0 -267
  152. package/tools/_deprecated/discovery-daily.js +0 -375
  153. package/tools/_deprecated/discovery-dashboard.js +0 -385
  154. package/tools/_deprecated/discovery-digest.js +0 -314
  155. package/tools/_deprecated/discovery-hub.js +0 -357
  156. package/tools/_deprecated/discovery-insights.js +0 -384
  157. package/tools/_deprecated/discovery-momentum.js +0 -281
  158. package/tools/_deprecated/discovery-monitor.js +0 -319
  159. package/tools/_deprecated/discovery-proactive.js +0 -300
  160. package/tools/_deprecated/draw.js +0 -317
  161. package/tools/_deprecated/farcaster.js +0 -307
  162. package/tools/_deprecated/games-catalog.js +0 -376
  163. package/tools/_deprecated/games.js +0 -313
  164. package/tools/_deprecated/guessnumber.js +0 -194
  165. package/tools/_deprecated/hangman.js +0 -129
  166. package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
  167. package/tools/_deprecated/riddle.js +0 -240
  168. package/tools/_deprecated/run-bootstrap.js +0 -69
  169. package/tools/_deprecated/skills-analytics.js +0 -349
  170. package/tools/_deprecated/skills-bootstrap.js +0 -301
  171. package/tools/_deprecated/skills-dashboard.js +0 -268
  172. package/tools/_deprecated/skills.js +0 -380
  173. package/tools/_deprecated/smart-intro.js +0 -353
  174. package/tools/_deprecated/storybuilder.js +0 -331
  175. package/tools/_deprecated/telegram-bot.js +0 -183
  176. package/tools/_deprecated/telegram-setup.js +0 -214
  177. package/tools/_deprecated/twentyquestions.js +0 -143
  178. package/tools/_shared.js +0 -234
  179. package/tools/_work-context.js +0 -338
  180. package/tools/_work-context.manual-test.js +0 -199
  181. package/tools/_work-context.test.js +0 -260
  182. package/tools/activity.js +0 -220
  183. package/tools/agent-treasury.js +0 -288
  184. package/tools/analytics.js +0 -191
  185. package/tools/approve.js +0 -197
  186. package/tools/arcade.js +0 -173
  187. package/tools/artifacts-price.js +0 -107
  188. package/tools/ask-expert.js +0 -160
  189. package/tools/available.js +0 -120
  190. package/tools/become-expert.js +0 -150
  191. package/tools/broadcast.js +0 -325
  192. package/tools/chat.js +0 -202
  193. package/tools/collaborative-drawing.js +0 -286
  194. package/tools/connection-status.js +0 -178
  195. package/tools/earnings.js +0 -126
  196. package/tools/friends.js +0 -207
  197. package/tools/genesis.js +0 -233
  198. package/tools/gig-browse.js +0 -206
  199. package/tools/gig-complete.js +0 -144
  200. package/tools/health.js +0 -87
  201. package/tools/leaderboard.js +0 -117
  202. package/tools/lib/git-apply.js +0 -206
  203. package/tools/lib/git-bundle.js +0 -407
  204. package/tools/mint.js +0 -377
  205. package/tools/plan.js +0 -225
  206. package/tools/profile.js +0 -219
  207. package/tools/proof-of-work.js +0 -144
  208. package/tools/pulse.js +0 -218
  209. package/tools/reply.js +0 -166
  210. package/tools/reputation.js +0 -175
  211. package/tools/schedule.js +0 -367
  212. package/tools/search-messages.js +0 -123
  213. package/tools/session.js +0 -467
  214. package/tools/session_price.js +0 -128
  215. package/tools/smart-check.js +0 -201
  216. package/tools/social-processor.js +0 -445
  217. package/tools/streak.js +0 -147
  218. package/tools/stuck.js +0 -297
  219. package/tools/subscribe.js +0 -148
  220. package/tools/subscriptions.js +0 -134
  221. package/tools/tip.js +0 -193
  222. package/tools/wallet.js +0 -269
  223. package/tools/webhook-test.js +0 -388
  224. package/tools/withdraw.js +0 -145
  225. package/tools/work-summary.js +0 -96
  226. package/tools/workshop.js +0 -327
  227. /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
  228. /package/tools/{l2.js → _experimental/l2.js} +0 -0
  229. /package/tools/{_deprecated/away.js → away.js} +0 -0
@@ -46,11 +46,11 @@ const definition = {
46
46
 
47
47
  // Skill categories for better organization
48
48
  const skillCategories = {
49
- 'technical': ['frontend', 'backend', 'mobile', 'ai', 'data', 'devops', 'security'],
50
- 'design': ['ui', 'ux', 'graphic-design', 'illustration', 'branding', 'figma'],
51
- 'business': ['product', 'marketing', 'strategy', 'sales', 'fundraising', 'leadership'],
52
- 'creative': ['writing', 'content', 'video', 'photography', 'music', 'storytelling'],
53
- 'research': ['user-research', 'market-research', 'data-analysis', 'academic'],
49
+ technical: ['frontend', 'backend', 'mobile', 'ai', 'data', 'devops', 'security'],
50
+ design: ['ui', 'ux', 'graphic-design', 'illustration', 'branding', 'figma'],
51
+ business: ['product', 'marketing', 'strategy', 'sales', 'fundraising', 'leadership'],
52
+ creative: ['writing', 'content', 'video', 'photography', 'music', 'storytelling'],
53
+ research: ['user-research', 'market-research', 'data-analysis', 'academic'],
54
54
  'soft-skills': ['communication', 'mentoring', 'project-management', 'team-building']
55
55
  };
56
56
 
@@ -77,7 +77,7 @@ async function storeSkillPost(handle, type, skill, details) {
77
77
  timestamp: Date.now(),
78
78
  status: 'active'
79
79
  };
80
-
80
+
81
81
  await store.appendSkillExchange(post);
82
82
  return post;
83
83
  }
@@ -85,7 +85,7 @@ async function storeSkillPost(handle, type, skill, details) {
85
85
  // Get all active skill posts
86
86
  async function getSkillPosts() {
87
87
  try {
88
- const posts = await store.getSkillExchanges() || [];
88
+ const posts = (await store.getSkillExchanges()) || [];
89
89
  return posts.filter(p => p.status === 'active');
90
90
  } catch (error) {
91
91
  return [];
@@ -97,22 +97,21 @@ async function findSkillMatches(handle) {
97
97
  const userProfile = await userProfiles.getProfile(handle);
98
98
  const allPosts = await getSkillPosts();
99
99
  const matches = [];
100
-
100
+
101
101
  // User's skills (what they can offer)
102
102
  const userSkills = (userProfile.tags || []).concat(userProfile.interests || []);
103
-
103
+
104
104
  // Find requests for skills the user has
105
105
  const requestMatches = allPosts.filter(post => {
106
106
  if (post.type === 'request' && post.handle !== handle) {
107
107
  const requestedSkill = post.skill.toLowerCase();
108
- return userSkills.some(skill =>
109
- skill.toLowerCase().includes(requestedSkill) ||
110
- requestedSkill.includes(skill.toLowerCase())
108
+ return userSkills.some(
109
+ skill => skill.toLowerCase().includes(requestedSkill) || requestedSkill.includes(skill.toLowerCase())
111
110
  );
112
111
  }
113
112
  return false;
114
113
  });
115
-
114
+
116
115
  // Find offers for skills the user might want
117
116
  const offerMatches = allPosts.filter(post => {
118
117
  if (post.type === 'offer' && post.handle !== handle) {
@@ -125,7 +124,7 @@ async function findSkillMatches(handle) {
125
124
  }
126
125
  return false;
127
126
  });
128
-
127
+
129
128
  return {
130
129
  canHelp: requestMatches.slice(0, 3),
131
130
  canLearn: offerMatches.slice(0, 3)
@@ -145,13 +144,13 @@ async function handler(args) {
145
144
  switch (command) {
146
145
  case 'post': {
147
146
  if (!args.type || !args.skill) {
148
- return {
149
- error: 'Usage: skills-exchange post --type offer|request --skill "skill name" --details "optional details"'
147
+ return {
148
+ error: 'Usage: skills-exchange post --type offer|request --skill "skill name" --details "optional details"'
150
149
  };
151
150
  }
152
-
151
+
153
152
  const post = await storeSkillPost(myHandle, args.type, args.skill, args.details);
154
-
153
+
155
154
  display = `## Skill ${args.type === 'offer' ? 'Offer' : 'Request'} Posted! 📝\n\n`;
156
155
  display += `**${args.type === 'offer' ? 'Offering' : 'Seeking'}:** ${args.skill}\n`;
157
156
  if (args.details) {
@@ -159,7 +158,7 @@ async function handler(args) {
159
158
  }
160
159
  display += `**Category:** ${post.category}\n`;
161
160
  display += `**Posted:** ${formatTimeAgo(post.timestamp)}\n\n`;
162
-
161
+
163
162
  display += `**What's next?**\n`;
164
163
  if (args.type === 'offer') {
165
164
  display += `• People seeking "${args.skill}" will see your offer\n`;
@@ -174,7 +173,7 @@ async function handler(args) {
174
173
 
175
174
  case 'browse': {
176
175
  const posts = await getSkillPosts();
177
-
176
+
178
177
  if (posts.length === 0) {
179
178
  display = `## No Skills Posted Yet 📭\n\n`;
180
179
  display += `_The skills exchange is empty._\n\n`;
@@ -193,13 +192,13 @@ async function handler(args) {
193
192
  }
194
193
  byCategory[post.category][post.type + 's'].push(post);
195
194
  }
196
-
195
+
197
196
  display = `## Skills Exchange Marketplace 🏪\n\n`;
198
-
197
+
199
198
  for (const [category, posts] of Object.entries(byCategory)) {
200
199
  if (posts.offers.length > 0 || posts.requests.length > 0) {
201
200
  display += `### ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
202
-
201
+
203
202
  if (posts.offers.length > 0) {
204
203
  display += `**Available Skills:**\n`;
205
204
  for (const offer of posts.offers) {
@@ -209,7 +208,7 @@ async function handler(args) {
209
208
  }
210
209
  display += `\n`;
211
210
  }
212
-
211
+
213
212
  if (posts.requests.length > 0) {
214
213
  display += `**Skill Requests:**\n`;
215
214
  for (const request of posts.requests) {
@@ -221,7 +220,7 @@ async function handler(args) {
221
220
  }
222
221
  }
223
222
  }
224
-
223
+
225
224
  display += `**Connect with people:**\n`;
226
225
  display += `\`dm @username "I saw your skills post..."\`\n`;
227
226
  display += `\`skills-exchange match\` — Find your perfect exchanges`;
@@ -231,13 +230,13 @@ async function handler(args) {
231
230
 
232
231
  case 'match': {
233
232
  const matches = await findSkillMatches(myHandle);
234
-
233
+
235
234
  display = `## Your Skill Exchange Matches 🎯\n\n`;
236
-
235
+
237
236
  if (matches.canHelp.length > 0) {
238
237
  display += `### You Can Help 🤝\n`;
239
238
  display += `_People requesting skills you have:_\n\n`;
240
-
239
+
241
240
  for (const request of matches.canHelp) {
242
241
  display += `**@${request.handle}** needs: **${request.skill}**\n`;
243
242
  if (request.details) display += `${request.details}\n`;
@@ -245,11 +244,11 @@ async function handler(args) {
245
244
  display += `💬 \`dm @${request.handle} "I can help with ${request.skill}!"\`\n\n`;
246
245
  }
247
246
  }
248
-
247
+
249
248
  if (matches.canLearn.length > 0) {
250
249
  display += `### You Can Learn 📚\n`;
251
250
  display += `_Skills offered that might interest you:_\n\n`;
252
-
251
+
253
252
  for (const offer of matches.canLearn) {
254
253
  display += `**@${offer.handle}** offers: **${offer.skill}**\n`;
255
254
  if (offer.details) display += `${offer.details}\n`;
@@ -257,7 +256,7 @@ async function handler(args) {
257
256
  display += `💬 \`dm @${offer.handle} "I'd love to learn ${offer.skill}!"\`\n\n`;
258
257
  }
259
258
  }
260
-
259
+
261
260
  if (matches.canHelp.length === 0 && matches.canLearn.length === 0) {
262
261
  display += `_No matches found right now._\n\n`;
263
262
  display += `**Improve your matches:**\n`;
@@ -272,7 +271,7 @@ async function handler(args) {
272
271
  case 'requests': {
273
272
  const posts = await getSkillPosts();
274
273
  const requests = posts.filter(p => p.type === 'request');
275
-
274
+
276
275
  if (requests.length === 0) {
277
276
  display = `## No Skill Requests Yet 📋\n\n`;
278
277
  display += `_No one has posted skill requests._\n\n`;
@@ -281,11 +280,11 @@ async function handler(args) {
281
280
  } else {
282
281
  display = `## Community Skill Requests 🙋\n\n`;
283
282
  display += `_People looking for help and expertise:_\n\n`;
284
-
283
+
285
284
  // Group by recency
286
- const recent = requests.filter(r => (Date.now() - r.timestamp) < 7 * 24 * 60 * 60 * 1000);
287
- const older = requests.filter(r => (Date.now() - r.timestamp) >= 7 * 24 * 60 * 60 * 1000);
288
-
285
+ const recent = requests.filter(r => Date.now() - r.timestamp < 7 * 24 * 60 * 60 * 1000);
286
+ const older = requests.filter(r => Date.now() - r.timestamp >= 7 * 24 * 60 * 60 * 1000);
287
+
289
288
  if (recent.length > 0) {
290
289
  display += `### Recent Requests\n`;
291
290
  for (const request of recent) {
@@ -294,7 +293,7 @@ async function handler(args) {
294
293
  display += `${formatTimeAgo(request.timestamp)}\n\n`;
295
294
  }
296
295
  }
297
-
296
+
298
297
  if (older.length > 0) {
299
298
  display += `### Earlier Requests\n`;
300
299
  for (const request of older.slice(0, 5)) {
@@ -302,7 +301,7 @@ async function handler(args) {
302
301
  }
303
302
  display += `\n`;
304
303
  }
305
-
304
+
306
305
  display += `**Help someone out:**\n`;
307
306
  display += `\`dm @username "I can help with [skill]!"\`\n`;
308
307
  display += `\`skills-exchange match\` — See requests matching your skills`;
@@ -339,4 +338,4 @@ Try: \`skills-exchange\` for available commands`;
339
338
  return { display };
340
339
  }
341
340
 
342
- module.exports = { definition, handler };
341
+ module.exports = { definition, handler };
@@ -8,7 +8,7 @@
8
8
  const twitter = require('../twitter');
9
9
  const telegram = require('../bridges/telegram');
10
10
  const farcaster = require('../bridges/farcaster');
11
- const { requireInit, header, divider, formatTimeAgo } = require('./_shared');
11
+ const { requireInit, header, divider, formatTimeAgo, debug } = require('./_shared');
12
12
 
13
13
  const definition = {
14
14
  name: 'vibe_social_inbox',
@@ -115,7 +115,6 @@ async function handler(args) {
115
115
  display += '• `vibe social-inbox --channel webhooks` for webhook events only';
116
116
 
117
117
  return { display };
118
-
119
118
  } catch (e) {
120
119
  return {
121
120
  display: `${header('Social Inbox')}\n\n_Error:_ ${e.message}`
@@ -130,29 +129,29 @@ async function handleStatus() {
130
129
  const channels = await getChannelStatuses();
131
130
 
132
131
  for (const [name, status] of Object.entries(channels)) {
133
- const icon = status.connected ? '✅' : (status.configured ? '⚠️' : '❌');
132
+ const icon = status.connected ? '✅' : status.configured ? '⚠️' : '❌';
134
133
  display += `${icon} **${name.toUpperCase()}**\n`;
135
-
134
+
136
135
  if (status.connected && status.username) {
137
136
  display += ` Connected as @${status.username}\n`;
138
137
  }
139
-
138
+
140
139
  display += ` Configured: ${status.configured ? 'Yes' : 'No'}\n`;
141
140
  display += ` Can read: ${status.canRead ? 'Yes' : 'No'}\n`;
142
141
  display += ` Can write: ${status.canWrite ? 'Yes' : 'No'}\n`;
143
-
142
+
144
143
  if (status.webhook_active) {
145
144
  display += ` Webhook: Active (real-time events)\n`;
146
145
  }
147
-
146
+
148
147
  if (status.error) {
149
148
  display += ` Error: ${status.error}\n`;
150
149
  }
151
-
150
+
152
151
  if (status.setup) {
153
152
  display += ` Setup: ${status.setup}\n`;
154
153
  }
155
-
154
+
156
155
  display += '\n';
157
156
  }
158
157
 
@@ -183,7 +182,7 @@ async function getChannelStatuses() {
183
182
  const me = await twitter.getMe();
184
183
  statuses.x.connected = true;
185
184
  statuses.x.username = me.data.username;
186
-
185
+
187
186
  // Check if webhook is configured
188
187
  const webhookSecret = process.env.X_WEBHOOK_SECRET;
189
188
  statuses.x.webhook_active = !!webhookSecret;
@@ -259,10 +258,10 @@ async function getWebhookInboxEvents(limit) {
259
258
 
260
259
  const { kv } = await import('@vercel/kv');
261
260
  const inboxKey = 'vibe:social_inbox';
262
-
261
+
263
262
  // Get recent webhook events
264
263
  const rawEvents = await kv.lrange(inboxKey, 0, limit - 1);
265
-
264
+
266
265
  return rawEvents.map(eventStr => {
267
266
  const event = JSON.parse(eventStr);
268
267
  return {
@@ -278,9 +277,8 @@ async function getWebhookInboxEvents(limit) {
278
277
  metadata: event.metadata
279
278
  };
280
279
  });
281
-
282
280
  } catch (e) {
283
- console.error('Error fetching webhook events:', e);
281
+ debug('social-inbox', 'Error fetching webhook events:', e);
284
282
  return [];
285
283
  }
286
284
  }
@@ -294,7 +292,7 @@ async function getUnifiedInbox(channel, limit, refresh, highSignal, includeWebho
294
292
  const webhookEvents = await getWebhookInboxEvents(Math.min(20, limit));
295
293
  messages.push(...webhookEvents);
296
294
  } catch (e) {
297
- console.error('Webhook events error:', e.message);
295
+ debug('social-inbox', 'Webhook events error:', e.message);
298
296
  }
299
297
  }
300
298
 
@@ -322,7 +320,7 @@ async function getUnifiedInbox(channel, limit, refresh, highSignal, includeWebho
322
320
  }
323
321
  }
324
322
  } catch (e) {
325
- console.error('X mentions error:', e.message);
323
+ debug('social-inbox', 'X mentions error:', e.message);
326
324
  }
327
325
  }
328
326
 
@@ -344,7 +342,7 @@ async function getUnifiedInbox(channel, limit, refresh, highSignal, includeWebho
344
342
  }
345
343
  }
346
344
  } catch (e) {
347
- console.error('Farcaster mentions error:', e.message);
345
+ debug('social-inbox', 'Farcaster mentions error:', e.message);
348
346
  }
349
347
  }
350
348
 
@@ -353,11 +351,7 @@ async function getUnifiedInbox(channel, limit, refresh, highSignal, includeWebho
353
351
 
354
352
  // Filter high signal if requested
355
353
  if (highSignal) {
356
- return messages.filter(msg =>
357
- msg.type === 'mention' ||
358
- msg.type === 'dm' ||
359
- msg.type === 'follow'
360
- ).slice(0, limit);
354
+ return messages.filter(msg => msg.type === 'mention' || msg.type === 'dm' || msg.type === 'follow').slice(0, limit);
361
355
  }
362
356
 
363
357
  return messages.slice(0, limit);
@@ -374,7 +368,7 @@ function getTwitterAuthor(tweet, includes) {
374
368
  };
375
369
  }
376
370
  }
377
-
371
+
378
372
  return {
379
373
  id: tweet.author_id,
380
374
  handle: 'unknown',
@@ -389,7 +383,7 @@ function formatMessage(msg) {
389
383
 
390
384
  let result = `${channelIcon} ${sourceIcon} **@${msg.from.handle}** ${typeIcon} — _${msg.timeAgo}_\n`;
391
385
  result += `${msg.content}\n`;
392
-
386
+
393
387
  // Show engagement if available
394
388
  if (msg.replies > 0 || msg.reactions > 0 || msg.recasts > 0) {
395
389
  const metrics = [];
@@ -398,14 +392,14 @@ function formatMessage(msg) {
398
392
  if (msg.recasts > 0) metrics.push(`${msg.recasts} recasts`);
399
393
  result += `_${metrics.join(' • ')}_\n`;
400
394
  }
401
-
395
+
402
396
  // Show metadata if available
403
397
  if (msg.metadata?.url) {
404
398
  result += `_${msg.metadata.url}_\n`;
405
399
  }
406
-
400
+
407
401
  result += `_[${msg.id}]_\n`;
408
-
402
+
409
403
  return result;
410
404
  }
411
405
 
@@ -434,4 +428,4 @@ function getTypeIcon(type) {
434
428
  return icons[type] || '';
435
429
  }
436
430
 
437
- module.exports = { definition, handler };
431
+ module.exports = { definition, handler };
@@ -23,7 +23,7 @@ const definition = {
23
23
  },
24
24
  channels: {
25
25
  type: 'array',
26
- items: {
26
+ items: {
27
27
  type: 'string',
28
28
  enum: ['x', 'twitter', 'telegram', 'discord', 'farcaster']
29
29
  },
@@ -66,13 +66,13 @@ async function handler(args) {
66
66
  }
67
67
 
68
68
  // Normalize channels (twitter -> x)
69
- const normalizedChannels = channels.map(ch => ch === 'twitter' ? 'x' : ch);
69
+ const normalizedChannels = channels.map(ch => (ch === 'twitter' ? 'x' : ch));
70
70
 
71
71
  const trimmed = content.trim();
72
72
 
73
73
  // Get bridge statuses
74
74
  const bridgeStatuses = await getBridgeStatuses();
75
-
75
+
76
76
  // Check requirements
77
77
  const errors = [];
78
78
  for (const channel of normalizedChannels) {
@@ -84,9 +84,9 @@ async function handler(args) {
84
84
  errors.push(`telegram: Need --chat_id parameter`);
85
85
  }
86
86
  }
87
-
87
+
88
88
  if (errors.length > 0) {
89
- return {
89
+ return {
90
90
  display: `${header('Post Error')}\n\n${errors.map(e => `• ${e}`).join('\n')}\n\nRun \`vibe bridges\` to see setup status.`
91
91
  };
92
92
  }
@@ -150,7 +150,7 @@ function handleDryRun(content, channels, statuses, warnings, chatId, farcasterCh
150
150
  display += ` _Not configured_\n`;
151
151
  } else {
152
152
  let previewContent = content;
153
-
153
+
154
154
  // Apply channel-specific formatting
155
155
  if (channel === 'x' && status.charLimit && content.length > status.charLimit) {
156
156
  previewContent = content.slice(0, status.charLimit - 3) + '...';
@@ -164,10 +164,8 @@ function handleDryRun(content, channels, statuses, warnings, chatId, farcasterCh
164
164
  display += ` 📤 To main feed\n`;
165
165
  }
166
166
  }
167
-
168
- const preview = previewContent.length > 100
169
- ? previewContent.slice(0, 100) + '...'
170
- : previewContent;
167
+
168
+ const preview = previewContent.length > 100 ? previewContent.slice(0, 100) + '...' : previewContent;
171
169
  display += ` "${preview}"\n`;
172
170
  }
173
171
  display += '\n';
@@ -194,7 +192,7 @@ async function handlePost(content, channels, replyTo, warnings, chatId, farcaste
194
192
  for (const channel of channels) {
195
193
  try {
196
194
  let result;
197
-
195
+
198
196
  switch (channel) {
199
197
  case 'x':
200
198
  result = await postToX(content, replyTo);
@@ -211,10 +209,9 @@ async function handlePost(content, channels, replyTo, warnings, chatId, farcaste
211
209
  default:
212
210
  throw new Error(`Unsupported channel: ${channel}`);
213
211
  }
214
-
212
+
215
213
  results[channel] = { success: true, ...result };
216
214
  anySuccess = true;
217
-
218
215
  } catch (e) {
219
216
  results[channel] = { success: false, error: e.message };
220
217
  }
@@ -255,13 +252,13 @@ async function handlePost(content, channels, replyTo, warnings, chatId, farcaste
255
252
  async function postToX(content, replyTo) {
256
253
  // Handle reply_to format: "x:1234567890" -> "1234567890"
257
254
  const tweetId = replyTo?.startsWith('x:') ? replyTo.slice(2) : replyTo;
258
-
255
+
259
256
  // Truncate if too long
260
257
  const text = content.length > 280 ? content.slice(0, 277) + '...' : content;
261
-
258
+
262
259
  const result = await twitter.sendTweet(text, tweetId);
263
260
  const id = result.data?.id;
264
-
261
+
265
262
  return {
266
263
  id,
267
264
  url: id ? `https://x.com/seth/status/${id}` : null
@@ -271,14 +268,14 @@ async function postToX(content, replyTo) {
271
268
  async function postToTelegram(content, chatId, replyTo) {
272
269
  // Handle reply_to format: "telegram:123" -> "123"
273
270
  const messageId = replyTo?.startsWith('telegram:') ? replyTo.slice(9) : null;
274
-
271
+
275
272
  const options = {};
276
273
  if (messageId) {
277
274
  options.replyTo = parseInt(messageId);
278
275
  }
279
-
276
+
280
277
  const result = await telegram.sendMessage(chatId, content, options);
281
-
278
+
282
279
  return {
283
280
  id: `telegram:${result.message_id}`,
284
281
  chat_id: chatId
@@ -287,11 +284,11 @@ async function postToTelegram(content, chatId, replyTo) {
287
284
 
288
285
  async function postToDiscord(content) {
289
286
  const success = await discord.post(content);
290
-
287
+
291
288
  if (!success) {
292
289
  throw new Error('Discord webhook failed');
293
290
  }
294
-
291
+
295
292
  return {
296
293
  id: 'discord:webhook',
297
294
  webhook: true
@@ -301,21 +298,21 @@ async function postToDiscord(content) {
301
298
  async function postToFarcaster(content, channelId, replyTo) {
302
299
  // Handle reply_to format: "farcaster:hash" -> "hash"
303
300
  const castHash = replyTo?.startsWith('farcaster:') ? replyTo.slice(10) : replyTo;
304
-
301
+
305
302
  const options = {};
306
303
  if (channelId) options.channel = channelId;
307
304
  if (castHash) options.replyTo = castHash;
308
-
305
+
309
306
  const result = await farcaster.publishCast(content, options);
310
-
307
+
311
308
  if (!result.success) {
312
309
  throw new Error(result.message || 'Failed to publish cast');
313
310
  }
314
-
311
+
315
312
  const cast = result.cast;
316
313
  const username = cast.author.username;
317
314
  const hash = cast.hash;
318
-
315
+
319
316
  return {
320
317
  id: `farcaster:${hash}`,
321
318
  hash: hash,
@@ -323,4 +320,4 @@ async function postToFarcaster(content, channelId, replyTo) {
323
320
  };
324
321
  }
325
322
 
326
- module.exports = { definition, handler };
323
+ module.exports = { definition, handler };