slashvibe-mcp 0.3.21 → 0.3.22
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.
- package/LICENSE +21 -0
- package/README.md +280 -47
- package/config.js +36 -31
- package/crypto.js +1 -6
- package/discord.js +19 -19
- package/index.js +217 -207
- package/intelligence/index.js +2 -9
- package/intelligence/infer.js +10 -16
- package/intelligence/patterns.js +23 -18
- package/intelligence/proactive.js +16 -15
- package/intelligence/serendipity.js +57 -20
- package/memory.js +13 -8
- package/notify.js +39 -14
- package/package.json +27 -20
- package/presence.js +2 -2
- package/prompts.js +5 -9
- package/protocol/index.js +123 -87
- package/protocol/telegram-commands.js +36 -37
- package/store/api.js +358 -529
- package/store/local.js +9 -10
- package/store/profiles.js +48 -192
- package/store/reservations.js +2 -9
- package/store/skills.js +69 -71
- package/store/sqlite.js +355 -0
- package/tools/_actions.js +48 -387
- package/tools/_connection-queue.js +45 -56
- package/tools/_discovery-enhanced.js +52 -57
- package/tools/_discovery.js +87 -185
- package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
- package/tools/{shipback.js → _experimental/shipback.js} +4 -3
- package/tools/_proactive-discovery.js +60 -73
- package/tools/_shared/index.js +41 -64
- package/tools/admin-inbox.js +10 -15
- package/tools/agents.js +1 -1
- package/tools/artifact-create.js +13 -23
- package/tools/artifact-view.js +4 -4
- package/tools/{_deprecated/back.js → back.js} +1 -1
- package/tools/bye.js +3 -5
- package/tools/consent.js +2 -2
- package/tools/context.js +9 -10
- package/tools/crossword.js +3 -2
- package/tools/discover.js +94 -356
- package/tools/dm.js +27 -86
- package/tools/doctor.js +12 -41
- package/tools/drawing.js +34 -20
- package/tools/echo.js +11 -11
- package/tools/feed.js +30 -58
- package/tools/follow.js +64 -187
- package/tools/{_deprecated/forget.js → forget.js} +4 -7
- package/tools/game.js +144 -48
- package/tools/handoff.js +6 -8
- package/tools/help.js +3 -3
- package/tools/idea.js +15 -27
- package/tools/inbox.js +121 -293
- package/tools/init.js +54 -151
- package/tools/invite.js +8 -21
- package/tools/migrate.js +27 -24
- package/tools/multiplayer-game.js +50 -40
- package/tools/{_deprecated/mute.js → mute.js} +4 -3
- package/tools/notifications.js +58 -48
- package/tools/observe.js +12 -15
- package/tools/onboarding.js +8 -11
- package/tools/open.js +13 -144
- package/tools/party-game.js +23 -12
- package/tools/patterns.js +2 -1
- package/tools/ping.js +5 -7
- package/tools/react.js +28 -30
- package/tools/{_deprecated/recall.js → recall.js} +5 -10
- package/tools/release.js +4 -2
- package/tools/{_deprecated/remember.js → remember.js} +4 -6
- package/tools/report.js +2 -2
- package/tools/request.js +6 -26
- package/tools/reserve.js +1 -1
- package/tools/session-fork.js +97 -0
- package/tools/session-save.js +109 -0
- package/tools/settings.js +30 -99
- package/tools/ship.js +74 -56
- package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
- package/tools/social-inbox.js +22 -28
- package/tools/social-post.js +24 -27
- package/tools/solo-game.js +54 -46
- package/tools/start.js +14 -148
- package/tools/status.js +21 -68
- package/tools/submit.js +4 -2
- package/tools/suggest-tags.js +36 -33
- package/tools/summarize.js +19 -16
- package/tools/tag-suggestions.js +72 -73
- package/tools/test.js +1 -1
- package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
- package/tools/token.js +4 -4
- package/tools/update.js +1 -2
- package/tools/watch.js +132 -112
- package/tools/who.js +20 -40
- package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
- package/tools/workshop-buddy.js +52 -53
- package/tools/x-mentions.js +0 -1
- package/tools/x-reply.js +0 -1
- package/twitter.js +14 -20
- package/version.json +8 -10
- package/analytics.js +0 -107
- package/auth-store.js +0 -148
- package/auto-update.js +0 -130
- package/bridges/bridge-monitor.js +0 -388
- package/bridges/discord-bot.js +0 -431
- package/bridges/farcaster.js +0 -299
- package/bridges/telegram.js +0 -261
- package/bridges/webhook-health.js +0 -420
- package/bridges/webhook-server.js +0 -437
- package/bridges/whatsapp.js +0 -441
- package/bridges/x-webhook.js +0 -423
- package/games/arcade.js +0 -406
- package/games/chess.js +0 -451
- package/games/colorguess.js +0 -343
- package/games/crossword-words.js +0 -171
- package/games/crossword.js +0 -461
- package/games/drawing.js +0 -347
- package/games/gameroulette.js +0 -300
- package/games/gamerouter.js +0 -336
- package/games/gamestatus.js +0 -337
- package/games/guessnumber.js +0 -209
- package/games/hangman.js +0 -279
- package/games/memory.js +0 -338
- package/games/multiplayer-tictactoe.js +0 -389
- package/games/pixelart.js +0 -399
- package/games/quickduel.js +0 -354
- package/games/riddle.js +0 -371
- package/games/rockpaperscissors.js +0 -291
- package/games/snake.js +0 -406
- package/games/storybuilder.js +0 -343
- package/games/tictactoe.js +0 -345
- package/games/twentyquestions.js +0 -286
- package/games/twotruths.js +0 -207
- package/games/werewolf.js +0 -508
- package/games/wordassociation.js +0 -247
- package/games/wordchain.js +0 -135
- package/intelligence/interests.js +0 -369
- package/notification-emitter.js +0 -77
- package/setup.js +0 -480
- package/smart-inbox.js +0 -276
- package/tools/_deprecated/auto-suggest-connections.js +0 -304
- package/tools/_deprecated/bootstrap-skills.js +0 -231
- package/tools/_deprecated/bridge-dashboard.js +0 -342
- package/tools/_deprecated/bridge-health.js +0 -400
- package/tools/_deprecated/bridge-live.js +0 -384
- package/tools/_deprecated/bridges.js +0 -383
- package/tools/_deprecated/colorguess.js +0 -281
- package/tools/_deprecated/discover-insights.js +0 -379
- package/tools/_deprecated/discover-momentum.js +0 -256
- package/tools/_deprecated/discovery-analytics.js +0 -345
- package/tools/_deprecated/discovery-auto-suggest.js +0 -275
- package/tools/_deprecated/discovery-bootstrap.js +0 -267
- package/tools/_deprecated/discovery-daily.js +0 -375
- package/tools/_deprecated/discovery-dashboard.js +0 -385
- package/tools/_deprecated/discovery-digest.js +0 -314
- package/tools/_deprecated/discovery-hub.js +0 -357
- package/tools/_deprecated/discovery-insights.js +0 -384
- package/tools/_deprecated/discovery-momentum.js +0 -281
- package/tools/_deprecated/discovery-monitor.js +0 -319
- package/tools/_deprecated/discovery-proactive.js +0 -300
- package/tools/_deprecated/draw.js +0 -317
- package/tools/_deprecated/farcaster.js +0 -307
- package/tools/_deprecated/games-catalog.js +0 -376
- package/tools/_deprecated/games.js +0 -313
- package/tools/_deprecated/guessnumber.js +0 -194
- package/tools/_deprecated/hangman.js +0 -129
- package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
- package/tools/_deprecated/riddle.js +0 -240
- package/tools/_deprecated/run-bootstrap.js +0 -69
- package/tools/_deprecated/skills-analytics.js +0 -349
- package/tools/_deprecated/skills-bootstrap.js +0 -301
- package/tools/_deprecated/skills-dashboard.js +0 -268
- package/tools/_deprecated/skills.js +0 -380
- package/tools/_deprecated/smart-intro.js +0 -353
- package/tools/_deprecated/storybuilder.js +0 -331
- package/tools/_deprecated/telegram-bot.js +0 -183
- package/tools/_deprecated/telegram-setup.js +0 -214
- package/tools/_deprecated/twentyquestions.js +0 -143
- package/tools/_shared.js +0 -234
- package/tools/_work-context.js +0 -338
- package/tools/_work-context.manual-test.js +0 -199
- package/tools/_work-context.test.js +0 -260
- package/tools/activity.js +0 -220
- package/tools/agent-treasury.js +0 -288
- package/tools/analytics.js +0 -191
- package/tools/approve.js +0 -197
- package/tools/arcade.js +0 -173
- package/tools/artifacts-price.js +0 -107
- package/tools/ask-expert.js +0 -160
- package/tools/available.js +0 -120
- package/tools/become-expert.js +0 -150
- package/tools/broadcast.js +0 -325
- package/tools/chat.js +0 -202
- package/tools/collaborative-drawing.js +0 -286
- package/tools/connection-status.js +0 -178
- package/tools/earnings.js +0 -126
- package/tools/friends.js +0 -207
- package/tools/genesis.js +0 -233
- package/tools/gig-browse.js +0 -206
- package/tools/gig-complete.js +0 -144
- package/tools/health.js +0 -87
- package/tools/leaderboard.js +0 -117
- package/tools/lib/git-apply.js +0 -206
- package/tools/lib/git-bundle.js +0 -407
- package/tools/mint.js +0 -377
- package/tools/plan.js +0 -225
- package/tools/profile.js +0 -219
- package/tools/proof-of-work.js +0 -144
- package/tools/pulse.js +0 -218
- package/tools/reply.js +0 -166
- package/tools/reputation.js +0 -175
- package/tools/schedule.js +0 -367
- package/tools/search-messages.js +0 -123
- package/tools/session.js +0 -467
- package/tools/session_price.js +0 -128
- package/tools/smart-check.js +0 -201
- package/tools/social-processor.js +0 -445
- package/tools/streak.js +0 -147
- package/tools/stuck.js +0 -297
- package/tools/subscribe.js +0 -148
- package/tools/subscriptions.js +0 -134
- package/tools/tip.js +0 -193
- package/tools/wallet.js +0 -269
- package/tools/webhook-test.js +0 -388
- package/tools/withdraw.js +0 -145
- package/tools/work-summary.js +0 -96
- package/tools/workshop.js +0 -327
- /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
- /package/tools/{l2.js → _experimental/l2.js} +0 -0
- /package/tools/{_deprecated/away.js → away.js} +0 -0
package/tools/agent-treasury.js
DELETED
|
@@ -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
|
-
};
|
package/tools/analytics.js
DELETED
|
@@ -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 };
|