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
package/tools/game.js CHANGED
@@ -1,26 +1,38 @@
1
1
  /**
2
- * vibe game — Start or continue a game with someone
2
+ * vibe game — Unified game entry point
3
3
  *
4
- * Supports: tic-tac-toe, chess
4
+ * Routes to all game types:
5
+ * - Multiplayer: tictactoe, chess
6
+ * - Solo: hangman, rps, memory
7
+ * - Party: twotruths, werewolf
8
+ * - AI: tictactoe-ai (play vs AI)
9
+ * - Collaborative: drawing, crossword, wordassociation, multiplayer-tictactoe, wordchain, storybuilder
5
10
  */
6
11
 
7
12
  const config = require('../config');
8
13
  const store = require('../store');
9
14
  const { createTicTacToePayload, createGamePayload, formatPayload } = require('../protocol');
10
- const { requireInit, normalizeHandle } = require('./_shared');
15
+ const { requireInit, normalizeHandle, debug } = require('./_shared');
11
16
 
12
17
  // Chess game implementation
13
18
  const chess = require('../games/chess');
14
19
 
20
+ // Delegate handlers for absorbed game tools
21
+ const soloGameTool = require('./solo-game');
22
+ const partyGameTool = require('./party-game');
23
+ const tictactoeTool = require('./tictactoe');
24
+ const wordassociationTool = require('./wordassociation');
25
+ const multiplayerGameTool = require('./multiplayer-game');
26
+ const drawingTool = require('./drawing');
27
+ const crosswordTool = require('./crossword');
28
+
15
29
  // Post game results to board and Discord
16
30
  async function postGameResult(winner, loser, isDraw, game = 'tic-tac-toe') {
17
- const API_URL = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
31
+ const API_URL = config.getApiUrl();
18
32
 
19
33
  // Post to board
20
34
  try {
21
- const content = isDraw
22
- ? `@${winner} and @${loser} tied at ${game}`
23
- : `@${winner} beat @${loser} at ${game}`;
35
+ const content = isDraw ? `@${winner} and @${loser} tied at ${game}` : `@${winner} beat @${loser} at ${game}`;
24
36
 
25
37
  await fetch(`${API_URL}/api/board`, {
26
38
  method: 'POST',
@@ -32,7 +44,7 @@ async function postGameResult(winner, loser, isDraw, game = 'tic-tac-toe') {
32
44
  })
33
45
  });
34
46
  } catch (e) {
35
- console.error('[game] Failed to post to board:', e.message);
47
+ debug('game', 'Failed to post to board:', e.message);
36
48
  }
37
49
 
38
50
  // Post to Discord
@@ -53,31 +65,76 @@ async function postGameResult(winner, loser, isDraw, game = 'tic-tac-toe') {
53
65
  })
54
66
  });
55
67
  } catch (e) {
56
- console.error('[game] Failed to post to Discord:', e.message);
68
+ debug('game', 'Failed to post to Discord:', e.message);
57
69
  }
58
70
  }
59
71
 
72
+ // Games that delegate to absorbed tool handlers
73
+ const DELEGATED_GAMES = {
74
+ // Solo games (from solo-game.js)
75
+ hangman: 'solo',
76
+ rps: 'solo',
77
+ memory: 'solo',
78
+ // Party games (from party-game.js)
79
+ twotruths: 'party',
80
+ werewolf: 'party',
81
+ // AI tictactoe (from tictactoe.js)
82
+ 'tictactoe-ai': 'tictactoe-ai',
83
+ // Collaborative (from multiplayer-game.js)
84
+ 'multiplayer-tictactoe': 'multiplayer',
85
+ wordchain: 'multiplayer',
86
+ storybuilder: 'multiplayer',
87
+ // Standalone tools
88
+ wordassociation: 'wordassociation',
89
+ drawing: 'drawing',
90
+ crossword: 'crossword'
91
+ };
92
+
60
93
  const definition = {
61
94
  name: 'vibe_game',
62
- description: 'Start or continue a game with someone. Supports: tictactoe, chess',
95
+ description:
96
+ 'Start or play any game. Multiplayer: tictactoe, chess. Solo: hangman, rps, memory. Party: twotruths, werewolf. AI: tictactoe-ai. Collaborative: drawing, crossword, wordassociation, wordchain, storybuilder, multiplayer-tictactoe.',
63
97
  inputSchema: {
64
98
  type: 'object',
65
99
  properties: {
66
100
  handle: {
67
101
  type: 'string',
68
- description: 'Who to play with (e.g., @solienne)'
102
+ description: 'Who to play with (for multiplayer games like tictactoe, chess)'
69
103
  },
70
104
  game: {
71
105
  type: 'string',
72
106
  description: 'Game to play (default: tictactoe)',
73
- enum: ['tictactoe', 'chess']
107
+ enum: [
108
+ 'tictactoe',
109
+ 'chess',
110
+ 'hangman',
111
+ 'rps',
112
+ 'memory',
113
+ 'twotruths',
114
+ 'werewolf',
115
+ 'tictactoe-ai',
116
+ 'drawing',
117
+ 'crossword',
118
+ 'wordassociation',
119
+ 'multiplayer-tictactoe',
120
+ 'wordchain',
121
+ 'storybuilder'
122
+ ]
74
123
  },
75
124
  move: {
76
125
  type: ['number', 'string'],
77
126
  description: 'Move to make (tictactoe: 1-9, chess: algebraic notation like e4, Nf3)'
127
+ },
128
+ action: {
129
+ type: 'string',
130
+ description: 'Action for party/collaborative games (e.g., new, join, draw, play, hint)'
131
+ },
132
+ difficulty: {
133
+ type: 'string',
134
+ description: 'Difficulty for solo/AI games (easy, medium, hard)',
135
+ enum: ['easy', 'medium', 'hard']
78
136
  }
79
- },
80
- required: ['handle']
137
+ }
81
138
  }
82
139
  };
83
140
 
@@ -100,9 +157,14 @@ function getGameState(thread, game) {
100
157
  */
101
158
  function checkTicTacToeWinner(board) {
102
159
  const lines = [
103
- [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows
104
- [0, 3, 6], [1, 4, 7], [2, 5, 8], // cols
105
- [0, 4, 8], [2, 4, 6] // diagonals
160
+ [0, 1, 2],
161
+ [3, 4, 5],
162
+ [6, 7, 8], // rows
163
+ [0, 3, 6],
164
+ [1, 4, 7],
165
+ [2, 5, 8], // cols
166
+ [0, 4, 8],
167
+ [2, 4, 6] // diagonals
106
168
  ];
107
169
 
108
170
  for (const [a, b, c] of lines) {
@@ -120,30 +182,40 @@ function checkTicTacToeWinner(board) {
120
182
  function formatChessPayload(payload) {
121
183
  const state = payload.state || {};
122
184
  const board = state.board || [];
123
-
185
+
124
186
  if (!board.length) return '♟️ **Chess** (setting up...)';
125
187
 
126
188
  const files = ' a b c d e f g h';
127
189
  let display = '♟️ **Chess** ' + (state.moves ? `(move ${state.moves})` : '(new game)') + '\n```\n' + files + '\n';
128
-
190
+
129
191
  for (let rank = 0; rank < 8; rank++) {
130
- let row = (8 - rank) + ' ';
192
+ let row = 8 - rank + ' ';
131
193
  for (let file = 0; file < 8; file++) {
132
194
  const piece = board[rank] && board[rank][file];
133
195
  // Use chess piece Unicode symbols
134
196
  const pieceSymbols = {
135
- 'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',
136
- 'k': '', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟'
197
+ K: '♔',
198
+ Q: '',
199
+ R: '♖',
200
+ B: '♗',
201
+ N: '♘',
202
+ P: '♙',
203
+ k: '♚',
204
+ q: '♛',
205
+ r: '♜',
206
+ b: '♝',
207
+ n: '♞',
208
+ p: '♟'
137
209
  };
138
- const symbol = piece ? (pieceSymbols[piece] || piece) : ((rank + file) % 2 === 0 ? '·' : ' ');
210
+ const symbol = piece ? pieceSymbols[piece] || piece : (rank + file) % 2 === 0 ? '·' : ' ';
139
211
  row += symbol + ' ';
140
212
  }
141
- row += (8 - rank);
213
+ row += 8 - rank;
142
214
  display += row + '\n';
143
215
  }
144
-
216
+
145
217
  display += files + '\n```\n';
146
-
218
+
147
219
  if (state.winner) {
148
220
  display += `**Winner: ${state.winner}**`;
149
221
  } else if (state.checkmate) {
@@ -153,11 +225,11 @@ function formatChessPayload(payload) {
153
225
  } else if (state.check) {
154
226
  display += '**Check!** ';
155
227
  }
156
-
228
+
157
229
  if (!state.winner && !state.checkmate && !state.stalemate) {
158
230
  display += `Turn: **${state.turn || 'white'}**`;
159
231
  }
160
-
232
+
161
233
  if (state.lastMove) {
162
234
  display += `\nLast move: ${state.lastMove.notation}`;
163
235
  }
@@ -169,13 +241,42 @@ async function handler(args) {
169
241
  const initCheck = requireInit();
170
242
  if (initCheck) return initCheck;
171
243
 
172
- const { handle, move } = args;
173
244
  const game = args.game || 'tictactoe';
245
+
246
+ // Delegate to absorbed game handlers
247
+ const delegateType = DELEGATED_GAMES[game];
248
+ if (delegateType === 'solo') {
249
+ return soloGameTool.handler({ ...args, game });
250
+ }
251
+ if (delegateType === 'party') {
252
+ return partyGameTool.handler({ ...args, game });
253
+ }
254
+ if (delegateType === 'tictactoe-ai') {
255
+ return tictactoeTool.handler(args);
256
+ }
257
+ if (delegateType === 'wordassociation') {
258
+ return wordassociationTool.handler(args);
259
+ }
260
+ if (delegateType === 'drawing') {
261
+ return drawingTool.handler(args);
262
+ }
263
+ if (delegateType === 'crossword') {
264
+ return crosswordTool.handler(args);
265
+ }
266
+ if (delegateType === 'multiplayer') {
267
+ return multiplayerGameTool.handler({ ...args, game });
268
+ }
269
+
270
+ // Original tictactoe/chess multiplayer logic
271
+ const { handle, move } = args;
272
+ if (!handle) {
273
+ return { display: `Game "${game}" requires a handle. Usage: vibe game --handle @someone --game ${game}` };
274
+ }
174
275
  const myHandle = config.getHandle();
175
276
  const them = normalizeHandle(handle);
176
277
 
177
278
  if (them === myHandle) {
178
- return { display: 'You can\'t play a game with yourself.' };
279
+ return { display: "You can't play a game with yourself." };
179
280
  }
180
281
 
181
282
  // Get existing thread
@@ -189,8 +290,14 @@ async function handler(args) {
189
290
  if (game === 'chess') {
190
291
  const newState = chess.createInitialChessState();
191
292
  const payload = createGamePayload('chess', newState);
192
-
193
- await store.sendMessage(myHandle, them, 'Starting a new chess game! You can play white and go first.', 'dm', payload);
293
+
294
+ await store.sendMessage(
295
+ myHandle,
296
+ them,
297
+ 'Starting a new chess game! You can play white and go first.',
298
+ 'dm',
299
+ payload
300
+ );
194
301
 
195
302
  return {
196
303
  display: `## New Chess Game with @${them}\n\n${formatChessPayload(payload)}\n\nUse \`vibe game @${them} --move e4\` to make moves in algebraic notation`
@@ -211,23 +318,18 @@ async function handler(args) {
211
318
  // Show existing game
212
319
  let payload;
213
320
  let displayText;
214
-
321
+
215
322
  if (game === 'chess') {
216
323
  payload = createGamePayload('chess', gameState);
217
324
  displayText = `## Chess Game with @${them}\n\n${formatChessPayload(payload)}\n`;
218
-
325
+
219
326
  if (gameState.winner || gameState.checkmate) {
220
327
  displayText += `\nGame over! Use \`vibe game @${them}\` with no move to start a new game.`;
221
328
  } else {
222
329
  displayText += `\nUse \`vibe game @${them} --move e4\` to make moves in algebraic notation`;
223
330
  }
224
331
  } else {
225
- payload = createTicTacToePayload(
226
- gameState.board,
227
- gameState.turn,
228
- gameState.moves,
229
- gameState.winner
230
- );
332
+ payload = createTicTacToePayload(gameState.board, gameState.turn, gameState.moves, gameState.winner);
231
333
  displayText = `## Game with @${them}\n\n${formatPayload(payload)}\n`;
232
334
 
233
335
  if (gameState.winner) {
@@ -281,7 +383,6 @@ async function handler(args) {
281
383
  return {
282
384
  display: `## Chess Game with @${them}\n\n${formatChessPayload(payload)}\n\n${newGameState.checkmate ? '🎉 You win!' : newGameState.stalemate ? '🤝 Stalemate!' : `Waiting for @${them}...`}`
283
385
  };
284
-
285
386
  } else {
286
387
  // Tic-tac-toe logic
287
388
  const position = move - 1; // Convert 1-9 to 0-8
@@ -327,12 +428,7 @@ async function handler(args) {
327
428
  const nextTurn = mySymbol === 'X' ? 'O' : 'X';
328
429
 
329
430
  // Create payload
330
- const payload = createTicTacToePayload(
331
- newBoard,
332
- winner ? mySymbol : nextTurn,
333
- newMoves,
334
- winner
335
- );
431
+ const payload = createTicTacToePayload(newBoard, winner ? mySymbol : nextTurn, newMoves, winner);
336
432
 
337
433
  // Send message with game state
338
434
  let message = '';
@@ -356,4 +452,4 @@ async function handler(args) {
356
452
  }
357
453
  }
358
454
 
359
- module.exports = { definition, handler };
455
+ module.exports = { definition, handler };
package/tools/handoff.js CHANGED
@@ -140,7 +140,7 @@ async function handler(args) {
140
140
  files: context.files || [],
141
141
  current_state: context.current_state,
142
142
  next_step: context.next_step,
143
- blockers: context.blockers || [],
143
+ blockers: context.blockers || []
144
144
  },
145
145
 
146
146
  history: {
@@ -152,13 +152,7 @@ async function handler(args) {
152
152
  const humanMessage = formatHandoffMessage(handoffPayload, myHandle);
153
153
 
154
154
  // Send via existing message system with structured payload
155
- await store.sendMessage(
156
- myHandle,
157
- them,
158
- humanMessage,
159
- 'handoff',
160
- handoffPayload
161
- );
155
+ await store.sendMessage(myHandle, them, humanMessage, 'handoff', handoffPayload);
162
156
 
163
157
  // Build response
164
158
  const filesCount = context.files?.length || 0;
@@ -178,6 +172,10 @@ async function handler(args) {
178
172
 
179
173
  display += `\n\n_Handoff ID: ${handoff_id}_`;
180
174
 
175
+ // Push handoff event to subscribed agent gateways
176
+ const { pushToAgents } = require('../notify');
177
+ pushToAgents('handoff', { from: myHandle, to: them, task, context, handoff_id }).catch(() => {});
178
+
181
179
  return {
182
180
  display,
183
181
  hint: 'handoff_sent',
package/tools/help.js CHANGED
@@ -197,7 +197,7 @@ Presence updates every 5 minutes. Run \`vibe who\` for fresh data.
197
197
  - Post on the board with category "question"
198
198
 
199
199
  ### Report Issues
200
- - GitHub: https://github.com/VibeCodingInc/vibe-mcp/issues
200
+ - GitHub: https://github.com/brightseth/vibe/issues
201
201
  - Or: \`vibe echo "your feedback"\``;
202
202
 
203
203
  async function handler(args) {
@@ -260,10 +260,10 @@ ${isInitialized ? `You're **@${handle}**` : '⚠️ Not initialized yet — run
260
260
 
261
261
  ### Links
262
262
  - Docs: https://slashvibe.dev/llms.txt
263
- - Issues: https://github.com/VibeCodingInc/vibe-mcp/issues
263
+ - Issues: https://github.com/brightseth/vibe/issues
264
264
  - Feedback: \`vibe echo "message"\``;
265
265
 
266
266
  return { display };
267
267
  }
268
268
 
269
- module.exports = { definition, handler };
269
+ module.exports = { definition, handler };
package/tools/idea.js CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  const config = require('../config');
13
13
  const patterns = require('../intelligence/patterns');
14
- const { requireInit, header, emptyState, formatTimeAgo, divider } = require('./_shared');
14
+ const { requireInit, normalizeHandle, header, emptyState, formatTimeAgo, divider } = require('./_shared');
15
15
 
16
16
  const definition = {
17
17
  name: 'vibe_idea',
@@ -25,7 +25,7 @@ const definition = {
25
25
  },
26
26
  riff_on: {
27
27
  type: 'string',
28
- description: 'Handle of person whose idea you\'re riffing on (e.g., @alice)'
28
+ description: "Handle of person whose idea you're riffing on (e.g., @alice)"
29
29
  },
30
30
  tags: {
31
31
  type: 'array',
@@ -50,7 +50,7 @@ const IDEA_STARTERS = [
50
50
  'What would happen if we combined...',
51
51
  'The intersection of X and Y could...',
52
52
  'A tool that lets you...',
53
- 'What\'s missing is...'
53
+ "What's missing is..."
54
54
  ];
55
55
 
56
56
  async function handler(args) {
@@ -78,22 +78,15 @@ async function handler(args) {
78
78
 
79
79
  // Add riff metadata
80
80
  if (args.riff_on) {
81
- const riffTarget = args.riff_on.replace('@', '').toLowerCase();
81
+ const riffTarget = normalizeHandle(args.riff_on);
82
82
  entry.content = `↳ riffing on @${riffTarget}: ${content}`;
83
83
  entry.tags = [...(entry.tags || []), `riff:${riffTarget}`];
84
84
  }
85
85
 
86
86
  try {
87
- // Include auth token for API authorization
88
- const authToken = config.getAuthToken();
89
- const headers = { 'Content-Type': 'application/json' };
90
- if (authToken) {
91
- headers['Authorization'] = `Bearer ${authToken}`;
92
- }
93
-
94
87
  const response = await fetch(`${apiUrl}/api/board`, {
95
88
  method: 'POST',
96
- headers,
89
+ headers: { 'Content-Type': 'application/json' },
97
90
  body: JSON.stringify(entry)
98
91
  });
99
92
 
@@ -110,9 +103,7 @@ async function handler(args) {
110
103
  patterns.logIdea(content, args.tags || []);
111
104
  }
112
105
 
113
- let display = args.riff_on
114
- ? `↳ riff posted\n\n`
115
- : `💡 posted\n\n`;
106
+ let display = args.riff_on ? `↳ riff posted\n\n` : `💡 posted\n\n`;
116
107
 
117
108
  display += `"${content}"`;
118
109
 
@@ -121,7 +112,6 @@ async function handler(args) {
121
112
  }
122
113
 
123
114
  return { display };
124
-
125
115
  } catch (error) {
126
116
  return { display: `⚠️ Failed to post: ${error.message}` };
127
117
  }
@@ -135,10 +125,7 @@ async function handler(args) {
135
125
  // Also fetch riffs
136
126
  const riffUrl = `${apiUrl}/api/board?limit=${limit}&category=riff`;
137
127
 
138
- const [ideasRes, riffsRes] = await Promise.all([
139
- fetch(url),
140
- fetch(riffUrl)
141
- ]);
128
+ const [ideasRes, riffsRes] = await Promise.all([fetch(url), fetch(riffUrl)]);
142
129
 
143
130
  const ideas = (await ideasRes.json()).entries || [];
144
131
  const riffs = (await riffsRes.json()).entries || [];
@@ -150,9 +137,7 @@ async function handler(args) {
150
137
  let filtered = allEntries;
151
138
  if (args.filter_tag) {
152
139
  const tag = args.filter_tag.toLowerCase();
153
- filtered = allEntries.filter(e =>
154
- e.tags && e.tags.some(t => t.toLowerCase().includes(tag))
155
- );
140
+ filtered = allEntries.filter(e => e.tags && e.tags.some(t => t.toLowerCase().includes(tag)));
156
141
  }
157
142
 
158
143
  if (filtered.length === 0) {
@@ -190,9 +175,13 @@ async function handler(args) {
190
175
  topLevel.slice(0, 10).forEach(entry => {
191
176
  const emoji = entry.category === 'riff' ? '↳' : '💡';
192
177
  const timeAgo = formatTimeAgo(entry.timestamp);
193
- const tags = entry.tags && entry.tags.length > 0
194
- ? ` ${entry.tags.filter(t => !t.startsWith('riff:')).map(t => `#${t}`).join(' ')}`
195
- : '';
178
+ const tags =
179
+ entry.tags && entry.tags.length > 0
180
+ ? ` ${entry.tags
181
+ .filter(t => !t.startsWith('riff:'))
182
+ .map(t => `#${t}`)
183
+ .join(' ')}`
184
+ : '';
196
185
 
197
186
  display += `${emoji} **@${entry.author}**${tags}\n`;
198
187
  display += ` "${entry.content}"\n`;
@@ -208,7 +197,6 @@ async function handler(args) {
208
197
  });
209
198
 
210
199
  return { display };
211
-
212
200
  } catch (error) {
213
201
  return { display: `⚠️ Failed to load ideas: ${error.message}` };
214
202
  }