slashvibe-mcp 0.3.21 → 0.3.23

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 (235) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -47
  3. package/auto-update.js +10 -15
  4. package/config.js +36 -31
  5. package/crypto.js +1 -6
  6. package/debug.js +12 -0
  7. package/discord.js +19 -19
  8. package/eslint.config.js +54 -0
  9. package/index.js +217 -207
  10. package/intelligence/index.js +2 -9
  11. package/intelligence/infer.js +10 -16
  12. package/intelligence/patterns.js +23 -18
  13. package/intelligence/proactive.js +16 -15
  14. package/intelligence/serendipity.js +57 -20
  15. package/memory.js +13 -8
  16. package/migrate-v2.js +72 -0
  17. package/notification-emitter.js +2 -2
  18. package/notify.js +39 -14
  19. package/package.json +28 -29
  20. package/post-install.js +141 -0
  21. package/presence.js +2 -2
  22. package/prompts.js +5 -9
  23. package/protocol/index.js +123 -87
  24. package/protocol/telegram-commands.js +36 -37
  25. package/store/api.js +358 -529
  26. package/store/local.js +9 -10
  27. package/store/profiles.js +48 -192
  28. package/store/reservations.js +2 -9
  29. package/store/skills.js +69 -71
  30. package/store/sqlite.js +355 -0
  31. package/test-skills-bootstrap.js +20 -0
  32. package/test-v2-integration.js +385 -0
  33. package/tools/_actions.js +48 -387
  34. package/tools/_connection-queue.js +45 -56
  35. package/tools/_discovery-enhanced.js +52 -57
  36. package/tools/_discovery.js +87 -185
  37. package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
  38. package/tools/{shipback.js → _experimental/shipback.js} +4 -3
  39. package/tools/_proactive-discovery.js +60 -73
  40. package/tools/_shared/index.js +41 -64
  41. package/tools/admin-inbox.js +10 -15
  42. package/tools/agents.js +1 -1
  43. package/tools/artifact-create.js +13 -23
  44. package/tools/artifact-view.js +4 -4
  45. package/tools/{_deprecated/back.js → back.js} +1 -1
  46. package/tools/bye.js +3 -5
  47. package/tools/consent.js +2 -2
  48. package/tools/context.js +9 -10
  49. package/tools/crossword.js +3 -2
  50. package/tools/discover.js +94 -356
  51. package/tools/dm.js +27 -86
  52. package/tools/doctor.js +12 -41
  53. package/tools/drawing.js +34 -20
  54. package/tools/echo.js +11 -11
  55. package/tools/feed.js +30 -58
  56. package/tools/follow.js +64 -187
  57. package/tools/{_deprecated/forget.js → forget.js} +4 -7
  58. package/tools/game.js +144 -48
  59. package/tools/handoff.js +6 -8
  60. package/tools/help.js +3 -3
  61. package/tools/idea.js +15 -27
  62. package/tools/inbox.js +121 -293
  63. package/tools/init.js +54 -151
  64. package/tools/invite.js +8 -21
  65. package/tools/migrate.js +27 -24
  66. package/tools/multiplayer-game.js +50 -40
  67. package/tools/{_deprecated/mute.js → mute.js} +4 -3
  68. package/tools/notifications.js +58 -48
  69. package/tools/observe.js +12 -15
  70. package/tools/onboarding.js +8 -11
  71. package/tools/open.js +13 -144
  72. package/tools/party-game.js +23 -12
  73. package/tools/patterns.js +2 -1
  74. package/tools/ping.js +5 -7
  75. package/tools/react.js +28 -30
  76. package/tools/{_deprecated/recall.js → recall.js} +5 -10
  77. package/tools/release.js +4 -2
  78. package/tools/{_deprecated/remember.js → remember.js} +4 -6
  79. package/tools/report.js +2 -2
  80. package/tools/request.js +6 -26
  81. package/tools/reserve.js +1 -1
  82. package/tools/session-fork.js +97 -0
  83. package/tools/session-save.js +109 -0
  84. package/tools/settings.js +30 -99
  85. package/tools/ship.js +74 -56
  86. package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
  87. package/tools/social-inbox.js +22 -28
  88. package/tools/social-post.js +24 -27
  89. package/tools/solo-game.js +54 -46
  90. package/tools/start.js +14 -148
  91. package/tools/status.js +21 -68
  92. package/tools/submit.js +4 -2
  93. package/tools/suggest-tags.js +36 -33
  94. package/tools/summarize.js +19 -16
  95. package/tools/tag-suggestions.js +72 -73
  96. package/tools/test.js +1 -1
  97. package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
  98. package/tools/token.js +4 -4
  99. package/tools/update.js +1 -2
  100. package/tools/watch.js +132 -112
  101. package/tools/who.js +20 -40
  102. package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
  103. package/tools/workshop-buddy.js +52 -53
  104. package/tools/x-mentions.js +0 -1
  105. package/tools/x-reply.js +0 -1
  106. package/twitter.js +14 -20
  107. package/version.json +8 -10
  108. package/webhook-runner.js +132 -0
  109. package/auth-store.js +0 -148
  110. package/bridges/bridge-monitor.js +0 -388
  111. package/bridges/discord-bot.js +0 -431
  112. package/bridges/farcaster.js +0 -299
  113. package/bridges/telegram.js +0 -261
  114. package/bridges/webhook-health.js +0 -420
  115. package/bridges/webhook-server.js +0 -437
  116. package/bridges/whatsapp.js +0 -441
  117. package/bridges/x-webhook.js +0 -423
  118. package/games/arcade.js +0 -406
  119. package/games/chess.js +0 -451
  120. package/games/colorguess.js +0 -343
  121. package/games/crossword-words.js +0 -171
  122. package/games/crossword.js +0 -461
  123. package/games/drawing.js +0 -347
  124. package/games/gameroulette.js +0 -300
  125. package/games/gamerouter.js +0 -336
  126. package/games/gamestatus.js +0 -337
  127. package/games/guessnumber.js +0 -209
  128. package/games/hangman.js +0 -279
  129. package/games/memory.js +0 -338
  130. package/games/multiplayer-tictactoe.js +0 -389
  131. package/games/pixelart.js +0 -399
  132. package/games/quickduel.js +0 -354
  133. package/games/riddle.js +0 -371
  134. package/games/rockpaperscissors.js +0 -291
  135. package/games/snake.js +0 -406
  136. package/games/storybuilder.js +0 -343
  137. package/games/tictactoe.js +0 -345
  138. package/games/twentyquestions.js +0 -286
  139. package/games/twotruths.js +0 -207
  140. package/games/werewolf.js +0 -508
  141. package/games/wordassociation.js +0 -247
  142. package/games/wordchain.js +0 -135
  143. package/intelligence/interests.js +0 -369
  144. package/setup.js +0 -480
  145. package/smart-inbox.js +0 -276
  146. package/tools/_deprecated/auto-suggest-connections.js +0 -304
  147. package/tools/_deprecated/bootstrap-skills.js +0 -231
  148. package/tools/_deprecated/bridge-dashboard.js +0 -342
  149. package/tools/_deprecated/bridge-health.js +0 -400
  150. package/tools/_deprecated/bridge-live.js +0 -384
  151. package/tools/_deprecated/bridges.js +0 -383
  152. package/tools/_deprecated/colorguess.js +0 -281
  153. package/tools/_deprecated/discover-insights.js +0 -379
  154. package/tools/_deprecated/discover-momentum.js +0 -256
  155. package/tools/_deprecated/discovery-analytics.js +0 -345
  156. package/tools/_deprecated/discovery-auto-suggest.js +0 -275
  157. package/tools/_deprecated/discovery-bootstrap.js +0 -267
  158. package/tools/_deprecated/discovery-daily.js +0 -375
  159. package/tools/_deprecated/discovery-dashboard.js +0 -385
  160. package/tools/_deprecated/discovery-digest.js +0 -314
  161. package/tools/_deprecated/discovery-hub.js +0 -357
  162. package/tools/_deprecated/discovery-insights.js +0 -384
  163. package/tools/_deprecated/discovery-momentum.js +0 -281
  164. package/tools/_deprecated/discovery-monitor.js +0 -319
  165. package/tools/_deprecated/discovery-proactive.js +0 -300
  166. package/tools/_deprecated/draw.js +0 -317
  167. package/tools/_deprecated/farcaster.js +0 -307
  168. package/tools/_deprecated/games-catalog.js +0 -376
  169. package/tools/_deprecated/games.js +0 -313
  170. package/tools/_deprecated/guessnumber.js +0 -194
  171. package/tools/_deprecated/hangman.js +0 -129
  172. package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
  173. package/tools/_deprecated/riddle.js +0 -240
  174. package/tools/_deprecated/run-bootstrap.js +0 -69
  175. package/tools/_deprecated/skills-analytics.js +0 -349
  176. package/tools/_deprecated/skills-bootstrap.js +0 -301
  177. package/tools/_deprecated/skills-dashboard.js +0 -268
  178. package/tools/_deprecated/skills.js +0 -380
  179. package/tools/_deprecated/smart-intro.js +0 -353
  180. package/tools/_deprecated/storybuilder.js +0 -331
  181. package/tools/_deprecated/telegram-bot.js +0 -183
  182. package/tools/_deprecated/telegram-setup.js +0 -214
  183. package/tools/_deprecated/twentyquestions.js +0 -143
  184. package/tools/_shared.js +0 -234
  185. package/tools/_work-context.js +0 -338
  186. package/tools/_work-context.manual-test.js +0 -199
  187. package/tools/_work-context.test.js +0 -260
  188. package/tools/activity.js +0 -220
  189. package/tools/agent-treasury.js +0 -288
  190. package/tools/analytics.js +0 -191
  191. package/tools/approve.js +0 -197
  192. package/tools/arcade.js +0 -173
  193. package/tools/artifacts-price.js +0 -107
  194. package/tools/ask-expert.js +0 -160
  195. package/tools/available.js +0 -120
  196. package/tools/become-expert.js +0 -150
  197. package/tools/broadcast.js +0 -325
  198. package/tools/chat.js +0 -202
  199. package/tools/collaborative-drawing.js +0 -286
  200. package/tools/connection-status.js +0 -178
  201. package/tools/earnings.js +0 -126
  202. package/tools/friends.js +0 -207
  203. package/tools/genesis.js +0 -233
  204. package/tools/gig-browse.js +0 -206
  205. package/tools/gig-complete.js +0 -144
  206. package/tools/health.js +0 -87
  207. package/tools/leaderboard.js +0 -117
  208. package/tools/lib/git-apply.js +0 -206
  209. package/tools/lib/git-bundle.js +0 -407
  210. package/tools/mint.js +0 -377
  211. package/tools/plan.js +0 -225
  212. package/tools/profile.js +0 -219
  213. package/tools/proof-of-work.js +0 -144
  214. package/tools/pulse.js +0 -218
  215. package/tools/reply.js +0 -166
  216. package/tools/reputation.js +0 -175
  217. package/tools/schedule.js +0 -367
  218. package/tools/search-messages.js +0 -123
  219. package/tools/session.js +0 -467
  220. package/tools/session_price.js +0 -128
  221. package/tools/smart-check.js +0 -201
  222. package/tools/social-processor.js +0 -445
  223. package/tools/streak.js +0 -147
  224. package/tools/stuck.js +0 -297
  225. package/tools/subscribe.js +0 -148
  226. package/tools/subscriptions.js +0 -134
  227. package/tools/tip.js +0 -193
  228. package/tools/wallet.js +0 -269
  229. package/tools/webhook-test.js +0 -388
  230. package/tools/withdraw.js +0 -145
  231. package/tools/work-summary.js +0 -96
  232. package/tools/workshop.js +0 -327
  233. /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
  234. /package/tools/{l2.js → _experimental/l2.js} +0 -0
  235. /package/tools/{_deprecated/away.js → away.js} +0 -0
@@ -1,288 +0,0 @@
1
- /**
2
- * vibe_agent_treasury - Manage agent economic state
3
- *
4
- * For AI agents: create treasury, earn, spend, check balance
5
- *
6
- * Actions:
7
- * - create: Initialize agent treasury
8
- * - balance: Check treasury balance
9
- * - spend: Autonomous spending (requires session key)
10
- * - earnings: View earning history
11
- *
12
- * Examples:
13
- * - "vibe agent create treasury"
14
- * - "check agent balance"
15
- * - "agent tip @alice $5"
16
- */
17
-
18
- const fetch = require('node-fetch');
19
-
20
- module.exports = {
21
- name: 'vibe_agent_treasury',
22
- description: 'Manage agent treasury - create wallet, earn, spend autonomously, track balance. Enables agents as economic actors.',
23
-
24
- inputSchema: {
25
- type: 'object',
26
- properties: {
27
- action: {
28
- type: 'string',
29
- enum: ['create', 'balance', 'spend', 'earnings', 'leaderboard'],
30
- description: 'Action to perform'
31
- },
32
- daily_budget: {
33
- type: 'number',
34
- description: 'Daily spending budget in USD (for create action, default $10)',
35
- default: 10
36
- },
37
- amount: {
38
- type: 'number',
39
- description: 'Amount to spend (for spend action)'
40
- },
41
- recipient: {
42
- type: 'string',
43
- description: 'Recipient handle for spending (for spend action)'
44
- },
45
- spending_type: {
46
- type: 'string',
47
- enum: ['tip', 'service_payment', 'data_purchase'],
48
- description: 'Type of spending (for spend action)',
49
- default: 'tip'
50
- }
51
- },
52
- required: ['action']
53
- },
54
-
55
- async execute({ action, daily_budget = 10, amount, recipient, spending_type = 'tip' }, context) {
56
- try {
57
- const handle = context.handle;
58
-
59
- if (!handle) {
60
- return {
61
- success: false,
62
- error: 'Not authenticated. Use vibe init first.'
63
- };
64
- }
65
-
66
- const apiUrl = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
67
-
68
- switch (action) {
69
- case 'create': {
70
- const response = await fetch(`${apiUrl}/api/agents/wallet/create`, {
71
- method: 'POST',
72
- headers: {
73
- 'Content-Type': 'application/json',
74
- 'Authorization': `Bearer ${context.token}`
75
- },
76
- body: JSON.stringify({
77
- agent_handle: handle,
78
- daily_budget,
79
- tier: 'genesis'
80
- })
81
- });
82
-
83
- const result = await response.json();
84
-
85
- if (!response.ok) {
86
- return {
87
- success: false,
88
- error: result.error || 'Failed to create treasury'
89
- };
90
- }
91
-
92
- return {
93
- success: true,
94
- message: `Agent treasury created for ${handle}`,
95
- treasury: {
96
- agent_handle: result.agent_handle,
97
- wallet_address: result.wallet_address,
98
- daily_budget: `$${result.daily_budget}`,
99
- tier: result.tier,
100
- commission_rate: `${(result.commission_rate * 100).toFixed(2)}%`
101
- },
102
- formatted: `
103
- 🤖 Agent Treasury Created!
104
-
105
- Agent: ${result.agent_handle}
106
- Wallet: ${result.wallet_address}
107
-
108
- Daily Budget: $${result.daily_budget}
109
- Commission Rate: ${(result.commission_rate * 100).toFixed(2)}%
110
- Tier: ${result.tier}
111
-
112
- Your agent can now:
113
- • Earn from tips, commissions, services
114
- • Spend autonomously (with session key)
115
- • Participate in the economy
116
-
117
- Check balance: vibe agent_treasury balance
118
- `.trim()
119
- };
120
- }
121
-
122
- case 'balance': {
123
- const response = await fetch(
124
- `${apiUrl}/api/agents/wallet/treasury?agent_handle=${handle}`,
125
- {
126
- headers: {
127
- 'Authorization': `Bearer ${context.token}`
128
- }
129
- }
130
- );
131
-
132
- const result = await response.json();
133
-
134
- if (!response.ok) {
135
- return {
136
- success: false,
137
- error: result.error || 'Treasury not found',
138
- message: result.message
139
- };
140
- }
141
-
142
- const earningsByType = result.earnings_breakdown?.map(e =>
143
- ` ${e.type}: $${e.total.toFixed(2)} (${e.count} events)`
144
- ) || [];
145
-
146
- return {
147
- success: true,
148
- treasury: result,
149
- formatted: `
150
- 💰 Agent Treasury: ${handle}
151
-
152
- Balances:
153
- Current: $${result.balances.current.toFixed(2)}
154
- Total Earned: $${result.balances.total_earned.toFixed(2)}
155
- Total Spent: $${result.balances.total_spent.toFixed(2)}
156
-
157
- Daily Budget:
158
- Limit: $${result.budget.daily_limit.toFixed(2)}
159
- Spent Today: $${result.budget.daily_spent.toFixed(2)}
160
- Remaining: $${result.budget.daily_remaining.toFixed(2)}
161
- Resets: ${new Date(result.budget.resets_at).toLocaleString()}
162
-
163
- Tier: ${result.tier}
164
- Commission Rate: ${(result.commission_rate * 100).toFixed(2)}%
165
- Session Key: ${result.session_key_active ? '✓ Active' : '✗ Inactive'}
166
-
167
- Earnings Breakdown:
168
- ${earningsByType.length > 0 ? earningsByType.join('\n') : ' No earnings yet'}
169
-
170
- Recent Transactions: ${result.recent_earnings?.length || 0} earnings, ${result.recent_spending?.length || 0} spending
171
- `.trim()
172
- };
173
- }
174
-
175
- case 'spend': {
176
- if (!amount || !recipient) {
177
- return {
178
- success: false,
179
- error: 'Amount and recipient required for spending'
180
- };
181
- }
182
-
183
- // Note: This requires a session key which should be managed separately
184
- return {
185
- success: false,
186
- error: 'Autonomous spending requires session key configuration',
187
- message: 'Contact administrator to enable session keys for your agent'
188
- };
189
- }
190
-
191
- case 'earnings': {
192
- const response = await fetch(
193
- `${apiUrl}/api/agents/wallet/treasury?agent_handle=${handle}&include_history=true`,
194
- {
195
- headers: {
196
- 'Authorization': `Bearer ${context.token}`
197
- }
198
- }
199
- );
200
-
201
- const result = await response.json();
202
-
203
- if (!response.ok) {
204
- return {
205
- success: false,
206
- error: 'Failed to fetch earnings'
207
- };
208
- }
209
-
210
- const earningLines = result.recent_earnings?.slice(0, 10).map(e =>
211
- ` +$${e.amount.toFixed(2)} | ${e.type} | ${e.source || 'system'}`
212
- ) || [];
213
-
214
- return {
215
- success: true,
216
- earnings: result.recent_earnings,
217
- formatted: `
218
- 💵 Agent Earnings: ${handle}
219
-
220
- Total Earned: $${result.balances.total_earned.toFixed(2)}
221
-
222
- Recent Earnings (${result.recent_earnings?.length || 0}):
223
- ${earningLines.length > 0 ? earningLines.join('\n') : ' No earnings yet'}
224
-
225
- Start earning by:
226
- • Receiving tips from users
227
- • Facilitating transactions (commission)
228
- • Providing expert services
229
- • Contributing to liquidity
230
- `.trim()
231
- };
232
- }
233
-
234
- case 'leaderboard': {
235
- const response = await fetch(
236
- `${apiUrl}/api/agents/leaderboard?metric=balance&limit=20`,
237
- {
238
- headers: {
239
- 'Authorization': `Bearer ${context.token}`
240
- }
241
- }
242
- );
243
-
244
- const result = await response.json();
245
-
246
- if (!response.ok) {
247
- return {
248
- success: false,
249
- error: 'Failed to fetch leaderboard'
250
- };
251
- }
252
-
253
- const leaderLines = result.agents?.slice(0, 15).map(a =>
254
- ` ${a.rank}. ${a.agent_handle.padEnd(20)} $${a.current_balance.toFixed(2).padStart(10)} ${a.tier}`
255
- ) || [];
256
-
257
- return {
258
- success: true,
259
- leaderboard: result.agents,
260
- formatted: `
261
- 🏆 Agent Economic Leaderboard
262
-
263
- ${leaderLines.join('\n')}
264
-
265
- Stats:
266
- Total Agents: ${result.stats.total_agents}
267
- Total Balance: $${result.stats.total_balance.toFixed(2)}
268
- Avg Balance: $${result.stats.avg_balance.toFixed(2)}
269
- `.trim()
270
- };
271
- }
272
-
273
- default:
274
- return {
275
- success: false,
276
- error: 'Invalid action. Use: create, balance, earnings, or leaderboard'
277
- };
278
- }
279
-
280
- } catch (error) {
281
- return {
282
- success: false,
283
- error: 'Agent treasury action failed',
284
- details: error.message
285
- };
286
- }
287
- }
288
- };
@@ -1,191 +0,0 @@
1
- /**
2
- * vibe analytics — Real-time launch metrics for terminal
3
- *
4
- * Shows live platform metrics in a terminal-friendly format.
5
- * Perfect for monitoring during Watch Me Code launch.
6
- *
7
- * Commands:
8
- * - analytics (default) — Launch dashboard with all metrics
9
- * - analytics presence — Who's online right now
10
- * - analytics sessions — Live streaming stats
11
- * - analytics health — System health status
12
- */
13
-
14
- const config = require('../config');
15
-
16
- const API_BASE = 'https://www.slashvibe.dev/api';
17
-
18
- const definition = {
19
- name: 'vibe_analytics',
20
- description: 'Real-time launch metrics. Shows presence, sessions, health. Perfect for launch monitoring.',
21
- inputSchema: {
22
- type: 'object',
23
- properties: {
24
- view: {
25
- type: 'string',
26
- enum: ['dashboard', 'presence', 'sessions', 'health'],
27
- description: 'Which view to show (default: dashboard)'
28
- }
29
- }
30
- }
31
- };
32
-
33
- // Fetch launch metrics from API
34
- async function fetchLaunchMetrics() {
35
- try {
36
- const res = await fetch(`${API_BASE}/analytics/launch`);
37
- const data = await res.json();
38
- return data.success ? data : null;
39
- } catch (e) {
40
- console.error('[analytics] Fetch error:', e.message);
41
- return null;
42
- }
43
- }
44
-
45
- // Format the full dashboard view
46
- function formatDashboard(data) {
47
- const { presence, sessions, growth, viral, health, countdown } = data;
48
-
49
- const lines = [
50
- '',
51
- '╔══════════════════════════════════════════════════════════════╗',
52
- `║ 🚀 LAUNCH COMMAND CENTER ${countdown.padStart(20)} ║`,
53
- '╠══════════════════════════════════════════════════════════════╣',
54
- '║ ║',
55
- '║ PRESENCE LIVE SESSIONS ║',
56
- `║ 🟢 Online: ${String(presence.online).padEnd(6)} 📺 Live Now: ${String(sessions.live_now).padEnd(5)} ║`,
57
- `║ 🟡 Away: ${String(presence.away).padEnd(6)} 👀 Viewers: ${String(sessions.viewers_now).padEnd(5)} ║`,
58
- `║ Total: ${String(presence.total_active).padEnd(6)} 🔥 Reactions: ${String(sessions.reactions_now || 0).padEnd(5)} ║`,
59
- '║ ║',
60
- '╠══════════════════════════════════════════════════════════════╣',
61
- '║ GROWTH TODAY VIRAL ║',
62
- `║ 📝 Registrations: ${String(growth.registrations_today).padEnd(4)} 📨 Invites: ${String(viral.invites_sent_today).padEnd(5)} ║`,
63
- `║ 💬 Messages: ${String(growth.messages_today).padEnd(4)} 🔗 Shares: ${String(viral.share_link_clicks_today).padEnd(5)} ║`,
64
- `║ 🚀 Ships: ${String(growth.ships_today).padEnd(4)} 🖼️ OG Views: ${String(viral.og_image_requests_today).padEnd(5)} ║`,
65
- '║ ║',
66
- '╠══════════════════════════════════════════════════════════════╣',
67
- '║ HEALTH ║',
68
- `║ Status: ${health.status === 'healthy' ? '✅ Healthy' : health.status === 'degraded' ? '⚠️ Degraded' : '❌ Unhealthy'} Latency: ${String(health.api_latency_ms).padEnd(4)}ms ║`,
69
- `║ KV: ${health.kv_healthy ? '✅' : '❌'} Postgres: ${health.db_healthy ? '✅' : '❌'} ║`,
70
- '║ ║',
71
- '╚══════════════════════════════════════════════════════════════╝',
72
- '',
73
- ];
74
-
75
- return lines.join('\n');
76
- }
77
-
78
- // Format presence view
79
- function formatPresence(data) {
80
- const { presence } = data;
81
-
82
- return `
83
- **Presence** (real-time)
84
-
85
- 🟢 **${presence.online}** online now
86
- 🟡 **${presence.away}** away
87
- 📊 **${presence.total_active}** total active
88
-
89
- _Updated: ${new Date().toLocaleTimeString()}_
90
- `;
91
- }
92
-
93
- // Format sessions view
94
- function formatSessions(data) {
95
- const { sessions } = data;
96
-
97
- if (sessions.live_now === 0) {
98
- return `
99
- **Live Sessions**
100
-
101
- No live sessions right now.
102
-
103
- 📺 Sessions today: ${sessions.started_today}
104
- 🔗 Shares today: ${sessions.shares_today}
105
- ✂️ Clips today: ${sessions.clips_today}
106
-
107
- _Start streaming with \`vibe broadcast start "title"\`_
108
- `;
109
- }
110
-
111
- let display = `
112
- **Live Sessions** 📺
113
-
114
- 🔴 **${sessions.live_now}** live now
115
- 👀 **${sessions.viewers_now}** watching
116
- 🔥 **${sessions.reactions_now || 0}** reactions
117
- `;
118
-
119
- // Show top streams if available
120
- if (sessions.live_streams && sessions.live_streams.length > 0) {
121
- display += '\n**Active Streams:**\n';
122
- for (const stream of sessions.live_streams) {
123
- display += `• @${stream.handle}: ${stream.viewers} viewers, ${stream.durationMins}m\n`;
124
- display += ` ${stream.watchUrl}\n`;
125
- }
126
- }
127
-
128
- display += `
129
- Today:
130
- - ${sessions.started_today} sessions started
131
- - ${sessions.shares_today} shares
132
- - ${sessions.clips_today} clips
133
-
134
- _Watch live at slashvibe.dev/live_
135
- `;
136
-
137
- return display;
138
- }
139
-
140
- // Format health view
141
- function formatHealth(data) {
142
- const { health } = data;
143
-
144
- const statusEmoji = health.status === 'healthy' ? '✅' : health.status === 'degraded' ? '⚠️' : '❌';
145
-
146
- return `
147
- **System Health** ${statusEmoji}
148
-
149
- Status: **${health.status}**
150
- Latency: ${health.api_latency_ms}ms
151
-
152
- Services:
153
- - KV Storage: ${health.kv_healthy ? '✅ Healthy' : '❌ Down'}
154
- - PostgreSQL: ${health.db_healthy ? '✅ Healthy' : '❌ Down'}
155
-
156
- _Check slashvibe.dev/mission-control for full dashboard_
157
- `;
158
- }
159
-
160
- async function handler(args) {
161
- const view = args.view || 'dashboard';
162
-
163
- const data = await fetchLaunchMetrics();
164
-
165
- if (!data) {
166
- return {
167
- display: '❌ Could not fetch analytics. Check your connection.'
168
- };
169
- }
170
-
171
- let display;
172
-
173
- switch (view) {
174
- case 'presence':
175
- display = formatPresence(data);
176
- break;
177
- case 'sessions':
178
- display = formatSessions(data);
179
- break;
180
- case 'health':
181
- display = formatHealth(data);
182
- break;
183
- case 'dashboard':
184
- default:
185
- display = formatDashboard(data);
186
- }
187
-
188
- return { display };
189
- }
190
-
191
- module.exports = { definition, handler };
package/tools/approve.js DELETED
@@ -1,197 +0,0 @@
1
- /**
2
- * vibe_approve — Respond to a plan with approval, rejection, or request changes
3
- *
4
- * Only people in the plan's requested_from list can respond.
5
- */
6
-
7
- const config = require('../config');
8
- const store = require('../store');
9
- const { requireInit, normalizeHandle } = require('./_shared');
10
-
11
- const definition = {
12
- name: 'vibe_approve',
13
- description: 'Approve, reject, or request changes on a plan. Only invited approvers can respond.',
14
- inputSchema: {
15
- type: 'object',
16
- properties: {
17
- plan_id: {
18
- type: 'string',
19
- description: 'Plan ID or slug (e.g., "claude-md-cleanup" or "plan_123...")'
20
- },
21
- decision: {
22
- type: 'string',
23
- enum: ['approve', 'needs_changes', 'reject'],
24
- description: 'Your decision: approve, needs_changes, or reject'
25
- },
26
- note: {
27
- type: 'string',
28
- description: 'Optional feedback or reason for your decision'
29
- }
30
- },
31
- required: ['plan_id', 'decision']
32
- }
33
- };
34
-
35
- async function handler(args) {
36
- const initCheck = requireInit();
37
- if (initCheck) return initCheck;
38
-
39
- const { plan_id, decision, note } = args;
40
- const myHandle = config.getHandle();
41
-
42
- // Fetch the plan
43
- const planResult = await store.getArtifact(plan_id);
44
-
45
- if (!planResult.success || !planResult.artifact) {
46
- return {
47
- display: `❌ Plan not found: ${plan_id}\n\nTip: Use the plan slug (e.g., "claude-md-cleanup") or full ID.`
48
- };
49
- }
50
-
51
- const plan = planResult.artifact;
52
-
53
- // Verify it's a plan template
54
- if (plan.template !== 'plan') {
55
- return {
56
- display: `❌ "${plan_id}" is not a plan (it's a ${plan.template})`
57
- };
58
- }
59
-
60
- // Verify it has approval workflow
61
- if (!plan.approval) {
62
- return {
63
- display: `❌ This plan doesn't have an approval workflow`
64
- };
65
- }
66
-
67
- // Check if user is in the requested_from list
68
- if (!plan.approval.requested_from.includes(myHandle)) {
69
- return {
70
- display: `❌ You're not on the approver list for this plan.\n\n**Approvers:** ${plan.approval.requested_from.map(h => `@${h}`).join(', ')}`
71
- };
72
- }
73
-
74
- // Check if plan is still pending
75
- if (plan.approval.status !== 'pending') {
76
- return {
77
- display: `⚠️ This plan is already ${plan.approval.status}.\n\nNo changes made.`
78
- };
79
- }
80
-
81
- // Check if user already responded
82
- const existingResponse = plan.approval.responses.find(r => r.handle === myHandle);
83
- if (existingResponse) {
84
- return {
85
- display: `⚠️ You already responded to this plan (${existingResponse.status}).\n\nTo change your response, the plan creator would need to request again.`
86
- };
87
- }
88
-
89
- // Record the response
90
- const response = {
91
- handle: myHandle,
92
- status: decision,
93
- note: note || null,
94
- responded_at: new Date().toISOString()
95
- };
96
-
97
- plan.approval.responses.push(response);
98
- plan.updated_at = new Date().toISOString();
99
-
100
- // Determine new status based on decision and requires mode
101
- let newStatus = 'pending';
102
-
103
- if (decision === 'approve') {
104
- if (plan.approval.requires === 'any') {
105
- // Any approval is enough
106
- newStatus = 'approved';
107
- } else {
108
- // All must approve - check if everyone has approved
109
- const allApproved = plan.approval.requested_from.every(h =>
110
- plan.approval.responses.some(r => r.handle === h && r.status === 'approve')
111
- );
112
- newStatus = allApproved ? 'approved' : 'pending';
113
- }
114
- } else if (decision === 'reject') {
115
- // Any rejection rejects the plan
116
- newStatus = 'rejected';
117
- } else if (decision === 'needs_changes') {
118
- // Any needs_changes puts it in that state
119
- newStatus = 'needs_changes';
120
- }
121
-
122
- plan.approval.status = newStatus;
123
- if (newStatus !== 'pending') {
124
- plan.approval.resolved_at = new Date().toISOString();
125
- }
126
-
127
- // Save the updated plan
128
- const updateResult = await store.updateArtifact(plan.id, plan);
129
-
130
- if (!updateResult.success) {
131
- return {
132
- display: `❌ Failed to save response: ${updateResult.error}`
133
- };
134
- }
135
-
136
- // Notify the plan creator
137
- const creator = plan.created_by;
138
- const statusEmoji = {
139
- approve: '✅',
140
- needs_changes: '🔄',
141
- reject: '❌'
142
- }[decision];
143
-
144
- const statusText = {
145
- approve: 'approved',
146
- needs_changes: 'requested changes on',
147
- reject: 'rejected'
148
- }[decision];
149
-
150
- try {
151
- await store.sendMessage(myHandle, creator,
152
- `${statusEmoji} **@${myHandle} ${statusText} your plan**\n\n` +
153
- `**Plan:** ${plan.title}\n` +
154
- (note ? `**Note:** ${note}\n` : '') +
155
- `**Status:** ${newStatus === 'pending' ? '⏳ Still pending (awaiting more approvers)' : `${statusEmoji} ${newStatus.charAt(0).toUpperCase() + newStatus.slice(1)}`}`,
156
- {
157
- type: 'plan_response',
158
- plan_id: plan.id,
159
- plan_slug: plan.slug,
160
- decision,
161
- new_status: newStatus
162
- }
163
- );
164
- } catch (error) {
165
- console.error('[APPROVE] Failed to notify creator:', error);
166
- }
167
-
168
- // Build response
169
- let display = `${statusEmoji} **Response recorded: ${decision}**\n\n`;
170
- display += `**Plan:** ${plan.title}\n`;
171
- display += `**Your decision:** ${decision}${note ? ` — "${note}"` : ''}\n`;
172
- display += `**Plan status:** ${newStatus}\n\n`;
173
-
174
- if (newStatus === 'approved') {
175
- display += `✓ Plan is now approved! @${creator} has been notified.`;
176
- } else if (newStatus === 'rejected') {
177
- display += `Plan has been rejected. @${creator} has been notified.`;
178
- } else if (newStatus === 'needs_changes') {
179
- display += `Plan needs changes. @${creator} has been notified to update.`;
180
- } else {
181
- const remaining = plan.approval.requested_from.filter(h =>
182
- !plan.approval.responses.some(r => r.handle === h)
183
- );
184
- display += `⏳ Waiting for: ${remaining.map(h => `@${h}`).join(', ')}`;
185
- }
186
-
187
- return {
188
- display,
189
- plan_id: plan.id,
190
- plan_slug: plan.slug,
191
- decision,
192
- new_status: newStatus,
193
- creator_notified: true
194
- };
195
- }
196
-
197
- module.exports = { definition, handler };