slashvibe-mcp 0.3.20 → 0.3.21

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 (167) hide show
  1. package/README.md +47 -252
  2. package/analytics.js +107 -0
  3. package/auth-store.js +148 -0
  4. package/auto-update.js +130 -0
  5. package/bridges/bridge-monitor.js +388 -0
  6. package/bridges/discord-bot.js +431 -0
  7. package/bridges/farcaster.js +299 -0
  8. package/bridges/telegram.js +261 -0
  9. package/bridges/webhook-health.js +420 -0
  10. package/bridges/webhook-server.js +437 -0
  11. package/bridges/whatsapp.js +441 -0
  12. package/bridges/x-webhook.js +423 -0
  13. package/config.js +27 -15
  14. package/games/arcade.js +406 -0
  15. package/games/chess.js +451 -0
  16. package/games/colorguess.js +343 -0
  17. package/games/crossword-words.js +171 -0
  18. package/games/crossword.js +461 -0
  19. package/games/drawing.js +347 -0
  20. package/games/gameroulette.js +300 -0
  21. package/games/gamerouter.js +336 -0
  22. package/games/gamestatus.js +337 -0
  23. package/games/guessnumber.js +209 -0
  24. package/games/hangman.js +279 -0
  25. package/games/memory.js +338 -0
  26. package/games/multiplayer-tictactoe.js +389 -0
  27. package/games/pixelart.js +399 -0
  28. package/games/quickduel.js +354 -0
  29. package/games/riddle.js +371 -0
  30. package/games/rockpaperscissors.js +291 -0
  31. package/games/snake.js +406 -0
  32. package/games/storybuilder.js +343 -0
  33. package/games/tictactoe.js +345 -0
  34. package/games/twentyquestions.js +286 -0
  35. package/games/twotruths.js +207 -0
  36. package/games/werewolf.js +508 -0
  37. package/games/wordassociation.js +247 -0
  38. package/games/wordchain.js +135 -0
  39. package/index.js +116 -159
  40. package/intelligence/index.js +9 -2
  41. package/intelligence/interests.js +369 -0
  42. package/notification-emitter.js +77 -0
  43. package/notify.js +5 -1
  44. package/package.json +21 -16
  45. package/prompts.js +1 -1
  46. package/protocol/index.js +73 -0
  47. package/setup.js +480 -0
  48. package/smart-inbox.js +276 -0
  49. package/store/api.js +536 -215
  50. package/store/profiles.js +160 -12
  51. package/tools/_actions.js +362 -21
  52. package/tools/_discovery.js +119 -26
  53. package/tools/_shared/index.js +64 -0
  54. package/tools/_shared.js +234 -0
  55. package/tools/_work-context.js +338 -0
  56. package/tools/_work-context.manual-test.js +199 -0
  57. package/tools/_work-context.test.js +260 -0
  58. package/tools/activity.js +220 -0
  59. package/tools/analytics.js +191 -0
  60. package/tools/approve.js +197 -0
  61. package/tools/artifact-create.js +14 -3
  62. package/tools/artifacts-price.js +107 -0
  63. package/tools/available.js +120 -0
  64. package/tools/broadcast.js +325 -0
  65. package/tools/chat.js +202 -0
  66. package/tools/collaborative-drawing.js +1 -1
  67. package/tools/connection-status.js +178 -0
  68. package/tools/discover.js +350 -34
  69. package/tools/dm.js +80 -8
  70. package/tools/earnings.js +126 -0
  71. package/tools/feed.js +35 -4
  72. package/tools/follow.js +224 -0
  73. package/tools/friends.js +207 -0
  74. package/tools/gig-browse.js +206 -0
  75. package/tools/gig-complete.js +144 -0
  76. package/tools/health.js +87 -0
  77. package/tools/help.js +3 -3
  78. package/tools/idea.js +9 -2
  79. package/tools/inbox.js +289 -105
  80. package/tools/init.js +131 -34
  81. package/tools/invite.js +15 -4
  82. package/tools/leaderboard.js +117 -0
  83. package/tools/lib/git-apply.js +206 -0
  84. package/tools/lib/git-bundle.js +407 -0
  85. package/tools/migrate.js +3 -3
  86. package/tools/multiplayer-game.js +1 -1
  87. package/tools/onboarding.js +7 -7
  88. package/tools/open.js +143 -12
  89. package/tools/party-game.js +1 -1
  90. package/tools/plan.js +225 -0
  91. package/tools/proof-of-work.js +144 -0
  92. package/tools/reply.js +166 -0
  93. package/tools/report.js +1 -1
  94. package/tools/request.js +17 -3
  95. package/tools/schedule.js +367 -0
  96. package/tools/search-messages.js +123 -0
  97. package/tools/session.js +467 -0
  98. package/tools/session_price.js +128 -0
  99. package/tools/settings.js +90 -2
  100. package/tools/ship.js +30 -7
  101. package/tools/smart-check.js +201 -0
  102. package/tools/start.js +147 -12
  103. package/tools/status.js +53 -6
  104. package/tools/streak.js +147 -0
  105. package/tools/stuck.js +297 -0
  106. package/tools/subscribe.js +148 -0
  107. package/tools/subscriptions.js +134 -0
  108. package/tools/suggest-tags.js +6 -8
  109. package/tools/tag-suggestions.js +1 -1
  110. package/tools/tip.js +150 -77
  111. package/tools/token.js +4 -4
  112. package/tools/update.js +1 -1
  113. package/tools/wallet.js +221 -79
  114. package/tools/watch.js +157 -0
  115. package/tools/who.js +30 -1
  116. package/tools/withdraw.js +145 -0
  117. package/tools/work-summary.js +96 -0
  118. package/version.json +10 -8
  119. package/LICENSE +0 -21
  120. package/store/sqlite.js +0 -347
  121. /package/tools/{auto-suggest-connections.js → _deprecated/auto-suggest-connections.js} +0 -0
  122. /package/tools/{away.js → _deprecated/away.js} +0 -0
  123. /package/tools/{back.js → _deprecated/back.js} +0 -0
  124. /package/tools/{bootstrap-skills.js → _deprecated/bootstrap-skills.js} +0 -0
  125. /package/tools/{bridge-dashboard.js → _deprecated/bridge-dashboard.js} +0 -0
  126. /package/tools/{bridge-health.js → _deprecated/bridge-health.js} +0 -0
  127. /package/tools/{bridge-live.js → _deprecated/bridge-live.js} +0 -0
  128. /package/tools/{bridges.js → _deprecated/bridges.js} +0 -0
  129. /package/tools/{colorguess.js → _deprecated/colorguess.js} +0 -0
  130. /package/tools/{discover-insights.js → _deprecated/discover-insights.js} +0 -0
  131. /package/tools/{discover-momentum.js → _deprecated/discover-momentum.js} +0 -0
  132. /package/tools/{discovery-analytics.js → _deprecated/discovery-analytics.js} +0 -0
  133. /package/tools/{discovery-auto-suggest.js → _deprecated/discovery-auto-suggest.js} +0 -0
  134. /package/tools/{discovery-bootstrap.js → _deprecated/discovery-bootstrap.js} +0 -0
  135. /package/tools/{discovery-daily.js → _deprecated/discovery-daily.js} +0 -0
  136. /package/tools/{discovery-dashboard.js → _deprecated/discovery-dashboard.js} +0 -0
  137. /package/tools/{discovery-digest.js → _deprecated/discovery-digest.js} +0 -0
  138. /package/tools/{discovery-hub.js → _deprecated/discovery-hub.js} +0 -0
  139. /package/tools/{discovery-insights.js → _deprecated/discovery-insights.js} +0 -0
  140. /package/tools/{discovery-momentum.js → _deprecated/discovery-momentum.js} +0 -0
  141. /package/tools/{discovery-monitor.js → _deprecated/discovery-monitor.js} +0 -0
  142. /package/tools/{discovery-proactive.js → _deprecated/discovery-proactive.js} +0 -0
  143. /package/tools/{draw.js → _deprecated/draw.js} +0 -0
  144. /package/tools/{farcaster.js → _deprecated/farcaster.js} +0 -0
  145. /package/tools/{forget.js → _deprecated/forget.js} +0 -0
  146. /package/tools/{games-catalog.js → _deprecated/games-catalog.js} +0 -0
  147. /package/tools/{games.js → _deprecated/games.js} +0 -0
  148. /package/tools/{guessnumber.js → _deprecated/guessnumber.js} +0 -0
  149. /package/tools/{hangman.js → _deprecated/hangman.js} +0 -0
  150. /package/tools/{multiplayer-tictactoe.js → _deprecated/multiplayer-tictactoe.js} +0 -0
  151. /package/tools/{mute.js → _deprecated/mute.js} +0 -0
  152. /package/tools/{recall.js → _deprecated/recall.js} +0 -0
  153. /package/tools/{remember.js → _deprecated/remember.js} +0 -0
  154. /package/tools/{riddle.js → _deprecated/riddle.js} +0 -0
  155. /package/tools/{run-bootstrap.js → _deprecated/run-bootstrap.js} +0 -0
  156. /package/tools/{skills-analytics.js → _deprecated/skills-analytics.js} +0 -0
  157. /package/tools/{skills-bootstrap.js → _deprecated/skills-bootstrap.js} +0 -0
  158. /package/tools/{skills-dashboard.js → _deprecated/skills-dashboard.js} +0 -0
  159. /package/tools/{skills-exchange.js → _deprecated/skills-exchange.js} +0 -0
  160. /package/tools/{skills.js → _deprecated/skills.js} +0 -0
  161. /package/tools/{smart-intro.js → _deprecated/smart-intro.js} +0 -0
  162. /package/tools/{storybuilder.js → _deprecated/storybuilder.js} +0 -0
  163. /package/tools/{telegram-bot.js → _deprecated/telegram-bot.js} +0 -0
  164. /package/tools/{telegram-setup.js → _deprecated/telegram-setup.js} +0 -0
  165. /package/tools/{tictactoe.js → _deprecated/tictactoe.js} +0 -0
  166. /package/tools/{twentyquestions.js → _deprecated/twentyquestions.js} +0 -0
  167. /package/tools/{wordassociation.js → _deprecated/wordassociation.js} +0 -0
package/setup.js ADDED
@@ -0,0 +1,480 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * vibe setup — One-click installation for /vibe MCP server
5
+ *
6
+ * Usage: npx slashvibe-mcp setup
7
+ *
8
+ * What it does:
9
+ * 1. Detects Claude Code config location (~/.claude.json or ~/claude_desktop_config.json)
10
+ * 2. Adds /vibe MCP server to the config
11
+ * 3. Tests the connection
12
+ * 4. Opens browser for GitHub auth
13
+ *
14
+ * Result: User is fully set up in ~30 seconds
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const os = require('os');
20
+ const { exec, execSync } = require('child_process');
21
+ const http = require('http');
22
+
23
+ // ANSI colors for terminal output
24
+ const colors = {
25
+ reset: '\x1b[0m',
26
+ green: '\x1b[32m',
27
+ cyan: '\x1b[36m',
28
+ yellow: '\x1b[33m',
29
+ red: '\x1b[31m',
30
+ bold: '\x1b[1m',
31
+ dim: '\x1b[2m'
32
+ };
33
+
34
+ const CALLBACK_PORT = 9876;
35
+ const API_BASE = 'https://www.slashvibe.dev';
36
+ const LOGIN_URL = 'https://www.slashvibe.dev/login';
37
+
38
+ /**
39
+ * Print styled banner
40
+ */
41
+ function printBanner() {
42
+ console.log(`
43
+ ${colors.green} █░█ █ █▄▄ █▀▀${colors.reset}
44
+ ${colors.green} ▀▄▀ █ █▄█ ██▄${colors.reset} ${colors.dim}ship together${colors.reset}
45
+ ──────────────────────────────────────────────────
46
+ `);
47
+ }
48
+
49
+ /**
50
+ * Print step with status
51
+ */
52
+ function printStep(num, text, status = 'pending') {
53
+ const statusIcon = {
54
+ pending: colors.dim + '○' + colors.reset,
55
+ running: colors.yellow + '◐' + colors.reset,
56
+ done: colors.green + '●' + colors.reset,
57
+ error: colors.red + '✗' + colors.reset
58
+ }[status];
59
+
60
+ console.log(` ${statusIcon} ${colors.bold}Step ${num}:${colors.reset} ${text}`);
61
+ }
62
+
63
+ /**
64
+ * Find Claude Code config file
65
+ */
66
+ function findClaudeConfig() {
67
+ const homeDir = os.homedir();
68
+
69
+ // Possible config locations
70
+ const configPaths = [
71
+ path.join(homeDir, '.claude.json'),
72
+ path.join(homeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
73
+ path.join(homeDir, '.config', 'claude', 'config.json'),
74
+ path.join(homeDir, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json')
75
+ ];
76
+
77
+ for (const configPath of configPaths) {
78
+ if (fs.existsSync(configPath)) {
79
+ return configPath;
80
+ }
81
+ }
82
+
83
+ // Default to ~/.claude.json (will create if doesn't exist)
84
+ return path.join(homeDir, '.claude.json');
85
+ }
86
+
87
+ /**
88
+ * Load existing config or create default
89
+ */
90
+ function loadConfig(configPath) {
91
+ try {
92
+ if (fs.existsSync(configPath)) {
93
+ const content = fs.readFileSync(configPath, 'utf8');
94
+ return JSON.parse(content);
95
+ }
96
+ } catch (e) {
97
+ console.log(`${colors.yellow} Warning: Could not parse existing config, creating new one${colors.reset}`);
98
+ }
99
+
100
+ // Default config structure
101
+ return {};
102
+ }
103
+
104
+ /**
105
+ * Add /vibe MCP server to config
106
+ */
107
+ function addVibeToConfig(config) {
108
+ // Initialize mcpServers if not present
109
+ if (!config.mcpServers) {
110
+ config.mcpServers = {};
111
+ }
112
+
113
+ // Check if already configured
114
+ if (config.mcpServers.vibe) {
115
+ return { added: false, alreadyExists: true };
116
+ }
117
+
118
+ // Add vibe MCP server
119
+ config.mcpServers.vibe = {
120
+ command: 'npx',
121
+ args: ['slashvibe-mcp'],
122
+ env: {
123
+ VIBE_API_URL: 'https://www.slashvibe.dev'
124
+ }
125
+ };
126
+
127
+ return { added: true, alreadyExists: false };
128
+ }
129
+
130
+ /**
131
+ * Save config to file
132
+ */
133
+ function saveConfig(configPath, config) {
134
+ const content = JSON.stringify(config, null, 2);
135
+ fs.writeFileSync(configPath, content, 'utf8');
136
+ }
137
+
138
+ /**
139
+ * Test API connection
140
+ */
141
+ async function testConnection() {
142
+ try {
143
+ const response = await fetch(`${API_BASE}/api/health`);
144
+ const data = await response.json();
145
+ return data.status === 'ok' || data.success;
146
+ } catch (e) {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Get online count
153
+ */
154
+ async function getOnlineCount() {
155
+ try {
156
+ const response = await fetch(`${API_BASE}/api/presence`);
157
+ const data = await response.json();
158
+ return (data.active?.length || 0) + (data.away?.length || 0);
159
+ } catch (e) {
160
+ return 0;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Get online users with details for display
166
+ */
167
+ async function getOnlineUsers() {
168
+ try {
169
+ const response = await fetch(`${API_BASE}/api/presence`);
170
+ const data = await response.json();
171
+ const active = data.active || [];
172
+ const away = data.away || [];
173
+
174
+ // Format: { users: [{handle, status, one_liner}], total: number }
175
+ const users = [
176
+ ...active.slice(0, 5).map(u => ({
177
+ handle: u.username || u.handle,
178
+ status: 'active',
179
+ one_liner: u.one_liner || u.status || ''
180
+ })),
181
+ ...away.slice(0, 2).map(u => ({
182
+ handle: u.username || u.handle,
183
+ status: 'away',
184
+ one_liner: u.one_liner || u.status || ''
185
+ }))
186
+ ].slice(0, 5);
187
+
188
+ return { users, total: active.length + away.length };
189
+ } catch (e) {
190
+ return { users: [], total: 0 };
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Open URL in browser
196
+ */
197
+ function openBrowser(url) {
198
+ const platform = process.platform;
199
+ let command;
200
+
201
+ if (platform === 'darwin') {
202
+ command = `open "${url}"`;
203
+ } else if (platform === 'win32') {
204
+ command = `start "" "${url}"`;
205
+ } else {
206
+ command = `xdg-open "${url}"`;
207
+ }
208
+
209
+ exec(command, (err) => {
210
+ if (err) {
211
+ console.log(`${colors.yellow} Could not open browser automatically.${colors.reset}`);
212
+ console.log(`${colors.cyan} Please open: ${url}${colors.reset}`);
213
+ }
214
+ });
215
+ }
216
+
217
+ /**
218
+ * Wait for OAuth callback
219
+ */
220
+ function waitForAuth() {
221
+ return new Promise((resolve, reject) => {
222
+ let resolved = false;
223
+
224
+ const server = http.createServer(async (req, res) => {
225
+ const url = new URL(req.url, `http://localhost:${CALLBACK_PORT}`);
226
+
227
+ if (url.pathname === '/callback') {
228
+ const token = url.searchParams.get('token');
229
+ const handle = url.searchParams.get('handle');
230
+
231
+ if (token && handle) {
232
+ // Send success page
233
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
234
+ res.end(`<!DOCTYPE html>
235
+ <html>
236
+ <head>
237
+ <title>Welcome to /vibe!</title>
238
+ <style>
239
+ body {
240
+ font-family: 'SF Mono', Monaco, monospace;
241
+ background: #0a0a0a;
242
+ color: #e0e0e0;
243
+ display: flex;
244
+ justify-content: center;
245
+ align-items: center;
246
+ min-height: 100vh;
247
+ margin: 0;
248
+ }
249
+ .container {
250
+ text-align: center;
251
+ padding: 2rem;
252
+ }
253
+ h1 { color: #00FF88; }
254
+ .handle { color: #6B8FFF; }
255
+ .close { color: #888; margin-top: 2rem; }
256
+ </style>
257
+ </head>
258
+ <body>
259
+ <div class="container">
260
+ <h1>✓ Setup Complete!</h1>
261
+ <p>Welcome, <span class="handle">@${handle}</span></p>
262
+ <p>You're now connected to /vibe</p>
263
+ <p class="close">You can close this window</p>
264
+ </div>
265
+ </body>
266
+ </html>`);
267
+
268
+ resolved = true;
269
+ setTimeout(() => server.close(), 500);
270
+ resolve({ success: true, handle, token });
271
+ } else {
272
+ res.writeHead(400);
273
+ res.end('Missing token or handle');
274
+ }
275
+ } else {
276
+ res.writeHead(404);
277
+ res.end('Not found');
278
+ }
279
+ });
280
+
281
+ server.on('error', (err) => {
282
+ if (err.code === 'EADDRINUSE') {
283
+ reject(new Error('Auth server port in use'));
284
+ } else {
285
+ reject(err);
286
+ }
287
+ });
288
+
289
+ server.listen(CALLBACK_PORT, '127.0.0.1');
290
+
291
+ // Timeout after 2 minutes
292
+ setTimeout(() => {
293
+ if (!resolved) {
294
+ server.close();
295
+ reject(new Error('Auth timed out'));
296
+ }
297
+ }, 120000);
298
+ });
299
+ }
300
+
301
+ /**
302
+ * Save auth config
303
+ */
304
+ function saveAuthConfig(handle, token) {
305
+ const homeDir = os.homedir();
306
+ const vibeDir = path.join(homeDir, '.vibe');
307
+
308
+ // Create .vibe directory if not exists
309
+ if (!fs.existsSync(vibeDir)) {
310
+ fs.mkdirSync(vibeDir, { recursive: true });
311
+ }
312
+
313
+ // Save config
314
+ const configPath = path.join(vibeDir, 'config.json');
315
+ const config = {
316
+ handle,
317
+ authToken: token,
318
+ authMethod: 'browser',
319
+ authenticatedAt: new Date().toISOString()
320
+ };
321
+
322
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
323
+ }
324
+
325
+ /**
326
+ * Main setup function
327
+ */
328
+ async function setup() {
329
+ printBanner();
330
+ console.log(`${colors.bold} One-Click Setup${colors.reset}`);
331
+ console.log('');
332
+
333
+ // Step 1: Find Claude config
334
+ printStep(1, 'Finding Claude Code config...', 'running');
335
+ const configPath = findClaudeConfig();
336
+ const configExists = fs.existsSync(configPath);
337
+ console.log(`${colors.dim} → ${configPath}${configExists ? '' : ' (will create)'}${colors.reset}`);
338
+ printStep(1, 'Finding Claude Code config...', 'done');
339
+
340
+ // Step 2: Add MCP config
341
+ printStep(2, 'Adding /vibe MCP server...', 'running');
342
+ const config = loadConfig(configPath);
343
+ const { added, alreadyExists } = addVibeToConfig(config);
344
+
345
+ if (alreadyExists) {
346
+ console.log(`${colors.dim} → Already configured!${colors.reset}`);
347
+ } else {
348
+ saveConfig(configPath, config);
349
+ console.log(`${colors.dim} → Config updated${colors.reset}`);
350
+ }
351
+ printStep(2, 'Adding /vibe MCP server...', 'done');
352
+
353
+ // Step 3: Test connection
354
+ printStep(3, 'Testing connection...', 'running');
355
+ const connected = await testConnection();
356
+ if (!connected) {
357
+ printStep(3, 'Testing connection...', 'error');
358
+ console.log(`${colors.red} → Could not reach slashvibe.dev${colors.reset}`);
359
+ console.log('');
360
+ console.log(`${colors.bold} Troubleshooting:${colors.reset}`);
361
+ console.log(`${colors.dim} 1. Check your internet connection${colors.reset}`);
362
+ console.log(`${colors.dim} 2. Try: ${colors.cyan}curl -s https://www.slashvibe.dev/api/health${colors.reset}`);
363
+ console.log(`${colors.dim} 3. If that works, try setup again${colors.reset}`);
364
+ console.log('');
365
+ console.log(`${colors.dim} Status page: ${colors.cyan}slashvibe.dev/status${colors.reset}`);
366
+ process.exit(1);
367
+ }
368
+
369
+ const onlineCount = await getOnlineCount();
370
+ console.log(`${colors.dim} → Connected! ${onlineCount} builders online${colors.reset}`);
371
+ printStep(3, 'Testing connection...', 'done');
372
+
373
+ // Step 4: Authenticate
374
+ printStep(4, 'Opening browser for GitHub auth...', 'running');
375
+
376
+ const callbackUrl = `http://localhost:${CALLBACK_PORT}/callback`;
377
+ const loginUrl = `${LOGIN_URL}?redirect=${encodeURIComponent(callbackUrl)}&setup=true`;
378
+
379
+ openBrowser(loginUrl);
380
+ console.log(`${colors.dim} → Waiting for authentication...${colors.reset}`);
381
+
382
+ try {
383
+ const authResult = await waitForAuth();
384
+
385
+ // Save auth config
386
+ saveAuthConfig(authResult.handle, authResult.token);
387
+
388
+ printStep(4, 'Opening browser for GitHub auth...', 'done');
389
+ console.log(`${colors.dim} → Authenticated as @${authResult.handle}${colors.reset}`);
390
+
391
+ // Success! Show who's online immediately
392
+ const presence = await getOnlineUsers();
393
+
394
+ console.log('');
395
+ console.log(`${colors.green} ✓ Setup complete!${colors.reset}`);
396
+ console.log('');
397
+
398
+ // Show who's vibing right now
399
+ if (presence.users.length > 0) {
400
+ console.log(`${colors.bold} 🟢 ${presence.total} builders vibing now:${colors.reset}`);
401
+ for (const user of presence.users) {
402
+ const statusIcon = user.status === 'active' ? colors.green + '●' : colors.yellow + '○';
403
+ const liner = user.one_liner ? ` — ${user.one_liner.slice(0, 40)}` : '';
404
+ console.log(` ${statusIcon}${colors.reset} @${user.handle}${colors.dim}${liner}${colors.reset}`);
405
+ }
406
+ if (presence.total > 5) {
407
+ console.log(`${colors.dim} ... and ${presence.total - 5} more${colors.reset}`);
408
+ }
409
+ console.log('');
410
+ }
411
+
412
+ console.log(`${colors.bold} Quick start:${colors.reset}`);
413
+ console.log(`${colors.dim} 1. Restart Claude Code${colors.reset}`);
414
+ console.log(`${colors.dim} 2. Type "who's vibing?" to see everyone${colors.reset}`);
415
+ console.log(`${colors.dim} 3. Type "dm @seth hey!" to send a message${colors.reset}`);
416
+ console.log('');
417
+ console.log(`${colors.cyan} 🚀 Welcome to /vibe, @${authResult.handle}!${colors.reset}`);
418
+ console.log('');
419
+
420
+ // Track setup completion
421
+ try {
422
+ await fetch(`${API_BASE}/api/analytics/track`, {
423
+ method: 'POST',
424
+ headers: { 'Content-Type': 'application/json' },
425
+ body: JSON.stringify({
426
+ event: 'setup_complete',
427
+ handle: authResult.handle,
428
+ source: 'one_click_install'
429
+ })
430
+ });
431
+ } catch (e) {}
432
+
433
+ } catch (err) {
434
+ printStep(4, 'Opening browser for GitHub auth...', 'error');
435
+
436
+ // Specific error recovery messages
437
+ if (err.message.includes('timed out')) {
438
+ console.log(`${colors.red} → Authentication timed out (2 min limit)${colors.reset}`);
439
+ console.log('');
440
+ console.log(`${colors.yellow} What happened:${colors.reset}`);
441
+ console.log(`${colors.dim} The browser auth wasn't completed in time.${colors.reset}`);
442
+ console.log('');
443
+ console.log(`${colors.bold} Try again:${colors.reset}`);
444
+ console.log(`${colors.cyan} npx slashvibe-mcp setup${colors.reset}`);
445
+ } else if (err.message.includes('port in use')) {
446
+ console.log(`${colors.red} → Auth callback port busy${colors.reset}`);
447
+ console.log('');
448
+ console.log(`${colors.yellow} What happened:${colors.reset}`);
449
+ console.log(`${colors.dim} Another setup or auth process is running.${colors.reset}`);
450
+ console.log('');
451
+ console.log(`${colors.bold} Fix it:${colors.reset}`);
452
+ console.log(`${colors.dim} 1. Wait a minute for it to finish, or${colors.reset}`);
453
+ console.log(`${colors.dim} 2. Kill the process: ${colors.cyan}lsof -ti:9876 | xargs kill${colors.reset}`);
454
+ console.log(`${colors.dim} 3. Try again: ${colors.cyan}npx slashvibe-mcp setup${colors.reset}`);
455
+ } else {
456
+ console.log(`${colors.red} → ${err.message}${colors.reset}`);
457
+ console.log('');
458
+ console.log(`${colors.bold} Try these steps:${colors.reset}`);
459
+ console.log(`${colors.dim} 1. Check internet connection${colors.reset}`);
460
+ console.log(`${colors.dim} 2. Try again: ${colors.cyan}npx slashvibe-mcp setup${colors.reset}`);
461
+ console.log(`${colors.dim} 3. Or in Claude Code, type: ${colors.cyan}add the vibe mcp server${colors.reset}`);
462
+ }
463
+ console.log('');
464
+ console.log(`${colors.dim} Need help? slashvibe.dev/help${colors.reset}`);
465
+ process.exit(1);
466
+ }
467
+ }
468
+
469
+ // Handle command line
470
+ const args = process.argv.slice(2);
471
+
472
+ if (args[0] === 'setup' || args.length === 0) {
473
+ setup().catch(err => {
474
+ console.error(`${colors.red}Setup failed: ${err.message}${colors.reset}`);
475
+ process.exit(1);
476
+ });
477
+ } else {
478
+ // Pass through to main MCP server
479
+ require('./index.js');
480
+ }