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.
- package/LICENSE +21 -0
- package/README.md +280 -47
- package/config.js +36 -31
- package/crypto.js +1 -6
- package/discord.js +19 -19
- package/index.js +217 -207
- package/intelligence/index.js +2 -9
- package/intelligence/infer.js +10 -16
- package/intelligence/patterns.js +23 -18
- package/intelligence/proactive.js +16 -15
- package/intelligence/serendipity.js +57 -20
- package/memory.js +13 -8
- package/notify.js +39 -14
- package/package.json +27 -20
- package/presence.js +2 -2
- package/prompts.js +5 -9
- package/protocol/index.js +123 -87
- package/protocol/telegram-commands.js +36 -37
- package/store/api.js +358 -529
- package/store/local.js +9 -10
- package/store/profiles.js +48 -192
- package/store/reservations.js +2 -9
- package/store/skills.js +69 -71
- package/store/sqlite.js +355 -0
- package/tools/_actions.js +48 -387
- package/tools/_connection-queue.js +45 -56
- package/tools/_discovery-enhanced.js +52 -57
- package/tools/_discovery.js +87 -185
- package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
- package/tools/{shipback.js → _experimental/shipback.js} +4 -3
- package/tools/_proactive-discovery.js +60 -73
- package/tools/_shared/index.js +41 -64
- package/tools/admin-inbox.js +10 -15
- package/tools/agents.js +1 -1
- package/tools/artifact-create.js +13 -23
- package/tools/artifact-view.js +4 -4
- package/tools/{_deprecated/back.js → back.js} +1 -1
- package/tools/bye.js +3 -5
- package/tools/consent.js +2 -2
- package/tools/context.js +9 -10
- package/tools/crossword.js +3 -2
- package/tools/discover.js +94 -356
- package/tools/dm.js +27 -86
- package/tools/doctor.js +12 -41
- package/tools/drawing.js +34 -20
- package/tools/echo.js +11 -11
- package/tools/feed.js +30 -58
- package/tools/follow.js +64 -187
- package/tools/{_deprecated/forget.js → forget.js} +4 -7
- package/tools/game.js +144 -48
- package/tools/handoff.js +6 -8
- package/tools/help.js +3 -3
- package/tools/idea.js +15 -27
- package/tools/inbox.js +121 -293
- package/tools/init.js +54 -151
- package/tools/invite.js +8 -21
- package/tools/migrate.js +27 -24
- package/tools/multiplayer-game.js +50 -40
- package/tools/{_deprecated/mute.js → mute.js} +4 -3
- package/tools/notifications.js +58 -48
- package/tools/observe.js +12 -15
- package/tools/onboarding.js +8 -11
- package/tools/open.js +13 -144
- package/tools/party-game.js +23 -12
- package/tools/patterns.js +2 -1
- package/tools/ping.js +5 -7
- package/tools/react.js +28 -30
- package/tools/{_deprecated/recall.js → recall.js} +5 -10
- package/tools/release.js +4 -2
- package/tools/{_deprecated/remember.js → remember.js} +4 -6
- package/tools/report.js +2 -2
- package/tools/request.js +6 -26
- package/tools/reserve.js +1 -1
- package/tools/session-fork.js +97 -0
- package/tools/session-save.js +109 -0
- package/tools/settings.js +30 -99
- package/tools/ship.js +74 -56
- package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
- package/tools/social-inbox.js +22 -28
- package/tools/social-post.js +24 -27
- package/tools/solo-game.js +54 -46
- package/tools/start.js +14 -148
- package/tools/status.js +21 -68
- package/tools/submit.js +4 -2
- package/tools/suggest-tags.js +36 -33
- package/tools/summarize.js +19 -16
- package/tools/tag-suggestions.js +72 -73
- package/tools/test.js +1 -1
- package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
- package/tools/token.js +4 -4
- package/tools/update.js +1 -2
- package/tools/watch.js +132 -112
- package/tools/who.js +20 -40
- package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
- package/tools/workshop-buddy.js +52 -53
- package/tools/x-mentions.js +0 -1
- package/tools/x-reply.js +0 -1
- package/twitter.js +14 -20
- package/version.json +8 -10
- package/analytics.js +0 -107
- package/auth-store.js +0 -148
- package/auto-update.js +0 -130
- package/bridges/bridge-monitor.js +0 -388
- package/bridges/discord-bot.js +0 -431
- package/bridges/farcaster.js +0 -299
- package/bridges/telegram.js +0 -261
- package/bridges/webhook-health.js +0 -420
- package/bridges/webhook-server.js +0 -437
- package/bridges/whatsapp.js +0 -441
- package/bridges/x-webhook.js +0 -423
- package/games/arcade.js +0 -406
- package/games/chess.js +0 -451
- package/games/colorguess.js +0 -343
- package/games/crossword-words.js +0 -171
- package/games/crossword.js +0 -461
- package/games/drawing.js +0 -347
- package/games/gameroulette.js +0 -300
- package/games/gamerouter.js +0 -336
- package/games/gamestatus.js +0 -337
- package/games/guessnumber.js +0 -209
- package/games/hangman.js +0 -279
- package/games/memory.js +0 -338
- package/games/multiplayer-tictactoe.js +0 -389
- package/games/pixelart.js +0 -399
- package/games/quickduel.js +0 -354
- package/games/riddle.js +0 -371
- package/games/rockpaperscissors.js +0 -291
- package/games/snake.js +0 -406
- package/games/storybuilder.js +0 -343
- package/games/tictactoe.js +0 -345
- package/games/twentyquestions.js +0 -286
- package/games/twotruths.js +0 -207
- package/games/werewolf.js +0 -508
- package/games/wordassociation.js +0 -247
- package/games/wordchain.js +0 -135
- package/intelligence/interests.js +0 -369
- package/notification-emitter.js +0 -77
- package/setup.js +0 -480
- package/smart-inbox.js +0 -276
- package/tools/_deprecated/auto-suggest-connections.js +0 -304
- package/tools/_deprecated/bootstrap-skills.js +0 -231
- package/tools/_deprecated/bridge-dashboard.js +0 -342
- package/tools/_deprecated/bridge-health.js +0 -400
- package/tools/_deprecated/bridge-live.js +0 -384
- package/tools/_deprecated/bridges.js +0 -383
- package/tools/_deprecated/colorguess.js +0 -281
- package/tools/_deprecated/discover-insights.js +0 -379
- package/tools/_deprecated/discover-momentum.js +0 -256
- package/tools/_deprecated/discovery-analytics.js +0 -345
- package/tools/_deprecated/discovery-auto-suggest.js +0 -275
- package/tools/_deprecated/discovery-bootstrap.js +0 -267
- package/tools/_deprecated/discovery-daily.js +0 -375
- package/tools/_deprecated/discovery-dashboard.js +0 -385
- package/tools/_deprecated/discovery-digest.js +0 -314
- package/tools/_deprecated/discovery-hub.js +0 -357
- package/tools/_deprecated/discovery-insights.js +0 -384
- package/tools/_deprecated/discovery-momentum.js +0 -281
- package/tools/_deprecated/discovery-monitor.js +0 -319
- package/tools/_deprecated/discovery-proactive.js +0 -300
- package/tools/_deprecated/draw.js +0 -317
- package/tools/_deprecated/farcaster.js +0 -307
- package/tools/_deprecated/games-catalog.js +0 -376
- package/tools/_deprecated/games.js +0 -313
- package/tools/_deprecated/guessnumber.js +0 -194
- package/tools/_deprecated/hangman.js +0 -129
- package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
- package/tools/_deprecated/riddle.js +0 -240
- package/tools/_deprecated/run-bootstrap.js +0 -69
- package/tools/_deprecated/skills-analytics.js +0 -349
- package/tools/_deprecated/skills-bootstrap.js +0 -301
- package/tools/_deprecated/skills-dashboard.js +0 -268
- package/tools/_deprecated/skills.js +0 -380
- package/tools/_deprecated/smart-intro.js +0 -353
- package/tools/_deprecated/storybuilder.js +0 -331
- package/tools/_deprecated/telegram-bot.js +0 -183
- package/tools/_deprecated/telegram-setup.js +0 -214
- package/tools/_deprecated/twentyquestions.js +0 -143
- package/tools/_shared.js +0 -234
- package/tools/_work-context.js +0 -338
- package/tools/_work-context.manual-test.js +0 -199
- package/tools/_work-context.test.js +0 -260
- package/tools/activity.js +0 -220
- package/tools/agent-treasury.js +0 -288
- package/tools/analytics.js +0 -191
- package/tools/approve.js +0 -197
- package/tools/arcade.js +0 -173
- package/tools/artifacts-price.js +0 -107
- package/tools/ask-expert.js +0 -160
- package/tools/available.js +0 -120
- package/tools/become-expert.js +0 -150
- package/tools/broadcast.js +0 -325
- package/tools/chat.js +0 -202
- package/tools/collaborative-drawing.js +0 -286
- package/tools/connection-status.js +0 -178
- package/tools/earnings.js +0 -126
- package/tools/friends.js +0 -207
- package/tools/genesis.js +0 -233
- package/tools/gig-browse.js +0 -206
- package/tools/gig-complete.js +0 -144
- package/tools/health.js +0 -87
- package/tools/leaderboard.js +0 -117
- package/tools/lib/git-apply.js +0 -206
- package/tools/lib/git-bundle.js +0 -407
- package/tools/mint.js +0 -377
- package/tools/plan.js +0 -225
- package/tools/profile.js +0 -219
- package/tools/proof-of-work.js +0 -144
- package/tools/pulse.js +0 -218
- package/tools/reply.js +0 -166
- package/tools/reputation.js +0 -175
- package/tools/schedule.js +0 -367
- package/tools/search-messages.js +0 -123
- package/tools/session.js +0 -467
- package/tools/session_price.js +0 -128
- package/tools/smart-check.js +0 -201
- package/tools/social-processor.js +0 -445
- package/tools/streak.js +0 -147
- package/tools/stuck.js +0 -297
- package/tools/subscribe.js +0 -148
- package/tools/subscriptions.js +0 -134
- package/tools/tip.js +0 -193
- package/tools/wallet.js +0 -269
- package/tools/webhook-test.js +0 -388
- package/tools/withdraw.js +0 -145
- package/tools/work-summary.js +0 -96
- package/tools/workshop.js +0 -327
- /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
- /package/tools/{l2.js → _experimental/l2.js} +0 -0
- /package/tools/{_deprecated/away.js → away.js} +0 -0
package/tools/solo-game.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
const config = require('../config');
|
|
8
8
|
const store = require('../store');
|
|
9
9
|
const { createGamePayload } = require('../protocol');
|
|
10
|
-
const { requireInit } = require('./_shared');
|
|
10
|
+
const { requireInit, debug } = require('./_shared');
|
|
11
11
|
|
|
12
12
|
// Import game implementations
|
|
13
13
|
const hangman = require('../games/hangman');
|
|
@@ -16,14 +16,12 @@ const memory = require('../games/memory');
|
|
|
16
16
|
|
|
17
17
|
// Post game results to board
|
|
18
18
|
async function postSoloGameResult(player, game, won, score = null) {
|
|
19
|
-
const API_URL =
|
|
19
|
+
const API_URL = config.getApiUrl();
|
|
20
20
|
|
|
21
21
|
try {
|
|
22
22
|
let content;
|
|
23
23
|
if (won) {
|
|
24
|
-
content = score
|
|
25
|
-
? `@${player} won ${game} with a score of ${score}! 🎉`
|
|
26
|
-
: `@${player} won ${game}! 🎉`;
|
|
24
|
+
content = score ? `@${player} won ${game} with a score of ${score}! 🎉` : `@${player} won ${game}! 🎉`;
|
|
27
25
|
} else {
|
|
28
26
|
content = `@${player} played ${game}`;
|
|
29
27
|
}
|
|
@@ -38,7 +36,7 @@ async function postSoloGameResult(player, game, won, score = null) {
|
|
|
38
36
|
})
|
|
39
37
|
});
|
|
40
38
|
} catch (e) {
|
|
41
|
-
|
|
39
|
+
debug('solo-game', 'Failed to post to board:', e.message);
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
|
|
@@ -55,7 +53,8 @@ const definition = {
|
|
|
55
53
|
},
|
|
56
54
|
action: {
|
|
57
55
|
type: 'string',
|
|
58
|
-
description:
|
|
56
|
+
description:
|
|
57
|
+
'Game action: hangman(guess, hint, new, status) | rps(rock, paper, scissors, new, status) | memory(input, new, status)'
|
|
59
58
|
},
|
|
60
59
|
guess: {
|
|
61
60
|
type: 'string',
|
|
@@ -90,7 +89,7 @@ const definition = {
|
|
|
90
89
|
async function getCurrentGameState(player, game) {
|
|
91
90
|
// For solo games, we store state with a special key
|
|
92
91
|
const thread = await store.getThread(player, `solo-${game}`);
|
|
93
|
-
|
|
92
|
+
|
|
94
93
|
// Find the most recent game payload
|
|
95
94
|
for (let i = thread.length - 1; i >= 0; i--) {
|
|
96
95
|
const msg = thread[i];
|
|
@@ -146,9 +145,9 @@ async function handler(args) {
|
|
|
146
145
|
// Start new game
|
|
147
146
|
const gameDifficulty = difficulty || 'medium';
|
|
148
147
|
gameState = hangman.createInitialHangmanState(gameDifficulty);
|
|
149
|
-
|
|
148
|
+
|
|
150
149
|
await saveGameState(myHandle, 'hangman', gameState, `Started new ${gameDifficulty} hangman game!`);
|
|
151
|
-
|
|
150
|
+
|
|
152
151
|
const payload = createGamePayload('hangman', gameState);
|
|
153
152
|
return {
|
|
154
153
|
display: `## New Hangman Game (${gameDifficulty})\n\n${formatHangmanPayload(payload)}\n\nUse \`vibe solo-game hangman --guess a\` to guess letters`
|
|
@@ -159,13 +158,13 @@ async function handler(args) {
|
|
|
159
158
|
// Show current game state
|
|
160
159
|
const payload = createGamePayload('hangman', gameState);
|
|
161
160
|
let displayText = `## Hangman Game\n\n${formatHangmanPayload(payload)}`;
|
|
162
|
-
|
|
161
|
+
|
|
163
162
|
if (gameState.gameOver) {
|
|
164
163
|
displayText += `\n\nUse \`vibe solo-game hangman --action new\` to start a new game`;
|
|
165
164
|
} else {
|
|
166
165
|
displayText += `\n\nUse \`vibe solo-game hangman --guess X\` to guess a letter`;
|
|
167
166
|
}
|
|
168
|
-
|
|
167
|
+
|
|
169
168
|
return { display: displayText };
|
|
170
169
|
}
|
|
171
170
|
|
|
@@ -178,19 +177,19 @@ async function handler(args) {
|
|
|
178
177
|
if (action === 'guess' || guess) {
|
|
179
178
|
// Make a guess
|
|
180
179
|
const guessLetter = guess || action;
|
|
181
|
-
|
|
180
|
+
|
|
182
181
|
if (!guessLetter) {
|
|
183
182
|
return { display: 'Please specify a letter to guess: `vibe solo-game hangman --guess a`' };
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
const result = hangman.makeGuess(gameState, guessLetter);
|
|
187
|
-
|
|
186
|
+
|
|
188
187
|
if (result.error) {
|
|
189
188
|
return { display: `Error: ${result.error}` };
|
|
190
189
|
}
|
|
191
190
|
|
|
192
191
|
const newGameState = result.gameState;
|
|
193
|
-
|
|
192
|
+
|
|
194
193
|
// Save updated state
|
|
195
194
|
let message = `Guessed "${guessLetter.toUpperCase()}"`;
|
|
196
195
|
if (newGameState.gameOver) {
|
|
@@ -202,18 +201,18 @@ async function handler(args) {
|
|
|
202
201
|
message += ' - Game over! 💀';
|
|
203
202
|
}
|
|
204
203
|
}
|
|
205
|
-
|
|
204
|
+
|
|
206
205
|
await saveGameState(myHandle, 'hangman', newGameState, message);
|
|
207
|
-
|
|
206
|
+
|
|
208
207
|
const payload = createGamePayload('hangman', newGameState);
|
|
209
208
|
let displayText = `## Hangman Game\n\n${formatHangmanPayload(payload)}`;
|
|
210
|
-
|
|
209
|
+
|
|
211
210
|
if (newGameState.gameOver) {
|
|
212
211
|
displayText += `\n\nUse \`vibe solo-game hangman --action new\` to start a new game`;
|
|
213
212
|
} else {
|
|
214
213
|
displayText += `\n\nUse \`vibe solo-game hangman --guess X\` to guess another letter`;
|
|
215
214
|
}
|
|
216
|
-
|
|
215
|
+
|
|
217
216
|
return { display: displayText };
|
|
218
217
|
}
|
|
219
218
|
|
|
@@ -229,9 +228,9 @@ async function handler(args) {
|
|
|
229
228
|
// Start new game
|
|
230
229
|
const gameBestOf = bestof || 1;
|
|
231
230
|
gameState = rps.createInitialRPSState(gameBestOf);
|
|
232
|
-
|
|
231
|
+
|
|
233
232
|
await saveGameState(myHandle, 'rps', gameState, `Started new Rock Paper Scissors game (best of ${gameBestOf})!`);
|
|
234
|
-
|
|
233
|
+
|
|
235
234
|
const payload = createGamePayload('rps', gameState);
|
|
236
235
|
return {
|
|
237
236
|
display: `## New Rock Paper Scissors Game${gameBestOf > 1 ? ` (Best of ${gameBestOf})` : ''}\n\n${formatRPSPayload(payload)}\n\nUse \`vibe solo-game rps --move rock\` (or paper/scissors) to play`
|
|
@@ -242,53 +241,57 @@ async function handler(args) {
|
|
|
242
241
|
// Show current game state
|
|
243
242
|
const payload = createGamePayload('rps', gameState);
|
|
244
243
|
let displayText = `## Rock Paper Scissors${gameState.bestOf > 1 ? ` (Best of ${gameState.bestOf})` : ''}\n\n${formatRPSPayload(payload)}`;
|
|
245
|
-
|
|
244
|
+
|
|
246
245
|
if (gameState.gameOver) {
|
|
247
246
|
displayText += `\n\nUse \`vibe solo-game rps --action new\` to start a new game`;
|
|
248
247
|
} else {
|
|
249
248
|
displayText += `\n\nUse \`vibe solo-game rps --move rock\` (or paper/scissors) to make your move`;
|
|
250
249
|
}
|
|
251
|
-
|
|
250
|
+
|
|
252
251
|
return { display: displayText };
|
|
253
252
|
}
|
|
254
253
|
|
|
255
254
|
// Handle moves (rock, paper, scissors can be action or move parameter)
|
|
256
255
|
const playerMove = move || action;
|
|
257
256
|
if (playerMove && ['rock', 'paper', 'scissors'].includes(playerMove.toLowerCase())) {
|
|
258
|
-
|
|
259
257
|
const result = rps.makeMove(gameState, playerMove);
|
|
260
|
-
|
|
258
|
+
|
|
261
259
|
if (result.error) {
|
|
262
260
|
return { display: `Error: ${result.error}` };
|
|
263
261
|
}
|
|
264
262
|
|
|
265
263
|
const newGameState = result.gameState;
|
|
266
|
-
|
|
264
|
+
|
|
267
265
|
// Save updated state
|
|
268
266
|
let message = `Played ${playerMove}`;
|
|
269
267
|
if (newGameState.gameOver) {
|
|
270
268
|
if (newGameState.winner === 'player') {
|
|
271
269
|
message += ' - You won the game! 🎉';
|
|
272
270
|
// Post to board for wins
|
|
273
|
-
postSoloGameResult(
|
|
271
|
+
postSoloGameResult(
|
|
272
|
+
myHandle,
|
|
273
|
+
'Rock Paper Scissors',
|
|
274
|
+
true,
|
|
275
|
+
`${newGameState.playerScore}-${newGameState.opponentScore}`
|
|
276
|
+
);
|
|
274
277
|
} else {
|
|
275
278
|
message += ' - You lost the game! 💀';
|
|
276
279
|
}
|
|
277
280
|
} else {
|
|
278
281
|
message += ` vs ${newGameState.lastRound.opponentChoice}`;
|
|
279
282
|
}
|
|
280
|
-
|
|
283
|
+
|
|
281
284
|
await saveGameState(myHandle, 'rps', newGameState, message);
|
|
282
|
-
|
|
285
|
+
|
|
283
286
|
const payload = createGamePayload('rps', newGameState);
|
|
284
287
|
let displayText = `## Rock Paper Scissors${newGameState.bestOf > 1 ? ` (Best of ${newGameState.bestOf})` : ''}\n\n${formatRPSPayload(payload)}`;
|
|
285
|
-
|
|
288
|
+
|
|
286
289
|
if (newGameState.gameOver) {
|
|
287
290
|
displayText += `\n\nUse \`vibe solo-game rps --action new\` to start a new game`;
|
|
288
291
|
} else {
|
|
289
292
|
displayText += `\n\nUse \`vibe solo-game rps --move rock\` (or paper/scissors) for the next round`;
|
|
290
293
|
}
|
|
291
|
-
|
|
294
|
+
|
|
292
295
|
return { display: displayText };
|
|
293
296
|
}
|
|
294
297
|
|
|
@@ -304,9 +307,9 @@ async function handler(args) {
|
|
|
304
307
|
// Start new game
|
|
305
308
|
const gameDifficulty = difficulty || 'medium';
|
|
306
309
|
gameState = memory.createInitialMemoryState(gameDifficulty);
|
|
307
|
-
|
|
310
|
+
|
|
308
311
|
await saveGameState(myHandle, 'memory', gameState, `Started new ${gameDifficulty} memory pattern game!`);
|
|
309
|
-
|
|
312
|
+
|
|
310
313
|
const payload = createGamePayload('memory', gameState);
|
|
311
314
|
return {
|
|
312
315
|
display: `## New Memory Pattern Game (${gameDifficulty})\n\n${formatMemoryPayload(payload)}`
|
|
@@ -317,26 +320,26 @@ async function handler(args) {
|
|
|
317
320
|
// Show current game state
|
|
318
321
|
const payload = createGamePayload('memory', gameState);
|
|
319
322
|
let displayText = `## Memory Pattern Game\n\n${formatMemoryPayload(payload)}`;
|
|
320
|
-
|
|
323
|
+
|
|
321
324
|
if (gameState.gameOver) {
|
|
322
325
|
displayText += `\n\nUse \`vibe solo-game memory --action new\` to start a new game`;
|
|
323
326
|
}
|
|
324
|
-
|
|
327
|
+
|
|
325
328
|
return { display: displayText };
|
|
326
329
|
}
|
|
327
330
|
|
|
328
331
|
if (action === 'input') {
|
|
329
332
|
// Start input phase
|
|
330
333
|
const result = memory.startInput(gameState);
|
|
331
|
-
|
|
334
|
+
|
|
332
335
|
if (result.error) {
|
|
333
336
|
return { display: `Error: ${result.error}` };
|
|
334
337
|
}
|
|
335
338
|
|
|
336
339
|
const newGameState = result.gameState;
|
|
337
|
-
|
|
340
|
+
|
|
338
341
|
await saveGameState(myHandle, 'memory', newGameState, 'Ready for input!');
|
|
339
|
-
|
|
342
|
+
|
|
340
343
|
const payload = createGamePayload('memory', newGameState);
|
|
341
344
|
return {
|
|
342
345
|
display: `## Memory Pattern Game\n\n${formatMemoryPayload(payload)}`
|
|
@@ -346,20 +349,25 @@ async function handler(args) {
|
|
|
346
349
|
if (pattern) {
|
|
347
350
|
// Submit pattern guess
|
|
348
351
|
const result = memory.submitPattern(gameState, pattern);
|
|
349
|
-
|
|
352
|
+
|
|
350
353
|
if (result.error) {
|
|
351
354
|
return { display: `Error: ${result.error}` };
|
|
352
355
|
}
|
|
353
356
|
|
|
354
357
|
const newGameState = result.gameState;
|
|
355
|
-
|
|
358
|
+
|
|
356
359
|
// Save updated state
|
|
357
360
|
let message = `Submitted pattern: ${pattern}`;
|
|
358
361
|
if (newGameState.gameOver) {
|
|
359
362
|
if (newGameState.won) {
|
|
360
363
|
message += ' - You won! 🎉';
|
|
361
364
|
// Post to board for wins
|
|
362
|
-
postSoloGameResult(
|
|
365
|
+
postSoloGameResult(
|
|
366
|
+
myHandle,
|
|
367
|
+
'Memory Pattern',
|
|
368
|
+
true,
|
|
369
|
+
`Level ${newGameState.maxLevelReached}, Score ${newGameState.score}`
|
|
370
|
+
);
|
|
363
371
|
} else {
|
|
364
372
|
message += ' - Game over! 🧠';
|
|
365
373
|
}
|
|
@@ -368,16 +376,16 @@ async function handler(args) {
|
|
|
368
376
|
} else if (newGameState.lastResult === 'wrong') {
|
|
369
377
|
message += ' - Wrong! Try again!';
|
|
370
378
|
}
|
|
371
|
-
|
|
379
|
+
|
|
372
380
|
await saveGameState(myHandle, 'memory', newGameState, message);
|
|
373
|
-
|
|
381
|
+
|
|
374
382
|
const payload = createGamePayload('memory', newGameState);
|
|
375
383
|
let displayText = `## Memory Pattern Game\n\n${formatMemoryPayload(payload)}`;
|
|
376
|
-
|
|
384
|
+
|
|
377
385
|
if (newGameState.gameOver) {
|
|
378
386
|
displayText += `\n\nUse \`vibe solo-game memory --action new\` to start a new game`;
|
|
379
387
|
}
|
|
380
|
-
|
|
388
|
+
|
|
381
389
|
return { display: displayText };
|
|
382
390
|
}
|
|
383
391
|
|
|
@@ -387,4 +395,4 @@ async function handler(args) {
|
|
|
387
395
|
return { display: 'Unknown game. Supported games: hangman, rps, memory' };
|
|
388
396
|
}
|
|
389
397
|
|
|
390
|
-
module.exports = { definition, handler };
|
|
398
|
+
module.exports = { definition, handler };
|
package/tools/start.js
CHANGED
|
@@ -18,7 +18,6 @@ const notify = require('../notify');
|
|
|
18
18
|
const patterns = require('../intelligence/patterns');
|
|
19
19
|
const { actions, formatActions } = require('./_actions');
|
|
20
20
|
const init = require('./init');
|
|
21
|
-
const { gatherWithTimeout } = require('./_work-context');
|
|
22
21
|
|
|
23
22
|
const REPO_DIR = path.join(process.env.HOME, '.vibe', 'vibe-repo');
|
|
24
23
|
|
|
@@ -170,7 +169,8 @@ function generateWelcomeCard({ handle, onlineCount, unreadCount, versionInfo })
|
|
|
170
169
|
|
|
171
170
|
const definition = {
|
|
172
171
|
name: 'vibe_start',
|
|
173
|
-
description:
|
|
172
|
+
description:
|
|
173
|
+
'Start socializing on /vibe. Use when user says "let\'s vibe", "start vibing", "who\'s around", or wants to connect with others.',
|
|
174
174
|
inputSchema: {
|
|
175
175
|
type: 'object',
|
|
176
176
|
properties: {
|
|
@@ -180,7 +180,7 @@ const definition = {
|
|
|
180
180
|
},
|
|
181
181
|
building: {
|
|
182
182
|
type: 'string',
|
|
183
|
-
description:
|
|
183
|
+
description: "What you're working on (one line). Only needed if not already initialized."
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
}
|
|
@@ -192,7 +192,7 @@ async function handler(args) {
|
|
|
192
192
|
|
|
193
193
|
// Step 1: Check if properly authenticated with OAuth
|
|
194
194
|
// If not, redirect to init for GitHub auth flow (shows pre-auth banner + OAuth)
|
|
195
|
-
if (!config.
|
|
195
|
+
if (!config.hasPrivyAuth()) {
|
|
196
196
|
return init.handler({
|
|
197
197
|
handle: args.handle,
|
|
198
198
|
one_liner: args.building
|
|
@@ -212,32 +212,6 @@ async function handler(args) {
|
|
|
212
212
|
// Fetch version info early (non-blocking, cached)
|
|
213
213
|
const versionInfo = await getVersionInfo().catch(() => null);
|
|
214
214
|
|
|
215
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
216
|
-
// AMBIENT CONTEXT: Gather work context and auto-set presence
|
|
217
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
218
|
-
let workContext = null;
|
|
219
|
-
const autoContextEnabled = config.get('autoContext', true); // Opt-out via settings
|
|
220
|
-
|
|
221
|
-
if (autoContextEnabled) {
|
|
222
|
-
try {
|
|
223
|
-
// Gather context with timeout (won't block startup)
|
|
224
|
-
workContext = await gatherWithTimeout(2000);
|
|
225
|
-
|
|
226
|
-
// Auto-set presence so others see what we're working on (silent, non-blocking)
|
|
227
|
-
if (workContext?.suggestions?.brief) {
|
|
228
|
-
// Use store.heartbeat directly instead of importing context tool
|
|
229
|
-
// This avoids circular dependencies and is simpler
|
|
230
|
-
store.heartbeat(myHandle, config.getOneLiner(), {
|
|
231
|
-
note: workContext.suggestions.brief,
|
|
232
|
-
branch: workContext.git?.branch || null
|
|
233
|
-
}).catch(() => {}); // Silent fail - don't block
|
|
234
|
-
}
|
|
235
|
-
} catch (e) {
|
|
236
|
-
// Silent fail - context is nice-to-have, not required
|
|
237
|
-
workContext = null;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
215
|
// Log session start for patterns
|
|
242
216
|
patterns.logSessionStart(myHandle);
|
|
243
217
|
|
|
@@ -252,12 +226,8 @@ async function handler(args) {
|
|
|
252
226
|
|
|
253
227
|
// Step 3: Check inbox + trigger notifications
|
|
254
228
|
let unreadCount = 0;
|
|
255
|
-
let inboxThreads = [];
|
|
256
229
|
try {
|
|
257
|
-
|
|
258
|
-
inboxThreads = await store.getInbox(myHandle);
|
|
259
|
-
unreadCount = inboxThreads.reduce((sum, t) => sum + (t.unread || 0), 0);
|
|
260
|
-
|
|
230
|
+
unreadCount = await store.getUnreadCount(myHandle);
|
|
261
231
|
if (unreadCount > 0) {
|
|
262
232
|
// Check for messages needing desktop notification escalation
|
|
263
233
|
const rawInbox = await store.getRawInbox(myHandle).catch(() => []);
|
|
@@ -267,24 +237,6 @@ async function handler(args) {
|
|
|
267
237
|
}
|
|
268
238
|
} catch (e) {}
|
|
269
239
|
|
|
270
|
-
// Step 4: Get connection suggestions from API
|
|
271
|
-
let suggestions = [];
|
|
272
|
-
try {
|
|
273
|
-
const apiUrl = config.getApiUrl();
|
|
274
|
-
const suggestionsResponse = await fetch(`${apiUrl}/api/suggestions?user=${myHandle}&limit=3`, {
|
|
275
|
-
headers: { 'User-Agent': 'vibe-mcp-client' }
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
if (suggestionsResponse.ok) {
|
|
279
|
-
const data = await suggestionsResponse.json();
|
|
280
|
-
if (data.success && data.suggestions) {
|
|
281
|
-
suggestions = data.suggestions;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
} catch (e) {
|
|
285
|
-
// Silent fail - suggestions are nice-to-have
|
|
286
|
-
}
|
|
287
|
-
|
|
288
240
|
// Generate the ASCII welcome card (matches init.js format)
|
|
289
241
|
const welcomeCard = generateWelcomeCard({
|
|
290
242
|
handle: myHandle,
|
|
@@ -296,46 +248,6 @@ async function handler(args) {
|
|
|
296
248
|
// Build display with card + any additional info
|
|
297
249
|
let display = welcomeCard;
|
|
298
250
|
|
|
299
|
-
// Add who's online section (top 5 with what they're building)
|
|
300
|
-
if (others.length > 0) {
|
|
301
|
-
const top5 = others.slice(0, 5);
|
|
302
|
-
display += `\n\n**🟢 Online now:**`;
|
|
303
|
-
top5.forEach(u => {
|
|
304
|
-
const status = u.status ? ` (${u.status})` : '';
|
|
305
|
-
const building = u.one_liner || u.note || '';
|
|
306
|
-
const truncated = building.length > 40 ? building.slice(0, 40) + '...' : building;
|
|
307
|
-
display += `\n• @${u.handle}${status}${truncated ? ' — ' + truncated : ''}`;
|
|
308
|
-
});
|
|
309
|
-
if (others.length > 5) {
|
|
310
|
-
display += `\n• _+${others.length - 5} more..._`;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Add unread messages section (if any)
|
|
315
|
-
if (unreadCount > 0) {
|
|
316
|
-
const unreadSenders = inboxThreads.filter(t => t.unread > 0);
|
|
317
|
-
display += `\n\n**📬 Unread (${unreadCount}):**`;
|
|
318
|
-
unreadSenders.slice(0, 3).forEach(t => {
|
|
319
|
-
const preview = t.lastMessage ? t.lastMessage.slice(0, 50) : '';
|
|
320
|
-
const truncated = preview.length > 50 ? preview + '...' : preview;
|
|
321
|
-
display += `\n• @${t.handle} (${t.unread}) — "${truncated}"`;
|
|
322
|
-
});
|
|
323
|
-
if (unreadSenders.length > 3) {
|
|
324
|
-
display += `\n• _+${unreadSenders.length - 3} more threads..._`;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Add connection suggestions (if any)
|
|
329
|
-
if (suggestions.length > 0) {
|
|
330
|
-
display += `\n\n**🤝 Suggested connections:**`;
|
|
331
|
-
suggestions.slice(0, 3).forEach(s => {
|
|
332
|
-
display += `\n• @${s.handle} — ${s.reason}`;
|
|
333
|
-
if (s.github_name) {
|
|
334
|
-
display += ` (${s.github_name})`;
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
|
|
339
251
|
// Add memory context for returning users
|
|
340
252
|
if (threads.length > 0) {
|
|
341
253
|
const recentThreads = threads.slice(0, 3);
|
|
@@ -348,48 +260,17 @@ async function handler(args) {
|
|
|
348
260
|
display += updateNotice;
|
|
349
261
|
}
|
|
350
262
|
|
|
351
|
-
// Step 6:
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const tipIndex = Math.floor(Date.now() / 60000) % tips.length; // Rotate every minute
|
|
359
|
-
display += `\n\n---\n${tips[tipIndex]}`;
|
|
263
|
+
// Step 6: Suggest background presence monitor (if not running)
|
|
264
|
+
const presenceAgentEnabled = config.get('presenceAgentEnabled', true);
|
|
265
|
+
const presenceAgentRunning = config.get('presenceAgentRunning');
|
|
266
|
+
|
|
267
|
+
if (presenceAgentEnabled && !presenceAgentRunning && others.length > 0) {
|
|
268
|
+
display += `\n\n---\n💡 **Tip:** Say "start presence monitor" for real-time alerts when interesting people come online.`;
|
|
269
|
+
}
|
|
360
270
|
|
|
361
271
|
// Build response with hints for structured dashboard flow
|
|
362
272
|
const response = { display };
|
|
363
273
|
|
|
364
|
-
// === ENRICHED DATA ===
|
|
365
|
-
// Include full online users list so Claude doesn't need to call vibe_who
|
|
366
|
-
response.onlineUsers = others.map(u => ({
|
|
367
|
-
handle: u.handle,
|
|
368
|
-
building: u.one_liner || u.note || null,
|
|
369
|
-
status: u.status || null,
|
|
370
|
-
lastActive: u.lastSeen ? new Date(u.lastSeen).toISOString() : null
|
|
371
|
-
}));
|
|
372
|
-
|
|
373
|
-
// Include unread thread summaries so Claude doesn't need to call vibe_inbox
|
|
374
|
-
const unreadSenders = inboxThreads.filter(t => t.unread > 0);
|
|
375
|
-
response.unreadThreads = unreadSenders.map(t => ({
|
|
376
|
-
handle: t.handle,
|
|
377
|
-
unread: t.unread,
|
|
378
|
-
preview: t.lastMessage ? t.lastMessage.slice(0, 80) : null,
|
|
379
|
-
isAgent: t.isAgent || false
|
|
380
|
-
}));
|
|
381
|
-
|
|
382
|
-
// Include connection suggestions for smart discovery
|
|
383
|
-
if (suggestions.length > 0) {
|
|
384
|
-
response.suggestions = suggestions.map(s => ({
|
|
385
|
-
handle: s.handle,
|
|
386
|
-
reason: s.reason,
|
|
387
|
-
githubName: s.github_name || null,
|
|
388
|
-
lastActive: s.last_active || null,
|
|
389
|
-
matchScore: s.score || null
|
|
390
|
-
}));
|
|
391
|
-
}
|
|
392
|
-
|
|
393
274
|
// Determine session state and suggest appropriate flow
|
|
394
275
|
let suggestion = null;
|
|
395
276
|
|
|
@@ -424,33 +305,18 @@ async function handler(args) {
|
|
|
424
305
|
|
|
425
306
|
if (others.length === 0 && unreadCount === 0) {
|
|
426
307
|
// Empty room
|
|
427
|
-
actionList = actions.emptyRoom(
|
|
308
|
+
actionList = actions.emptyRoom();
|
|
428
309
|
} else {
|
|
429
310
|
// Normal dashboard
|
|
430
311
|
actionList = actions.dashboard({
|
|
431
312
|
unreadCount,
|
|
432
313
|
onlineUsers: onlineHandles,
|
|
433
|
-
suggestion
|
|
434
|
-
workContext
|
|
314
|
+
suggestion
|
|
435
315
|
});
|
|
436
316
|
}
|
|
437
317
|
|
|
438
318
|
response.actions = formatActions(actionList);
|
|
439
319
|
|
|
440
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
441
|
-
// WORK CONTEXT: Include in response for Claude to use
|
|
442
|
-
// ═══════════════════════════════════════════════════════════════════════
|
|
443
|
-
if (workContext?.suggestions?.brief) {
|
|
444
|
-
response.workContext = {
|
|
445
|
-
summary: workContext.suggestions.brief,
|
|
446
|
-
detailed: workContext.suggestions.detailed,
|
|
447
|
-
project: workContext.project?.name,
|
|
448
|
-
branch: workContext.git?.branch,
|
|
449
|
-
recentCommit: workContext.git?.recentCommits?.[0]?.message || null,
|
|
450
|
-
hasUncommitted: workContext.git?.hasUncommitted || false
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
|
|
454
320
|
return response;
|
|
455
321
|
}
|
|
456
322
|
|
package/tools/status.js
CHANGED
|
@@ -1,27 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vibe status — Set your mood/status
|
|
3
|
-
*
|
|
4
|
-
* Now includes away/back functionality (previously vibe_away/vibe_back)
|
|
5
3
|
*/
|
|
6
4
|
|
|
5
|
+
const { requireInit } = require('./_shared');
|
|
7
6
|
const config = require('../config');
|
|
8
7
|
const store = require('../store');
|
|
9
8
|
const discord = require('../discord');
|
|
10
9
|
const { trackMood } = require('./summarize');
|
|
11
|
-
const { markAway, markBack, getProactiveSummary } = require('../intelligence/proactive');
|
|
12
10
|
|
|
13
11
|
const MOODS = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
'back': null, // Merged from vibe_back (clears status)
|
|
24
|
-
'clear': null
|
|
12
|
+
shipping: '🔥',
|
|
13
|
+
thinking: '🧠',
|
|
14
|
+
afk: '☕',
|
|
15
|
+
debugging: '🐛',
|
|
16
|
+
pairing: '👯',
|
|
17
|
+
deep: '🎧',
|
|
18
|
+
celebrating: '🎉',
|
|
19
|
+
struggling: '😤',
|
|
20
|
+
clear: null
|
|
25
21
|
};
|
|
26
22
|
|
|
27
23
|
// Special modes that toggle settings
|
|
@@ -29,17 +25,14 @@ const SPECIAL_MODES = ['guided', 'freeform'];
|
|
|
29
25
|
|
|
30
26
|
const definition = {
|
|
31
27
|
name: 'vibe_status',
|
|
32
|
-
description:
|
|
28
|
+
description:
|
|
29
|
+
'Set your mood/status. Options: shipping, thinking, afk, debugging, pairing, deep, celebrating, struggling, clear',
|
|
33
30
|
inputSchema: {
|
|
34
31
|
type: 'object',
|
|
35
32
|
properties: {
|
|
36
33
|
mood: {
|
|
37
34
|
type: 'string',
|
|
38
|
-
description: 'Your mood (shipping, thinking, afk, debugging, pairing, deep, celebrating, struggling,
|
|
39
|
-
},
|
|
40
|
-
message: {
|
|
41
|
-
type: 'string',
|
|
42
|
-
description: 'Optional away message (only used with away mood, e.g., "grabbing coffee")'
|
|
35
|
+
description: 'Your mood (shipping, thinking, afk, debugging, pairing, deep, celebrating, struggling, clear)'
|
|
43
36
|
}
|
|
44
37
|
},
|
|
45
38
|
required: ['mood']
|
|
@@ -47,15 +40,11 @@ const definition = {
|
|
|
47
40
|
};
|
|
48
41
|
|
|
49
42
|
async function handler(args) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
display: 'Run `vibe init` first to set your identity.'
|
|
53
|
-
};
|
|
54
|
-
}
|
|
43
|
+
const initCheck = requireInit();
|
|
44
|
+
if (initCheck) return initCheck;
|
|
55
45
|
|
|
56
|
-
const { mood
|
|
46
|
+
const { mood } = args;
|
|
57
47
|
const moodKey = mood.toLowerCase().replace(/[^a-z]/g, '');
|
|
58
|
-
const handle = config.getHandle();
|
|
59
48
|
|
|
60
49
|
// Handle special modes (guided/freeform)
|
|
61
50
|
if (moodKey === 'guided') {
|
|
@@ -82,58 +71,22 @@ _Say "set status guided" to re-enable interactive menus._`
|
|
|
82
71
|
};
|
|
83
72
|
}
|
|
84
73
|
|
|
85
|
-
// Handle 'away' mood (merged from vibe_away)
|
|
86
|
-
if (moodKey === 'away') {
|
|
87
|
-
const awayMessage = message?.trim();
|
|
88
|
-
|
|
89
|
-
// Validate message length
|
|
90
|
-
if (awayMessage && awayMessage.length > 100) {
|
|
91
|
-
return { display: '⚠️ Away message too long (100 char max)' };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Set away status with optional message
|
|
95
|
-
await store.setAwayStatus(handle, 'away', awayMessage || null);
|
|
96
|
-
markAway();
|
|
97
|
-
|
|
98
|
-
if (awayMessage) {
|
|
99
|
-
return { display: `☕ away — "${awayMessage}"` };
|
|
100
|
-
}
|
|
101
|
-
return { display: '☕ away' };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Handle 'back' mood (merged from vibe_back)
|
|
105
|
-
if (moodKey === 'back') {
|
|
106
|
-
// Clear away status
|
|
107
|
-
await store.clearAwayStatus(handle);
|
|
108
|
-
|
|
109
|
-
let display = '👋 back';
|
|
110
|
-
|
|
111
|
-
// Check if anything happened while away
|
|
112
|
-
const unreadCount = await store.getUnreadCount(handle).catch(() => 0);
|
|
113
|
-
if (unreadCount > 0) {
|
|
114
|
-
display += ` — ${unreadCount} unread`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Mark as back for proactive tracking
|
|
118
|
-
markBack();
|
|
119
|
-
|
|
120
|
-
return { display };
|
|
121
|
-
}
|
|
122
|
-
|
|
123
74
|
if (!MOODS.hasOwnProperty(moodKey)) {
|
|
124
75
|
const options = Object.entries(MOODS)
|
|
125
|
-
.filter(([k, v]) => v
|
|
76
|
+
.filter(([k, v]) => v)
|
|
126
77
|
.map(([k, v]) => `${v} ${k}`)
|
|
127
78
|
.join(', ');
|
|
128
79
|
return {
|
|
129
|
-
display: `Unknown mood. Options: ${options}, or "clear"
|
|
80
|
+
display: `Unknown mood. Options: ${options}, or "clear" to remove`
|
|
130
81
|
};
|
|
131
82
|
}
|
|
132
83
|
|
|
133
84
|
const emoji = MOODS[moodKey];
|
|
85
|
+
const handle = config.getHandle();
|
|
134
86
|
|
|
135
87
|
// Update presence with mood via context
|
|
136
|
-
|
|
88
|
+
// Phase 1 Presence Bridge: include source so platform knows this came from MCP
|
|
89
|
+
await store.heartbeat(handle, config.getOneLiner(), { mood: emoji }, 'mcp');
|
|
137
90
|
|
|
138
91
|
// Track for session summary
|
|
139
92
|
if (emoji) {
|