slashvibe-mcp 0.2.2 → 0.2.4
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/README.md +1 -0
- package/analytics.js +107 -0
- package/config.js +174 -3
- package/index.js +163 -34
- package/intelligence/index.js +45 -0
- package/intelligence/infer.js +316 -0
- package/intelligence/interests.js +369 -0
- package/intelligence/patterns.js +651 -0
- package/intelligence/proactive.js +358 -0
- package/intelligence/serendipity.js +306 -0
- package/notification-emitter.js +77 -0
- package/notify.js +141 -18
- package/package.json +14 -6
- package/presence.js +5 -1
- package/protocol/index.js +88 -1
- package/protocol/telegram-commands.js +199 -0
- package/store/api.js +469 -29
- package/store/index.js +7 -7
- package/store/local.js +67 -11
- package/store/profiles.js +435 -0
- package/store/reservations.js +321 -0
- package/store/skills.js +378 -0
- package/tools/_actions.js +491 -22
- package/tools/_connection-queue.js +257 -0
- package/tools/_discovery-enhanced.js +290 -0
- package/tools/_discovery.js +439 -0
- package/tools/_proactive-discovery.js +301 -0
- package/tools/_shared/index.js +64 -0
- package/tools/_work-context.js +338 -0
- package/tools/_work-context.manual-test.js +199 -0
- package/tools/_work-context.test.js +260 -0
- package/tools/admin-inbox.js +218 -0
- package/tools/agent-treasury.js +288 -0
- package/tools/agents.js +122 -0
- package/tools/analytics.js +191 -0
- package/tools/approve.js +197 -0
- package/tools/arcade.js +173 -0
- package/tools/artifact-create.js +247 -0
- package/tools/artifact-view.js +174 -0
- package/tools/artifacts-price.js +107 -0
- package/tools/ask-expert.js +160 -0
- package/tools/auto-suggest-connections.js +304 -0
- package/tools/away.js +68 -0
- package/tools/back.js +51 -0
- package/tools/become-expert.js +150 -0
- package/tools/bootstrap-skills.js +231 -0
- package/tools/bridge-dashboard.js +342 -0
- package/tools/bridge-health.js +400 -0
- package/tools/bridge-live.js +384 -0
- package/tools/bridges.js +383 -0
- package/tools/broadcast.js +286 -0
- package/tools/bye.js +4 -0
- package/tools/chat.js +202 -0
- package/tools/collaborative-drawing.js +286 -0
- package/tools/colorguess.js +281 -0
- package/tools/crossword.js +369 -0
- package/tools/discover-insights.js +379 -0
- package/tools/discover-momentum.js +256 -0
- package/tools/discover.js +675 -0
- package/tools/discovery-analytics.js +345 -0
- package/tools/discovery-auto-suggest.js +275 -0
- package/tools/discovery-bootstrap.js +267 -0
- package/tools/discovery-daily.js +375 -0
- package/tools/discovery-dashboard.js +385 -0
- package/tools/discovery-digest.js +314 -0
- package/tools/discovery-hub.js +357 -0
- package/tools/discovery-insights.js +384 -0
- package/tools/discovery-momentum.js +281 -0
- package/tools/discovery-monitor.js +319 -0
- package/tools/discovery-proactive.js +300 -0
- package/tools/dm.js +84 -14
- package/tools/draw.js +317 -0
- package/tools/drawing.js +310 -0
- package/tools/earnings.js +126 -0
- package/tools/echo.js +16 -0
- package/tools/farcaster.js +307 -0
- package/tools/feed.js +215 -0
- package/tools/follow.js +224 -0
- package/tools/friends.js +192 -0
- package/tools/game.js +218 -110
- package/tools/games-catalog.js +376 -0
- package/tools/games.js +313 -0
- package/tools/genesis.js +233 -0
- package/tools/gig-browse.js +206 -0
- package/tools/gig-complete.js +139 -0
- package/tools/guessnumber.js +194 -0
- package/tools/hangman.js +129 -0
- package/tools/help.js +269 -0
- package/tools/idea.js +217 -0
- package/tools/inbox.js +291 -25
- package/tools/init.js +657 -33
- package/tools/insights.js +123 -0
- package/tools/invite.js +142 -21
- package/tools/l2-bridge.js +272 -0
- package/tools/l2-status.js +217 -0
- package/tools/l2.js +206 -0
- package/tools/migrate.js +156 -0
- package/tools/mint.js +377 -0
- package/tools/multiplayer-game.js +275 -0
- package/tools/multiplayer-tictactoe.js +303 -0
- package/tools/mute.js +97 -0
- package/tools/notifications.js +415 -0
- package/tools/observe.js +200 -0
- package/tools/onboarding.js +147 -0
- package/tools/open.js +52 -3
- package/tools/party-game.js +314 -0
- package/tools/plan.js +225 -0
- package/tools/presence-agent.js +167 -0
- package/tools/profile.js +219 -0
- package/tools/proof-of-work.js +139 -0
- package/tools/pulse.js +218 -0
- package/tools/react.js +4 -0
- package/tools/release.js +83 -0
- package/tools/report.js +109 -0
- package/tools/reputation.js +175 -0
- package/tools/request.js +231 -0
- package/tools/reservations.js +116 -0
- package/tools/reserve.js +111 -0
- package/tools/riddle.js +240 -0
- package/tools/run-bootstrap.js +69 -0
- package/tools/schedule.js +367 -0
- package/tools/session.js +420 -0
- package/tools/session_price.js +128 -0
- package/tools/settings.js +200 -0
- package/tools/ship.js +188 -0
- package/tools/shipback.js +326 -0
- package/tools/skills-analytics.js +349 -0
- package/tools/skills-bootstrap.js +301 -0
- package/tools/skills-dashboard.js +268 -0
- package/tools/skills-exchange.js +342 -0
- package/tools/skills.js +380 -0
- package/tools/smart-intro.js +353 -0
- package/tools/social-inbox.js +326 -69
- package/tools/social-post.js +251 -66
- package/tools/social-processor.js +445 -0
- package/tools/solo-game.js +390 -0
- package/tools/start.js +296 -81
- package/tools/status.js +53 -6
- package/tools/storybuilder.js +331 -0
- package/tools/stuck.js +297 -0
- package/tools/subscribe.js +148 -0
- package/tools/subscriptions.js +134 -0
- package/tools/suggest-tags.js +184 -0
- package/tools/tag-suggestions.js +257 -0
- package/tools/telegram-bot.js +183 -0
- package/tools/telegram-setup.js +214 -0
- package/tools/tictactoe.js +155 -0
- package/tools/tip.js +120 -0
- package/tools/token.js +103 -0
- package/tools/twentyquestions.js +143 -0
- package/tools/update.js +1 -1
- package/tools/wallet.js +127 -0
- package/tools/watch.js +157 -0
- package/tools/webhook-test.js +388 -0
- package/tools/who.js +118 -25
- package/tools/withdraw.js +145 -0
- package/tools/wordassociation.js +247 -0
- package/tools/work-summary.js +96 -0
- package/tools/workshop-buddy.js +394 -0
- package/tools/workshop.js +327 -0
- package/version.json +12 -3
- package/tools/board.js +0 -130
package/tools/drawing.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibe drawing — Start or join a collaborative drawing session
|
|
3
|
+
*
|
|
4
|
+
* A shared canvas where multiple users can draw together in real-time
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const config = require('../config');
|
|
8
|
+
const store = require('../store');
|
|
9
|
+
const { createGamePayload } = require('../protocol');
|
|
10
|
+
const { requireInit, normalizeHandle } = require('./_shared');
|
|
11
|
+
|
|
12
|
+
// Drawing game implementation
|
|
13
|
+
const drawing = require('../games/drawing');
|
|
14
|
+
|
|
15
|
+
const definition = {
|
|
16
|
+
name: 'vibe_drawing',
|
|
17
|
+
description: 'Start or join a collaborative drawing session. Draw together on a shared canvas!',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
action: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Action to perform',
|
|
24
|
+
enum: ['start', 'join', 'draw', 'line', 'clear', 'theme', 'view', 'stats']
|
|
25
|
+
},
|
|
26
|
+
room: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Drawing room name (default: general)'
|
|
29
|
+
},
|
|
30
|
+
x: {
|
|
31
|
+
type: 'number',
|
|
32
|
+
description: 'X coordinate (0-19) for drawing'
|
|
33
|
+
},
|
|
34
|
+
y: {
|
|
35
|
+
type: 'number',
|
|
36
|
+
description: 'Y coordinate (0-11) for drawing'
|
|
37
|
+
},
|
|
38
|
+
x1: {
|
|
39
|
+
type: 'number',
|
|
40
|
+
description: 'End X coordinate for line drawing'
|
|
41
|
+
},
|
|
42
|
+
y1: {
|
|
43
|
+
type: 'number',
|
|
44
|
+
description: 'End Y coordinate for line drawing'
|
|
45
|
+
},
|
|
46
|
+
char: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'Character to draw (empty, dot, circle, square, star, heart, tree, house, sun, moon, water, mountain, person, cat, dog, car, plane, flower, umbrella, rainbow)'
|
|
49
|
+
},
|
|
50
|
+
theme: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'Drawing theme/prompt to set'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
required: ['action']
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get drawing game state from global store
|
|
61
|
+
*/
|
|
62
|
+
async function getDrawingState(room) {
|
|
63
|
+
try {
|
|
64
|
+
const key = `drawing:${room}`;
|
|
65
|
+
const state = await store.get(key);
|
|
66
|
+
return state ? JSON.parse(state) : null;
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error('[drawing] Failed to get state:', e.message);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Save drawing game state to global store
|
|
75
|
+
*/
|
|
76
|
+
async function saveDrawingState(room, state) {
|
|
77
|
+
try {
|
|
78
|
+
const key = `drawing:${room}`;
|
|
79
|
+
await store.set(key, JSON.stringify(state));
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.error('[drawing] Failed to save state:', e.message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Post drawing activity to board
|
|
87
|
+
*/
|
|
88
|
+
async function postDrawingActivity(action, room, player, details = '') {
|
|
89
|
+
const API_URL = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
let content;
|
|
93
|
+
switch (action) {
|
|
94
|
+
case 'start':
|
|
95
|
+
content = `🎨 @${player} started a drawing session in #${room}`;
|
|
96
|
+
break;
|
|
97
|
+
case 'join':
|
|
98
|
+
content = `🖌️ @${player} joined the drawing session in #${room}`;
|
|
99
|
+
break;
|
|
100
|
+
case 'theme':
|
|
101
|
+
content = `🎯 @${player} set drawing theme in #${room}: ${details}`;
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
return; // Don't post for every drawing move
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await fetch(`${API_URL}/api/board`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: { 'Content-Type': 'application/json' },
|
|
110
|
+
body: JSON.stringify({
|
|
111
|
+
author: 'games-agent',
|
|
112
|
+
content,
|
|
113
|
+
category: 'games'
|
|
114
|
+
})
|
|
115
|
+
});
|
|
116
|
+
} catch (e) {
|
|
117
|
+
console.error('[drawing] Failed to post to board:', e.message);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function handler(args) {
|
|
122
|
+
const initCheck = requireInit();
|
|
123
|
+
if (initCheck) return initCheck;
|
|
124
|
+
|
|
125
|
+
const { action, room = 'general', x, y, x1, y1, char, theme } = args;
|
|
126
|
+
const myHandle = config.getHandle();
|
|
127
|
+
|
|
128
|
+
// Get current drawing state
|
|
129
|
+
let drawingState = await getDrawingState(room);
|
|
130
|
+
|
|
131
|
+
switch (action) {
|
|
132
|
+
case 'start':
|
|
133
|
+
// Create new drawing session
|
|
134
|
+
drawingState = drawing.createInitialDrawingState();
|
|
135
|
+
const addResult = drawing.addPlayer(drawingState, myHandle);
|
|
136
|
+
if (addResult.error) {
|
|
137
|
+
return { display: `Error: ${addResult.error}` };
|
|
138
|
+
}
|
|
139
|
+
drawingState = addResult.gameState;
|
|
140
|
+
await saveDrawingState(room, drawingState);
|
|
141
|
+
await postDrawingActivity('start', room, myHandle);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
display: `## 🎨 Started Drawing Session in #${room}\n\n${drawing.formatDrawingDisplay(drawingState)}\n\nUse \`vibe drawing --action join --room ${room}\` to let others join!\nUse \`vibe drawing --action draw --room ${room} --x 5 --y 5 --char star\` to draw!`
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
case 'join':
|
|
148
|
+
if (!drawingState) {
|
|
149
|
+
return { display: `No drawing session found in #${room}. Use \`vibe drawing --action start --room ${room}\` to create one!` };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const joinResult = drawing.addPlayer(drawingState, myHandle);
|
|
153
|
+
if (joinResult.error) {
|
|
154
|
+
return { display: `Error: ${joinResult.error}` };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
drawingState = joinResult.gameState;
|
|
158
|
+
await saveDrawingState(room, drawingState);
|
|
159
|
+
await postDrawingActivity('join', room, myHandle);
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
display: `## 🖌️ Joined Drawing Session in #${room}\n\n${drawing.formatDrawingDisplay(drawingState)}\n\nUse \`vibe drawing --action draw --room ${room} --x 10 --y 6 --char heart\` to draw!`
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
case 'draw':
|
|
166
|
+
if (!drawingState) {
|
|
167
|
+
return { display: `No drawing session found in #${room}. Use \`vibe drawing --action start --room ${room}\` to create one!` };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (x === undefined || y === undefined || !char) {
|
|
171
|
+
return { display: 'For drawing, you need: --x [0-19] --y [0-11] --char [character name]' };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Validate character name and get symbol
|
|
175
|
+
const charName = char.toLowerCase();
|
|
176
|
+
if (!drawing.DRAWING_CHARS[charName]) {
|
|
177
|
+
const validChars = Object.keys(drawing.DRAWING_CHARS).join(', ');
|
|
178
|
+
return { display: `Invalid character "${char}". Valid options: ${validChars}` };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const drawResult = drawing.makeMove(drawingState, x, y, drawing.DRAWING_CHARS[charName], myHandle);
|
|
182
|
+
if (drawResult.error) {
|
|
183
|
+
return { display: `Error: ${drawResult.error}` };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
drawingState = drawResult.gameState;
|
|
187
|
+
await saveDrawingState(room, drawingState);
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
display: `## 🎨 Drew in #${room}\n\n${drawing.formatDrawingDisplay(drawingState)}\n\nKeep drawing! Use \`vibe drawing --action view --room ${room}\` to see the canvas.`
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
case 'line':
|
|
194
|
+
if (!drawingState) {
|
|
195
|
+
return { display: `No drawing session found in #${room}. Use \`vibe drawing --action start --room ${room}\` to create one!` };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (x === undefined || y === undefined || x1 === undefined || y1 === undefined || !char) {
|
|
199
|
+
return { display: 'For line drawing, you need: --x [start x] --y [start y] --x1 [end x] --y1 [end y] --char [character name]' };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const charName2 = char.toLowerCase();
|
|
203
|
+
if (!drawing.DRAWING_CHARS[charName2]) {
|
|
204
|
+
const validChars = Object.keys(drawing.DRAWING_CHARS).join(', ');
|
|
205
|
+
return { display: `Invalid character "${char}". Valid options: ${validChars}` };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const lineResult = drawing.drawLine(drawingState, x, y, x1, y1, drawing.DRAWING_CHARS[charName2], myHandle);
|
|
209
|
+
if (lineResult.error) {
|
|
210
|
+
return { display: `Error: ${lineResult.error}` };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
drawingState = lineResult.gameState;
|
|
214
|
+
await saveDrawingState(room, drawingState);
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
display: `## 🎨 Drew Line in #${room}\n\n${drawing.formatDrawingDisplay(drawingState)}\n\nLooking good! Use \`vibe drawing --action view --room ${room}\` to see the full canvas.`
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
case 'clear':
|
|
221
|
+
if (!drawingState) {
|
|
222
|
+
return { display: `No drawing session found in #${room}.` };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const clearResult = drawing.clearRegion(drawingState,
|
|
226
|
+
x || 0, y || 0,
|
|
227
|
+
x1 !== undefined ? x1 : drawing.CANVAS_WIDTH - 1,
|
|
228
|
+
y1 !== undefined ? y1 : drawing.CANVAS_HEIGHT - 1,
|
|
229
|
+
myHandle
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
if (clearResult.error) {
|
|
233
|
+
return { display: `Error: ${clearResult.error}` };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
drawingState = clearResult.gameState;
|
|
237
|
+
await saveDrawingState(room, drawingState);
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
display: `## 🗑️ Cleared Region in #${room}\n\n${drawing.formatDrawingDisplay(drawingState)}\n\nCanvas cleared! Start drawing again.`
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
case 'theme':
|
|
244
|
+
if (!drawingState) {
|
|
245
|
+
return { display: `No drawing session found in #${room}.` };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!theme) {
|
|
249
|
+
return { display: 'Please provide a --theme for the drawing session' };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const themeResult = drawing.setTheme(drawingState, theme, myHandle);
|
|
253
|
+
if (themeResult.error) {
|
|
254
|
+
return { display: `Error: ${themeResult.error}` };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
drawingState = themeResult.gameState;
|
|
258
|
+
await saveDrawingState(room, drawingState);
|
|
259
|
+
await postDrawingActivity('theme', room, myHandle, theme);
|
|
260
|
+
|
|
261
|
+
const tips = drawing.getDrawingTips(theme);
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
display: `## 🎯 Set Theme in #${room}\n\n${drawing.formatDrawingDisplay(drawingState)}\n\n**Drawing tips for "${theme}":**\n${tips.map(tip => `• ${tip}`).join('\n')}`
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
case 'view':
|
|
268
|
+
if (!drawingState) {
|
|
269
|
+
return { display: `No drawing session found in #${room}. Use \`vibe drawing --action start --room ${room}\` to create one!` };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
display: `## 🎨 Drawing Session in #${room}\n\n${drawing.formatDrawingDisplay(drawingState)}\n\nUse \`vibe drawing --action draw --room ${room} --x 10 --y 6 --char heart\` to draw!`
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
case 'stats':
|
|
277
|
+
if (!drawingState) {
|
|
278
|
+
return { display: `No drawing session found in #${room}.` };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const stats = drawing.getCanvasStats(drawingState);
|
|
282
|
+
|
|
283
|
+
let statsDisplay = `## 📊 Drawing Stats for #${room}\n\n`;
|
|
284
|
+
statsDisplay += `**Canvas:** ${stats.fillPercentage}% filled (${stats.totalDrawnCells}/${drawing.CANVAS_WIDTH * drawing.CANVAS_HEIGHT} cells)\n`;
|
|
285
|
+
statsDisplay += `**Moves:** ${stats.totalMoves} total\n`;
|
|
286
|
+
statsDisplay += `**Characters:** ${stats.uniqueCharsUsed} different types used\n\n`;
|
|
287
|
+
|
|
288
|
+
if (stats.mostUsedChar) {
|
|
289
|
+
statsDisplay += `**Most popular:** ${stats.mostUsedChar[0]} (used ${stats.mostUsedChar[1]} times)\n\n`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (Object.keys(stats.playerMoves).length > 0) {
|
|
293
|
+
statsDisplay += `**Artists:**\n`;
|
|
294
|
+
Object.entries(stats.playerMoves)
|
|
295
|
+
.sort(([,a], [,b]) => b - a)
|
|
296
|
+
.forEach(([player, moves]) => {
|
|
297
|
+
statsDisplay += `• @${player}: ${moves} moves\n`;
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return { display: statsDisplay };
|
|
302
|
+
|
|
303
|
+
default:
|
|
304
|
+
return {
|
|
305
|
+
display: `## 🎨 Collaborative Drawing\n\nAvailable actions:\n• \`--action start\` - Create new drawing session\n• \`--action join\` - Join existing session\n• \`--action draw --x [0-19] --y [0-11] --char [name]\` - Draw on canvas\n• \`--action line --x [x] --y [y] --x1 [x1] --y1 [y1] --char [name]\` - Draw line\n• \`--action clear\` - Clear canvas (optionally specify region)\n• \`--action theme --theme [text]\` - Set drawing theme\n• \`--action view\` - View current canvas\n• \`--action stats\` - View drawing statistics\n\nAdd \`--room [name]\` to specify room (default: general)`
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
module.exports = { definition, handler };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibe_earnings - View unified earnings dashboard
|
|
3
|
+
*
|
|
4
|
+
* Shows all revenue sources aggregated:
|
|
5
|
+
* - Artifact sales
|
|
6
|
+
* - Session PPV revenue
|
|
7
|
+
* - Subscription revenue
|
|
8
|
+
* - Gig completions
|
|
9
|
+
* - Tips received
|
|
10
|
+
* - On-chain balance
|
|
11
|
+
*
|
|
12
|
+
* Examples:
|
|
13
|
+
* - "vibe earnings"
|
|
14
|
+
* - "show my earnings"
|
|
15
|
+
* - "how much have I made"
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fetch = require('node-fetch');
|
|
19
|
+
const config = require('../config');
|
|
20
|
+
|
|
21
|
+
const definition = {
|
|
22
|
+
name: 'vibe_earnings',
|
|
23
|
+
description: 'View your unified earnings dashboard - artifact sales, session PPV, subscriptions, gigs, tips, and on-chain balance.',
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
handle: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Handle to check earnings for (defaults to your handle)'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
async function handler(args) {
|
|
36
|
+
const { handle } = args;
|
|
37
|
+
|
|
38
|
+
if (!config.isInitialized()) {
|
|
39
|
+
return {
|
|
40
|
+
display: 'Run `vibe init` first to set your identity.'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const targetHandle = handle || config.getHandle();
|
|
45
|
+
const apiUrl = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
|
|
46
|
+
const token = config.getToken();
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch(
|
|
50
|
+
`${apiUrl}/api/earnings?handle=${encodeURIComponent(targetHandle)}`,
|
|
51
|
+
{
|
|
52
|
+
headers: token ? {
|
|
53
|
+
'Authorization': `Bearer ${token}`
|
|
54
|
+
} : {}
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const result = await response.json();
|
|
59
|
+
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
return {
|
|
62
|
+
display: `❌ ${result.error || 'Failed to fetch earnings'}`
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { earnings, total_earned_display, pending_display, on_chain } = result;
|
|
67
|
+
|
|
68
|
+
let formatted = `
|
|
69
|
+
┌────────────────────────────────────────────────────────────┐
|
|
70
|
+
│ 💰 EARNINGS DASHBOARD │
|
|
71
|
+
│ @${targetHandle.padEnd(33)}│
|
|
72
|
+
├────────────────────────────────────────────────────────────┤
|
|
73
|
+
│ │
|
|
74
|
+
│ Total Earned: ${(total_earned_display || '$0').padEnd(40)} │
|
|
75
|
+
│ Pending (On-chain): ${(pending_display || '$0').padEnd(34)} │
|
|
76
|
+
│ │
|
|
77
|
+
├────────────────────────────────────────────────────────────┤
|
|
78
|
+
│ 📊 Breakdown by Source: │
|
|
79
|
+
│ │
|
|
80
|
+
│ Artifacts: ${(earnings.artifacts.revenue_display || '$0').padEnd(15)} (${earnings.artifacts.sales || 0} sales)${' '.repeat(17)} │
|
|
81
|
+
│ Sessions: ${(earnings.sessions.revenue_display || '$0').padEnd(15)} (${earnings.sessions.ppv_sales || 0} PPV)${' '.repeat(18)} │
|
|
82
|
+
│ Gigs: ${(earnings.gigs.revenue_display || '$0').padEnd(15)} (${earnings.gigs.completed || 0} completed)${' '.repeat(12)} │
|
|
83
|
+
│ Tips: ${(earnings.tips.revenue_display || '$0').padEnd(15)} (${earnings.tips.received || 0} received)${' '.repeat(13)} │
|
|
84
|
+
│ │
|
|
85
|
+
`.trim();
|
|
86
|
+
|
|
87
|
+
if (on_chain) {
|
|
88
|
+
formatted += `
|
|
89
|
+
├────────────────────────────────────────────────────────────┤
|
|
90
|
+
│ ⛓️ On-Chain Status: │`;
|
|
91
|
+
|
|
92
|
+
if (on_chain.registered) {
|
|
93
|
+
const walletDisplay = on_chain.wallet
|
|
94
|
+
? `${on_chain.wallet.slice(0, 10)}...${on_chain.wallet.slice(-8)}`
|
|
95
|
+
: 'not set';
|
|
96
|
+
formatted += `
|
|
97
|
+
│ │
|
|
98
|
+
│ Registered: Yes │
|
|
99
|
+
│ Wallet: ${walletDisplay.padEnd(47)} │
|
|
100
|
+
│ Balance: ${(on_chain.balance_eth + ' ETH').padEnd(46)} │`;
|
|
101
|
+
if (on_chain.can_withdraw) {
|
|
102
|
+
formatted += `
|
|
103
|
+
│ ✅ Ready to withdraw │`;
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
formatted += `
|
|
107
|
+
│ │
|
|
108
|
+
│ Registered: No │
|
|
109
|
+
│ ⚠️ Register to receive payments: vibe register_onchain │`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
formatted += `
|
|
114
|
+
│ │
|
|
115
|
+
└────────────────────────────────────────────────────────────┘`;
|
|
116
|
+
|
|
117
|
+
return { display: formatted, data: result };
|
|
118
|
+
|
|
119
|
+
} catch (error) {
|
|
120
|
+
return {
|
|
121
|
+
display: `❌ Failed to fetch earnings: ${error.message}`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = { definition, handler };
|
package/tools/echo.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
const config = require('../config');
|
|
14
14
|
const { formatTimeAgo, requireInit } = require('./_shared');
|
|
15
|
+
const store = require('../store');
|
|
15
16
|
|
|
16
17
|
const API_URL = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
|
|
17
18
|
|
|
@@ -186,6 +187,21 @@ async function handler(args) {
|
|
|
186
187
|
return { display };
|
|
187
188
|
}
|
|
188
189
|
|
|
190
|
+
// Track feedback for onboarding checklist
|
|
191
|
+
try {
|
|
192
|
+
await fetch(`${API_URL}/api/onboarding/checklist`, {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
headers: { 'Content-Type': 'application/json' },
|
|
195
|
+
body: JSON.stringify({
|
|
196
|
+
handle: myHandle,
|
|
197
|
+
taskId: 'leave_feedback',
|
|
198
|
+
metadata: { anonymous }
|
|
199
|
+
})
|
|
200
|
+
});
|
|
201
|
+
} catch (e) {
|
|
202
|
+
// Non-critical, continue
|
|
203
|
+
}
|
|
204
|
+
|
|
189
205
|
if (anonymous) {
|
|
190
206
|
display += pickRandom(responses.receivedAnon);
|
|
191
207
|
} else {
|