slashvibe-mcp 0.2.9 → 0.3.13

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 (205) hide show
  1. package/README.md +1 -0
  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 +154 -5
  14. package/crypto.js +3 -8
  15. package/games/arcade.js +406 -0
  16. package/games/chess.js +451 -0
  17. package/games/colorguess.js +343 -0
  18. package/games/crossword-words.js +171 -0
  19. package/games/crossword.js +461 -0
  20. package/games/drawing.js +347 -0
  21. package/games/gameroulette.js +300 -0
  22. package/games/gamerouter.js +336 -0
  23. package/games/gamestatus.js +337 -0
  24. package/games/guessnumber.js +209 -0
  25. package/games/hangman.js +279 -0
  26. package/games/memory.js +338 -0
  27. package/games/multiplayer-tictactoe.js +389 -0
  28. package/games/pixelart.js +399 -0
  29. package/games/quickduel.js +354 -0
  30. package/games/riddle.js +371 -0
  31. package/games/rockpaperscissors.js +291 -0
  32. package/games/snake.js +406 -0
  33. package/games/storybuilder.js +343 -0
  34. package/games/tictactoe.js +345 -0
  35. package/games/twentyquestions.js +286 -0
  36. package/games/twotruths.js +207 -0
  37. package/games/werewolf.js +508 -0
  38. package/games/wordassociation.js +247 -0
  39. package/games/wordchain.js +135 -0
  40. package/index.js +105 -216
  41. package/intelligence/index.js +45 -0
  42. package/intelligence/infer.js +316 -0
  43. package/intelligence/interests.js +369 -0
  44. package/intelligence/patterns.js +651 -0
  45. package/intelligence/proactive.js +358 -0
  46. package/intelligence/serendipity.js +306 -0
  47. package/memory.js +166 -0
  48. package/notification-emitter.js +77 -0
  49. package/notify.js +102 -1
  50. package/package.json +21 -7
  51. package/prompts.js +1 -1
  52. package/protocol/index.js +161 -1
  53. package/setup.js +402 -0
  54. package/store/api.js +528 -82
  55. package/store/profiles.js +160 -12
  56. package/tools/_actions.js +463 -16
  57. package/tools/_deprecated/auto-suggest-connections.js +304 -0
  58. package/tools/_deprecated/bootstrap-skills.js +231 -0
  59. package/tools/_deprecated/bridge-dashboard.js +342 -0
  60. package/tools/_deprecated/bridge-health.js +400 -0
  61. package/tools/_deprecated/bridge-live.js +384 -0
  62. package/tools/_deprecated/bridges.js +383 -0
  63. package/tools/_deprecated/colorguess.js +281 -0
  64. package/tools/_deprecated/discover-insights.js +379 -0
  65. package/tools/_deprecated/discover-momentum.js +256 -0
  66. package/tools/_deprecated/discovery-analytics.js +345 -0
  67. package/tools/_deprecated/discovery-auto-suggest.js +275 -0
  68. package/tools/_deprecated/discovery-bootstrap.js +267 -0
  69. package/tools/_deprecated/discovery-daily.js +375 -0
  70. package/tools/_deprecated/discovery-dashboard.js +385 -0
  71. package/tools/_deprecated/discovery-digest.js +314 -0
  72. package/tools/_deprecated/discovery-hub.js +357 -0
  73. package/tools/_deprecated/discovery-insights.js +384 -0
  74. package/tools/_deprecated/discovery-momentum.js +281 -0
  75. package/tools/_deprecated/discovery-monitor.js +319 -0
  76. package/tools/_deprecated/discovery-proactive.js +300 -0
  77. package/tools/_deprecated/draw.js +317 -0
  78. package/tools/_deprecated/farcaster.js +307 -0
  79. package/tools/_deprecated/forget.js +119 -0
  80. package/tools/_deprecated/games-catalog.js +376 -0
  81. package/tools/_deprecated/games.js +313 -0
  82. package/tools/_deprecated/guessnumber.js +194 -0
  83. package/tools/_deprecated/hangman.js +129 -0
  84. package/tools/_deprecated/multiplayer-tictactoe.js +303 -0
  85. package/tools/_deprecated/recall.js +147 -0
  86. package/tools/_deprecated/remember.js +86 -0
  87. package/tools/_deprecated/riddle.js +240 -0
  88. package/tools/_deprecated/run-bootstrap.js +69 -0
  89. package/tools/_deprecated/skills-analytics.js +349 -0
  90. package/tools/_deprecated/skills-bootstrap.js +301 -0
  91. package/tools/_deprecated/skills-dashboard.js +268 -0
  92. package/tools/_deprecated/skills.js +380 -0
  93. package/tools/_deprecated/smart-intro.js +353 -0
  94. package/tools/_deprecated/storybuilder.js +331 -0
  95. package/tools/_deprecated/telegram-bot.js +183 -0
  96. package/tools/_deprecated/telegram-setup.js +214 -0
  97. package/tools/_deprecated/twentyquestions.js +143 -0
  98. package/tools/_discovery-enhanced.js +290 -0
  99. package/tools/_discovery.js +439 -0
  100. package/tools/_proactive-discovery.js +301 -0
  101. package/tools/_shared/index.js +64 -0
  102. package/tools/_shared.js +234 -0
  103. package/tools/_work-context.js +338 -0
  104. package/tools/_work-context.manual-test.js +199 -0
  105. package/tools/_work-context.test.js +260 -0
  106. package/tools/activity.js +220 -0
  107. package/tools/admin-inbox.js +218 -0
  108. package/tools/agent-treasury.js +288 -0
  109. package/tools/analytics.js +191 -0
  110. package/tools/approve.js +197 -0
  111. package/tools/arcade.js +173 -0
  112. package/tools/artifact-create.js +17 -11
  113. package/tools/artifact-view.js +31 -1
  114. package/tools/artifacts-price.js +47 -43
  115. package/tools/ask-expert.js +160 -0
  116. package/tools/available.js +120 -0
  117. package/tools/become-expert.js +150 -0
  118. package/tools/broadcast.js +286 -0
  119. package/tools/chat.js +202 -0
  120. package/tools/collaborative-drawing.js +286 -0
  121. package/tools/connection-status.js +178 -0
  122. package/tools/crossword.js +17 -1
  123. package/tools/discover.js +350 -34
  124. package/tools/dm.js +115 -73
  125. package/tools/drawing.js +1 -1
  126. package/tools/earnings.js +126 -0
  127. package/tools/echo.js +16 -0
  128. package/tools/feed.js +51 -7
  129. package/tools/follow.js +224 -0
  130. package/tools/friends.js +207 -0
  131. package/tools/game.js +2 -2
  132. package/tools/genesis.js +233 -0
  133. package/tools/gig-browse.js +206 -0
  134. package/tools/gig-complete.js +144 -0
  135. package/tools/handoff.js +7 -1
  136. package/tools/help.js +4 -4
  137. package/tools/idea.js +9 -2
  138. package/tools/inbox.js +334 -28
  139. package/tools/init.js +727 -36
  140. package/tools/invite.js +15 -4
  141. package/tools/l2-bridge.js +272 -0
  142. package/tools/l2-status.js +217 -0
  143. package/tools/l2.js +206 -0
  144. package/tools/migrate.js +156 -0
  145. package/tools/mint.js +377 -0
  146. package/tools/multiplayer-game.js +1 -1
  147. package/tools/notifications.js +415 -0
  148. package/tools/observe.js +200 -0
  149. package/tools/onboarding.js +147 -0
  150. package/tools/open.js +143 -12
  151. package/tools/party-game.js +2 -2
  152. package/tools/plan.js +225 -0
  153. package/tools/presence-agent.js +7 -0
  154. package/tools/proof-of-work.js +100 -104
  155. package/tools/pulse.js +218 -0
  156. package/tools/reply.js +166 -0
  157. package/tools/report.js +2 -2
  158. package/tools/reputation.js +175 -0
  159. package/tools/request.js +17 -3
  160. package/tools/schedule.js +367 -0
  161. package/tools/search-messages.js +123 -0
  162. package/tools/session.js +420 -0
  163. package/tools/session_price.js +128 -0
  164. package/tools/settings.js +126 -3
  165. package/tools/ship.js +31 -8
  166. package/tools/shipback.js +326 -0
  167. package/tools/smart-check.js +201 -0
  168. package/tools/social-processor.js +445 -0
  169. package/tools/solo-game.js +1 -1
  170. package/tools/start.js +335 -93
  171. package/tools/status.js +53 -6
  172. package/tools/stuck.js +297 -0
  173. package/tools/subscribe.js +148 -0
  174. package/tools/subscriptions.js +134 -0
  175. package/tools/suggest-tags.js +6 -8
  176. package/tools/tag-suggestions.js +257 -0
  177. package/tools/tip.js +193 -0
  178. package/tools/token.js +103 -0
  179. package/tools/update.js +1 -1
  180. package/tools/wallet.js +239 -186
  181. package/tools/watch.js +157 -0
  182. package/tools/webhook-test.js +388 -0
  183. package/tools/who.js +54 -3
  184. package/tools/withdraw.js +145 -0
  185. package/tools/work-summary.js +96 -0
  186. package/tools/workshop.js +327 -0
  187. package/tools/x-mentions.js +1 -1
  188. package/version.json +14 -3
  189. package/tools/artifacts-buy.js +0 -111
  190. package/tools/connect.js +0 -284
  191. package/tools/gigs-apply.js +0 -99
  192. package/tools/gigs-browse.js +0 -114
  193. package/tools/gigs-complete.js +0 -128
  194. package/tools/gigs-post.js +0 -140
  195. package/tools/live-off.js +0 -109
  196. package/tools/live-watch.js +0 -176
  197. package/tools/live.js +0 -128
  198. package/tools/sessions-browse.js +0 -105
  199. package/tools/whats-happening.js +0 -125
  200. /package/tools/{away.js → _deprecated/away.js} +0 -0
  201. /package/tools/{back.js → _deprecated/back.js} +0 -0
  202. /package/tools/{mute.js → _deprecated/mute.js} +0 -0
  203. /package/tools/{skills-exchange.js → _deprecated/skills-exchange.js} +0 -0
  204. /package/tools/{tictactoe.js → _deprecated/tictactoe.js} +0 -0
  205. /package/tools/{wordassociation.js → _deprecated/wordassociation.js} +0 -0
@@ -0,0 +1,420 @@
1
+ /**
2
+ * vibe session — Session management
3
+ *
4
+ * Save broadcasts as replayable sessions, browse sessions, and fork them.
5
+ *
6
+ * Commands:
7
+ * - session save → Save current/recent broadcast as session
8
+ * - session save --room X → Save specific broadcast
9
+ * - session list → List my sessions
10
+ * - session browse → Browse all public sessions
11
+ * - session fork <id> → Fork a session
12
+ * - session view <id> → View session details
13
+ */
14
+
15
+ const config = require('../config');
16
+
17
+ const definition = {
18
+ name: 'vibe_session',
19
+ description: 'Save broadcasts as sessions, list your sessions, fork others\' sessions.',
20
+ inputSchema: {
21
+ type: 'object',
22
+ properties: {
23
+ action: {
24
+ type: 'string',
25
+ enum: ['save', 'list', 'browse', 'fork', 'view'],
26
+ description: 'Action: save, list, browse, fork, or view'
27
+ },
28
+ room: {
29
+ type: 'string',
30
+ description: 'Room ID to save (for save action)'
31
+ },
32
+ id: {
33
+ type: 'string',
34
+ description: 'Session ID (for fork/view action)'
35
+ },
36
+ title: {
37
+ type: 'string',
38
+ description: 'Session title (for save action)'
39
+ },
40
+ visibility: {
41
+ type: 'string',
42
+ enum: ['public', 'unlisted', 'private'],
43
+ description: 'Session visibility (default: public)'
44
+ },
45
+ limit: {
46
+ type: 'number',
47
+ description: 'Number of sessions to show (default: 10)'
48
+ }
49
+ }
50
+ }
51
+ };
52
+
53
+ async function handler(args) {
54
+ const myHandle = config.getHandle();
55
+ const apiUrl = config.getApiUrl();
56
+ const action = args.action || 'list';
57
+
58
+ if (!myHandle && action !== 'browse' && action !== 'view') {
59
+ return { display: '⚠️ Not initialized. Run `vibe init` first.' };
60
+ }
61
+
62
+ // SAVE broadcast as session
63
+ if (action === 'save') {
64
+ // Get room ID from args or from active broadcast
65
+ let roomId = args.room;
66
+
67
+ if (!roomId) {
68
+ // Check for active broadcast
69
+ const broadcast = config.get('broadcast');
70
+ if (broadcast) {
71
+ roomId = broadcast.roomId;
72
+ }
73
+ }
74
+
75
+ if (!roomId) {
76
+ return {
77
+ display: `⚠️ No broadcast to save.\n\n**Options:**\n1. Specify a room: \`vibe session save --room room_xxx\`\n2. Start a broadcast first: \`vibe broadcast start\``
78
+ };
79
+ }
80
+
81
+ const title = args.title || `Session by @${myHandle}`;
82
+ const visibility = args.visibility || 'public';
83
+
84
+ try {
85
+ const response = await fetch(`${apiUrl}/api/sessions`, {
86
+ method: 'POST',
87
+ headers: { 'Content-Type': 'application/json' },
88
+ body: JSON.stringify({
89
+ fromBroadcast: roomId,
90
+ handle: myHandle,
91
+ title,
92
+ visibility
93
+ })
94
+ });
95
+
96
+ const data = await response.json();
97
+
98
+ if (!data.success) {
99
+ if (data.error?.includes('buffer not found')) {
100
+ return {
101
+ display: `⚠️ Broadcast buffer expired.\n\n_Buffers expire 1 hour after broadcast ends. Start a new broadcast to create a session._`
102
+ };
103
+ }
104
+ return { display: `⚠️ Failed to save session: ${data.error}` };
105
+ }
106
+
107
+ const formatDuration = (secs) => {
108
+ if (!secs || secs < 60) return 'under 1 minute';
109
+ if (secs < 3600) return `${Math.floor(secs / 60)} minutes`;
110
+ return `${Math.floor(secs / 3600)}h ${Math.floor((secs % 3600) / 60)}m`;
111
+ };
112
+
113
+ // Chapter icons for display
114
+ const chapterIcons = {
115
+ setup: '🔧',
116
+ problem: '❌',
117
+ investigation: '🔍',
118
+ breakthrough: '💡',
119
+ implementation: '⚡',
120
+ ship: '🚀'
121
+ };
122
+
123
+ let display = `✅ **Session Saved**\n\n`;
124
+ display += `**${data.title}**\n\n`;
125
+ display += `📎 ${data.shareUrl}\n\n`;
126
+ display += `**Stats:**\n`;
127
+ display += `- Duration: ${formatDuration(data.stats?.durationSeconds)}\n`;
128
+ display += `- Chunks: ${data.stats?.chunks || 0}\n`;
129
+
130
+ // Show chapters if detected
131
+ const chapters = data.chapters || [];
132
+ if (chapters.length > 0) {
133
+ display += `- Chapters: ${chapters.length}\n\n`;
134
+ display += `📖 **Story Arc:**\n`;
135
+ const chapterFlow = chapters.map(ch => {
136
+ const icon = chapterIcons[ch.type] || '📋';
137
+ return `${icon} ${ch.title}`;
138
+ }).join(' → ');
139
+ display += ` ${chapterFlow}\n\n`;
140
+ } else {
141
+ display += `- Fork points: ${data.stats?.forkPoints || 0}\n\n`;
142
+ }
143
+
144
+ display += `_Share this URL or find it later with \`vibe session list\`_`;
145
+
146
+ return { display };
147
+
148
+ } catch (error) {
149
+ return { display: `## Save Error\n\n${error.message}` };
150
+ }
151
+ }
152
+
153
+ // LIST my sessions
154
+ if (action === 'list') {
155
+ const limit = args.limit || 10;
156
+
157
+ try {
158
+ const response = await fetch(
159
+ `${apiUrl}/api/sessions/browse?author=${myHandle}&limit=${limit}`,
160
+ { headers: { 'Accept': 'application/json' } }
161
+ );
162
+
163
+ const data = await response.json();
164
+
165
+ if (!data.success) {
166
+ return { display: `⚠️ Failed to fetch sessions: ${data.error}` };
167
+ }
168
+
169
+ if (!data.sessions || data.sessions.length === 0) {
170
+ let display = `📼 **No Sessions Yet**\n\n`;
171
+ display += `You haven't saved any sessions.\n\n`;
172
+ display += `**Create your first session:**\n`;
173
+ display += `1. \`vibe broadcast start "What you're building"\`\n`;
174
+ display += `2. Code for a while...\n`;
175
+ display += `3. \`vibe broadcast stop\`\n`;
176
+ display += `4. \`vibe session save\``;
177
+ return { display };
178
+ }
179
+
180
+ const formatDuration = (secs) => {
181
+ if (!secs || secs < 60) return '<1m';
182
+ if (secs < 3600) return `${Math.floor(secs / 60)}m`;
183
+ return `${Math.floor(secs / 3600)}h ${Math.floor((secs % 3600) / 60)}m`;
184
+ };
185
+
186
+ const formatDate = (dateStr) => {
187
+ const date = new Date(dateStr);
188
+ return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
189
+ };
190
+
191
+ let display = `📼 **Your Sessions** (${data.sessions.length}${data.hasMore ? '+' : ''})\n\n`;
192
+
193
+ for (const s of data.sessions) {
194
+ const duration = formatDuration(s.duration_seconds);
195
+ const date = formatDate(s.created_at);
196
+ const views = s.views || 0;
197
+ const forks = s.forks || 0;
198
+
199
+ display += `**${s.title}**\n`;
200
+ display += ` ${date} · ${duration}`;
201
+ if (views > 0) display += ` · ${views} views`;
202
+ if (forks > 0) display += ` · ${forks} forks`;
203
+ display += `\n`;
204
+ display += ` → \`vibe session view ${s.id}\`\n\n`;
205
+ }
206
+
207
+ if (data.hasMore) {
208
+ display += `_More sessions available. Use \`--limit 20\` to see more._`;
209
+ }
210
+
211
+ return { display };
212
+
213
+ } catch (error) {
214
+ return { display: `## List Error\n\n${error.message}` };
215
+ }
216
+ }
217
+
218
+ // BROWSE all public sessions
219
+ if (action === 'browse') {
220
+ const limit = args.limit || 10;
221
+
222
+ try {
223
+ const response = await fetch(
224
+ `${apiUrl}/api/sessions/browse?limit=${limit}&sort=popular`,
225
+ { headers: { 'Accept': 'application/json' } }
226
+ );
227
+
228
+ const data = await response.json();
229
+
230
+ if (!data.success) {
231
+ return { display: `⚠️ Failed to fetch sessions: ${data.error}` };
232
+ }
233
+
234
+ if (!data.sessions || data.sessions.length === 0) {
235
+ return {
236
+ display: `📼 No public sessions yet.\n\n_Be the first! Start a broadcast and save it._`
237
+ };
238
+ }
239
+
240
+ const formatDuration = (secs) => {
241
+ if (!secs || secs < 60) return '<1m';
242
+ if (secs < 3600) return `${Math.floor(secs / 60)}m`;
243
+ return `${Math.floor(secs / 3600)}h`;
244
+ };
245
+
246
+ let display = `📼 **Public Sessions** (${data.total} total)\n\n`;
247
+
248
+ for (const s of data.sessions) {
249
+ const duration = formatDuration(s.duration_seconds);
250
+ const views = s.views || 0;
251
+ const forks = s.forks || 0;
252
+
253
+ display += `**${s.title}** by @${s.author_handle}\n`;
254
+ display += ` ${duration}`;
255
+ if (views > 0) display += ` · ${views} views`;
256
+ if (forks > 0) display += ` · ${forks} forks`;
257
+ display += `\n`;
258
+ display += ` → \`vibe session view ${s.id}\`\n\n`;
259
+ }
260
+
261
+ if (data.hasMore) {
262
+ display += `_More sessions available. Use \`--limit 20\` to see more._`;
263
+ }
264
+
265
+ return { display };
266
+
267
+ } catch (error) {
268
+ return { display: `## Browse Error\n\n${error.message}` };
269
+ }
270
+ }
271
+
272
+ // VIEW session details
273
+ if (action === 'view') {
274
+ if (!args.id) {
275
+ return { display: '⚠️ Session ID required. Usage: `vibe session view ses_xxx`' };
276
+ }
277
+
278
+ const sessionId = args.id;
279
+
280
+ try {
281
+ // Use the story endpoint which returns full session details
282
+ const response = await fetch(`${apiUrl}/story/${sessionId}?format=json`);
283
+
284
+ if (!response.ok) {
285
+ return {
286
+ display: `⚠️ Session not found: ${sessionId}\n\n_Check the ID or browse sessions with \`vibe session browse\`_`
287
+ };
288
+ }
289
+
290
+ const data = await response.json();
291
+
292
+ if (!data.success && !data.session) {
293
+ return { display: `⚠️ Failed to fetch session: ${data.error}` };
294
+ }
295
+
296
+ const s = data.session || data.story || data;
297
+
298
+ const formatDuration = (secs) => {
299
+ if (!secs || secs < 60) return 'under 1 minute';
300
+ if (secs < 3600) return `${Math.floor(secs / 60)} minutes`;
301
+ return `${Math.floor(secs / 3600)}h ${Math.floor((secs % 3600) / 60)}m`;
302
+ };
303
+
304
+ // Chapter icons for display
305
+ const chapterIcons = {
306
+ setup: '🔧',
307
+ problem: '❌',
308
+ investigation: '🔍',
309
+ breakthrough: '💡',
310
+ implementation: '⚡',
311
+ ship: '🚀'
312
+ };
313
+
314
+ let display = `📼 **${s.title}**\n\n`;
315
+ display += `**Author:** @${s.author || s.author_handle}\n`;
316
+ display += `**Duration:** ${formatDuration(s.durationSeconds || s.duration_seconds)}\n`;
317
+ display += `**Views:** ${s.views || 0}\n`;
318
+ display += `**Forks:** ${s.forks || 0}\n\n`;
319
+
320
+ // Display chapters if available
321
+ const chapters = s.chapters || [];
322
+ if (chapters.length > 0) {
323
+ display += `📖 **Chapters** (${chapters.length})\n`;
324
+ for (let i = 0; i < chapters.length; i++) {
325
+ const ch = chapters[i];
326
+ const icon = chapterIcons[ch.type] || '📋';
327
+ display += ` ${i + 1}. ${icon} **${ch.title}** (${ch.startTime || '0:00'})\n`;
328
+ if (ch.summary) {
329
+ display += ` _${ch.summary.slice(0, 60)}${ch.summary.length > 60 ? '...' : ''}_\n`;
330
+ }
331
+ }
332
+ display += '\n';
333
+ }
334
+
335
+ // Display fork points if available
336
+ const forkPoints = s.forkPoints || [];
337
+ if (forkPoints.length > 0) {
338
+ display += `🔀 **Fork Points** (${forkPoints.length})\n`;
339
+ for (const fp of forkPoints.slice(0, 5)) {
340
+ display += ` - ${fp.label}: ${fp.description || ''}\n`;
341
+ }
342
+ if (forkPoints.length > 5) {
343
+ display += ` _...and ${forkPoints.length - 5} more_\n`;
344
+ }
345
+ display += '\n';
346
+ }
347
+
348
+ if (s.description) {
349
+ display += `**Description:**\n${s.description}\n\n`;
350
+ }
351
+
352
+ if (s.summary) {
353
+ display += `**Summary:**\n${s.summary}\n\n`;
354
+ }
355
+
356
+ display += `**View full session:**\n`;
357
+ display += `https://slashvibe.dev/story/${sessionId}\n\n`;
358
+
359
+ display += `**Actions:**\n`;
360
+ display += `- Fork: \`vibe session fork ${sessionId}\`\n`;
361
+
362
+ return { display };
363
+
364
+ } catch (error) {
365
+ return { display: `## View Error\n\n${error.message}` };
366
+ }
367
+ }
368
+
369
+ // FORK a session
370
+ if (action === 'fork') {
371
+ if (!args.id) {
372
+ return { display: '⚠️ Session ID required. Usage: `vibe session fork ses_xxx`' };
373
+ }
374
+
375
+ const sessionId = args.id;
376
+
377
+ try {
378
+ const response = await fetch(`${apiUrl}/api/sessions/fork`, {
379
+ method: 'POST',
380
+ headers: { 'Content-Type': 'application/json' },
381
+ body: JSON.stringify({
382
+ parentSessionId: sessionId,
383
+ forkerHandle: myHandle,
384
+ forkTo: 'session',
385
+ forkLevel: 'story_only'
386
+ })
387
+ });
388
+
389
+ const data = await response.json();
390
+
391
+ if (!data.success) {
392
+ if (data.error?.includes('not found')) {
393
+ return {
394
+ display: `⚠️ Session not found: ${sessionId}\n\n_Check the ID or browse sessions with \`vibe session browse\`_`
395
+ };
396
+ }
397
+ if (data.error?.includes('private')) {
398
+ return { display: `⚠️ Cannot fork a private session.` };
399
+ }
400
+ return { display: `⚠️ Failed to fork session: ${data.error}` };
401
+ }
402
+
403
+ let display = `🍴 **Session Forked!**\n\n`;
404
+ display += `**From:** ${data.parentSession?.title || sessionId}\n`;
405
+ display += `**By:** @${data.parentSession?.author || 'unknown'}\n\n`;
406
+ display += `**Fork ID:** ${data.forkId}\n\n`;
407
+ display += `**View the story:**\n${data.storyUrl}\n\n`;
408
+ display += `_Learn from this session and build your own version!_`;
409
+
410
+ return { display };
411
+
412
+ } catch (error) {
413
+ return { display: `## Fork Error\n\n${error.message}` };
414
+ }
415
+ }
416
+
417
+ return { display: 'Unknown action. Use: save, list, browse, view, or fork' };
418
+ }
419
+
420
+ module.exports = { definition, handler };
@@ -0,0 +1,128 @@
1
+ /**
2
+ * vibe_session_price - Set session access type and price
3
+ *
4
+ * Configure how others can access your sessions:
5
+ * - public: Free for all
6
+ * - ppv: Pay-per-view ($1-$50)
7
+ * - subscribers_only: Requires active subscription
8
+ * - private: Creator only
9
+ *
10
+ * Examples:
11
+ * - "set session to ppv $5"
12
+ * - "make my session public"
13
+ * - "set session price to $10"
14
+ */
15
+
16
+ const fetch = require('node-fetch');
17
+ const config = require('../config');
18
+
19
+ const definition = {
20
+ name: 'vibe_session_price',
21
+ description: 'Set session access type and price. Options: public (free), ppv ($1-$50), subscribers_only, private.',
22
+ inputSchema: {
23
+ type: 'object',
24
+ properties: {
25
+ session_id: {
26
+ type: 'string',
27
+ description: 'Session ID to configure (defaults to current session if available)'
28
+ },
29
+ access_type: {
30
+ type: 'string',
31
+ enum: ['public', 'ppv', 'subscribers_only', 'private'],
32
+ description: 'Access type: public (free), ppv (pay-per-view), subscribers_only, private'
33
+ },
34
+ price_dollars: {
35
+ type: 'number',
36
+ description: 'Price in dollars for PPV access (1-50). Required if access_type is ppv.'
37
+ }
38
+ },
39
+ required: ['access_type']
40
+ }
41
+ };
42
+
43
+ async function handler(args) {
44
+ const { session_id, access_type, price_dollars } = args;
45
+
46
+ if (!config.isInitialized()) {
47
+ return {
48
+ display: 'Run `vibe init` first to set your identity.'
49
+ };
50
+ }
51
+
52
+ // Validate PPV pricing
53
+ if (access_type === 'ppv') {
54
+ if (!price_dollars || price_dollars < 1 || price_dollars > 50) {
55
+ return {
56
+ display: '❌ PPV access requires a price between $1 and $50'
57
+ };
58
+ }
59
+ }
60
+
61
+ const token = config.getToken();
62
+ const apiUrl = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
63
+
64
+ try {
65
+ const response = await fetch(
66
+ `${apiUrl}/api/sessions/access`,
67
+ {
68
+ method: 'POST',
69
+ headers: {
70
+ 'Content-Type': 'application/json',
71
+ 'Authorization': `Bearer ${token}`
72
+ },
73
+ body: JSON.stringify({
74
+ session_id: session_id || undefined,
75
+ access_type,
76
+ ppv_price_dollars: price_dollars || undefined
77
+ })
78
+ }
79
+ );
80
+
81
+ const result = await response.json();
82
+
83
+ if (!response.ok) {
84
+ return {
85
+ display: `❌ ${result.error || 'Failed to update session access'}`
86
+ };
87
+ }
88
+
89
+ // Format success message
90
+ let accessDesc;
91
+ switch (access_type) {
92
+ case 'public':
93
+ accessDesc = '🌐 Public - Free for everyone';
94
+ break;
95
+ case 'ppv':
96
+ accessDesc = `💵 Pay-Per-View - $${price_dollars}`;
97
+ break;
98
+ case 'subscribers_only':
99
+ accessDesc = '⭐ Subscribers Only';
100
+ break;
101
+ case 'private':
102
+ accessDesc = '🔒 Private - Only you';
103
+ break;
104
+ }
105
+
106
+ let display = `
107
+ ✅ Session Access Updated
108
+
109
+ Session: ${result.session_id}
110
+ Access: ${accessDesc}`;
111
+
112
+ if (access_type === 'ppv') {
113
+ display += `\nPrice: $${price_dollars}`;
114
+ display += '\n\nViewers will need to purchase access to see this session.';
115
+ } else if (access_type === 'subscribers_only') {
116
+ display += '\n\nOnly your subscribers can view this session.';
117
+ }
118
+
119
+ return { display: display.trim(), data: result };
120
+
121
+ } catch (error) {
122
+ return {
123
+ display: `❌ Failed to update session access: ${error.message}`
124
+ };
125
+ }
126
+ }
127
+
128
+ module.exports = { definition, handler };