slashvibe-mcp 0.3.21 → 0.3.23
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/auto-update.js +10 -15
- package/config.js +36 -31
- package/crypto.js +1 -6
- package/debug.js +12 -0
- package/discord.js +19 -19
- package/eslint.config.js +54 -0
- 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/migrate-v2.js +72 -0
- package/notification-emitter.js +2 -2
- package/notify.js +39 -14
- package/package.json +28 -29
- package/post-install.js +141 -0
- 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/test-skills-bootstrap.js +20 -0
- package/test-v2-integration.js +385 -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/webhook-runner.js +132 -0
- package/auth-store.js +0 -148
- 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/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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tic-Tac-Toe tool - Play against AI with different difficulty levels
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Usage:
|
|
5
5
|
* vibe tictactoe --difficulty easy (start new game)
|
|
6
6
|
* vibe tictactoe --move 5 (make move)
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
const config = require('../config');
|
|
11
11
|
const store = require('../store');
|
|
12
|
-
const {
|
|
13
|
-
createInitialTicTacToeState,
|
|
14
|
-
makeMove,
|
|
15
|
-
makeAIMove,
|
|
12
|
+
const {
|
|
13
|
+
createInitialTicTacToeState,
|
|
14
|
+
makeMove,
|
|
15
|
+
makeAIMove,
|
|
16
16
|
formatTicTacToeDisplay,
|
|
17
17
|
getDifficultyDescription
|
|
18
18
|
} = require('../games/tictactoe');
|
|
@@ -50,90 +50,90 @@ async function handler(args) {
|
|
|
50
50
|
|
|
51
51
|
const { difficulty, move, reset } = args;
|
|
52
52
|
const myHandle = config.getHandle();
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
// Get or create game state from memory
|
|
55
55
|
let gameState = await store.getMemory(myHandle, 'tictactoe_game');
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
// Start new game if requested, no game exists, or game is over
|
|
58
58
|
if (reset || !gameState || gameState.gameOver) {
|
|
59
59
|
const newDifficulty = difficulty || 'medium';
|
|
60
60
|
gameState = createInitialTicTacToeState(newDifficulty);
|
|
61
61
|
await store.setMemory(myHandle, 'tictactoe_game', gameState);
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
return {
|
|
64
64
|
display: `🎯 **New Tic-Tac-Toe Game Started!**\n\n${getDifficultyDescription(newDifficulty)}\n\n${formatTicTacToeDisplay(gameState)}\n\n💡 Use \`vibe tictactoe --move N\` to play position 1-9`
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
// Show current game if no move specified
|
|
69
69
|
if (move === undefined) {
|
|
70
70
|
let display = `🎯 **Current Tic-Tac-Toe Game**\n\n${formatTicTacToeDisplay(gameState)}`;
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
if (gameState.gameOver) {
|
|
73
73
|
display += `\n\n💡 Use \`vibe tictactoe --reset\` to start a new game`;
|
|
74
74
|
display += `\n💡 Use \`vibe tictactoe --difficulty hard\` to start with different difficulty`;
|
|
75
75
|
} else {
|
|
76
76
|
display += `\n\n💡 Use \`vibe tictactoe --move N\` to play position 1-9`;
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
return { display };
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
// Check if game is over
|
|
83
83
|
if (gameState.gameOver) {
|
|
84
84
|
return {
|
|
85
85
|
display: `🎯 **Game Over!**\n\n${formatTicTacToeDisplay(gameState)}\n\n💡 Use \`vibe tictactoe --reset\` to start a new game`
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
// Check if it's player's turn
|
|
90
90
|
if (gameState.turn !== gameState.playerSymbol) {
|
|
91
91
|
return {
|
|
92
92
|
display: `⏳ **Not your turn!**\n\n${formatTicTacToeDisplay(gameState)}\n\nWait for AI to move.`
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
// Make player move
|
|
97
97
|
const playerMoveResult = makeMove(gameState, move, gameState.playerSymbol);
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
if (playerMoveResult.error) {
|
|
100
100
|
return {
|
|
101
101
|
display: `❌ **Invalid move:** ${playerMoveResult.error}\n\n${formatTicTacToeDisplay(gameState)}\n\n💡 Choose an empty position (1-9)`
|
|
102
102
|
};
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
gameState = playerMoveResult.gameState;
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
// Check if game ended after player move
|
|
108
108
|
if (gameState.gameOver) {
|
|
109
109
|
await store.setMemory(myHandle, 'tictactoe_game', gameState);
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
let endMessage = '';
|
|
112
112
|
if (gameState.winner === gameState.playerSymbol) {
|
|
113
113
|
endMessage = `🎉 **Congratulations! You won!**`;
|
|
114
114
|
} else if (gameState.isDraw) {
|
|
115
115
|
endMessage = `🤝 **It's a draw!** Well played!`;
|
|
116
116
|
}
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
return {
|
|
119
119
|
display: `${endMessage}\n\n${formatTicTacToeDisplay(gameState)}\n\n💡 Use \`vibe tictactoe --reset\` to start a new game`
|
|
120
120
|
};
|
|
121
121
|
}
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
// Make AI move
|
|
124
124
|
const aiMoveResult = makeAIMove(gameState);
|
|
125
|
-
|
|
125
|
+
|
|
126
126
|
if (aiMoveResult.error) {
|
|
127
127
|
return {
|
|
128
128
|
display: `🤖 **AI Error:** ${aiMoveResult.error}\n\n${formatTicTacToeDisplay(gameState)}`
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
gameState = aiMoveResult.gameState;
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
// Save game state
|
|
135
135
|
await store.setMemory(myHandle, 'tictactoe_game', gameState);
|
|
136
|
-
|
|
136
|
+
|
|
137
137
|
// Check if game ended after AI move
|
|
138
138
|
let endMessage = '';
|
|
139
139
|
if (gameState.gameOver) {
|
|
@@ -146,10 +146,10 @@ async function handler(args) {
|
|
|
146
146
|
} else {
|
|
147
147
|
endMessage = `💡 Your turn! Use \`vibe tictactoe --move N\` to play position 1-9`;
|
|
148
148
|
}
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
return {
|
|
151
151
|
display: `🎯 **Move Complete**\n\n${formatTicTacToeDisplay(gameState)}\n\n${endMessage}`
|
|
152
152
|
};
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
module.exports = { definition, handler };
|
|
155
|
+
module.exports = { definition, handler };
|
package/tools/token.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vibe token — Set auth token after
|
|
2
|
+
* vibe token — Set Privy auth token after browser OAuth
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
5
|
* vibe token <paste-token-here>
|
|
@@ -44,7 +44,7 @@ If you haven't authenticated yet:
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Verify token with server
|
|
47
|
-
const verification = await store.
|
|
47
|
+
const verification = await store.verifyPrivyToken(token.trim());
|
|
48
48
|
|
|
49
49
|
if (!verification.valid) {
|
|
50
50
|
return {
|
|
@@ -60,7 +60,7 @@ The token may be expired or invalid. Try authenticating again:
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Save token
|
|
63
|
-
config.
|
|
63
|
+
config.savePrivyToken(token.trim());
|
|
64
64
|
|
|
65
65
|
// Update session identity with verified handle
|
|
66
66
|
const handle = verification.handle;
|
|
@@ -96,7 +96,7 @@ You're ready to vibe! Try:
|
|
|
96
96
|
• \`vibe dm @someone "hello"\` — Send a message`,
|
|
97
97
|
handle,
|
|
98
98
|
github: verification.github,
|
|
99
|
-
authMethod: '
|
|
99
|
+
authMethod: 'privy'
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
|
package/tools/update.js
CHANGED
|
@@ -49,7 +49,7 @@ async function handler(args) {
|
|
|
49
49
|
display += `Your install doesn't support automatic updates.\n\n`;
|
|
50
50
|
display += `To update, re-run the installer:\n`;
|
|
51
51
|
display += `\`\`\`\n`;
|
|
52
|
-
display += `curl -fsSL https://raw.githubusercontent.com/
|
|
52
|
+
display += `curl -fsSL https://raw.githubusercontent.com/brightseth/vibe/main/install.sh | bash\n`;
|
|
53
53
|
display += `\`\`\`\n\n`;
|
|
54
54
|
display += `This will migrate you to the git-based installer for future updates.\n\n`;
|
|
55
55
|
display += `---\n`;
|
|
@@ -87,7 +87,6 @@ async function handler(args) {
|
|
|
87
87
|
|
|
88
88
|
display += `---\n`;
|
|
89
89
|
display += `⚠️ **Restart Claude Code to apply changes**`;
|
|
90
|
-
|
|
91
90
|
} catch (e) {
|
|
92
91
|
display += `❌ **Update failed**\n\n`;
|
|
93
92
|
display += `Error: ${e.message}\n\n`;
|
package/tools/watch.js
CHANGED
|
@@ -1,157 +1,177 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vibe watch — Watch live
|
|
2
|
+
* vibe watch/live — Watch broadcasts and see who's live
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Commands:
|
|
7
|
-
* - watch → List active broadcasts
|
|
8
|
-
* - watch @handle → Watch specific person's broadcast
|
|
9
|
-
* - watch room_xxx → Watch by room ID
|
|
4
|
+
* vibe_watch: Watch a specific user's broadcast
|
|
5
|
+
* vibe_live: List all active broadcasts with viewer counts
|
|
10
6
|
*/
|
|
11
7
|
|
|
8
|
+
const { requireInit, normalizeHandle, formatTimeAgo } = require('./_shared');
|
|
12
9
|
const config = require('../config');
|
|
10
|
+
const store = require('../store');
|
|
13
11
|
|
|
14
|
-
const
|
|
12
|
+
const watchDefinition = {
|
|
15
13
|
name: 'vibe_watch',
|
|
16
|
-
description:
|
|
14
|
+
description: "Check if someone is broadcasting live and get their stream info. If they're live, returns a watch link and engagement stats.",
|
|
17
15
|
inputSchema: {
|
|
18
16
|
type: 'object',
|
|
19
17
|
properties: {
|
|
20
|
-
|
|
18
|
+
handle: {
|
|
21
19
|
type: 'string',
|
|
22
|
-
description: '
|
|
20
|
+
description: 'Who to watch (e.g., @stan)'
|
|
23
21
|
}
|
|
24
|
-
}
|
|
22
|
+
},
|
|
23
|
+
required: ['handle']
|
|
25
24
|
}
|
|
26
25
|
};
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
headers: { 'Accept': 'application/json' }
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const data = await response.json();
|
|
27
|
+
const liveDefinition = {
|
|
28
|
+
name: 'vibe_live',
|
|
29
|
+
description: 'List all active broadcasts with viewer counts. See who is live right now.',
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: {}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
async function watchHandler(args) {
|
|
37
|
+
const initCheck = requireInit();
|
|
38
|
+
if (initCheck) return initCheck;
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
let display = `📺 **No Live Broadcasts**\n\n`;
|
|
47
|
-
display += `_No one is streaming right now._\n\n`;
|
|
48
|
-
display += `**Start your own:**\n`;
|
|
49
|
-
display += `\`vibe broadcast start "What you're building"\`\n\n`;
|
|
50
|
-
display += `**Browse saved sessions:**\n`;
|
|
51
|
-
display += `\`vibe session list\``;
|
|
52
|
-
return { display };
|
|
53
|
-
}
|
|
40
|
+
const them = normalizeHandle(args.handle);
|
|
54
41
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (secs < 3600) return `${Math.floor(secs / 60)}m`;
|
|
58
|
-
return `${Math.floor(secs / 3600)}h ${Math.floor((secs % 3600) / 60)}m`;
|
|
59
|
-
};
|
|
42
|
+
// Get all live broadcasts and find this user
|
|
43
|
+
const result = await store.getLiveBroadcasts();
|
|
60
44
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const viewers = b.viewers || 0;
|
|
65
|
-
const duration = formatDuration(b.duration || 0);
|
|
45
|
+
if (result.success === false) {
|
|
46
|
+
return { display: `Failed to check live status: ${result.error || 'Unknown error'}` };
|
|
47
|
+
}
|
|
66
48
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
display += ` — ${viewers} watching`;
|
|
70
|
-
}
|
|
71
|
-
display += ` — ${duration}\n`;
|
|
72
|
-
display += ` → \`vibe watch ${b.roomId}\`\n\n`;
|
|
73
|
-
}
|
|
49
|
+
const broadcasts = result.broadcasts || [];
|
|
50
|
+
const broadcast = broadcasts.find(b => b.handle === them);
|
|
74
51
|
|
|
75
|
-
|
|
52
|
+
if (!broadcast) {
|
|
53
|
+
// Not live — check if they have an upcoming session
|
|
54
|
+
const upcoming = (result.upcoming || []).find(u => u.handle === them);
|
|
76
55
|
|
|
77
|
-
|
|
56
|
+
let display = `**@${them}** is not broadcasting right now.`;
|
|
78
57
|
|
|
79
|
-
|
|
80
|
-
|
|
58
|
+
if (upcoming) {
|
|
59
|
+
const when = new Date(upcoming.scheduledFor);
|
|
60
|
+
const rsvp = upcoming.rsvpCount || 0;
|
|
61
|
+
display += `\n\nNext scheduled session: **${upcoming.title || 'Untitled'}**`;
|
|
62
|
+
display += `\nWhen: ${when.toLocaleString()}`;
|
|
63
|
+
if (rsvp > 0) display += ` (${rsvp} RSVPs)`;
|
|
81
64
|
}
|
|
82
|
-
}
|
|
83
65
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
66
|
+
display += `\n\nTry \`vibe live\` to see who's broadcasting now.`;
|
|
67
|
+
return { display };
|
|
68
|
+
}
|
|
87
69
|
|
|
70
|
+
// They're live — get metrics for richer display
|
|
71
|
+
let metrics = null;
|
|
88
72
|
try {
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
metrics = await store.getBroadcastMetrics(broadcast.roomId);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
// Metrics are best-effort
|
|
76
|
+
}
|
|
91
77
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
78
|
+
const duration = broadcast.duration || 0;
|
|
79
|
+
const durationMin = Math.floor(duration / 60);
|
|
80
|
+
const viewers = broadcast.viewers || broadcast.viewerCount || 0;
|
|
81
|
+
const watchUrl = `https://slashvibe.dev/watch/${broadcast.roomId}`;
|
|
95
82
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
83
|
+
let display = `## @${them} is LIVE\n\n`;
|
|
84
|
+
display += `**Watch:** ${watchUrl}\n\n`;
|
|
85
|
+
display += `Viewers: **${viewers}**`;
|
|
86
|
+
if (durationMin > 0) {
|
|
87
|
+
display += ` | Duration: ${durationMin}m`;
|
|
88
|
+
}
|
|
100
89
|
|
|
101
|
-
|
|
90
|
+
// Add engagement metrics if available
|
|
91
|
+
if (metrics && metrics.success !== false) {
|
|
92
|
+
const engagement = metrics.engagement || {};
|
|
93
|
+
const chat = metrics.chat || {};
|
|
94
|
+
const reactions = metrics.reactions || {};
|
|
102
95
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
96
|
+
if (engagement.score) {
|
|
97
|
+
display += ` | Engagement: ${engagement.score}/100`;
|
|
98
|
+
}
|
|
99
|
+
if (chat.total > 0) {
|
|
100
|
+
display += `\nChat: ${chat.total} messages`;
|
|
101
|
+
}
|
|
102
|
+
if (reactions.total > 0) {
|
|
103
|
+
display += `\nReactions: ${reactions.total}`;
|
|
104
|
+
// Show top reactions
|
|
105
|
+
const breakdown = reactions.breakdown || {};
|
|
106
|
+
const topReactions = Object.entries(breakdown)
|
|
107
|
+
.sort(([, a], [, b]) => b - a)
|
|
108
|
+
.slice(0, 3)
|
|
109
|
+
.map(([name, count]) => `${name}: ${count}`)
|
|
110
|
+
.join(', ');
|
|
111
|
+
if (topReactions) display += ` (${topReactions})`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
b => b.handle.toLowerCase() === broadcasterHandle
|
|
109
|
-
);
|
|
115
|
+
display += `\n\nOpen the link above to watch their terminal live.`;
|
|
110
116
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
display: `📺 @${broadcasterHandle} is not live right now.\n\n_Check who's streaming with \`vibe watch\`_`
|
|
114
|
-
};
|
|
115
|
-
}
|
|
117
|
+
return { display };
|
|
118
|
+
}
|
|
116
119
|
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
async function liveHandler() {
|
|
121
|
+
const initCheck = requireInit();
|
|
122
|
+
if (initCheck) return initCheck;
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
const response = await fetch(`${apiUrl}/api/watch?room=${roomId}`);
|
|
122
|
-
const data = await response.json();
|
|
124
|
+
const result = await store.getLiveBroadcasts();
|
|
123
125
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
};
|
|
128
|
-
}
|
|
126
|
+
if (result.success === false) {
|
|
127
|
+
return { display: `Failed to get live broadcasts: ${result.error || 'Unknown error'}` };
|
|
128
|
+
}
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
? Math.round((Date.now() - new Date(broadcast.startedAt).getTime()) / 1000)
|
|
133
|
-
: 0;
|
|
130
|
+
const broadcasts = result.broadcasts || [];
|
|
131
|
+
const upcoming = result.upcoming || [];
|
|
134
132
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return `${Math.floor(secs / 3600)}h ${Math.floor((secs % 3600) / 60)}m`;
|
|
133
|
+
if (broadcasts.length === 0 && upcoming.length === 0) {
|
|
134
|
+
return {
|
|
135
|
+
display: `## Live Now\n\n_No one is broadcasting right now._\n\nStart your own: The terminal app (vibe-terminal) supports broadcasting.\nOr check back later — builders come and go.`
|
|
139
136
|
};
|
|
137
|
+
}
|
|
140
138
|
|
|
141
|
-
|
|
142
|
-
display += `**Duration:** ${formatDuration(duration)}\n`;
|
|
143
|
-
display += `**Viewers:** ${broadcast.viewerCount || 0}\n\n`;
|
|
144
|
-
display += `**Watch in browser:**\n`;
|
|
145
|
-
display += `https://slashvibe.dev/watch/${roomId}\n\n`;
|
|
146
|
-
display += `_Open the URL above to watch the live terminal stream._\n\n`;
|
|
147
|
-
display += `---\n`;
|
|
148
|
-
display += `_Coming soon: inline terminal replay in Claude Code_`;
|
|
139
|
+
let display = `## Live Now\n\n`;
|
|
149
140
|
|
|
150
|
-
|
|
141
|
+
if (broadcasts.length === 0) {
|
|
142
|
+
display += `_No active broadcasts._\n\n`;
|
|
143
|
+
} else {
|
|
144
|
+
for (const b of broadcasts) {
|
|
145
|
+
const viewers = b.viewers || b.viewerCount || 0;
|
|
146
|
+
const durationMin = Math.floor((b.duration || 0) / 60);
|
|
147
|
+
const watchUrl = `https://slashvibe.dev/watch/${b.roomId}`;
|
|
151
148
|
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
display += `**@${b.handle}** — ${viewers} viewer${viewers !== 1 ? 's' : ''}`;
|
|
150
|
+
if (durationMin > 0) display += ` | ${durationMin}m`;
|
|
151
|
+
display += `\n`;
|
|
152
|
+
display += `Watch: ${watchUrl}\n\n`;
|
|
153
|
+
}
|
|
154
154
|
}
|
|
155
|
+
|
|
156
|
+
if (upcoming.length > 0) {
|
|
157
|
+
display += `---\n\n**Upcoming:**\n\n`;
|
|
158
|
+
for (const u of upcoming) {
|
|
159
|
+
const when = new Date(u.scheduledFor);
|
|
160
|
+
const rsvp = u.rsvpCount || 0;
|
|
161
|
+
display += `**@${u.handle}** — ${u.title || 'Untitled'}`;
|
|
162
|
+
display += `\n${when.toLocaleString()}`;
|
|
163
|
+
if (rsvp > 0) display += ` (${rsvp} RSVPs)`;
|
|
164
|
+
display += `\n\n`;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
display += `---\n`;
|
|
169
|
+
display += `Watch someone: \`vibe watch @handle\``;
|
|
170
|
+
|
|
171
|
+
return { display };
|
|
155
172
|
}
|
|
156
173
|
|
|
157
|
-
module.exports = {
|
|
174
|
+
module.exports = {
|
|
175
|
+
watch: { definition: watchDefinition, handler: watchHandler },
|
|
176
|
+
live: { definition: liveDefinition, handler: liveHandler }
|
|
177
|
+
};
|
package/tools/who.js
CHANGED
|
@@ -13,11 +13,11 @@ const notify = require('../notify');
|
|
|
13
13
|
const { formatTimeAgo, requireInit } = require('./_shared');
|
|
14
14
|
const { actions, formatActions } = require('./_actions');
|
|
15
15
|
const { enhanceUsersWithInference } = require('../intelligence/infer');
|
|
16
|
-
const { getTopSerendipity
|
|
16
|
+
const { getTopSerendipity } = require('../intelligence/serendipity');
|
|
17
17
|
|
|
18
18
|
const definition = {
|
|
19
19
|
name: 'vibe_who',
|
|
20
|
-
description:
|
|
20
|
+
description: "See who's online and what they're building.",
|
|
21
21
|
inputSchema: {
|
|
22
22
|
type: 'object',
|
|
23
23
|
properties: {}
|
|
@@ -50,9 +50,7 @@ function getHeat(user) {
|
|
|
50
50
|
|
|
51
51
|
// Check for inferred state from smart detection
|
|
52
52
|
if (user.mood_inferred && user.mood) {
|
|
53
|
-
const inferredLabel = user.inferred_state
|
|
54
|
-
? `${user.inferred_state.replace('-', ' ')}`
|
|
55
|
-
: 'active';
|
|
53
|
+
const inferredLabel = user.inferred_state ? `${user.inferred_state.replace('-', ' ')}` : 'active';
|
|
56
54
|
return {
|
|
57
55
|
icon: user.mood,
|
|
58
56
|
label: inferredLabel,
|
|
@@ -134,7 +132,7 @@ function formatActivity(user) {
|
|
|
134
132
|
// GitHub active repos (if no other context and GitHub connected)
|
|
135
133
|
if (user.github?.active_repos?.length > 0) {
|
|
136
134
|
const repos = user.github.active_repos.slice(0, 2);
|
|
137
|
-
const repoNames = repos.map(r => r.split('/').pop());
|
|
135
|
+
const repoNames = repos.map(r => r.split('/').pop()); // Get just repo name
|
|
138
136
|
return `pushing to ${repoNames.join(', ')}`;
|
|
139
137
|
}
|
|
140
138
|
|
|
@@ -150,19 +148,6 @@ async function handler(args) {
|
|
|
150
148
|
// Apply smart detection — infer states from context signals
|
|
151
149
|
const users = enhanceUsersWithInference(rawUsers);
|
|
152
150
|
const myHandle = config.getHandle();
|
|
153
|
-
const apiUrl = config.getApiUrl();
|
|
154
|
-
|
|
155
|
-
// Fetch active help requests (non-blocking)
|
|
156
|
-
let helpRequests = [];
|
|
157
|
-
try {
|
|
158
|
-
const helpResponse = await fetch(`${apiUrl}/api/help?limit=5`);
|
|
159
|
-
const helpData = await helpResponse.json();
|
|
160
|
-
if (helpData.success && helpData.requests) {
|
|
161
|
-
helpRequests = helpData.requests;
|
|
162
|
-
}
|
|
163
|
-
} catch (e) {
|
|
164
|
-
// Silent fail - help requests are nice-to-have
|
|
165
|
-
}
|
|
166
151
|
|
|
167
152
|
// Check for notifications (presence + messages)
|
|
168
153
|
notify.checkAll(store);
|
|
@@ -190,17 +175,6 @@ _Check back in a bit — builders come and go._`
|
|
|
190
175
|
|
|
191
176
|
let display = `## Who's Around\n\n`;
|
|
192
177
|
|
|
193
|
-
// Help requests section (if any)
|
|
194
|
-
if (helpRequests.length > 0) {
|
|
195
|
-
display += `**🆘 Needs Help:**\n`;
|
|
196
|
-
for (const req of helpRequests.slice(0, 3)) {
|
|
197
|
-
const urgencyIcon = req.urgency === 'high' ? '🔴' : req.urgency === 'low' ? '🟢' : '🟡';
|
|
198
|
-
const shortProblem = req.problem.length > 50 ? req.problem.slice(0, 47) + '...' : req.problem;
|
|
199
|
-
display += `${urgencyIcon} **@${req.handle}**: ${shortProblem}\n`;
|
|
200
|
-
}
|
|
201
|
-
display += `→ \`vibe stuck\` to help or ask\n\n---\n\n`;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
178
|
// Activity section for active users
|
|
205
179
|
if (active.length > 0) {
|
|
206
180
|
active.forEach(u => {
|
|
@@ -214,16 +188,20 @@ _Check back in a bit — builders come and go._`
|
|
|
214
188
|
const activity = formatActivity(u);
|
|
215
189
|
const timeAgo = formatTimeAgo(u.lastSeen);
|
|
216
190
|
|
|
217
|
-
//
|
|
218
|
-
const
|
|
219
|
-
? `
|
|
191
|
+
// Phase 1 Presence Bridge: source badges + reach channels
|
|
192
|
+
const sourceBadge = u.sources && u.sources.length > 0
|
|
193
|
+
? ` _(via ${u.sources.join(', ')})_`
|
|
194
|
+
: '';
|
|
195
|
+
const reachTag = u.reach_via && u.reach_via.length > 0
|
|
196
|
+
? ` reach: ${u.reach_via.join(', ')}\n`
|
|
220
197
|
: '';
|
|
221
198
|
|
|
222
|
-
display += `${heat.icon} **@${u.handle}**${agentBadge}${tag}${heatLabel}${
|
|
199
|
+
display += `${heat.icon} **@${u.handle}**${agentBadge}${tag}${heatLabel}${sourceBadge}\n`;
|
|
223
200
|
if (operatorTag) {
|
|
224
201
|
display += ` ${operatorTag}\n`;
|
|
225
202
|
}
|
|
226
203
|
display += ` ${activity}\n`;
|
|
204
|
+
if (reachTag) display += reachTag;
|
|
227
205
|
display += ` _${timeAgo}_\n\n`;
|
|
228
206
|
});
|
|
229
207
|
}
|
|
@@ -265,7 +243,7 @@ _Check back in a bit — builders come and go._`
|
|
|
265
243
|
`Say "message @handle" to reach someone`,
|
|
266
244
|
`Try "react 🔥 to @handle" for a quick high-five`,
|
|
267
245
|
`"ping @handle" sends a friendly wave 👋`,
|
|
268
|
-
`"play tictactoe with @handle" to challenge someone
|
|
246
|
+
`"play tictactoe with @handle" to challenge someone`
|
|
269
247
|
];
|
|
270
248
|
const randomAction = quickActions[Math.floor(Math.random() * quickActions.length)];
|
|
271
249
|
|
|
@@ -364,11 +342,13 @@ _Check back in a bit — builders come and go._`
|
|
|
364
342
|
response.actions = formatActions(actions.emptyRoom());
|
|
365
343
|
} else {
|
|
366
344
|
// People are here
|
|
367
|
-
response.actions = formatActions(
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
345
|
+
response.actions = formatActions(
|
|
346
|
+
actions.dashboard({
|
|
347
|
+
unreadCount,
|
|
348
|
+
onlineUsers: onlineHandles,
|
|
349
|
+
suggestion: topSuggestion
|
|
350
|
+
})
|
|
351
|
+
);
|
|
372
352
|
}
|
|
373
353
|
|
|
374
354
|
return response;
|