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/README.md CHANGED
@@ -1,288 +1,83 @@
1
- # /vibe MCP Server
1
+ # vibe-mcp
2
2
 
3
- The social layer for AI coding. DMs, presence, discovery, and games between developers — without leaving your editor.
3
+ Social layer for AI-assisted coding. DMs, presence, and connection between developers.
4
4
 
5
- Works with Claude Code, Cursor, VS Code, Windsurf, Cline, Continue.dev, JetBrains, and any MCP-compatible client.
5
+ **Works in:** Claude Code Cursor Any MCP-compatible IDE
6
6
 
7
- ## Install
7
+ ## Quick Start
8
8
 
9
- Add to your MCP config and restart your editor:
10
-
11
- <details open>
12
- <summary><strong>Claude Code</strong></summary>
13
-
14
- Add to `~/.claude.json`:
15
- ```json
16
- {
17
- "mcpServers": {
18
- "vibe": {
19
- "command": "npx",
20
- "args": ["-y", "slashvibe-mcp"]
21
- }
22
- }
23
- }
24
- ```
25
-
26
- Or via CLI:
9
+ **Claude Code:**
27
10
  ```bash
28
- claude mcp add vibe -- npx -y slashvibe-mcp
11
+ npx slashvibe-mcp setup
29
12
  ```
30
- </details>
31
13
 
32
- <details>
33
- <summary><strong>Cursor</strong></summary>
14
+ **Cursor:** See [Cursor Setup Guide](docs/CURSOR_SETUP.md)
34
15
 
35
- Add to `~/.cursor/mcp.json`:
36
- ```json
37
- {
38
- "mcpServers": {
39
- "vibe": {
40
- "command": "npx",
41
- "args": ["-y", "slashvibe-mcp"]
42
- }
43
- }
44
- }
45
- ```
46
- </details>
16
+ **Other IDEs:** Any editor supporting MCP protocol can use the manual config below.
47
17
 
48
- <details>
49
- <summary><strong>VS Code (GitHub Copilot)</strong></summary>
18
+ ## Installation
50
19
 
51
- Add to `.vscode/mcp.json` in your workspace:
52
- ```json
53
- {
54
- "servers": {
55
- "vibe": {
56
- "command": "npx",
57
- "args": ["-y", "slashvibe-mcp"]
58
- }
59
- }
60
- }
61
- ```
20
+ ```bash
21
+ # Install globally
22
+ npm install -g vibe-mcp
62
23
 
63
- Or add to your `settings.json`:
64
- ```json
65
- {
66
- "mcp": {
67
- "servers": {
68
- "vibe": {
69
- "command": "npx",
70
- "args": ["-y", "slashvibe-mcp"]
71
- }
72
- }
73
- }
74
- }
24
+ # Or add to Claude Code MCP config
25
+ claude mcp add vibe-mcp
75
26
  ```
76
- </details>
77
-
78
- <details>
79
- <summary><strong>Windsurf</strong></summary>
80
27
 
81
- Add to `~/.codeium/windsurf/mcp_config.json`:
82
- ```json
83
- {
84
- "mcpServers": {
85
- "vibe": {
86
- "command": "npx",
87
- "args": ["-y", "slashvibe-mcp"]
88
- }
89
- }
90
- }
91
- ```
92
- </details>
28
+ ## Manual Setup
93
29
 
94
- <details>
95
- <summary><strong>Cline (VS Code)</strong></summary>
30
+ Add to `~/.claude.json`:
96
31
 
97
- Open Cline > MCP Servers icon > Configure > Edit JSON, then add:
98
32
  ```json
99
33
  {
100
34
  "mcpServers": {
101
35
  "vibe": {
102
36
  "command": "npx",
103
- "args": ["-y", "slashvibe-mcp"]
37
+ "args": ["vibe-mcp"],
38
+ "env": {
39
+ "VIBE_API_URL": "https://www.slashvibe.dev"
40
+ }
104
41
  }
105
42
  }
106
43
  }
107
44
  ```
108
- </details>
109
-
110
- <details>
111
- <summary><strong>Continue.dev</strong></summary>
112
-
113
- Create `.continue/mcpServers/vibe.json`:
114
- ```json
115
- {
116
- "command": "npx",
117
- "args": ["-y", "slashvibe-mcp"]
118
- }
119
- ```
120
- </details>
121
-
122
- <details>
123
- <summary><strong>JetBrains (IntelliJ, WebStorm, etc.)</strong></summary>
124
-
125
- Go to **Settings > Tools > AI Assistant > Model Context Protocol (MCP)** and add a new server:
126
- - **Command:** `npx`
127
- - **Arguments:** `-y slashvibe-mcp`
128
-
129
- Or import from your Claude Code config if you already have one.
130
- </details>
131
-
132
- ## Getting Started
133
-
134
- Once installed, tell Claude:
135
-
136
- ```
137
- "let's vibe"
138
- ```
139
-
140
- That's it. Claude will authenticate you via GitHub, show who's online, and check your inbox.
141
-
142
- If you prefer step-by-step:
143
-
144
- 1. **Authenticate** — `vibe init` opens GitHub OAuth in your browser. Takes 30 seconds.
145
- 2. **See who's around** — `vibe who` shows online builders and what they're working on.
146
- 3. **Check messages** — `vibe inbox` shows unread DMs.
147
- 4. **Send your first message** — `vibe dm @seth hey, just set up /vibe!`
148
-
149
- ## Tools
150
-
151
- ### Core — Messaging & Presence
152
-
153
- | Tool | What it does |
154
- |------|-------------|
155
- | `vibe_start` | Entry point — authenticates, shows who's online, checks inbox |
156
- | `vibe_init` | Set up your identity via GitHub OAuth |
157
- | `vibe_who` | See who's online and what they're building |
158
- | `vibe_dm` | Send a direct message |
159
- | `vibe_inbox` | Check your unread messages |
160
- | `vibe_open` | Open a conversation thread with someone |
161
- | `vibe_ping` | Send a quick wave to someone |
162
- | `vibe_react` | React to a message |
163
- | `vibe_status` | Set your mood or what you're working on |
164
- | `vibe_away` / `vibe_back` | Set yourself away or return |
165
- | `vibe_bye` | End your session |
166
-
167
- ### Discovery — Find Your People
168
-
169
- | Tool | What it does |
170
- |------|-------------|
171
- | `vibe_discover` | Find builders by interests, projects, or activity |
172
- | `vibe_suggest_tags` | Get tag suggestions for your profile |
173
- | `vibe_skills_exchange` | Browse and offer skills |
174
- | `vibe_workshop_buddy` | Find a learning partner |
175
- | `vibe_invite` | Generate an invite link |
176
-
177
- ### Creative — Ship & Share
178
-
179
- | Tool | What it does |
180
- |------|-------------|
181
- | `vibe_ship` | Announce what you shipped |
182
- | `vibe_idea` | Share an idea with the community |
183
- | `vibe_request` | Ask the community for help |
184
- | `vibe_feed` | See what people are shipping and sharing |
185
- | `vibe_create_artifact` | Create a shareable guide, workspace, or learning |
186
- | `vibe_view_artifact` | View shared artifacts |
187
-
188
- ### Memory — Context That Persists
189
-
190
- | Tool | What it does |
191
- |------|-------------|
192
- | `vibe_remember` | Save a note about someone for next time |
193
- | `vibe_recall` | Pull up everything you know about someone |
194
- | `vibe_forget` | Delete a memory |
195
- | `vibe_handoff` | Create an AIRC context handoff for another tool |
196
-
197
- ### Games — 27 Multiplayer & Solo Games
198
-
199
- | Tool | What it does |
200
- |------|-------------|
201
- | `vibe_game` | Start a multiplayer game with someone |
202
- | `vibe_solo_game` | Play a solo game (riddles, hangman, number guess) |
203
- | `vibe_tictactoe` | Challenge someone to tic-tac-toe |
204
- | `vibe_crossword` | Collaborative crossword puzzle |
205
- | `vibe_drawing` | Collaborative ASCII drawing |
206
- | `vibe_party_game` | Start a party game for 3+ players |
207
-
208
- ### Bridges — Cross-Platform Social
209
-
210
- | Tool | What it does |
211
- |------|-------------|
212
- | `vibe_x_mentions` | Check your X/Twitter mentions |
213
- | `vibe_x_reply` | Reply on X from the terminal |
214
- | `vibe_social_inbox` | Unified inbox across platforms |
215
- | `vibe_social_post` | Post to multiple networks at once |
216
-
217
- ### Diagnostics
218
-
219
- | Tool | What it does |
220
- |------|-------------|
221
- | `vibe_doctor` | Full health check — API, auth, storage, presence |
222
- | `vibe_test` | Quick connection and identity test |
223
- | `vibe_help` | Show available commands |
224
- | `vibe_update` | Check for and apply updates |
225
- | `vibe_settings` | Configure preferences |
226
-
227
- ## How It Works
228
-
229
- /vibe is an MCP server that connects your editor to [slashvibe.dev](https://slashvibe.dev). Messages sync via a Postgres backend with local SQLite persistence for offline-first speed. Everyone using /vibe is on the same network — regardless of which editor they use.
230
-
231
- ```
232
- Your Editor ←→ /vibe MCP (stdio) ←→ slashvibe.dev API ←→ Other users
233
-
234
- Local SQLite DB
235
- (~/.vibecodings/sessions.db)
236
- ```
237
-
238
- - **Identity** persists via GitHub OAuth — your handle follows you across sessions
239
- - **Messages** are stored locally first, then synced to the server (optimistic send)
240
- - **Presence** broadcasts via heartbeat — others see you in real time
241
- - **Memory** is local — notes you save about people stay on your machine
242
-
243
- ## Troubleshooting
244
45
 
245
- **"I installed but don't see /vibe tools in Claude Code"**
246
- - Make sure you restarted Claude Code after adding the MCP config
247
- - Check your config file: `~/.claude.json` or `~/.config/claude-code/mcp.json`
248
- - Run `vibe doctor` to diagnose issues
46
+ ## Features
249
47
 
250
- **"Authentication failed or timed out"**
251
- - The OAuth flow opens a browser window — if it didn't open, go to [slashvibe.dev/login](https://slashvibe.dev/login) manually
252
- - The auth callback runs on `localhost:9876` — make sure that port is free
253
- - You have 2 minutes to complete the GitHub login
48
+ - **Presence** - See who's online building with Claude Code
49
+ - **DMs** - Direct messages between developers
50
+ - **Memory** - Remember context about connections
51
+ - **Status** - Share what you're working on
52
+ - **Games** - Play tic-tac-toe while coding
254
53
 
255
- **"Messages aren't sending"**
256
- - Run `vibe doctor` to check API connectivity
257
- - Check your internet connection
258
- - Messages are saved locally even if the API is down — they'll sync when you reconnect
54
+ ## Commands
259
55
 
260
- **"I see 'Unknown tool' errors"**
261
- - You may be running an older version. Run `vibe update` or reinstall: `npm install -g slashvibe-mcp`
56
+ Once installed, use these in Claude Code:
262
57
 
263
- ## Configuration
58
+ | Command | Description |
59
+ |---------|-------------|
60
+ | `vibe` | Check inbox and see who's online |
61
+ | `vibe who` | List online users |
62
+ | `vibe dm @handle "message"` | Send a DM |
63
+ | `vibe status shipping` | Set your status |
64
+ | `vibe remember @handle "note"` | Save a memory |
65
+ | `vibe recall @handle` | Recall memories |
264
66
 
265
- Config lives at `~/.vibecodings/config.json` (primary) or `~/.vibe/config.json` (legacy fallback).
67
+ ## API
266
68
 
267
- Local message database: `~/.vibecodings/sessions.db` (SQLite, shared with Vibe Terminal desktop app).
69
+ The MCP server connects to `slashvibe.dev` for:
70
+ - User presence and discovery
71
+ - Message routing
72
+ - Identity verification
268
73
 
269
- ## Contributing
74
+ ## Related
270
75
 
271
- We welcome contributions. Please read our [Contributor License Agreement](./CLA.md) before submitting pull requests.
272
-
273
- - Report bugs via [GitHub Issues](https://github.com/VibeCodingInc/vibe-mcp/issues)
274
- - Propose features via [Discussions](https://github.com/VibeCodingInc/vibe-mcp/discussions)
76
+ - [GitHub](https://github.com/VibeCodingInc/vibe-mcp) - Source code
77
+ - [slashvibe.dev](https://slashvibe.dev) - Web presence
78
+ - [Spirit Protocol](https://spiritprotocol.io) - Parent ecosystem
79
+ - [AIRC](https://airc.chat) - Agent identity protocol
275
80
 
276
81
  ## License
277
82
 
278
- MIT — see [LICENSE](./LICENSE)
279
-
280
- ## Links
281
-
282
- - [slashvibe.dev](https://slashvibe.dev) — The platform
283
- - [Vibe Terminal](https://github.com/VibeCodingInc/vibe-terminal) — Desktop app
284
- - [@slashvibe on X](https://twitter.com/slashvibe) — Updates
285
-
286
- ---
287
-
288
- Built by [Slash Vibe, Inc.](https://slashvibe.dev)
83
+ 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.authToken || 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
+ };