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
package/intelligence/infer.js
CHANGED
|
@@ -16,7 +16,7 @@ const STATES = {
|
|
|
16
16
|
'github-shipping': {
|
|
17
17
|
emoji: '🔥',
|
|
18
18
|
label: 'shipping code',
|
|
19
|
-
priority: 0,
|
|
19
|
+
priority: 0, // Highest priority — real GitHub commits
|
|
20
20
|
description: 'Active GitHub commits detected'
|
|
21
21
|
},
|
|
22
22
|
'deep-focus': {
|
|
@@ -25,31 +25,31 @@ const STATES = {
|
|
|
25
25
|
priority: 1,
|
|
26
26
|
description: 'Long session, minimal messaging'
|
|
27
27
|
},
|
|
28
|
-
|
|
28
|
+
shipping: {
|
|
29
29
|
emoji: '🚀',
|
|
30
30
|
label: 'shipping',
|
|
31
31
|
priority: 2,
|
|
32
32
|
description: 'Active commits, on main/master branch'
|
|
33
33
|
},
|
|
34
|
-
|
|
34
|
+
debugging: {
|
|
35
35
|
emoji: '🐛',
|
|
36
36
|
label: 'debugging',
|
|
37
37
|
priority: 3,
|
|
38
38
|
description: 'Errors present or fix- branch'
|
|
39
39
|
},
|
|
40
|
-
|
|
40
|
+
exploring: {
|
|
41
41
|
emoji: '🔍',
|
|
42
42
|
label: 'exploring',
|
|
43
43
|
priority: 4,
|
|
44
44
|
description: 'Many file switches, few edits'
|
|
45
45
|
},
|
|
46
|
-
|
|
46
|
+
stuck: {
|
|
47
47
|
emoji: '🤔',
|
|
48
48
|
label: 'might be stuck',
|
|
49
49
|
priority: 5,
|
|
50
50
|
description: 'Same file for a while, no commits'
|
|
51
51
|
},
|
|
52
|
-
|
|
52
|
+
pairing: {
|
|
53
53
|
emoji: '👥',
|
|
54
54
|
label: 'pairing',
|
|
55
55
|
priority: 6,
|
|
@@ -93,10 +93,8 @@ function inferState(context = {}) {
|
|
|
93
93
|
if (signals.githubShippingMode === 'hot') {
|
|
94
94
|
candidates.push({
|
|
95
95
|
state: 'github-shipping',
|
|
96
|
-
confidence: 0.95,
|
|
97
|
-
reason: signals.githubCommits > 0
|
|
98
|
-
? `${signals.githubCommits} commits recently`
|
|
99
|
-
: 'active on GitHub'
|
|
96
|
+
confidence: 0.95, // Very high - based on actual commits
|
|
97
|
+
reason: signals.githubCommits > 0 ? `${signals.githubCommits} commits recently` : 'active on GitHub'
|
|
100
98
|
});
|
|
101
99
|
} else if (signals.githubShippingMode === 'active') {
|
|
102
100
|
candidates.push({
|
|
@@ -120,9 +118,7 @@ function inferState(context = {}) {
|
|
|
120
118
|
// Has error OR on a fix/debug/bug branch
|
|
121
119
|
if (signals.hasError || signals.isDebugBranch) {
|
|
122
120
|
const confidence = signals.hasError ? 0.85 : 0.7;
|
|
123
|
-
const reason = signals.hasError
|
|
124
|
-
? 'working through an error'
|
|
125
|
-
: `on ${context.branch}`;
|
|
121
|
+
const reason = signals.hasError ? 'working through an error' : `on ${context.branch}`;
|
|
126
122
|
candidates.push({
|
|
127
123
|
state: 'debugging',
|
|
128
124
|
confidence,
|
|
@@ -214,9 +210,7 @@ function analyzeSignals(context) {
|
|
|
214
210
|
const recentCommit = minutesSinceCommit < 30;
|
|
215
211
|
|
|
216
212
|
// File stickiness (how long on same file)
|
|
217
|
-
const sameFileDuration = context.sameFileSince
|
|
218
|
-
? (now - context.sameFileSince) / (1000 * 60)
|
|
219
|
-
: 0;
|
|
213
|
+
const sameFileDuration = context.sameFileSince ? (now - context.sameFileSince) / (1000 * 60) : 0;
|
|
220
214
|
|
|
221
215
|
// Message activity
|
|
222
216
|
const messageCount = context.messageCount || 0;
|
package/intelligence/patterns.js
CHANGED
|
@@ -56,8 +56,8 @@ function createEmpty() {
|
|
|
56
56
|
sessions: {
|
|
57
57
|
total: 0,
|
|
58
58
|
totalMinutes: 0,
|
|
59
|
-
byHour: Array(24).fill(0),
|
|
60
|
-
byDay: Array(7).fill(0),
|
|
59
|
+
byHour: Array(24).fill(0), // Activity by hour of day
|
|
60
|
+
byDay: Array(7).fill(0), // Activity by day of week (0=Sun)
|
|
61
61
|
longestMinutes: 0,
|
|
62
62
|
averageMinutes: 0
|
|
63
63
|
},
|
|
@@ -96,7 +96,7 @@ function createEmpty() {
|
|
|
96
96
|
// Domains they explore
|
|
97
97
|
domains: {},
|
|
98
98
|
// Attribution given/received
|
|
99
|
-
inspired: [],
|
|
99
|
+
inspired: [], // who inspired them
|
|
100
100
|
inspiredOthers: [] // who they've inspired
|
|
101
101
|
}
|
|
102
102
|
};
|
|
@@ -140,9 +140,7 @@ function logSessionEnd() {
|
|
|
140
140
|
|
|
141
141
|
// Update totals
|
|
142
142
|
patterns.sessions.totalMinutes += durationMinutes;
|
|
143
|
-
patterns.sessions.averageMinutes = Math.round(
|
|
144
|
-
patterns.sessions.totalMinutes / patterns.sessions.total
|
|
145
|
-
);
|
|
143
|
+
patterns.sessions.averageMinutes = Math.round(patterns.sessions.totalMinutes / patterns.sessions.total);
|
|
146
144
|
if (durationMinutes > patterns.sessions.longestMinutes) {
|
|
147
145
|
patterns.sessions.longestMinutes = durationMinutes;
|
|
148
146
|
}
|
|
@@ -312,13 +310,11 @@ function updateTopConnections(patterns) {
|
|
|
312
310
|
return bTotal - aTotal;
|
|
313
311
|
});
|
|
314
312
|
|
|
315
|
-
patterns.social.topConnections = connections
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
lastContact: data.lastContact
|
|
321
|
-
}));
|
|
313
|
+
patterns.social.topConnections = connections.slice(0, 5).map(([handle, data]) => ({
|
|
314
|
+
handle,
|
|
315
|
+
total: data.messages + data.received,
|
|
316
|
+
lastContact: data.lastContact
|
|
317
|
+
}));
|
|
322
318
|
}
|
|
323
319
|
|
|
324
320
|
// ============ CREATIVE LOGGING ============
|
|
@@ -450,9 +446,7 @@ function getDominantState() {
|
|
|
450
446
|
return {
|
|
451
447
|
state: states[0][0],
|
|
452
448
|
minutes: states[0][1].totalMinutes,
|
|
453
|
-
percentage: Math.round(
|
|
454
|
-
(states[0][1].totalMinutes / patterns.sessions.totalMinutes) * 100
|
|
455
|
-
)
|
|
449
|
+
percentage: Math.round((states[0][1].totalMinutes / patterns.sessions.totalMinutes) * 100)
|
|
456
450
|
};
|
|
457
451
|
}
|
|
458
452
|
|
|
@@ -595,8 +589,19 @@ function extractModule(filePath) {
|
|
|
595
589
|
if (!filePath) return null;
|
|
596
590
|
|
|
597
591
|
const parts = filePath.split('/');
|
|
598
|
-
const meaningful = [
|
|
599
|
-
|
|
592
|
+
const meaningful = [
|
|
593
|
+
'src',
|
|
594
|
+
'lib',
|
|
595
|
+
'app',
|
|
596
|
+
'components',
|
|
597
|
+
'pages',
|
|
598
|
+
'api',
|
|
599
|
+
'services',
|
|
600
|
+
'utils',
|
|
601
|
+
'hooks',
|
|
602
|
+
'store',
|
|
603
|
+
'models'
|
|
604
|
+
];
|
|
600
605
|
|
|
601
606
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
602
607
|
if (meaningful.includes(parts[i])) {
|
|
@@ -14,11 +14,11 @@ const config = require('../config');
|
|
|
14
14
|
|
|
15
15
|
// Thresholds — conservative, non-intrusive
|
|
16
16
|
const CONFIG = {
|
|
17
|
-
BREAK_SUGGESTION_HOURS: 6,
|
|
18
|
-
AWAY_THRESHOLD_MINUTES: 60,
|
|
19
|
-
RECENT_SHIP_MINUTES: 30,
|
|
20
|
-
WELCOME_WINDOW_HOURS: 4,
|
|
21
|
-
MIN_SESSIONS_FOR_NUDGE: 5
|
|
17
|
+
BREAK_SUGGESTION_HOURS: 6, // Only after 6h (gentle)
|
|
18
|
+
AWAY_THRESHOLD_MINUTES: 60, // Consider "away" after 1h
|
|
19
|
+
RECENT_SHIP_MINUTES: 30, // "Recent" ship within 30min
|
|
20
|
+
WELCOME_WINDOW_HOURS: 4, // Welcome only very new users
|
|
21
|
+
MIN_SESSIONS_FOR_NUDGE: 5 // High bar for nudges
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
// Track state for proactive suggestions
|
|
@@ -83,9 +83,10 @@ async function generateProactiveSuggestions(context = {}) {
|
|
|
83
83
|
*/
|
|
84
84
|
async function getShipsInTheNight(myHandle, activeUsers) {
|
|
85
85
|
// Check if user was recently away
|
|
86
|
-
const wasRecentlyAway =
|
|
86
|
+
const wasRecentlyAway =
|
|
87
|
+
proactiveState.wasAway &&
|
|
87
88
|
proactiveState.awayStartTime &&
|
|
88
|
-
|
|
89
|
+
Date.now() - proactiveState.awayStartTime > CONFIG.AWAY_THRESHOLD_MINUTES * 60 * 1000;
|
|
89
90
|
|
|
90
91
|
if (!wasRecentlyAway) return null;
|
|
91
92
|
|
|
@@ -212,12 +213,10 @@ function getMilestoneCelebrations(myHandle, activeUsers) {
|
|
|
212
213
|
if (user.handle === myHandle) continue;
|
|
213
214
|
|
|
214
215
|
// Check for shipping indicators
|
|
215
|
-
const isShipping = user.inferred_state === 'shipping' ||
|
|
216
|
-
user.mood === '🚀' ||
|
|
217
|
-
user.builderMode === 'shipping';
|
|
216
|
+
const isShipping = user.inferred_state === 'shipping' || user.mood === '🚀' || user.builderMode === 'shipping';
|
|
218
217
|
|
|
219
218
|
if (isShipping) {
|
|
220
|
-
const shipKey = `${user.handle}:${Date.now() / (1000 * 60 * 60) | 0}`; // Hourly key
|
|
219
|
+
const shipKey = `${user.handle}:${(Date.now() / (1000 * 60 * 60)) | 0}`; // Hourly key
|
|
221
220
|
if (proactiveState.celebratedShips.has(shipKey)) continue;
|
|
222
221
|
|
|
223
222
|
proactiveState.celebratedShips.add(shipKey);
|
|
@@ -255,10 +254,12 @@ function getConnectionNudges(myHandle, activeUsers) {
|
|
|
255
254
|
if (user.handle === myHandle) continue;
|
|
256
255
|
|
|
257
256
|
// Both in same inferred state
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
if (
|
|
258
|
+
myUser.inferred_state &&
|
|
259
|
+
user.inferred_state &&
|
|
260
|
+
myUser.inferred_state === user.inferred_state &&
|
|
261
|
+
['debugging', 'deep-focus', 'shipping'].includes(myUser.inferred_state)
|
|
262
|
+
) {
|
|
262
263
|
nudges.push({
|
|
263
264
|
type: 'connection_nudge',
|
|
264
265
|
priority: 4,
|
|
@@ -134,7 +134,20 @@ function getModule(filePath) {
|
|
|
134
134
|
const parts = filePath.split('/');
|
|
135
135
|
|
|
136
136
|
// Look for meaningful directories
|
|
137
|
-
const meaningfulDirs = [
|
|
137
|
+
const meaningfulDirs = [
|
|
138
|
+
'src',
|
|
139
|
+
'lib',
|
|
140
|
+
'app',
|
|
141
|
+
'components',
|
|
142
|
+
'pages',
|
|
143
|
+
'api',
|
|
144
|
+
'services',
|
|
145
|
+
'utils',
|
|
146
|
+
'hooks',
|
|
147
|
+
'store',
|
|
148
|
+
'models',
|
|
149
|
+
'controllers'
|
|
150
|
+
];
|
|
138
151
|
|
|
139
152
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
140
153
|
if (meaningfulDirs.includes(parts[i])) {
|
|
@@ -165,7 +178,24 @@ function extractBranchTopic(branch) {
|
|
|
165
178
|
const parts = cleaned.split('-').filter(p => p.length > 2);
|
|
166
179
|
|
|
167
180
|
// Common topic keywords
|
|
168
|
-
const topics = [
|
|
181
|
+
const topics = [
|
|
182
|
+
'auth',
|
|
183
|
+
'user',
|
|
184
|
+
'api',
|
|
185
|
+
'db',
|
|
186
|
+
'database',
|
|
187
|
+
'ui',
|
|
188
|
+
'test',
|
|
189
|
+
'config',
|
|
190
|
+
'payment',
|
|
191
|
+
'email',
|
|
192
|
+
'notification',
|
|
193
|
+
'search',
|
|
194
|
+
'cache',
|
|
195
|
+
'session',
|
|
196
|
+
'login',
|
|
197
|
+
'signup'
|
|
198
|
+
];
|
|
169
199
|
|
|
170
200
|
// Look for topic keywords
|
|
171
201
|
for (const part of parts) {
|
|
@@ -200,12 +230,13 @@ function errorSimilarity(error1, error2) {
|
|
|
200
230
|
if (!error1 || !error2) return 0;
|
|
201
231
|
|
|
202
232
|
// Normalize errors
|
|
203
|
-
const normalize =
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
233
|
+
const normalize = err =>
|
|
234
|
+
err
|
|
235
|
+
.toLowerCase()
|
|
236
|
+
.replace(/[0-9]+/g, 'N') // Replace numbers
|
|
237
|
+
.replace(/['"`]/g, '') // Remove quotes
|
|
238
|
+
.replace(/\s+/g, ' ') // Normalize whitespace
|
|
239
|
+
.slice(0, 100); // Truncate
|
|
209
240
|
|
|
210
241
|
const e1 = normalize(error1);
|
|
211
242
|
const e2 = normalize(error2);
|
|
@@ -214,9 +245,17 @@ function errorSimilarity(error1, error2) {
|
|
|
214
245
|
|
|
215
246
|
// Check for common error types
|
|
216
247
|
const errorTypes = [
|
|
217
|
-
'TypeError',
|
|
218
|
-
'
|
|
219
|
-
'
|
|
248
|
+
'TypeError',
|
|
249
|
+
'SyntaxError',
|
|
250
|
+
'ReferenceError',
|
|
251
|
+
'RangeError',
|
|
252
|
+
'undefined is not',
|
|
253
|
+
'cannot read property',
|
|
254
|
+
'is not a function',
|
|
255
|
+
'module not found',
|
|
256
|
+
'cannot find module',
|
|
257
|
+
'ENOENT',
|
|
258
|
+
'ECONNREFUSED'
|
|
220
259
|
];
|
|
221
260
|
|
|
222
261
|
for (const type of errorTypes) {
|
|
@@ -252,12 +291,12 @@ function isNewUser(user) {
|
|
|
252
291
|
*/
|
|
253
292
|
function formatSerendipityMoment(moment) {
|
|
254
293
|
const emoji = {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
294
|
+
same_file: '✨',
|
|
295
|
+
same_module: '🔗',
|
|
296
|
+
same_topic: '🎯',
|
|
297
|
+
same_struggle: '🤝',
|
|
298
|
+
complementary: '💡',
|
|
299
|
+
both_new: '👋'
|
|
261
300
|
};
|
|
262
301
|
|
|
263
302
|
return {
|
|
@@ -289,9 +328,7 @@ function getTopSerendipity(currentUser, allUsers) {
|
|
|
289
328
|
*/
|
|
290
329
|
function getAllSerendipity(currentUser, allUsers, minRelevance = 0.5) {
|
|
291
330
|
const matches = findSerendipity(currentUser, allUsers);
|
|
292
|
-
return matches
|
|
293
|
-
.filter(m => m.relevance >= minRelevance)
|
|
294
|
-
.map(formatSerendipityMoment);
|
|
331
|
+
return matches.filter(m => m.relevance >= minRelevance).map(formatSerendipityMoment);
|
|
295
332
|
}
|
|
296
333
|
|
|
297
334
|
module.exports = {
|
package/memory.js
CHANGED
|
@@ -71,14 +71,19 @@ function recall(handle, limit = 10) {
|
|
|
71
71
|
|
|
72
72
|
try {
|
|
73
73
|
const content = fs.readFileSync(threadFile, 'utf8');
|
|
74
|
-
const lines = content
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
const lines = content
|
|
75
|
+
.trim()
|
|
76
|
+
.split('\n')
|
|
77
|
+
.filter(l => l.trim());
|
|
78
|
+
const memories = lines
|
|
79
|
+
.map(line => {
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(line);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
.filter(m => m !== null);
|
|
82
87
|
|
|
83
88
|
// Return newest first, limited
|
|
84
89
|
return memories.reverse().slice(0, limit);
|
package/migrate-v2.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Migration: Add thread_id column for V2 Postgres integration
|
|
4
|
+
*
|
|
5
|
+
* This migration adds the thread_id column to the messages table
|
|
6
|
+
* and creates the necessary index for V2 API compatibility.
|
|
7
|
+
*
|
|
8
|
+
* Run: node migrate-v2.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const Database = require('better-sqlite3');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
|
|
15
|
+
const DB_PATH = path.join(os.homedir(), '.vibecodings', 'sessions.db');
|
|
16
|
+
|
|
17
|
+
function migrate() {
|
|
18
|
+
console.log('[Migration] Starting V2 schema migration...');
|
|
19
|
+
console.log(`[Migration] Database: ${DB_PATH}`);
|
|
20
|
+
|
|
21
|
+
const db = new Database(DB_PATH);
|
|
22
|
+
|
|
23
|
+
// Check if thread_id column already exists
|
|
24
|
+
const columns = db.prepare('PRAGMA table_info(messages)').all();
|
|
25
|
+
const hasThreadId = columns.some(col => col.name === 'thread_id');
|
|
26
|
+
|
|
27
|
+
if (hasThreadId) {
|
|
28
|
+
console.log('[Migration] ✅ thread_id column already exists. No migration needed.');
|
|
29
|
+
db.close();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log('[Migration] Adding thread_id column...');
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
// Add thread_id column
|
|
37
|
+
db.exec(`ALTER TABLE messages ADD COLUMN thread_id TEXT;`);
|
|
38
|
+
|
|
39
|
+
// Create index for thread_id
|
|
40
|
+
db.exec(`
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_messages_thread_id
|
|
42
|
+
ON messages(thread_id);
|
|
43
|
+
`);
|
|
44
|
+
|
|
45
|
+
console.log('[Migration] ✅ Successfully added thread_id column and index');
|
|
46
|
+
|
|
47
|
+
// Verify migration
|
|
48
|
+
const newColumns = db.prepare('PRAGMA table_info(messages)').all();
|
|
49
|
+
const threadIdColumn = newColumns.find(col => col.name === 'thread_id');
|
|
50
|
+
|
|
51
|
+
if (threadIdColumn) {
|
|
52
|
+
console.log('[Migration] ✅ Verification passed');
|
|
53
|
+
console.log(`[Migration] Column details: ${JSON.stringify(threadIdColumn)}`);
|
|
54
|
+
} else {
|
|
55
|
+
console.error('[Migration] ❌ Verification failed - column not found after migration');
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('[Migration] ❌ Migration failed:', error.message);
|
|
59
|
+
throw error;
|
|
60
|
+
} finally {
|
|
61
|
+
db.close();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('[Migration] Complete!');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Run migration
|
|
68
|
+
if (require.main === module) {
|
|
69
|
+
migrate();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { migrate };
|
package/notification-emitter.js
CHANGED
|
@@ -30,7 +30,7 @@ class NotificationEmitter {
|
|
|
30
30
|
this.debounceTimers[reason] = setTimeout(() => {
|
|
31
31
|
try {
|
|
32
32
|
this.server.notification({
|
|
33
|
-
method:
|
|
33
|
+
method: 'notifications/list_changed'
|
|
34
34
|
});
|
|
35
35
|
delete this.debounceTimers[reason];
|
|
36
36
|
} catch (e) {
|
|
@@ -47,7 +47,7 @@ class NotificationEmitter {
|
|
|
47
47
|
emitImmediate() {
|
|
48
48
|
try {
|
|
49
49
|
this.server.notification({
|
|
50
|
-
method:
|
|
50
|
+
method: 'notifications/list_changed'
|
|
51
51
|
});
|
|
52
52
|
} catch (e) {
|
|
53
53
|
// Silent fail
|
package/notify.js
CHANGED
|
@@ -65,7 +65,7 @@ function showNotification(title, message, sound = false, bell = true) {
|
|
|
65
65
|
script += ` sound name "Ping"`;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
exec(`osascript -e '${script}'`,
|
|
68
|
+
exec(`osascript -e '${script}'`, err => {
|
|
69
69
|
if (err) {
|
|
70
70
|
// Silently fail - notifications are best-effort
|
|
71
71
|
}
|
|
@@ -89,8 +89,6 @@ async function checkAndNotify(inbox) {
|
|
|
89
89
|
|
|
90
90
|
let notified = false;
|
|
91
91
|
|
|
92
|
-
const myHandle = config.getHandle();
|
|
93
|
-
|
|
94
92
|
for (const msg of inbox) {
|
|
95
93
|
// Skip if already notified
|
|
96
94
|
if (state.notifiedIds.includes(msg.id)) continue;
|
|
@@ -98,9 +96,6 @@ async function checkAndNotify(inbox) {
|
|
|
98
96
|
// Skip if already read
|
|
99
97
|
if (msg.read) continue;
|
|
100
98
|
|
|
101
|
-
// Skip messages FROM yourself (don't notify about your own sends)
|
|
102
|
-
if (myHandle && msg.from?.toLowerCase() === myHandle.toLowerCase()) continue;
|
|
103
|
-
|
|
104
99
|
const msgTime = new Date(msg.createdAt).getTime();
|
|
105
100
|
const age = now - msgTime;
|
|
106
101
|
|
|
@@ -109,6 +104,7 @@ async function checkAndNotify(inbox) {
|
|
|
109
104
|
let reason = '';
|
|
110
105
|
|
|
111
106
|
// Rule 1: Direct mention in message (always if not "off")
|
|
107
|
+
const myHandle = config.getHandle();
|
|
112
108
|
if (myHandle && msg.text && msg.text.toLowerCase().includes(`@${myHandle}`)) {
|
|
113
109
|
shouldNotify = true;
|
|
114
110
|
reason = 'mention';
|
|
@@ -134,6 +130,15 @@ async function checkAndNotify(inbox) {
|
|
|
134
130
|
reason === 'mention' // Sound only for mentions
|
|
135
131
|
);
|
|
136
132
|
|
|
133
|
+
// Phase 2: Forward inbound DMs to subscribed agent gateways (clawdbot → Telegram)
|
|
134
|
+
pushToAgents('dm_received', {
|
|
135
|
+
from: msg.from,
|
|
136
|
+
to: myHandle,
|
|
137
|
+
body: msg.text,
|
|
138
|
+
reason,
|
|
139
|
+
id: msg.id
|
|
140
|
+
});
|
|
141
|
+
|
|
137
142
|
state.notifiedIds.push(msg.id);
|
|
138
143
|
notified = true;
|
|
139
144
|
}
|
|
@@ -202,9 +207,9 @@ function checkPresence(activeUsers) {
|
|
|
202
207
|
const lastSeen = state.seenHandles[user.handle];
|
|
203
208
|
|
|
204
209
|
// New user or returning after cooldown
|
|
205
|
-
if (!lastSeen ||
|
|
210
|
+
if (!lastSeen || now - lastSeen > COOLDOWN) {
|
|
206
211
|
// Check if they're actually recently active (last 5 min)
|
|
207
|
-
const userActive = user.lastSeen &&
|
|
212
|
+
const userActive = user.lastSeen && now - user.lastSeen < 5 * 60 * 1000;
|
|
208
213
|
|
|
209
214
|
if (userActive) {
|
|
210
215
|
justJoined.push(user);
|
|
@@ -215,8 +220,8 @@ function checkPresence(activeUsers) {
|
|
|
215
220
|
showNotification(
|
|
216
221
|
`/vibe — @${user.handle} is here`,
|
|
217
222
|
context,
|
|
218
|
-
false,
|
|
219
|
-
false
|
|
223
|
+
false, // no system sound
|
|
224
|
+
false // no terminal bell for presence (too noisy)
|
|
220
225
|
);
|
|
221
226
|
}
|
|
222
227
|
}
|
|
@@ -299,8 +304,8 @@ async function checkShips(memoryHandles = []) {
|
|
|
299
304
|
showNotification(
|
|
300
305
|
`/vibe — @${ship.author} shipped! 🚀`,
|
|
301
306
|
content,
|
|
302
|
-
false,
|
|
303
|
-
true
|
|
307
|
+
false, // no system sound
|
|
308
|
+
true // terminal bell (soft nudge)
|
|
304
309
|
);
|
|
305
310
|
newShips.push(ship);
|
|
306
311
|
}
|
|
@@ -315,7 +320,6 @@ async function checkShips(memoryHandles = []) {
|
|
|
315
320
|
|
|
316
321
|
state.lastCheck = now;
|
|
317
322
|
saveShipsState(state);
|
|
318
|
-
|
|
319
323
|
} catch (e) {
|
|
320
324
|
// Silent fail - notifications are best-effort
|
|
321
325
|
}
|
|
@@ -360,6 +364,26 @@ async function checkAll(store) {
|
|
|
360
364
|
}
|
|
361
365
|
}
|
|
362
366
|
|
|
367
|
+
/**
|
|
368
|
+
* Push event to subscribed agent gateways (Clawdbot, @seth, etc.)
|
|
369
|
+
* Wraps agent-gateway pushEvent for use in tool handlers.
|
|
370
|
+
*
|
|
371
|
+
* Call this from any tool that produces a notable event:
|
|
372
|
+
* pushToAgents('dm', { from, to, body })
|
|
373
|
+
* pushToAgents('ship', { author, what, tags })
|
|
374
|
+
* pushToAgents('presence', { handle, status, mood })
|
|
375
|
+
* pushToAgents('mention', { handle, context })
|
|
376
|
+
* pushToAgents('handoff', { from, to, task, context })
|
|
377
|
+
*/
|
|
378
|
+
async function pushToAgents(eventType, eventData) {
|
|
379
|
+
try {
|
|
380
|
+
const agentGateway = require('./bridges/agent-gateway');
|
|
381
|
+
await agentGateway.pushEvent(eventType, eventData);
|
|
382
|
+
} catch (e) {
|
|
383
|
+
// Silent fail — agent gateway is optional infrastructure
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
363
387
|
module.exports = {
|
|
364
388
|
showNotification,
|
|
365
389
|
checkAndNotify,
|
|
@@ -367,5 +391,6 @@ module.exports = {
|
|
|
367
391
|
checkShips,
|
|
368
392
|
checkAll,
|
|
369
393
|
notify,
|
|
370
|
-
ringBell
|
|
394
|
+
ringBell,
|
|
395
|
+
pushToAgents
|
|
371
396
|
};
|
package/package.json
CHANGED
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slashvibe-mcp",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"mcpName": "io.github.vibecodinginc/vibe",
|
|
5
|
-
"description": "Social
|
|
3
|
+
"version": "0.3.23",
|
|
4
|
+
"mcpName": "io.github.vibecodinginc/vibe-mcp",
|
|
5
|
+
"description": "Social MCP server - DMs, presence, discovery, and games for AI-assisted developers. Works with Claude Code, Cursor, VS Code, Windsurf, and any MCP client.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"slashvibe-mcp": "./index.js"
|
|
9
|
-
"vibe-setup": "./setup.js"
|
|
8
|
+
"slashvibe-mcp": "./index.js"
|
|
10
9
|
},
|
|
11
10
|
"scripts": {
|
|
12
11
|
"start": "node index.js",
|
|
13
|
-
"test": "node --test
|
|
14
|
-
"
|
|
15
|
-
"lint": "eslint . --
|
|
16
|
-
"
|
|
12
|
+
"test": "node test/smoke.js && node --test test/*.test.js",
|
|
13
|
+
"lint": "node test/lint.js && npx eslint .",
|
|
14
|
+
"lint:fix": "npx eslint . --fix",
|
|
15
|
+
"format": "npx prettier --write \"**/*.js\" \"**/*.json\" \"**/*.md\" \"**/*.yml\"",
|
|
16
|
+
"format:check": "npx prettier --check \"**/*.js\" \"**/*.json\" \"**/*.yml\"",
|
|
17
|
+
"typecheck": "tsc --noEmit"
|
|
17
18
|
},
|
|
18
19
|
"keywords": [
|
|
19
20
|
"mcp",
|
|
21
|
+
"mcp-server",
|
|
22
|
+
"model-context-protocol",
|
|
20
23
|
"claude-code",
|
|
24
|
+
"cursor",
|
|
25
|
+
"windsurf",
|
|
26
|
+
"vscode",
|
|
21
27
|
"vibe",
|
|
22
28
|
"social",
|
|
23
29
|
"developer-tools",
|
|
24
30
|
"ai",
|
|
25
|
-
"anthropic"
|
|
31
|
+
"anthropic",
|
|
32
|
+
"messaging",
|
|
33
|
+
"presence",
|
|
34
|
+
"multiplayer"
|
|
26
35
|
],
|
|
27
36
|
"author": "Seth Goldstein <seth@slashvibe.dev>",
|
|
28
37
|
"license": "MIT",
|
|
@@ -38,32 +47,22 @@
|
|
|
38
47
|
"node": ">=18.0.0"
|
|
39
48
|
},
|
|
40
49
|
"files": [
|
|
41
|
-
"
|
|
42
|
-
"setup.js",
|
|
43
|
-
"auth-store.js",
|
|
44
|
-
"auto-update.js",
|
|
45
|
-
"config.js",
|
|
46
|
-
"crypto.js",
|
|
47
|
-
"discord.js",
|
|
48
|
-
"memory.js",
|
|
49
|
-
"notify.js",
|
|
50
|
-
"notification-emitter.js",
|
|
51
|
-
"analytics.js",
|
|
52
|
-
"smart-inbox.js",
|
|
53
|
-
"presence.js",
|
|
54
|
-
"prompts.js",
|
|
55
|
-
"twitter.js",
|
|
50
|
+
"*.js",
|
|
56
51
|
"version.json",
|
|
57
52
|
"tools/",
|
|
58
53
|
"store/",
|
|
59
54
|
"protocol/",
|
|
60
55
|
"intelligence/",
|
|
61
|
-
"games/",
|
|
62
|
-
"bridges/",
|
|
63
56
|
"README.md"
|
|
64
57
|
],
|
|
65
58
|
"dependencies": {
|
|
66
|
-
"
|
|
67
|
-
"
|
|
59
|
+
"better-sqlite3": "^11.10.0",
|
|
60
|
+
"crossword-layout-generator": "^0.1.1"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@eslint/js": "^9.39.2",
|
|
64
|
+
"eslint": "^9.39.2",
|
|
65
|
+
"prettier": "^3.8.1",
|
|
66
|
+
"typescript": "^5.9.3"
|
|
68
67
|
}
|
|
69
68
|
}
|