slashvibe-mcp 0.2.2 → 0.2.4
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/README.md +1 -0
- package/analytics.js +107 -0
- package/config.js +174 -3
- package/index.js +163 -34
- package/intelligence/index.js +45 -0
- package/intelligence/infer.js +316 -0
- package/intelligence/interests.js +369 -0
- package/intelligence/patterns.js +651 -0
- package/intelligence/proactive.js +358 -0
- package/intelligence/serendipity.js +306 -0
- package/notification-emitter.js +77 -0
- package/notify.js +141 -18
- package/package.json +14 -6
- package/presence.js +5 -1
- package/protocol/index.js +88 -1
- package/protocol/telegram-commands.js +199 -0
- package/store/api.js +469 -29
- package/store/index.js +7 -7
- package/store/local.js +67 -11
- package/store/profiles.js +435 -0
- package/store/reservations.js +321 -0
- package/store/skills.js +378 -0
- package/tools/_actions.js +491 -22
- package/tools/_connection-queue.js +257 -0
- package/tools/_discovery-enhanced.js +290 -0
- package/tools/_discovery.js +439 -0
- package/tools/_proactive-discovery.js +301 -0
- package/tools/_shared/index.js +64 -0
- package/tools/_work-context.js +338 -0
- package/tools/_work-context.manual-test.js +199 -0
- package/tools/_work-context.test.js +260 -0
- package/tools/admin-inbox.js +218 -0
- package/tools/agent-treasury.js +288 -0
- package/tools/agents.js +122 -0
- package/tools/analytics.js +191 -0
- package/tools/approve.js +197 -0
- package/tools/arcade.js +173 -0
- package/tools/artifact-create.js +247 -0
- package/tools/artifact-view.js +174 -0
- package/tools/artifacts-price.js +107 -0
- package/tools/ask-expert.js +160 -0
- package/tools/auto-suggest-connections.js +304 -0
- package/tools/away.js +68 -0
- package/tools/back.js +51 -0
- package/tools/become-expert.js +150 -0
- package/tools/bootstrap-skills.js +231 -0
- package/tools/bridge-dashboard.js +342 -0
- package/tools/bridge-health.js +400 -0
- package/tools/bridge-live.js +384 -0
- package/tools/bridges.js +383 -0
- package/tools/broadcast.js +286 -0
- package/tools/bye.js +4 -0
- package/tools/chat.js +202 -0
- package/tools/collaborative-drawing.js +286 -0
- package/tools/colorguess.js +281 -0
- package/tools/crossword.js +369 -0
- package/tools/discover-insights.js +379 -0
- package/tools/discover-momentum.js +256 -0
- package/tools/discover.js +675 -0
- package/tools/discovery-analytics.js +345 -0
- package/tools/discovery-auto-suggest.js +275 -0
- package/tools/discovery-bootstrap.js +267 -0
- package/tools/discovery-daily.js +375 -0
- package/tools/discovery-dashboard.js +385 -0
- package/tools/discovery-digest.js +314 -0
- package/tools/discovery-hub.js +357 -0
- package/tools/discovery-insights.js +384 -0
- package/tools/discovery-momentum.js +281 -0
- package/tools/discovery-monitor.js +319 -0
- package/tools/discovery-proactive.js +300 -0
- package/tools/dm.js +84 -14
- package/tools/draw.js +317 -0
- package/tools/drawing.js +310 -0
- package/tools/earnings.js +126 -0
- package/tools/echo.js +16 -0
- package/tools/farcaster.js +307 -0
- package/tools/feed.js +215 -0
- package/tools/follow.js +224 -0
- package/tools/friends.js +192 -0
- package/tools/game.js +218 -110
- package/tools/games-catalog.js +376 -0
- package/tools/games.js +313 -0
- package/tools/genesis.js +233 -0
- package/tools/gig-browse.js +206 -0
- package/tools/gig-complete.js +139 -0
- package/tools/guessnumber.js +194 -0
- package/tools/hangman.js +129 -0
- package/tools/help.js +269 -0
- package/tools/idea.js +217 -0
- package/tools/inbox.js +291 -25
- package/tools/init.js +657 -33
- package/tools/insights.js +123 -0
- package/tools/invite.js +142 -21
- package/tools/l2-bridge.js +272 -0
- package/tools/l2-status.js +217 -0
- package/tools/l2.js +206 -0
- package/tools/migrate.js +156 -0
- package/tools/mint.js +377 -0
- package/tools/multiplayer-game.js +275 -0
- package/tools/multiplayer-tictactoe.js +303 -0
- package/tools/mute.js +97 -0
- package/tools/notifications.js +415 -0
- package/tools/observe.js +200 -0
- package/tools/onboarding.js +147 -0
- package/tools/open.js +52 -3
- package/tools/party-game.js +314 -0
- package/tools/plan.js +225 -0
- package/tools/presence-agent.js +167 -0
- package/tools/profile.js +219 -0
- package/tools/proof-of-work.js +139 -0
- package/tools/pulse.js +218 -0
- package/tools/react.js +4 -0
- package/tools/release.js +83 -0
- package/tools/report.js +109 -0
- package/tools/reputation.js +175 -0
- package/tools/request.js +231 -0
- package/tools/reservations.js +116 -0
- package/tools/reserve.js +111 -0
- package/tools/riddle.js +240 -0
- package/tools/run-bootstrap.js +69 -0
- package/tools/schedule.js +367 -0
- package/tools/session.js +420 -0
- package/tools/session_price.js +128 -0
- package/tools/settings.js +200 -0
- package/tools/ship.js +188 -0
- package/tools/shipback.js +326 -0
- package/tools/skills-analytics.js +349 -0
- package/tools/skills-bootstrap.js +301 -0
- package/tools/skills-dashboard.js +268 -0
- package/tools/skills-exchange.js +342 -0
- package/tools/skills.js +380 -0
- package/tools/smart-intro.js +353 -0
- package/tools/social-inbox.js +326 -69
- package/tools/social-post.js +251 -66
- package/tools/social-processor.js +445 -0
- package/tools/solo-game.js +390 -0
- package/tools/start.js +296 -81
- package/tools/status.js +53 -6
- package/tools/storybuilder.js +331 -0
- package/tools/stuck.js +297 -0
- package/tools/subscribe.js +148 -0
- package/tools/subscriptions.js +134 -0
- package/tools/suggest-tags.js +184 -0
- package/tools/tag-suggestions.js +257 -0
- package/tools/telegram-bot.js +183 -0
- package/tools/telegram-setup.js +214 -0
- package/tools/tictactoe.js +155 -0
- package/tools/tip.js +120 -0
- package/tools/token.js +103 -0
- package/tools/twentyquestions.js +143 -0
- package/tools/update.js +1 -1
- package/tools/wallet.js +127 -0
- package/tools/watch.js +157 -0
- package/tools/webhook-test.js +388 -0
- package/tools/who.js +118 -25
- package/tools/withdraw.js +145 -0
- package/tools/wordassociation.js +247 -0
- package/tools/work-summary.js +96 -0
- package/tools/workshop-buddy.js +394 -0
- package/tools/workshop.js +327 -0
- package/version.json +12 -3
- package/tools/board.js +0 -130
package/README.md
CHANGED
|
@@ -60,6 +60,7 @@ The MCP server connects to `slashvibe.dev` for:
|
|
|
60
60
|
|
|
61
61
|
## Related
|
|
62
62
|
|
|
63
|
+
- [GitHub](https://github.com/VibeCodingInc/vibe-mcp) - Source code
|
|
63
64
|
- [slashvibe.dev](https://slashvibe.dev) - Web presence
|
|
64
65
|
- [Spirit Protocol](https://spiritprotocol.io) - Parent ecosystem
|
|
65
66
|
- [AIRC](https://airc.chat) - Agent identity protocol
|
package/analytics.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics — Retention event tracking from MCP server
|
|
3
|
+
*
|
|
4
|
+
* Logs events to the /api/analytics/event endpoint for measuring
|
|
5
|
+
* user engagement and retention funnel performance.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const analytics = require('./analytics');
|
|
9
|
+
* analytics.track('empty_inbox_action', { action: 'discover', source: 'inbox' });
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const config = require('./config');
|
|
13
|
+
|
|
14
|
+
const API_URL = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Track an analytics event (fire and forget)
|
|
18
|
+
* @param {string} eventType - Event type (from valid types in api/lib/events.js)
|
|
19
|
+
* @param {object} data - Additional event data
|
|
20
|
+
*/
|
|
21
|
+
async function track(eventType, data = {}) {
|
|
22
|
+
const handle = config.getHandle();
|
|
23
|
+
if (!handle) return; // Skip if not initialized
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Fire and forget - don't await or block
|
|
27
|
+
fetch(`${API_URL}/api/analytics/events`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
body: JSON.stringify({
|
|
31
|
+
type: eventType,
|
|
32
|
+
handle,
|
|
33
|
+
data: {
|
|
34
|
+
...data,
|
|
35
|
+
client: 'mcp-server',
|
|
36
|
+
timestamp: Date.now()
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}).catch(() => {}); // Silently ignore errors
|
|
40
|
+
} catch (e) {
|
|
41
|
+
// Analytics should never block or fail user flows
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Track empty inbox interaction
|
|
47
|
+
* @param {string} action - Which action was taken (or 'none' if user closed)
|
|
48
|
+
* @param {object} context - Context about the state (hadOnboardingTask, hadRecentShips, etc.)
|
|
49
|
+
*/
|
|
50
|
+
function trackEmptyInbox(action, context = {}) {
|
|
51
|
+
// Track that user reached empty inbox state
|
|
52
|
+
track('empty_inbox_reached', {
|
|
53
|
+
hadRecentThreads: context.recentThreads?.length > 0,
|
|
54
|
+
hadOnboardingTask: !!context.onboardingTask,
|
|
55
|
+
hadRecentShips: context.recentShips?.length > 0
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// If an action was taken, track it
|
|
59
|
+
if (action && action !== 'none') {
|
|
60
|
+
track('empty_inbox_action', {
|
|
61
|
+
action,
|
|
62
|
+
...context
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Track lurk mode state change
|
|
69
|
+
* @param {boolean} enabled - Whether lurk mode was enabled or disabled
|
|
70
|
+
*/
|
|
71
|
+
function trackLurkMode(enabled) {
|
|
72
|
+
track(enabled ? 'lurk_mode_enabled' : 'lurk_mode_disabled', {});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Track onboarding task completion
|
|
77
|
+
* @param {string} taskId - The task that was completed
|
|
78
|
+
*/
|
|
79
|
+
function trackOnboardingTask(taskId) {
|
|
80
|
+
track('onboarding_task_completed', { taskId });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Track discovery initiation
|
|
85
|
+
* @param {string} source - Where discovery was initiated from (inbox, start, etc.)
|
|
86
|
+
*/
|
|
87
|
+
function trackDiscovery(source) {
|
|
88
|
+
track('discovery_initiated', { source });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Track session lifecycle
|
|
93
|
+
* @param {string} event - 'started' or 'ended'
|
|
94
|
+
* @param {object} sessionData - Session metrics (duration, actions, etc.)
|
|
95
|
+
*/
|
|
96
|
+
function trackSession(event, sessionData = {}) {
|
|
97
|
+
track(event === 'started' ? 'session_started' : 'session_ended', sessionData);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = {
|
|
101
|
+
track,
|
|
102
|
+
trackEmptyInbox,
|
|
103
|
+
trackLurkMode,
|
|
104
|
+
trackOnboardingTask,
|
|
105
|
+
trackDiscovery,
|
|
106
|
+
trackSession
|
|
107
|
+
};
|
package/config.js
CHANGED
|
@@ -66,7 +66,15 @@ function save(config) {
|
|
|
66
66
|
publicKey: config.publicKey || existing.publicKey || null,
|
|
67
67
|
privateKey: config.privateKey || existing.privateKey || null,
|
|
68
68
|
// Guided mode (AskUserQuestion menus)
|
|
69
|
-
guided_mode: config.guided_mode !== undefined ? config.guided_mode : existing.guided_mode
|
|
69
|
+
guided_mode: config.guided_mode !== undefined ? config.guided_mode : existing.guided_mode,
|
|
70
|
+
// Notification level
|
|
71
|
+
notifications: config.notifications || existing.notifications || null,
|
|
72
|
+
// GitHub Activity settings
|
|
73
|
+
github_activity_enabled: config.github_activity_enabled !== undefined ? config.github_activity_enabled : existing.github_activity_enabled,
|
|
74
|
+
github_activity_privacy: config.github_activity_privacy || existing.github_activity_privacy || null,
|
|
75
|
+
// Privy OAuth token (persisted across MCP process restarts)
|
|
76
|
+
privyToken: config.privyToken || existing.privyToken || null,
|
|
77
|
+
authMethod: config.authMethod || existing.authMethod || null
|
|
70
78
|
};
|
|
71
79
|
fs.writeFileSync(PRIMARY_CONFIG, JSON.stringify(data, null, 2));
|
|
72
80
|
}
|
|
@@ -203,8 +211,80 @@ function setAuthToken(token, sessionId = null) {
|
|
|
203
211
|
}
|
|
204
212
|
|
|
205
213
|
function getAuthToken() {
|
|
214
|
+
// First check session data
|
|
215
|
+
const data = getSessionData();
|
|
216
|
+
if (data?.token) return data.token;
|
|
217
|
+
|
|
218
|
+
// Fall back to shared config (persisted across MCP process restarts)
|
|
219
|
+
const cfg = load();
|
|
220
|
+
return cfg?.privyToken || null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Save Privy JWT token (used after browser OAuth flow)
|
|
225
|
+
* @param {string} token - Privy access token
|
|
226
|
+
*/
|
|
227
|
+
function savePrivyToken(token) {
|
|
228
|
+
// Save to session data
|
|
229
|
+
const data = getSessionData() || {};
|
|
230
|
+
saveSessionData({
|
|
231
|
+
...data,
|
|
232
|
+
sessionId: data.sessionId || generateSessionId(),
|
|
233
|
+
token,
|
|
234
|
+
authMethod: 'privy' // Track that this is a Privy token
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Also save to shared config for persistence across MCP restarts
|
|
238
|
+
const cfg = load();
|
|
239
|
+
cfg.privyToken = token;
|
|
240
|
+
cfg.authMethod = 'privy';
|
|
241
|
+
save(cfg);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check if user has Privy auth (vs legacy keypair)
|
|
246
|
+
* Accepts both 'privy' and 'browser' as valid auth methods
|
|
247
|
+
*/
|
|
248
|
+
function hasPrivyAuth() {
|
|
249
|
+
const validAuthMethods = ['privy', 'browser'];
|
|
250
|
+
|
|
206
251
|
const data = getSessionData();
|
|
207
|
-
|
|
252
|
+
if (validAuthMethods.includes(data?.authMethod) && data?.token) return true;
|
|
253
|
+
|
|
254
|
+
const cfg = load();
|
|
255
|
+
return validAuthMethods.includes(cfg?.authMethod) && cfg?.privyToken;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Remove keypair after migration to Privy
|
|
260
|
+
* Clears private key from config (security improvement)
|
|
261
|
+
*/
|
|
262
|
+
function removeKeypair() {
|
|
263
|
+
const cfg = load();
|
|
264
|
+
delete cfg.publicKey;
|
|
265
|
+
delete cfg.privateKey;
|
|
266
|
+
save(cfg);
|
|
267
|
+
|
|
268
|
+
// Also clear from session
|
|
269
|
+
const data = getSessionData();
|
|
270
|
+
if (data) {
|
|
271
|
+
delete data.publicKey;
|
|
272
|
+
delete data.privateKey;
|
|
273
|
+
saveSessionData(data);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get auth URL for browser-based GitHub OAuth
|
|
279
|
+
* @param {string|null} handle - Custom handle (optional - defaults to GitHub username)
|
|
280
|
+
*/
|
|
281
|
+
function getAuthUrl(handle = null) {
|
|
282
|
+
const apiUrl = getApiUrl();
|
|
283
|
+
if (handle) {
|
|
284
|
+
return `${apiUrl}/api/auth/github?handle=${encodeURIComponent(handle)}`;
|
|
285
|
+
}
|
|
286
|
+
// No handle = use GitHub username as handle
|
|
287
|
+
return `${apiUrl}/api/auth/github`;
|
|
208
288
|
}
|
|
209
289
|
|
|
210
290
|
function clearSession() {
|
|
@@ -228,6 +308,81 @@ function setGuidedMode(enabled) {
|
|
|
228
308
|
save(config);
|
|
229
309
|
}
|
|
230
310
|
|
|
311
|
+
// Notification settings
|
|
312
|
+
// Levels: "all" | "mentions" | "off"
|
|
313
|
+
// - all: desktop + bell for unread, mentions, presence (default)
|
|
314
|
+
// - mentions: only @mentions trigger notifications
|
|
315
|
+
// - off: no notifications
|
|
316
|
+
function getNotifications() {
|
|
317
|
+
const config = load();
|
|
318
|
+
return config.notifications || 'all';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function setNotifications(level) {
|
|
322
|
+
const validLevels = ['all', 'mentions', 'off'];
|
|
323
|
+
if (!validLevels.includes(level)) {
|
|
324
|
+
throw new Error(`Invalid notification level. Use: ${validLevels.join(', ')}`);
|
|
325
|
+
}
|
|
326
|
+
const config = load();
|
|
327
|
+
config.notifications = level;
|
|
328
|
+
save(config);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// GitHub Activity settings
|
|
332
|
+
// Shows shipping status based on GitHub commit activity
|
|
333
|
+
// Default: false (opt-in for privacy)
|
|
334
|
+
function getGithubActivityEnabled() {
|
|
335
|
+
const config = load();
|
|
336
|
+
return config.github_activity_enabled === true;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function setGithubActivityEnabled(enabled) {
|
|
340
|
+
const config = load();
|
|
341
|
+
config.github_activity_enabled = enabled;
|
|
342
|
+
save(config);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// GitHub Activity privacy level
|
|
346
|
+
// Levels: "full" | "status_only" | "off"
|
|
347
|
+
// - full: Show repos, commit counts, tech stack (default when enabled)
|
|
348
|
+
// - status_only: Just show shipping badge (🔥/⚡), no details
|
|
349
|
+
// - off: Disabled completely
|
|
350
|
+
function getGithubActivityPrivacy() {
|
|
351
|
+
const config = load();
|
|
352
|
+
return config.github_activity_privacy || 'full';
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function setGithubActivityPrivacy(level) {
|
|
356
|
+
const validLevels = ['full', 'status_only', 'off'];
|
|
357
|
+
if (!validLevels.includes(level)) {
|
|
358
|
+
throw new Error(`Invalid privacy level. Use: ${validLevels.join(', ')}`);
|
|
359
|
+
}
|
|
360
|
+
const config = load();
|
|
361
|
+
config.github_activity_privacy = level;
|
|
362
|
+
save(config);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// API URL — central endpoint for all API calls
|
|
366
|
+
function getApiUrl() {
|
|
367
|
+
return process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ─────────────────────────────────────────────────────────────
|
|
371
|
+
// Generic key-value store for ephemeral session state
|
|
372
|
+
// Used by presence-agent, mute, and other tools for runtime state
|
|
373
|
+
// NOT persisted to disk — resets when MCP server restarts
|
|
374
|
+
// ─────────────────────────────────────────────────────────────
|
|
375
|
+
const sessionState = {};
|
|
376
|
+
|
|
377
|
+
function get(key, defaultValue = null) {
|
|
378
|
+
return sessionState[key] !== undefined ? sessionState[key] : defaultValue;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function set(key, value) {
|
|
382
|
+
sessionState[key] = value;
|
|
383
|
+
return value;
|
|
384
|
+
}
|
|
385
|
+
|
|
231
386
|
module.exports = {
|
|
232
387
|
VIBE_DIR,
|
|
233
388
|
CONFIG_FILE,
|
|
@@ -248,5 +403,21 @@ module.exports = {
|
|
|
248
403
|
clearSession,
|
|
249
404
|
generateSessionId,
|
|
250
405
|
getGuidedMode,
|
|
251
|
-
setGuidedMode
|
|
406
|
+
setGuidedMode,
|
|
407
|
+
getNotifications,
|
|
408
|
+
setNotifications,
|
|
409
|
+
// GitHub Activity settings
|
|
410
|
+
getGithubActivityEnabled,
|
|
411
|
+
setGithubActivityEnabled,
|
|
412
|
+
getGithubActivityPrivacy,
|
|
413
|
+
setGithubActivityPrivacy,
|
|
414
|
+
getApiUrl,
|
|
415
|
+
// Privy OAuth helpers
|
|
416
|
+
savePrivyToken,
|
|
417
|
+
hasPrivyAuth,
|
|
418
|
+
removeKeypair,
|
|
419
|
+
getAuthUrl,
|
|
420
|
+
// Generic key-value for ephemeral session state
|
|
421
|
+
get,
|
|
422
|
+
set
|
|
252
423
|
};
|
package/index.js
CHANGED
|
@@ -10,9 +10,11 @@ const presence = require('./presence');
|
|
|
10
10
|
const config = require('./config');
|
|
11
11
|
const store = require('./store');
|
|
12
12
|
const prompts = require('./prompts');
|
|
13
|
+
const NotificationEmitter = require('./notification-emitter');
|
|
14
|
+
const authStore = require('./auth-store');
|
|
13
15
|
|
|
14
16
|
// Tools that shouldn't show presence footer (would be redundant/noisy)
|
|
15
|
-
const SKIP_FOOTER_TOOLS = ['vibe_init', 'vibe_doctor', 'vibe_test', 'vibe_update'];
|
|
17
|
+
const SKIP_FOOTER_TOOLS = ['vibe_init', 'vibe_doctor', 'vibe_test', 'vibe_update', 'vibe_settings', 'vibe_notifications'];
|
|
16
18
|
|
|
17
19
|
// Infer user prompt from tool arguments (for pattern logging)
|
|
18
20
|
function inferPromptFromArgs(toolName, args) {
|
|
@@ -35,15 +37,30 @@ function inferPromptFromArgs(toolName, args) {
|
|
|
35
37
|
case 'context': return 'share context';
|
|
36
38
|
case 'summarize': return 'summarize session';
|
|
37
39
|
case 'bye': return 'end session';
|
|
38
|
-
case 'remember': return `remember about ${handle}`;
|
|
39
|
-
case 'recall': return `recall ${handle}`;
|
|
40
|
-
case 'forget': return `forget ${handle}`;
|
|
41
40
|
case 'board': return args.content ? 'post to board' : 'view board';
|
|
41
|
+
case 'observe': return args.content ? 'record observation' : 'view observations';
|
|
42
42
|
case 'invite': return 'generate invite';
|
|
43
43
|
case 'echo': return 'send feedback';
|
|
44
44
|
case 'x_mentions': return 'check x mentions';
|
|
45
45
|
case 'x_reply': return 'reply on x';
|
|
46
46
|
case 'handoff': return `handoff task to ${handle}`;
|
|
47
|
+
case 'reserve': return args.paths ? `reserve ${args.paths.join(', ')}` : 'reserve files';
|
|
48
|
+
case 'release': return `release ${args.reservation_id || 'reservation'}`;
|
|
49
|
+
case 'reservations': return 'list reservations';
|
|
50
|
+
case 'solo_game': return `play ${args.game || 'game'}`;
|
|
51
|
+
case 'game': return `play ${args.game || 'game'} with ${handle}`;
|
|
52
|
+
case 'multiplayer_game': return `multiplayer ${args.game || 'game'}`;
|
|
53
|
+
case 'drawing': return args.action ? `drawing ${args.action}` : 'collaborative drawing';
|
|
54
|
+
case 'crossword': return `crossword ${args.action || 'daily'}`;
|
|
55
|
+
case 'discover': return `discover ${args.command || 'suggest'}`;
|
|
56
|
+
case 'suggest_tags': return `suggest tags ${args.command || 'suggest'}`;
|
|
57
|
+
case 'settings': return args.mute ? `mute for ${args.mute}` : 'view settings';
|
|
58
|
+
case 'create_artifact': return `create ${args.template || 'artifact'}: ${args.title || 'untitled'}`;
|
|
59
|
+
case 'view_artifact': return args.slug ? `view artifact ${args.slug}` : `list ${args.list || 'artifacts'}`;
|
|
60
|
+
case 'broadcast': return args.action ? `broadcast ${args.action}` : 'broadcast status';
|
|
61
|
+
case 'watch': return args.target ? `watch ${args.target}` : 'list live broadcasts';
|
|
62
|
+
case 'session': return args.action ? `session ${args.action}` : 'list sessions';
|
|
63
|
+
case 'chat': return args.message ? `chat "${args.message.slice(0, 30)}..."` : 'view chat';
|
|
47
64
|
default: return `${action} ${handle}`.trim() || null;
|
|
48
65
|
}
|
|
49
66
|
}
|
|
@@ -145,12 +162,14 @@ async function getPresenceFooter() {
|
|
|
145
162
|
}
|
|
146
163
|
}
|
|
147
164
|
|
|
148
|
-
// Load
|
|
149
|
-
const
|
|
165
|
+
// Load core tools (always available)
|
|
166
|
+
const coreTools = {
|
|
150
167
|
// Entry point
|
|
151
168
|
vibe_start: require('./tools/start'),
|
|
152
169
|
// Core
|
|
153
170
|
vibe_init: require('./tools/init'),
|
|
171
|
+
vibe_token: require('./tools/token'), // Privy OAuth token setter
|
|
172
|
+
vibe_migrate: require('./tools/migrate'), // Migrate existing handle to GitHub auth
|
|
154
173
|
vibe_who: require('./tools/who'),
|
|
155
174
|
vibe_ping: require('./tools/ping'),
|
|
156
175
|
vibe_react: require('./tools/react'),
|
|
@@ -159,25 +178,56 @@ const tools = {
|
|
|
159
178
|
vibe_open: require('./tools/open'),
|
|
160
179
|
vibe_status: require('./tools/status'),
|
|
161
180
|
vibe_context: require('./tools/context'),
|
|
181
|
+
vibe_work_summary: require('./tools/work-summary'), // Ambient context for composing messages
|
|
162
182
|
vibe_summarize: require('./tools/summarize'),
|
|
163
183
|
vibe_bye: require('./tools/bye'),
|
|
164
184
|
vibe_game: require('./tools/game'),
|
|
185
|
+
vibe_solo_game: require('./tools/solo-game'),
|
|
186
|
+
vibe_party_game: require('./tools/party-game'),
|
|
187
|
+
vibe_multiplayer_game: require('./tools/multiplayer-game'),
|
|
188
|
+
vibe_drawing: require('./tools/drawing'),
|
|
189
|
+
vibe_crossword: require('./tools/crossword'),
|
|
165
190
|
// AIRC Handoff (v1) — context portability
|
|
166
191
|
vibe_handoff: require('./tools/handoff'),
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
192
|
+
// File reservations (advisory locks)
|
|
193
|
+
vibe_reserve: require('./tools/reserve'),
|
|
194
|
+
vibe_release: require('./tools/release'),
|
|
195
|
+
vibe_reservations: require('./tools/reservations'),
|
|
196
|
+
// Memory tools removed — simplified UX
|
|
171
197
|
// Consent (AIRC compliance)
|
|
172
198
|
vibe_consent: require('./tools/consent'),
|
|
199
|
+
// Trust & Safety
|
|
200
|
+
vibe_report: require('./tools/report'),
|
|
201
|
+
// Support
|
|
202
|
+
vibe_help: require('./tools/help'),
|
|
203
|
+
vibe_agents: require('./tools/agents'),
|
|
173
204
|
// Community
|
|
174
205
|
vibe_invite: require('./tools/invite'),
|
|
175
|
-
vibe_board: require('./tools/board'),
|
|
176
206
|
vibe_submit: require('./tools/submit'),
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
207
|
+
vibe_observe: require('./tools/observe'),
|
|
208
|
+
// Creative Layer — Ideas, Requests, Ships
|
|
209
|
+
vibe_idea: require('./tools/idea'),
|
|
210
|
+
vibe_request: require('./tools/request'),
|
|
211
|
+
vibe_ship: require('./tools/ship'),
|
|
212
|
+
vibe_feed: require('./tools/feed'),
|
|
213
|
+
vibe_insights: require('./tools/insights'),
|
|
214
|
+
// Launch Analytics — Real-time metrics dashboard
|
|
215
|
+
vibe_analytics: require('./tools/analytics'),
|
|
216
|
+
// Artifacts — Just-in-time social objects
|
|
217
|
+
vibe_create_artifact: require('./tools/artifact-create'),
|
|
218
|
+
vibe_view_artifact: require('./tools/artifact-view'),
|
|
219
|
+
// Plans — Async approval workflow
|
|
220
|
+
vibe_plan: require('./tools/plan'),
|
|
221
|
+
vibe_approve: require('./tools/approve'),
|
|
222
|
+
// Discovery & Matchmaking
|
|
223
|
+
vibe_discover: require('./tools/discover'),
|
|
224
|
+
vibe_suggest_tags: require('./tools/suggest-tags'),
|
|
225
|
+
// Follow system
|
|
226
|
+
vibe_follow: require('./tools/follow'),
|
|
227
|
+
// GitHub friends import (Plaxo move)
|
|
228
|
+
vibe_friends: require('./tools/friends'),
|
|
229
|
+
// Scheduling
|
|
230
|
+
vibe_schedule: require('./tools/schedule'),
|
|
181
231
|
// @echo feedback agent (by Flynn)
|
|
182
232
|
vibe_echo: require('./tools/echo'),
|
|
183
233
|
// X/Twitter bridge
|
|
@@ -186,19 +236,83 @@ const tools = {
|
|
|
186
236
|
// Unified social inbox (Phase 1a)
|
|
187
237
|
vibe_social_inbox: require('./tools/social-inbox'),
|
|
188
238
|
vibe_social_post: require('./tools/social-post'),
|
|
189
|
-
//
|
|
190
|
-
|
|
239
|
+
// Settings
|
|
240
|
+
vibe_settings: require('./tools/settings'),
|
|
241
|
+
// External notification channels
|
|
242
|
+
vibe_notifications: require('./tools/notifications'),
|
|
243
|
+
// Background presence agent (Claude Code 2.1)
|
|
244
|
+
vibe_presence_agent: require('./tools/presence-agent'),
|
|
245
|
+
// Onboarding checklist
|
|
246
|
+
vibe_onboarding: require('./tools/onboarding'),
|
|
247
|
+
// VIBE L2 tools
|
|
248
|
+
vibe_l2: require('./tools/l2'),
|
|
249
|
+
vibe_l2_status: require('./tools/l2-status'),
|
|
250
|
+
vibe_shipback: require('./tools/shipback'),
|
|
251
|
+
vibe_bridge: require('./tools/l2-bridge'),
|
|
252
|
+
// Gig Marketplace & Proof-of-Work
|
|
253
|
+
vibe_gig_browse: require('./tools/gig-browse'),
|
|
254
|
+
vibe_gig_complete: require('./tools/gig-complete'),
|
|
255
|
+
vibe_proof_of_work: require('./tools/proof-of-work'),
|
|
256
|
+
vibe_artifacts_price: require('./tools/artifacts-price'),
|
|
257
|
+
// Watch Me Code — Live broadcasting & sessions
|
|
258
|
+
vibe_broadcast: require('./tools/broadcast'),
|
|
259
|
+
vibe_watch: require('./tools/watch'),
|
|
260
|
+
vibe_session: require('./tools/session'),
|
|
261
|
+
vibe_chat: require('./tools/chat'),
|
|
262
|
+
// Help Signal — Symbiosis layer
|
|
263
|
+
vibe_stuck: require('./tools/stuck'),
|
|
264
|
+
// VIBE Economy — Earnings, Withdrawals, Subscriptions
|
|
265
|
+
vibe_earnings: require('./tools/earnings'),
|
|
266
|
+
vibe_withdraw: require('./tools/withdraw'),
|
|
267
|
+
vibe_session_price: require('./tools/session_price'),
|
|
268
|
+
vibe_subscribe: require('./tools/subscribe'),
|
|
269
|
+
vibe_subscriptions: require('./tools/subscriptions')
|
|
191
270
|
};
|
|
192
271
|
|
|
272
|
+
// Admin tools (only loaded when VIBE_ADMIN=true)
|
|
273
|
+
const adminTools = process.env.VIBE_ADMIN === 'true' ? {
|
|
274
|
+
vibe_admin_inbox: require('./tools/admin-inbox'),
|
|
275
|
+
vibe_test: require('./tools/test'),
|
|
276
|
+
vibe_doctor: require('./tools/doctor'),
|
|
277
|
+
vibe_update: require('./tools/update'),
|
|
278
|
+
vibe_patterns: require('./tools/patterns'),
|
|
279
|
+
} : {};
|
|
280
|
+
|
|
281
|
+
// Combine tools
|
|
282
|
+
const tools = { ...coreTools, ...adminTools };
|
|
283
|
+
|
|
193
284
|
/**
|
|
194
285
|
* MCP Protocol Handler
|
|
195
286
|
*/
|
|
196
287
|
class VibeMCPServer {
|
|
197
288
|
constructor() {
|
|
289
|
+
// Hydrate auth state from disk FIRST (before any tools need it)
|
|
290
|
+
authStore.hydrate();
|
|
291
|
+
|
|
292
|
+
// Initialize notification emitter
|
|
293
|
+
this.notifier = new NotificationEmitter(this);
|
|
294
|
+
|
|
295
|
+
// Make notifier globally accessible for tools and store layer
|
|
296
|
+
global.vibeNotifier = this.notifier;
|
|
297
|
+
|
|
198
298
|
// Start presence heartbeat
|
|
199
299
|
presence.start();
|
|
200
300
|
}
|
|
201
301
|
|
|
302
|
+
/**
|
|
303
|
+
* Send MCP notification
|
|
304
|
+
* Called by NotificationEmitter to push list_changed events
|
|
305
|
+
*/
|
|
306
|
+
notification(payload) {
|
|
307
|
+
// Send notification via stdout (MCP protocol)
|
|
308
|
+
const notification = {
|
|
309
|
+
jsonrpc: '2.0',
|
|
310
|
+
method: payload.method,
|
|
311
|
+
params: payload.params || {}
|
|
312
|
+
};
|
|
313
|
+
process.stdout.write(JSON.stringify(notification) + '\n');
|
|
314
|
+
}
|
|
315
|
+
|
|
202
316
|
async handleRequest(request) {
|
|
203
317
|
const { method, params, id } = request;
|
|
204
318
|
|
|
@@ -252,34 +366,32 @@ class VibeMCPServer {
|
|
|
252
366
|
|
|
253
367
|
const result = await tool.handler(args);
|
|
254
368
|
|
|
369
|
+
// Emit list_changed notification for state-changing tools
|
|
370
|
+
// This triggers Claude to refresh without reconnection
|
|
371
|
+
const stateChangingTools = [
|
|
372
|
+
'vibe_dm', 'vibe_ping', 'vibe_react',
|
|
373
|
+
'vibe_status', 'vibe_context', 'vibe_handoff',
|
|
374
|
+
'vibe_reserve', 'vibe_release',
|
|
375
|
+
'vibe_broadcast', 'vibe_session', 'vibe_chat'
|
|
376
|
+
];
|
|
377
|
+
if (stateChangingTools.includes(params.name)) {
|
|
378
|
+
// Debounced notification (prevents spam)
|
|
379
|
+
global.vibeNotifier?.emitChange(params.name);
|
|
380
|
+
}
|
|
381
|
+
|
|
255
382
|
// Add ambient presence footer (unless tool is in skip list)
|
|
256
383
|
let footer = '';
|
|
257
384
|
if (!SKIP_FOOTER_TOOLS.includes(params.name)) {
|
|
258
385
|
footer = await getPresenceFooter();
|
|
259
386
|
}
|
|
260
387
|
|
|
261
|
-
// Build hint indicator for Claude to trigger dashboard flows
|
|
262
|
-
let hintIndicator = '';
|
|
263
|
-
if (result.hint || result.actions) {
|
|
264
|
-
const hintData = {
|
|
265
|
-
...(result.hint && { hint: result.hint }),
|
|
266
|
-
...(result.suggestion && { suggestion: result.suggestion }),
|
|
267
|
-
...(result.unread_count && { unread_count: result.unread_count }),
|
|
268
|
-
...(result.for_handle && { for_handle: result.for_handle }),
|
|
269
|
-
...(result.memories && { memories: result.memories }),
|
|
270
|
-
...(result.threads && { threads: result.threads }),
|
|
271
|
-
...(result.actions && { actions: result.actions })
|
|
272
|
-
};
|
|
273
|
-
hintIndicator = `\n\n<!-- vibe:dashboard ${JSON.stringify(hintData)} -->`;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
388
|
return {
|
|
277
389
|
jsonrpc: '2.0',
|
|
278
390
|
id,
|
|
279
391
|
result: {
|
|
280
392
|
content: [{
|
|
281
393
|
type: 'text',
|
|
282
|
-
text: (result.display || JSON.stringify(result, null, 2)) +
|
|
394
|
+
text: (result.display || JSON.stringify(result, null, 2)) + footer
|
|
283
395
|
}]
|
|
284
396
|
}
|
|
285
397
|
};
|
|
@@ -333,9 +445,26 @@ class VibeMCPServer {
|
|
|
333
445
|
process.stderr.write('vibe init → set identity\n');
|
|
334
446
|
process.stderr.write('vibe who → see who\'s around\n');
|
|
335
447
|
process.stderr.write('vibe dm → send a message\n\n');
|
|
448
|
+
|
|
449
|
+
// Check for updates (non-blocking)
|
|
450
|
+
this.checkForUpdates();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async checkForUpdates() {
|
|
454
|
+
try {
|
|
455
|
+
const { checkForUpdates, formatUpdateNotification } = await import('./auto-update.js');
|
|
456
|
+
const update = await checkForUpdates();
|
|
457
|
+
|
|
458
|
+
if (update) {
|
|
459
|
+
const notification = formatUpdateNotification(update);
|
|
460
|
+
process.stderr.write(notification);
|
|
461
|
+
}
|
|
462
|
+
} catch (error) {
|
|
463
|
+
// Silent fail - don't block startup
|
|
464
|
+
}
|
|
336
465
|
}
|
|
337
466
|
}
|
|
338
467
|
|
|
339
468
|
// Start
|
|
340
469
|
const server = new VibeMCPServer();
|
|
341
|
-
server.start();
|
|
470
|
+
server.start();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intelligence Module — Ambient Social Awareness
|
|
3
|
+
*
|
|
4
|
+
* Five layers of intelligence:
|
|
5
|
+
* 1. Infer — Smart state detection from context signals
|
|
6
|
+
* 2. Serendipity — Surface meaningful coincidences
|
|
7
|
+
* 3. Proactive — Background agent for social moments
|
|
8
|
+
* 4. Patterns — Persistent behavioral memory (work, social, creative)
|
|
9
|
+
* 5. Interests — Live interest inference from context (Phase 2)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const infer = require('./infer');
|
|
13
|
+
const serendipity = require('./serendipity');
|
|
14
|
+
const proactive = require('./proactive');
|
|
15
|
+
const patterns = require('./patterns');
|
|
16
|
+
const interests = require('./interests');
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
// Inference
|
|
20
|
+
inferState: infer.inferState,
|
|
21
|
+
enhanceUserWithInference: infer.enhanceUserWithInference,
|
|
22
|
+
enhanceUsersWithInference: infer.enhanceUsersWithInference,
|
|
23
|
+
STATES: infer.STATES,
|
|
24
|
+
|
|
25
|
+
// Serendipity
|
|
26
|
+
findSerendipity: serendipity.findSerendipity,
|
|
27
|
+
getTopSerendipity: serendipity.getTopSerendipity,
|
|
28
|
+
getAllSerendipity: serendipity.getAllSerendipity,
|
|
29
|
+
|
|
30
|
+
// Proactive
|
|
31
|
+
generateProactiveSuggestions: proactive.generateProactiveSuggestions,
|
|
32
|
+
getProactiveSummary: proactive.getProactiveSummary,
|
|
33
|
+
checkProactiveOpportunities: proactive.checkProactiveOpportunities,
|
|
34
|
+
markAway: proactive.markAway,
|
|
35
|
+
markBack: proactive.markBack,
|
|
36
|
+
setSessionStart: proactive.setSessionStart,
|
|
37
|
+
|
|
38
|
+
// Patterns (persistent behavioral memory)
|
|
39
|
+
patterns,
|
|
40
|
+
|
|
41
|
+
// Interests (live context inference - Phase 2)
|
|
42
|
+
inferLiveInterests: interests.inferLiveInterests,
|
|
43
|
+
mergeInterests: interests.mergeInterests,
|
|
44
|
+
formatLiveInterests: interests.formatLiveInterests
|
|
45
|
+
};
|