slashvibe-mcp 0.3.20 → 0.3.21
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 +47 -252
- package/analytics.js +107 -0
- package/auth-store.js +148 -0
- package/auto-update.js +130 -0
- package/bridges/bridge-monitor.js +388 -0
- package/bridges/discord-bot.js +431 -0
- package/bridges/farcaster.js +299 -0
- package/bridges/telegram.js +261 -0
- package/bridges/webhook-health.js +420 -0
- package/bridges/webhook-server.js +437 -0
- package/bridges/whatsapp.js +441 -0
- package/bridges/x-webhook.js +423 -0
- package/config.js +27 -15
- package/games/arcade.js +406 -0
- package/games/chess.js +451 -0
- package/games/colorguess.js +343 -0
- package/games/crossword-words.js +171 -0
- package/games/crossword.js +461 -0
- package/games/drawing.js +347 -0
- package/games/gameroulette.js +300 -0
- package/games/gamerouter.js +336 -0
- package/games/gamestatus.js +337 -0
- package/games/guessnumber.js +209 -0
- package/games/hangman.js +279 -0
- package/games/memory.js +338 -0
- package/games/multiplayer-tictactoe.js +389 -0
- package/games/pixelart.js +399 -0
- package/games/quickduel.js +354 -0
- package/games/riddle.js +371 -0
- package/games/rockpaperscissors.js +291 -0
- package/games/snake.js +406 -0
- package/games/storybuilder.js +343 -0
- package/games/tictactoe.js +345 -0
- package/games/twentyquestions.js +286 -0
- package/games/twotruths.js +207 -0
- package/games/werewolf.js +508 -0
- package/games/wordassociation.js +247 -0
- package/games/wordchain.js +135 -0
- package/index.js +116 -159
- package/intelligence/index.js +9 -2
- package/intelligence/interests.js +369 -0
- package/notification-emitter.js +77 -0
- package/notify.js +5 -1
- package/package.json +21 -16
- package/prompts.js +1 -1
- package/protocol/index.js +73 -0
- package/setup.js +480 -0
- package/smart-inbox.js +276 -0
- package/store/api.js +536 -215
- package/store/profiles.js +160 -12
- package/tools/_actions.js +362 -21
- package/tools/_discovery.js +119 -26
- package/tools/_shared/index.js +64 -0
- package/tools/_shared.js +234 -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/activity.js +220 -0
- package/tools/analytics.js +191 -0
- package/tools/approve.js +197 -0
- package/tools/artifact-create.js +14 -3
- package/tools/artifacts-price.js +107 -0
- package/tools/available.js +120 -0
- package/tools/broadcast.js +325 -0
- package/tools/chat.js +202 -0
- package/tools/collaborative-drawing.js +1 -1
- package/tools/connection-status.js +178 -0
- package/tools/discover.js +350 -34
- package/tools/dm.js +80 -8
- package/tools/earnings.js +126 -0
- package/tools/feed.js +35 -4
- package/tools/follow.js +224 -0
- package/tools/friends.js +207 -0
- package/tools/gig-browse.js +206 -0
- package/tools/gig-complete.js +144 -0
- package/tools/health.js +87 -0
- package/tools/help.js +3 -3
- package/tools/idea.js +9 -2
- package/tools/inbox.js +289 -105
- package/tools/init.js +131 -34
- package/tools/invite.js +15 -4
- package/tools/leaderboard.js +117 -0
- package/tools/lib/git-apply.js +206 -0
- package/tools/lib/git-bundle.js +407 -0
- package/tools/migrate.js +3 -3
- package/tools/multiplayer-game.js +1 -1
- package/tools/onboarding.js +7 -7
- package/tools/open.js +143 -12
- package/tools/party-game.js +1 -1
- package/tools/plan.js +225 -0
- package/tools/proof-of-work.js +144 -0
- package/tools/reply.js +166 -0
- package/tools/report.js +1 -1
- package/tools/request.js +17 -3
- package/tools/schedule.js +367 -0
- package/tools/search-messages.js +123 -0
- package/tools/session.js +467 -0
- package/tools/session_price.js +128 -0
- package/tools/settings.js +90 -2
- package/tools/ship.js +30 -7
- package/tools/smart-check.js +201 -0
- package/tools/start.js +147 -12
- package/tools/status.js +53 -6
- package/tools/streak.js +147 -0
- package/tools/stuck.js +297 -0
- package/tools/subscribe.js +148 -0
- package/tools/subscriptions.js +134 -0
- package/tools/suggest-tags.js +6 -8
- package/tools/tag-suggestions.js +1 -1
- package/tools/tip.js +150 -77
- package/tools/token.js +4 -4
- package/tools/update.js +1 -1
- package/tools/wallet.js +221 -79
- package/tools/watch.js +157 -0
- package/tools/who.js +30 -1
- package/tools/withdraw.js +145 -0
- package/tools/work-summary.js +96 -0
- package/version.json +10 -8
- package/LICENSE +0 -21
- package/store/sqlite.js +0 -347
- /package/tools/{auto-suggest-connections.js → _deprecated/auto-suggest-connections.js} +0 -0
- /package/tools/{away.js → _deprecated/away.js} +0 -0
- /package/tools/{back.js → _deprecated/back.js} +0 -0
- /package/tools/{bootstrap-skills.js → _deprecated/bootstrap-skills.js} +0 -0
- /package/tools/{bridge-dashboard.js → _deprecated/bridge-dashboard.js} +0 -0
- /package/tools/{bridge-health.js → _deprecated/bridge-health.js} +0 -0
- /package/tools/{bridge-live.js → _deprecated/bridge-live.js} +0 -0
- /package/tools/{bridges.js → _deprecated/bridges.js} +0 -0
- /package/tools/{colorguess.js → _deprecated/colorguess.js} +0 -0
- /package/tools/{discover-insights.js → _deprecated/discover-insights.js} +0 -0
- /package/tools/{discover-momentum.js → _deprecated/discover-momentum.js} +0 -0
- /package/tools/{discovery-analytics.js → _deprecated/discovery-analytics.js} +0 -0
- /package/tools/{discovery-auto-suggest.js → _deprecated/discovery-auto-suggest.js} +0 -0
- /package/tools/{discovery-bootstrap.js → _deprecated/discovery-bootstrap.js} +0 -0
- /package/tools/{discovery-daily.js → _deprecated/discovery-daily.js} +0 -0
- /package/tools/{discovery-dashboard.js → _deprecated/discovery-dashboard.js} +0 -0
- /package/tools/{discovery-digest.js → _deprecated/discovery-digest.js} +0 -0
- /package/tools/{discovery-hub.js → _deprecated/discovery-hub.js} +0 -0
- /package/tools/{discovery-insights.js → _deprecated/discovery-insights.js} +0 -0
- /package/tools/{discovery-momentum.js → _deprecated/discovery-momentum.js} +0 -0
- /package/tools/{discovery-monitor.js → _deprecated/discovery-monitor.js} +0 -0
- /package/tools/{discovery-proactive.js → _deprecated/discovery-proactive.js} +0 -0
- /package/tools/{draw.js → _deprecated/draw.js} +0 -0
- /package/tools/{farcaster.js → _deprecated/farcaster.js} +0 -0
- /package/tools/{forget.js → _deprecated/forget.js} +0 -0
- /package/tools/{games-catalog.js → _deprecated/games-catalog.js} +0 -0
- /package/tools/{games.js → _deprecated/games.js} +0 -0
- /package/tools/{guessnumber.js → _deprecated/guessnumber.js} +0 -0
- /package/tools/{hangman.js → _deprecated/hangman.js} +0 -0
- /package/tools/{multiplayer-tictactoe.js → _deprecated/multiplayer-tictactoe.js} +0 -0
- /package/tools/{mute.js → _deprecated/mute.js} +0 -0
- /package/tools/{recall.js → _deprecated/recall.js} +0 -0
- /package/tools/{remember.js → _deprecated/remember.js} +0 -0
- /package/tools/{riddle.js → _deprecated/riddle.js} +0 -0
- /package/tools/{run-bootstrap.js → _deprecated/run-bootstrap.js} +0 -0
- /package/tools/{skills-analytics.js → _deprecated/skills-analytics.js} +0 -0
- /package/tools/{skills-bootstrap.js → _deprecated/skills-bootstrap.js} +0 -0
- /package/tools/{skills-dashboard.js → _deprecated/skills-dashboard.js} +0 -0
- /package/tools/{skills-exchange.js → _deprecated/skills-exchange.js} +0 -0
- /package/tools/{skills.js → _deprecated/skills.js} +0 -0
- /package/tools/{smart-intro.js → _deprecated/smart-intro.js} +0 -0
- /package/tools/{storybuilder.js → _deprecated/storybuilder.js} +0 -0
- /package/tools/{telegram-bot.js → _deprecated/telegram-bot.js} +0 -0
- /package/tools/{telegram-setup.js → _deprecated/telegram-setup.js} +0 -0
- /package/tools/{tictactoe.js → _deprecated/tictactoe.js} +0 -0
- /package/tools/{twentyquestions.js → _deprecated/twentyquestions.js} +0 -0
- /package/tools/{wordassociation.js → _deprecated/wordassociation.js} +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibe_subscriptions - List my subscriptions
|
|
3
|
+
*
|
|
4
|
+
* View all your active subscriptions to creators.
|
|
5
|
+
* Shows subscription status, renewal dates, and access benefits.
|
|
6
|
+
*
|
|
7
|
+
* Examples:
|
|
8
|
+
* - "show my subscriptions"
|
|
9
|
+
* - "what am I subscribed to"
|
|
10
|
+
* - "list subscriptions"
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fetch = require('node-fetch');
|
|
14
|
+
const config = require('../config');
|
|
15
|
+
|
|
16
|
+
const definition = {
|
|
17
|
+
name: 'vibe_subscriptions',
|
|
18
|
+
description: 'List your active subscriptions to creators.',
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
include_expired: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
description: 'Include expired/cancelled subscriptions (default: false)'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
async function handler(args) {
|
|
31
|
+
const { include_expired = false } = args;
|
|
32
|
+
|
|
33
|
+
if (!config.isInitialized()) {
|
|
34
|
+
return {
|
|
35
|
+
display: 'Run `vibe init` first to set your identity.'
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const token = config.getToken();
|
|
40
|
+
const apiUrl = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch(
|
|
44
|
+
`${apiUrl}/api/subscriptions/subscribe?include_expired=${include_expired}`,
|
|
45
|
+
{
|
|
46
|
+
headers: {
|
|
47
|
+
'Authorization': `Bearer ${token}`
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const result = await response.json();
|
|
53
|
+
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
return {
|
|
56
|
+
display: `❌ ${result.error || 'Failed to fetch subscriptions'}`
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const { subscriptions, stats } = result;
|
|
61
|
+
|
|
62
|
+
if (!subscriptions || subscriptions.length === 0) {
|
|
63
|
+
return {
|
|
64
|
+
display: `
|
|
65
|
+
📋 My Subscriptions
|
|
66
|
+
|
|
67
|
+
No active subscriptions yet.
|
|
68
|
+
|
|
69
|
+
Discover creators to subscribe to:
|
|
70
|
+
• Browse sessions with "subscribers_only" content
|
|
71
|
+
• Check out popular creators on the board
|
|
72
|
+
`.trim(),
|
|
73
|
+
data: result
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Format subscription list
|
|
78
|
+
let formatted = `
|
|
79
|
+
┌────────────────────────────────────────────────────────────┐
|
|
80
|
+
│ 📋 MY SUBSCRIPTIONS │
|
|
81
|
+
├────────────────────────────────────────────────────────────┤
|
|
82
|
+
│ Active: ${String(stats?.active || subscriptions.filter(s => s.status === 'active').length).padEnd(48)} │
|
|
83
|
+
├────────────────────────────────────────────────────────────┤`;
|
|
84
|
+
|
|
85
|
+
for (const sub of subscriptions) {
|
|
86
|
+
const statusIcon = sub.status === 'active' ? '✅' :
|
|
87
|
+
sub.status === 'cancelled' ? '⏸️' :
|
|
88
|
+
sub.status === 'expired' ? '❌' : '⏳';
|
|
89
|
+
|
|
90
|
+
const periodEnd = new Date(sub.period_end);
|
|
91
|
+
const formattedEnd = periodEnd.toLocaleDateString('en-US', {
|
|
92
|
+
month: 'short',
|
|
93
|
+
day: 'numeric'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
formatted += `
|
|
97
|
+
│ │
|
|
98
|
+
│ ${statusIcon} @${sub.creator_handle.padEnd(52)} │
|
|
99
|
+
│ Plan: ${(sub.plan_name || 'Standard').padEnd(46)} │
|
|
100
|
+
│ Price: ${(sub.price_display + '/' + sub.billing_period).padEnd(45)} │`;
|
|
101
|
+
|
|
102
|
+
if (sub.status === 'active') {
|
|
103
|
+
formatted += `
|
|
104
|
+
│ Renews: ${formattedEnd.padEnd(44)} │`;
|
|
105
|
+
} else if (sub.status === 'cancelled') {
|
|
106
|
+
formatted += `
|
|
107
|
+
│ Access until: ${formattedEnd.padEnd(38)} │`;
|
|
108
|
+
} else if (sub.status === 'expired') {
|
|
109
|
+
formatted += `
|
|
110
|
+
│ Expired: ${formattedEnd.padEnd(43)} │`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Add summary
|
|
115
|
+
if (stats) {
|
|
116
|
+
formatted += `
|
|
117
|
+
├────────────────────────────────────────────────────────────┤
|
|
118
|
+
│ Total spent: ${(stats.total_spent_display || '$0').padEnd(42)} │`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
formatted += `
|
|
122
|
+
│ │
|
|
123
|
+
└────────────────────────────────────────────────────────────┘`;
|
|
124
|
+
|
|
125
|
+
return { display: formatted, data: result };
|
|
126
|
+
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return {
|
|
129
|
+
display: `❌ Failed to fetch subscriptions: ${error.message}`
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
module.exports = { definition, handler };
|
package/tools/suggest-tags.js
CHANGED
|
@@ -101,8 +101,8 @@ async function handler(args) {
|
|
|
101
101
|
display += `---\n`;
|
|
102
102
|
display += `_Confidence: ${result.confidence}% (${result.matches.length} patterns matched)_`;
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
|
|
105
|
+
return { display };
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
case 'trending': {
|
|
@@ -137,8 +137,8 @@ async function handler(args) {
|
|
|
137
137
|
display += `**Find people:** \`discover search "tag_name"\`\n`;
|
|
138
138
|
display += `**Add tags:** \`vibe update tags add "tag_name"\``;
|
|
139
139
|
}
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
|
|
141
|
+
return { display };
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
case 'complete': {
|
|
@@ -163,8 +163,8 @@ async function handler(args) {
|
|
|
163
163
|
|
|
164
164
|
display += `\n**Add any tag:**\n`;
|
|
165
165
|
display += `\`vibe update tags add "tag_name"\` or \`vibe update interests add "interest_name"\``;
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
|
|
167
|
+
return { display };
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
default: {
|
|
@@ -174,8 +174,6 @@ async function handler(args) {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
return { display };
|
|
178
|
-
|
|
179
177
|
} catch (error) {
|
|
180
178
|
return {
|
|
181
179
|
display: `## Tag Suggestion Error\n\n${error.message}\n\nTry: \`suggest-tags\` for available commands`
|
package/tools/tag-suggestions.js
CHANGED
|
@@ -122,7 +122,7 @@ async function findSimilarBuilders(suggestedTags, limit = 3) {
|
|
|
122
122
|
if (!profile.tags && !profile.interests) continue;
|
|
123
123
|
|
|
124
124
|
let overlap = 0;
|
|
125
|
-
|
|
125
|
+
const overlappingTags = [];
|
|
126
126
|
|
|
127
127
|
// Check tech tag overlap
|
|
128
128
|
if (profile.tags) {
|
package/tools/tip.js
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vibe_tip - Send
|
|
2
|
+
* vibe_tip - Send an instant on-chain USDC tip
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Real crypto tips with instant settlement on Base Sepolia.
|
|
5
|
+
* No fees - creator gets 100% of the tip.
|
|
6
|
+
* Gas is sponsored by /vibe.
|
|
5
7
|
*
|
|
6
8
|
* Examples:
|
|
7
9
|
* - "tip @alice $5 for helping debug"
|
|
8
|
-
* - "send @bob $
|
|
9
|
-
* - "vibe tip @charlie
|
|
10
|
+
* - "send @bob $1 thanks for the intro"
|
|
11
|
+
* - "vibe tip @charlie 10"
|
|
12
|
+
*
|
|
13
|
+
* Preset amounts: $1 (default), $5, $10
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
|
-
const
|
|
16
|
+
const config = require('../config');
|
|
17
|
+
const { requireInit, normalizeHandle, displayHandle } = require('./_shared');
|
|
18
|
+
const { actions, formatActions } = require('./_actions');
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
// Preset tip amounts in cents
|
|
21
|
+
const TIP_PRESETS = {
|
|
22
|
+
1: 100, // $1
|
|
23
|
+
5: 500, // $5
|
|
24
|
+
10: 1000 // $10
|
|
25
|
+
};
|
|
17
26
|
|
|
27
|
+
const definition = {
|
|
28
|
+
name: 'vibe_tip',
|
|
29
|
+
description: 'Send an instant on-chain USDC tip. 0% fee - creator gets 100%. Gas is sponsored. Amounts: $1 (default), $5, $10.',
|
|
18
30
|
inputSchema: {
|
|
19
31
|
type: 'object',
|
|
20
32
|
properties: {
|
|
@@ -24,97 +36,158 @@ module.exports = {
|
|
|
24
36
|
},
|
|
25
37
|
amount: {
|
|
26
38
|
type: 'number',
|
|
27
|
-
description: 'Amount in USD (
|
|
39
|
+
description: 'Amount in USD (1, 5, or 10). Default: 1'
|
|
28
40
|
},
|
|
29
41
|
message: {
|
|
30
42
|
type: 'string',
|
|
31
43
|
description: 'Optional message to include with the tip'
|
|
44
|
+
},
|
|
45
|
+
context: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
description: 'Optional context (type: dm_reply|ship|profile|gig_bonus, reference_id)',
|
|
48
|
+
properties: {
|
|
49
|
+
type: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
enum: ['dm_reply', 'ship', 'profile', 'gig_bonus']
|
|
52
|
+
},
|
|
53
|
+
reference_id: {
|
|
54
|
+
type: 'string'
|
|
55
|
+
}
|
|
56
|
+
}
|
|
32
57
|
}
|
|
33
58
|
},
|
|
34
|
-
required: ['to'
|
|
35
|
-
}
|
|
59
|
+
required: ['to']
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
async function handler(args) {
|
|
64
|
+
const initCheck = requireInit();
|
|
65
|
+
if (initCheck) return initCheck;
|
|
66
|
+
|
|
67
|
+
const { to, message, context } = args;
|
|
68
|
+
let { amount = 1 } = args;
|
|
69
|
+
|
|
70
|
+
const myHandle = config.getHandle();
|
|
71
|
+
const token = config.getToken();
|
|
72
|
+
|
|
73
|
+
if (!token) {
|
|
74
|
+
return {
|
|
75
|
+
display: '❌ **Not authenticated**\n\nRun `vibe init` to authenticate with GitHub first.'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Normalize recipient handle
|
|
80
|
+
const recipient = normalizeHandle(to);
|
|
81
|
+
if (!recipient) {
|
|
82
|
+
return {
|
|
83
|
+
display: '❌ **Missing recipient**\n\nPlease specify who to tip (e.g., `tip @alice 5`).'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Validate and normalize amount to preset
|
|
88
|
+
amount = parseFloat(amount);
|
|
89
|
+
if (isNaN(amount) || amount <= 0) {
|
|
90
|
+
amount = 1;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Round to nearest preset
|
|
94
|
+
let amountCents;
|
|
95
|
+
if (amount >= 7.5) {
|
|
96
|
+
amountCents = TIP_PRESETS[10];
|
|
97
|
+
amount = 10;
|
|
98
|
+
} else if (amount >= 3) {
|
|
99
|
+
amountCents = TIP_PRESETS[5];
|
|
100
|
+
amount = 5;
|
|
101
|
+
} else {
|
|
102
|
+
amountCents = TIP_PRESETS[1];
|
|
103
|
+
amount = 1;
|
|
104
|
+
}
|
|
36
105
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const from = context.handle;
|
|
106
|
+
// Call instant tip API
|
|
107
|
+
const apiUrl = config.getApiUrl();
|
|
40
108
|
|
|
41
|
-
|
|
109
|
+
// Generate idempotency key to prevent duplicate tips from retries
|
|
110
|
+
// Key is based on: sender + recipient + amount + timestamp (1-minute bucket)
|
|
111
|
+
const timeBucket = Math.floor(Date.now() / 60000); // 1-minute buckets
|
|
112
|
+
const idempotencyKey = `${myHandle}:${recipient}:${amountCents}:${timeBucket}`;
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const response = await fetch(`${apiUrl}/api/tips/instant`, {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: {
|
|
118
|
+
'Content-Type': 'application/json',
|
|
119
|
+
'Authorization': `Bearer ${token}`,
|
|
120
|
+
'Idempotency-Key': idempotencyKey
|
|
121
|
+
},
|
|
122
|
+
body: JSON.stringify({
|
|
123
|
+
to: recipient,
|
|
124
|
+
amount_cents: amountCents,
|
|
125
|
+
message,
|
|
126
|
+
context
|
|
127
|
+
})
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const result = await response.json();
|
|
131
|
+
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
// Handle specific error cases
|
|
134
|
+
if (result.error === 'insufficient_balance') {
|
|
42
135
|
return {
|
|
43
|
-
|
|
44
|
-
|
|
136
|
+
display: `❌ **Insufficient USDC balance**\n\nYou need USDC to tip. Your balance: $${result.balance_usdc}\n\n` +
|
|
137
|
+
`Get USDC at [bridge.base.org](${result.help_url})`
|
|
45
138
|
};
|
|
46
139
|
}
|
|
47
140
|
|
|
48
|
-
|
|
49
|
-
if (amount <= 0 || amount > 100) {
|
|
141
|
+
if (result.error === 'recipient_no_wallet') {
|
|
50
142
|
return {
|
|
51
|
-
|
|
52
|
-
|
|
143
|
+
display: `❌ **${displayHandle(recipient)} can't receive tips yet**\n\n` +
|
|
144
|
+
`They need to complete their wallet setup first.`
|
|
53
145
|
};
|
|
54
146
|
}
|
|
55
147
|
|
|
56
|
-
|
|
57
|
-
const apiUrl = process.env.VIBE_API_URL || 'https://www.slashvibe.dev';
|
|
58
|
-
|
|
59
|
-
const response = await fetch(`${apiUrl}/api/payments/tip`, {
|
|
60
|
-
method: 'POST',
|
|
61
|
-
headers: {
|
|
62
|
-
'Content-Type': 'application/json',
|
|
63
|
-
'Authorization': `Bearer ${context.token}`
|
|
64
|
-
},
|
|
65
|
-
body: JSON.stringify({
|
|
66
|
-
from,
|
|
67
|
-
to,
|
|
68
|
-
amount,
|
|
69
|
-
message
|
|
70
|
-
})
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const result = await response.json();
|
|
74
|
-
|
|
75
|
-
if (!response.ok) {
|
|
148
|
+
if (result.error === 'rate_limited') {
|
|
76
149
|
return {
|
|
77
|
-
|
|
78
|
-
error: result.error || 'Tip failed',
|
|
79
|
-
details: result.details
|
|
150
|
+
display: `⏳ **Rate limit reached**\n\n${result.message}\n\nTry again in ${Math.ceil(result.reset_in_seconds / 60)} minutes.`
|
|
80
151
|
};
|
|
81
152
|
}
|
|
82
153
|
|
|
83
|
-
// Format success message
|
|
84
|
-
const fee = result.fee || (amount * 0.025);
|
|
85
|
-
const net = amount - fee;
|
|
86
|
-
|
|
87
154
|
return {
|
|
88
|
-
|
|
89
|
-
message: `💰 Tipped ${to} $${amount}`,
|
|
90
|
-
details: {
|
|
91
|
-
recipient: to,
|
|
92
|
-
amount: `$${amount}`,
|
|
93
|
-
fee: `$${fee.toFixed(2)} (2.5%)`,
|
|
94
|
-
net_to_recipient: `$${net.toFixed(2)}`,
|
|
95
|
-
tx_hash: result.tx_hash,
|
|
96
|
-
status: result.status,
|
|
97
|
-
explorer_url: `https://sepolia.basescan.org/tx/${result.tx_hash}`
|
|
98
|
-
},
|
|
99
|
-
formatted: `
|
|
100
|
-
✓ Tip sent!
|
|
101
|
-
To: ${to}
|
|
102
|
-
Amount: $${amount}
|
|
103
|
-
Fee: $${fee.toFixed(2)}
|
|
104
|
-
Net: $${net.toFixed(2)}
|
|
105
|
-
${message ? `Message: "${message}"` : ''}
|
|
106
|
-
|
|
107
|
-
Tx: ${result.tx_hash?.substring(0, 10)}...
|
|
108
|
-
Status: ${result.status}
|
|
109
|
-
`.trim()
|
|
155
|
+
display: `❌ **Tip failed**\n\n${result.message || 'Please try again.'}`
|
|
110
156
|
};
|
|
157
|
+
}
|
|
111
158
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
159
|
+
// Success!
|
|
160
|
+
let display = `✅ **Tipped ${displayHandle(recipient)} $${amount} USDC**\n\n`;
|
|
161
|
+
|
|
162
|
+
display += `💰 Amount: $${amount}.00\n`;
|
|
163
|
+
display += `📤 To: ${displayHandle(recipient)}\n`;
|
|
164
|
+
display += `📥 Fee: $0.00 (0%)\n`;
|
|
165
|
+
display += `✨ Net to creator: $${amount}.00\n`;
|
|
166
|
+
|
|
167
|
+
if (message) {
|
|
168
|
+
display += `\n💬 _"${message}"_\n`;
|
|
118
169
|
}
|
|
170
|
+
|
|
171
|
+
display += `\n🔗 [View on Explorer](${result.explorer_url})`;
|
|
172
|
+
|
|
173
|
+
// Build response with actions
|
|
174
|
+
const response_obj = {
|
|
175
|
+
display,
|
|
176
|
+
tx_hash: result.tx_hash,
|
|
177
|
+
explorer_url: result.explorer_url
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Add follow-up actions
|
|
181
|
+
response_obj.actions = formatActions(actions.afterTip ? actions.afterTip(recipient) : actions.afterDm(recipient));
|
|
182
|
+
|
|
183
|
+
return response_obj;
|
|
184
|
+
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error('[tip] Error:', error);
|
|
187
|
+
return {
|
|
188
|
+
display: `❌ **Tip failed**\n\nError: ${error.message}\n\nPlease try again.`
|
|
189
|
+
};
|
|
119
190
|
}
|
|
120
|
-
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
module.exports = { definition, handler };
|
package/tools/token.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vibe token — Set
|
|
2
|
+
* vibe token — Set auth token after GitHub OAuth
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
5
|
* vibe token <paste-token-here>
|
|
@@ -44,7 +44,7 @@ If you haven't authenticated yet:
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Verify token with server
|
|
47
|
-
const verification = await store.
|
|
47
|
+
const verification = await store.verifyAuthToken(token.trim());
|
|
48
48
|
|
|
49
49
|
if (!verification.valid) {
|
|
50
50
|
return {
|
|
@@ -60,7 +60,7 @@ The token may be expired or invalid. Try authenticating again:
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Save token
|
|
63
|
-
config.
|
|
63
|
+
config.saveAuthToken(token.trim());
|
|
64
64
|
|
|
65
65
|
// Update session identity with verified handle
|
|
66
66
|
const handle = verification.handle;
|
|
@@ -96,7 +96,7 @@ You're ready to vibe! Try:
|
|
|
96
96
|
• \`vibe dm @someone "hello"\` — Send a message`,
|
|
97
97
|
handle,
|
|
98
98
|
github: verification.github,
|
|
99
|
-
authMethod: '
|
|
99
|
+
authMethod: 'github'
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
|
package/tools/update.js
CHANGED
|
@@ -49,7 +49,7 @@ async function handler(args) {
|
|
|
49
49
|
display += `Your install doesn't support automatic updates.\n\n`;
|
|
50
50
|
display += `To update, re-run the installer:\n`;
|
|
51
51
|
display += `\`\`\`\n`;
|
|
52
|
-
display += `curl -fsSL https://raw.githubusercontent.com/
|
|
52
|
+
display += `curl -fsSL https://raw.githubusercontent.com/VibeCodingInc/vibe-mcp/main/install.sh | bash\n`;
|
|
53
53
|
display += `\`\`\`\n\n`;
|
|
54
54
|
display += `This will migrate you to the git-based installer for future updates.\n\n`;
|
|
55
55
|
display += `---\n`;
|