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.
Files changed (162) hide show
  1. package/README.md +1 -0
  2. package/analytics.js +107 -0
  3. package/config.js +174 -3
  4. package/index.js +163 -34
  5. package/intelligence/index.js +45 -0
  6. package/intelligence/infer.js +316 -0
  7. package/intelligence/interests.js +369 -0
  8. package/intelligence/patterns.js +651 -0
  9. package/intelligence/proactive.js +358 -0
  10. package/intelligence/serendipity.js +306 -0
  11. package/notification-emitter.js +77 -0
  12. package/notify.js +141 -18
  13. package/package.json +14 -6
  14. package/presence.js +5 -1
  15. package/protocol/index.js +88 -1
  16. package/protocol/telegram-commands.js +199 -0
  17. package/store/api.js +469 -29
  18. package/store/index.js +7 -7
  19. package/store/local.js +67 -11
  20. package/store/profiles.js +435 -0
  21. package/store/reservations.js +321 -0
  22. package/store/skills.js +378 -0
  23. package/tools/_actions.js +491 -22
  24. package/tools/_connection-queue.js +257 -0
  25. package/tools/_discovery-enhanced.js +290 -0
  26. package/tools/_discovery.js +439 -0
  27. package/tools/_proactive-discovery.js +301 -0
  28. package/tools/_shared/index.js +64 -0
  29. package/tools/_work-context.js +338 -0
  30. package/tools/_work-context.manual-test.js +199 -0
  31. package/tools/_work-context.test.js +260 -0
  32. package/tools/admin-inbox.js +218 -0
  33. package/tools/agent-treasury.js +288 -0
  34. package/tools/agents.js +122 -0
  35. package/tools/analytics.js +191 -0
  36. package/tools/approve.js +197 -0
  37. package/tools/arcade.js +173 -0
  38. package/tools/artifact-create.js +247 -0
  39. package/tools/artifact-view.js +174 -0
  40. package/tools/artifacts-price.js +107 -0
  41. package/tools/ask-expert.js +160 -0
  42. package/tools/auto-suggest-connections.js +304 -0
  43. package/tools/away.js +68 -0
  44. package/tools/back.js +51 -0
  45. package/tools/become-expert.js +150 -0
  46. package/tools/bootstrap-skills.js +231 -0
  47. package/tools/bridge-dashboard.js +342 -0
  48. package/tools/bridge-health.js +400 -0
  49. package/tools/bridge-live.js +384 -0
  50. package/tools/bridges.js +383 -0
  51. package/tools/broadcast.js +286 -0
  52. package/tools/bye.js +4 -0
  53. package/tools/chat.js +202 -0
  54. package/tools/collaborative-drawing.js +286 -0
  55. package/tools/colorguess.js +281 -0
  56. package/tools/crossword.js +369 -0
  57. package/tools/discover-insights.js +379 -0
  58. package/tools/discover-momentum.js +256 -0
  59. package/tools/discover.js +675 -0
  60. package/tools/discovery-analytics.js +345 -0
  61. package/tools/discovery-auto-suggest.js +275 -0
  62. package/tools/discovery-bootstrap.js +267 -0
  63. package/tools/discovery-daily.js +375 -0
  64. package/tools/discovery-dashboard.js +385 -0
  65. package/tools/discovery-digest.js +314 -0
  66. package/tools/discovery-hub.js +357 -0
  67. package/tools/discovery-insights.js +384 -0
  68. package/tools/discovery-momentum.js +281 -0
  69. package/tools/discovery-monitor.js +319 -0
  70. package/tools/discovery-proactive.js +300 -0
  71. package/tools/dm.js +84 -14
  72. package/tools/draw.js +317 -0
  73. package/tools/drawing.js +310 -0
  74. package/tools/earnings.js +126 -0
  75. package/tools/echo.js +16 -0
  76. package/tools/farcaster.js +307 -0
  77. package/tools/feed.js +215 -0
  78. package/tools/follow.js +224 -0
  79. package/tools/friends.js +192 -0
  80. package/tools/game.js +218 -110
  81. package/tools/games-catalog.js +376 -0
  82. package/tools/games.js +313 -0
  83. package/tools/genesis.js +233 -0
  84. package/tools/gig-browse.js +206 -0
  85. package/tools/gig-complete.js +139 -0
  86. package/tools/guessnumber.js +194 -0
  87. package/tools/hangman.js +129 -0
  88. package/tools/help.js +269 -0
  89. package/tools/idea.js +217 -0
  90. package/tools/inbox.js +291 -25
  91. package/tools/init.js +657 -33
  92. package/tools/insights.js +123 -0
  93. package/tools/invite.js +142 -21
  94. package/tools/l2-bridge.js +272 -0
  95. package/tools/l2-status.js +217 -0
  96. package/tools/l2.js +206 -0
  97. package/tools/migrate.js +156 -0
  98. package/tools/mint.js +377 -0
  99. package/tools/multiplayer-game.js +275 -0
  100. package/tools/multiplayer-tictactoe.js +303 -0
  101. package/tools/mute.js +97 -0
  102. package/tools/notifications.js +415 -0
  103. package/tools/observe.js +200 -0
  104. package/tools/onboarding.js +147 -0
  105. package/tools/open.js +52 -3
  106. package/tools/party-game.js +314 -0
  107. package/tools/plan.js +225 -0
  108. package/tools/presence-agent.js +167 -0
  109. package/tools/profile.js +219 -0
  110. package/tools/proof-of-work.js +139 -0
  111. package/tools/pulse.js +218 -0
  112. package/tools/react.js +4 -0
  113. package/tools/release.js +83 -0
  114. package/tools/report.js +109 -0
  115. package/tools/reputation.js +175 -0
  116. package/tools/request.js +231 -0
  117. package/tools/reservations.js +116 -0
  118. package/tools/reserve.js +111 -0
  119. package/tools/riddle.js +240 -0
  120. package/tools/run-bootstrap.js +69 -0
  121. package/tools/schedule.js +367 -0
  122. package/tools/session.js +420 -0
  123. package/tools/session_price.js +128 -0
  124. package/tools/settings.js +200 -0
  125. package/tools/ship.js +188 -0
  126. package/tools/shipback.js +326 -0
  127. package/tools/skills-analytics.js +349 -0
  128. package/tools/skills-bootstrap.js +301 -0
  129. package/tools/skills-dashboard.js +268 -0
  130. package/tools/skills-exchange.js +342 -0
  131. package/tools/skills.js +380 -0
  132. package/tools/smart-intro.js +353 -0
  133. package/tools/social-inbox.js +326 -69
  134. package/tools/social-post.js +251 -66
  135. package/tools/social-processor.js +445 -0
  136. package/tools/solo-game.js +390 -0
  137. package/tools/start.js +296 -81
  138. package/tools/status.js +53 -6
  139. package/tools/storybuilder.js +331 -0
  140. package/tools/stuck.js +297 -0
  141. package/tools/subscribe.js +148 -0
  142. package/tools/subscriptions.js +134 -0
  143. package/tools/suggest-tags.js +184 -0
  144. package/tools/tag-suggestions.js +257 -0
  145. package/tools/telegram-bot.js +183 -0
  146. package/tools/telegram-setup.js +214 -0
  147. package/tools/tictactoe.js +155 -0
  148. package/tools/tip.js +120 -0
  149. package/tools/token.js +103 -0
  150. package/tools/twentyquestions.js +143 -0
  151. package/tools/update.js +1 -1
  152. package/tools/wallet.js +127 -0
  153. package/tools/watch.js +157 -0
  154. package/tools/webhook-test.js +388 -0
  155. package/tools/who.js +118 -25
  156. package/tools/withdraw.js +145 -0
  157. package/tools/wordassociation.js +247 -0
  158. package/tools/work-summary.js +96 -0
  159. package/tools/workshop-buddy.js +394 -0
  160. package/tools/workshop.js +327 -0
  161. package/version.json +12 -3
  162. package/tools/board.js +0 -130
@@ -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 {