slashvibe-mcp 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +41 -58
  2. package/analytics.js +107 -0
  3. package/auth-store.js +148 -0
  4. package/auto-update.js +125 -0
  5. package/config.js +5 -2
  6. package/games/arcade.js +406 -0
  7. package/games/chess.js +451 -0
  8. package/games/colorguess.js +343 -0
  9. package/games/crossword-words.js +171 -0
  10. package/games/crossword.js +461 -0
  11. package/games/drawing.js +347 -0
  12. package/games/gameroulette.js +300 -0
  13. package/games/gamerouter.js +336 -0
  14. package/games/gamestatus.js +337 -0
  15. package/games/guessnumber.js +209 -0
  16. package/games/hangman.js +279 -0
  17. package/games/memory.js +338 -0
  18. package/games/multiplayer-tictactoe.js +389 -0
  19. package/games/pixelart.js +399 -0
  20. package/games/quickduel.js +354 -0
  21. package/games/riddle.js +371 -0
  22. package/games/rockpaperscissors.js +291 -0
  23. package/games/snake.js +406 -0
  24. package/games/storybuilder.js +343 -0
  25. package/games/tictactoe.js +345 -0
  26. package/games/twentyquestions.js +286 -0
  27. package/games/twotruths.js +207 -0
  28. package/games/werewolf.js +508 -0
  29. package/games/wordassociation.js +247 -0
  30. package/games/wordchain.js +135 -0
  31. package/index.js +60 -51
  32. package/intelligence/index.js +9 -2
  33. package/intelligence/interests.js +369 -0
  34. package/notification-emitter.js +77 -0
  35. package/package.json +10 -3
  36. package/store/api.js +109 -4
  37. package/store/profiles.js +160 -12
  38. package/tools/_actions.js +230 -17
  39. package/tools/_discovery.js +119 -26
  40. package/tools/_shared/index.js +64 -0
  41. package/tools/_work-context.js +338 -0
  42. package/tools/_work-context.manual-test.js +199 -0
  43. package/tools/_work-context.test.js +260 -0
  44. package/tools/analytics.js +191 -0
  45. package/tools/approve.js +197 -0
  46. package/tools/artifact-create.js +14 -3
  47. package/tools/artifacts-price.js +107 -0
  48. package/tools/broadcast.js +286 -0
  49. package/tools/chat.js +202 -0
  50. package/tools/discover.js +314 -34
  51. package/tools/dm.js +22 -5
  52. package/tools/earnings.js +126 -0
  53. package/tools/feed.js +22 -3
  54. package/tools/follow.js +224 -0
  55. package/tools/friends.js +192 -0
  56. package/tools/gig-browse.js +206 -0
  57. package/tools/gig-complete.js +139 -0
  58. package/tools/help.js +2 -2
  59. package/tools/idea.js +8 -1
  60. package/tools/inbox.js +248 -105
  61. package/tools/init.js +52 -9
  62. package/tools/open.js +42 -5
  63. package/tools/plan.js +225 -0
  64. package/tools/proof-of-work.js +139 -0
  65. package/tools/request.js +16 -2
  66. package/tools/schedule.js +367 -0
  67. package/tools/session.js +420 -0
  68. package/tools/session_price.js +128 -0
  69. package/tools/settings.js +90 -2
  70. package/tools/ship.js +8 -2
  71. package/tools/start.js +96 -3
  72. package/tools/status.js +53 -6
  73. package/tools/stuck.js +297 -0
  74. package/tools/subscribe.js +148 -0
  75. package/tools/subscriptions.js +134 -0
  76. package/tools/suggest-tags.js +6 -8
  77. package/tools/update.js +1 -1
  78. package/tools/watch.js +157 -0
  79. package/tools/withdraw.js +145 -0
  80. package/tools/work-summary.js +96 -0
  81. package/LICENSE +0 -21
package/README.md CHANGED
@@ -1,87 +1,70 @@
1
- # /vibe MCP Server
1
+ # vibe-mcp
2
2
 
3
- The social layer for Claude Code. DMs, presence, and connection between AI developers.
4
-
5
- ## What is /vibe?
6
-
7
- /vibe brings social connection to the terminal. While you're building with Claude Code, /vibe lets you:
8
-
9
- - **See who's online** - Know when other developers are in flow
10
- - **Send DMs** - Message fellow builders without leaving your terminal
11
- - **Share your presence** - Let others know what you're working on
12
- - **Build reputation** - Your sessions become proof of work
3
+ Social layer for Claude Code. DMs, presence, and connection between AI-assisted developers.
13
4
 
14
5
  ## Installation
15
6
 
16
7
  ```bash
17
- npx slashvibe-mcp
8
+ # Install globally
9
+ npm install -g vibe-mcp
10
+
11
+ # Or add to Claude Code MCP config
12
+ claude mcp add vibe-mcp
18
13
  ```
19
14
 
20
- Or add to your Claude Code MCP settings (`~/.claude.json`):
15
+ ## Manual Setup
16
+
17
+ Add to `~/.claude.json`:
21
18
 
22
19
  ```json
23
20
  {
24
21
  "mcpServers": {
25
22
  "vibe": {
26
23
  "command": "npx",
27
- "args": ["-y", "slashvibe-mcp"]
24
+ "args": ["vibe-mcp"],
25
+ "env": {
26
+ "VIBE_API_URL": "https://www.slashvibe.dev"
27
+ }
28
28
  }
29
29
  }
30
30
  }
31
31
  ```
32
32
 
33
- ## Quick Start
34
-
35
- 1. Install the MCP server
36
- 2. Authenticate: `vibe_auth` tool will guide you
37
- 3. Check who's online: `vibe_presence`
38
- 4. Send a message: `vibe_dm`
39
-
40
- ## Available Tools
33
+ ## Features
41
34
 
42
- | Tool | Description |
43
- |------|-------------|
44
- | `vibe_auth` | Authenticate with slashvibe.dev |
45
- | `vibe_presence` | See who's online now |
46
- | `vibe_dm` | Send a direct message |
47
- | `vibe_inbox` | Check your messages |
48
- | `vibe_ship` | Announce what you shipped |
49
- | `vibe_idea` | Share an idea with the community |
50
- | `vibe_discover` | Find interesting builders |
51
- | `vibe_remember` | Save context about a connection |
52
- | `vibe_recall` | Recall memories about someone |
35
+ - **Presence** - See who's online building with Claude Code
36
+ - **DMs** - Direct messages between developers
37
+ - **Memory** - Remember context about connections
38
+ - **Status** - Share what you're working on
39
+ - **Games** - Play tic-tac-toe while coding
53
40
 
54
- ## The Platform
41
+ ## Commands
55
42
 
56
- This MCP server connects to [slashvibe.dev](https://slashvibe.dev), where:
43
+ Once installed, use these in Claude Code:
57
44
 
58
- - Your identity persists across sessions
59
- - Your work builds reputation over time
60
- - The community grows through genuine connection
45
+ | Command | Description |
46
+ |---------|-------------|
47
+ | `vibe` | Check inbox and see who's online |
48
+ | `vibe who` | List online users |
49
+ | `vibe dm @handle "message"` | Send a DM |
50
+ | `vibe status shipping` | Set your status |
51
+ | `vibe remember @handle "note"` | Save a memory |
52
+ | `vibe recall @handle` | Recall memories |
61
53
 
62
- ## Philosophy
54
+ ## API
63
55
 
64
- We believe AI development should be social, not solitary. The terminal is where real work happens - decisions, debugging, breakthroughs. /vibe makes that visible and connectable.
56
+ The MCP server connects to `slashvibe.dev` for:
57
+ - User presence and discovery
58
+ - Message routing
59
+ - Identity verification
65
60
 
66
- **Empathy. Collaboration. Shared value creation.**
61
+ ## Related
67
62
 
68
- ## Contributing
69
-
70
- We welcome contributions! Please read our [Contributor License Agreement](./CLA.md) before submitting pull requests.
71
-
72
- - Report bugs via [GitHub Issues](https://github.com/VibeCodingInc/vibe-mcp/issues)
73
- - Propose features via [Discussions](https://github.com/VibeCodingInc/vibe-mcp/discussions)
74
- - Submit PRs for review
63
+ - [GitHub](https://github.com/VibeCodingInc/vibe-mcp) - Source code
64
+ - [slashvibe.dev](https://slashvibe.dev) - Web presence
65
+ - [Spirit Protocol](https://spiritprotocol.io) - Parent ecosystem
66
+ - [AIRC](https://airc.chat) - Agent identity protocol
75
67
 
76
68
  ## License
77
69
 
78
- MIT - see [LICENSE](./LICENSE)
79
-
80
- ## Links
81
-
82
- - [slashvibe.dev](https://slashvibe.dev) - The platform
83
- - [Twitter](https://twitter.com/slashvibe) - Updates
84
-
85
- ---
86
-
87
- Built with obsession by [Slash Vibe, Inc.](https://slashvibe.dev)
70
+ MIT
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/auth-store.js ADDED
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Auth Store - In-memory singleton for authentication state
3
+ *
4
+ * This is the SOURCE OF TRUTH for auth during MCP runtime.
5
+ * File persistence (config.json) is only for durability across restarts.
6
+ *
7
+ * Why this exists:
8
+ * - OAuth callback and API calls happen in the same MCP process
9
+ * - File-based auth was unreliable due to per-PID session files and caching
10
+ * - In-memory state is immediate and deterministic
11
+ *
12
+ * Usage:
13
+ * - Startup: authStore.hydrate() loads from disk once
14
+ * - OAuth: authStore.setToken(token) updates immediately
15
+ * - API calls: authStore.getToken() returns current token (no file I/O)
16
+ */
17
+
18
+ // In-memory state - the single source of truth during runtime
19
+ let _token = null;
20
+ let _handle = null;
21
+ let _oneLiner = null;
22
+ let _hydrated = false;
23
+
24
+ /**
25
+ * Hydrate auth state from disk (call once at MCP startup)
26
+ * This loads persisted state from config.json
27
+ */
28
+ function hydrate() {
29
+ if (_hydrated) return; // Only hydrate once
30
+
31
+ try {
32
+ const config = require('./config');
33
+ const cfg = config.load();
34
+
35
+ _token = cfg.privyToken || null;
36
+ _handle = cfg.handle || cfg.username || null;
37
+ _oneLiner = cfg.one_liner || cfg.workingOn || null;
38
+ _hydrated = true;
39
+
40
+ if (_token) {
41
+ console.error('[auth-store] Hydrated from disk: @' + _handle);
42
+ } else {
43
+ console.error('[auth-store] Hydrated from disk: no token');
44
+ }
45
+ } catch (e) {
46
+ console.error('[auth-store] Hydration failed:', e.message);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Set auth token (call after OAuth completes)
52
+ * @param {string} token - JWT token
53
+ */
54
+ function setToken(token) {
55
+ const hadToken = !!_token;
56
+ _token = token;
57
+
58
+ if (!hadToken && token) {
59
+ console.error('[auth-store] Token set (was empty)');
60
+ } else if (hadToken && token && token !== _token) {
61
+ console.error('[auth-store] Token updated');
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Get current auth token
67
+ * @returns {string|null} Current token or null
68
+ */
69
+ function getToken() {
70
+ return _token;
71
+ }
72
+
73
+ /**
74
+ * Set user handle
75
+ * @param {string} handle - User handle (without @)
76
+ */
77
+ function setHandle(handle) {
78
+ _handle = handle;
79
+ }
80
+
81
+ /**
82
+ * Get current handle
83
+ * @returns {string|null} Current handle or null
84
+ */
85
+ function getHandle() {
86
+ return _handle;
87
+ }
88
+
89
+ /**
90
+ * Set one-liner (what user is building)
91
+ * @param {string} oneLiner - One-liner description
92
+ */
93
+ function setOneLiner(oneLiner) {
94
+ _oneLiner = oneLiner;
95
+ }
96
+
97
+ /**
98
+ * Get current one-liner
99
+ * @returns {string|null} Current one-liner or null
100
+ */
101
+ function getOneLiner() {
102
+ return _oneLiner;
103
+ }
104
+
105
+ /**
106
+ * Check if user is authenticated
107
+ * @returns {boolean} True if token exists
108
+ */
109
+ function isAuthenticated() {
110
+ return !!_token;
111
+ }
112
+
113
+ /**
114
+ * Clear all auth state (for logout/reset)
115
+ */
116
+ function clear() {
117
+ _token = null;
118
+ _handle = null;
119
+ _oneLiner = null;
120
+ console.error('[auth-store] Cleared');
121
+ }
122
+
123
+ /**
124
+ * Get full auth state (for debugging)
125
+ * @returns {object} Current auth state
126
+ */
127
+ function getState() {
128
+ return {
129
+ token: _token ? _token.substring(0, 20) + '...' : null,
130
+ handle: _handle,
131
+ oneLiner: _oneLiner,
132
+ hydrated: _hydrated,
133
+ isAuthenticated: !!_token
134
+ };
135
+ }
136
+
137
+ module.exports = {
138
+ hydrate,
139
+ setToken,
140
+ getToken,
141
+ setHandle,
142
+ getHandle,
143
+ setOneLiner,
144
+ getOneLiner,
145
+ isAuthenticated,
146
+ clear,
147
+ getState
148
+ };
package/auto-update.js ADDED
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Auto-update mechanism for /vibe MCP server
3
+ * Checks for updates and prompts user to update
4
+ */
5
+
6
+ import { exec } from 'child_process';
7
+ import { promisify } from 'util';
8
+ import fs from 'fs/promises';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const execAsync = promisify(exec);
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+
15
+ export async function checkForUpdates() {
16
+ try {
17
+ // Read local version
18
+ const versionPath = path.join(__dirname, 'version.json');
19
+ const localVersion = JSON.parse(await fs.readFile(versionPath, 'utf-8'));
20
+
21
+ // Check remote version
22
+ const response = await fetch('https://www.slashvibe.dev/api/version', {
23
+ headers: { 'User-Agent': 'vibe-mcp-client' }
24
+ });
25
+
26
+ if (!response.ok) {
27
+ return null; // Silent fail - don't block startup
28
+ }
29
+
30
+ const remoteVersion = await response.json();
31
+
32
+ // Compare versions
33
+ if (compareVersions(remoteVersion.version, localVersion.version) > 0) {
34
+ return {
35
+ current: localVersion.version,
36
+ latest: remoteVersion.version,
37
+ changelog: remoteVersion.changelog,
38
+ features: remoteVersion.features,
39
+ breaking: remoteVersion.breaking
40
+ };
41
+ }
42
+
43
+ return null; // Up to date
44
+ } catch (error) {
45
+ // Silent fail - don't block startup
46
+ return null;
47
+ }
48
+ }
49
+
50
+ export async function performUpdate() {
51
+ try {
52
+ const repoPath = path.join(__dirname, '..');
53
+
54
+ // Check if we're in a git repo
55
+ try {
56
+ await execAsync('git rev-parse --git-dir', { cwd: repoPath });
57
+ } catch {
58
+ throw new Error('Not a git repository. Manual update required.');
59
+ }
60
+
61
+ // Stash any local changes
62
+ await execAsync('git stash', { cwd: repoPath });
63
+
64
+ // Pull latest
65
+ const { stdout, stderr } = await execAsync('git pull origin main', { cwd: repoPath });
66
+
67
+ // Pop stash if we had changes
68
+ try {
69
+ await execAsync('git stash pop', { cwd: repoPath });
70
+ } catch {
71
+ // No stash to pop, that's fine
72
+ }
73
+
74
+ return {
75
+ success: true,
76
+ output: stdout,
77
+ message: 'Update successful! Restart /vibe to apply changes.'
78
+ };
79
+ } catch (error) {
80
+ return {
81
+ success: false,
82
+ error: error.message
83
+ };
84
+ }
85
+ }
86
+
87
+ export function compareVersions(v1, v2) {
88
+ const parts1 = v1.split('.').map(Number);
89
+ const parts2 = v2.split('.').map(Number);
90
+
91
+ for (let i = 0; i < 3; i++) {
92
+ if (parts1[i] > parts2[i]) return 1;
93
+ if (parts1[i] < parts2[i]) return -1;
94
+ }
95
+
96
+ return 0;
97
+ }
98
+
99
+ export function formatUpdateNotification(update) {
100
+ if (!update) return null;
101
+
102
+ let message = `\n${'='.repeat(60)}\n`;
103
+ message += `📦 /vibe UPDATE AVAILABLE\n`;
104
+ message += `${'='.repeat(60)}\n\n`;
105
+ message += `Current: v${update.current}\n`;
106
+ message += `Latest: v${update.latest}${update.breaking ? ' ⚠️ BREAKING' : ''}\n\n`;
107
+ message += `${update.changelog}\n\n`;
108
+
109
+ if (update.features && update.features.length > 0) {
110
+ message += `New features:\n`;
111
+ update.features.forEach(f => {
112
+ message += ` • ${f}\n`;
113
+ });
114
+ message += `\n`;
115
+ }
116
+
117
+ message += `Update now:\n`;
118
+ message += ` vibe update\n`;
119
+ message += `\n`;
120
+ message += `Or manually:\n`;
121
+ message += ` cd ~/.vibe/vibe-repo && git pull origin main\n`;
122
+ message += `${'='.repeat(60)}\n`;
123
+
124
+ return message;
125
+ }
package/config.js CHANGED
@@ -243,13 +243,16 @@ function savePrivyToken(token) {
243
243
 
244
244
  /**
245
245
  * Check if user has Privy auth (vs legacy keypair)
246
+ * Accepts both 'privy' and 'browser' as valid auth methods
246
247
  */
247
248
  function hasPrivyAuth() {
249
+ const validAuthMethods = ['privy', 'browser'];
250
+
248
251
  const data = getSessionData();
249
- if (data?.authMethod === 'privy' && data?.token) return true;
252
+ if (validAuthMethods.includes(data?.authMethod) && data?.token) return true;
250
253
 
251
254
  const cfg = load();
252
- return cfg?.authMethod === 'privy' && cfg?.privyToken;
255
+ return validAuthMethods.includes(cfg?.authMethod) && cfg?.privyToken;
253
256
  }
254
257
 
255
258
  /**