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
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibe session-fork — Fork someone else's session
|
|
3
|
+
*
|
|
4
|
+
* Creates a fork of an existing session, giving you a copy to build on.
|
|
5
|
+
* Supports 3 temporal destinations: session (replay), branch (code), or live (broadcast).
|
|
6
|
+
*
|
|
7
|
+
* Part of the core demo loop:
|
|
8
|
+
* Code with AI -> Session captured -> Replayable -> Discoverable -> Forkable -> Reputation accrues
|
|
9
|
+
*
|
|
10
|
+
* API: POST /api/sessions/fork
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const config = require('../config');
|
|
14
|
+
const { requireInit } = require('./_shared');
|
|
15
|
+
|
|
16
|
+
const definition = {
|
|
17
|
+
name: 'vibe_session_fork',
|
|
18
|
+
description: 'Fork an existing session to build on it. Creates a copy you can extend.',
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
session_id: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Session ID to fork (e.g., ses_xxx)'
|
|
25
|
+
},
|
|
26
|
+
fork_to: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
enum: ['session', 'branch', 'live'],
|
|
29
|
+
description: 'Fork destination: session (replay copy), branch (code copy), live (start broadcast from fork)'
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
required: ['session_id']
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
async function handler(args) {
|
|
37
|
+
const initCheck = requireInit();
|
|
38
|
+
if (initCheck) return initCheck;
|
|
39
|
+
|
|
40
|
+
const { session_id, fork_to } = args;
|
|
41
|
+
const myHandle = config.getHandle();
|
|
42
|
+
const apiUrl = config.getApiUrl();
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const body = {
|
|
46
|
+
parentSessionId: session_id,
|
|
47
|
+
forkerHandle: myHandle,
|
|
48
|
+
forkTo: fork_to || 'session'
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const response = await fetch(`${apiUrl}/api/sessions/fork`, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: { 'Content-Type': 'application/json' },
|
|
54
|
+
body: JSON.stringify(body)
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
|
|
59
|
+
if (!response.ok || data.error) {
|
|
60
|
+
return {
|
|
61
|
+
display: `## Fork Failed\n\n${data.error || `HTTP ${response.status}`}\n\nMake sure the session ID is valid. Try \`vibe feed\` to browse sessions.`
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const forkId = data.forkId || data.id || 'unknown';
|
|
66
|
+
const destination = data.destination || fork_to || 'session';
|
|
67
|
+
const forkUrl = data.url || `https://slashvibe.dev/sessions/${forkId}`;
|
|
68
|
+
|
|
69
|
+
let display = `## Session Forked\n\n`;
|
|
70
|
+
display += `**Forked from:** \`${session_id}\`\n`;
|
|
71
|
+
display += `**Fork ID:** \`${forkId}\`\n`;
|
|
72
|
+
display += `**Destination:** ${destination}\n`;
|
|
73
|
+
display += `**URL:** ${forkUrl}\n\n`;
|
|
74
|
+
|
|
75
|
+
switch (destination) {
|
|
76
|
+
case 'session':
|
|
77
|
+
display += `Your fork is saved as a new session. You can replay or extend it.`;
|
|
78
|
+
break;
|
|
79
|
+
case 'branch':
|
|
80
|
+
display += `Code copy created. Start building on top of the original session.`;
|
|
81
|
+
break;
|
|
82
|
+
case 'live':
|
|
83
|
+
display += `Live broadcast started from fork. Others can watch you build on this.`;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
display += `\n\nThe original author gets credit — fork lineage is tracked.`;
|
|
88
|
+
|
|
89
|
+
return { display };
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
display: `## Fork Error\n\n${error.message}\n\nRun \`vibe doctor\` to diagnose connectivity issues.`
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = { definition, handler };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibe session-save — Save your current session
|
|
3
|
+
*
|
|
4
|
+
* Persists a coding session to the platform so it becomes
|
|
5
|
+
* replayable, discoverable, and forkable.
|
|
6
|
+
*
|
|
7
|
+
* Part of the core demo loop:
|
|
8
|
+
* Code with AI -> Session captured -> Replayable -> Discoverable -> Forkable -> Reputation accrues
|
|
9
|
+
*
|
|
10
|
+
* API: POST /api/sessions
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const config = require('../config');
|
|
14
|
+
const { requireInit } = require('./_shared');
|
|
15
|
+
|
|
16
|
+
const definition = {
|
|
17
|
+
name: 'vibe_session_save',
|
|
18
|
+
description: 'Save your current coding session. Makes it replayable, discoverable, and forkable on slashvibe.dev.',
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
title: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Session title (e.g., "Building auth with OAuth")'
|
|
25
|
+
},
|
|
26
|
+
description: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Brief description of what happened in the session'
|
|
29
|
+
},
|
|
30
|
+
from_broadcast: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'Room ID if saving from a live broadcast'
|
|
33
|
+
},
|
|
34
|
+
visibility: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
enum: ['public', 'unlisted', 'private'],
|
|
37
|
+
description: 'Session visibility (default: public)'
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
required: ['title']
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
async function handler(args) {
|
|
45
|
+
const initCheck = requireInit();
|
|
46
|
+
if (initCheck) return initCheck;
|
|
47
|
+
|
|
48
|
+
const { title, description, from_broadcast, visibility } = args;
|
|
49
|
+
const myHandle = config.getHandle();
|
|
50
|
+
const apiUrl = config.getApiUrl();
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const body = {
|
|
54
|
+
author_handle: myHandle,
|
|
55
|
+
title,
|
|
56
|
+
visibility: visibility || 'public'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (description) {
|
|
60
|
+
body.description = description;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (from_broadcast) {
|
|
64
|
+
body.fromBroadcast = from_broadcast;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const response = await fetch(`${apiUrl}/api/sessions`, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: { 'Content-Type': 'application/json' },
|
|
70
|
+
body: JSON.stringify(body)
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const data = await response.json();
|
|
74
|
+
|
|
75
|
+
if (!response.ok || data.error) {
|
|
76
|
+
return {
|
|
77
|
+
display: `## Session Save Failed\n\n${data.error || `HTTP ${response.status}`}\n\nCheck \`vibe doctor\` if this persists.`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const session = data.session || data;
|
|
82
|
+
const sessionId = session.id || session.sessionId || 'unknown';
|
|
83
|
+
const sessionUrl = session.url || `https://slashvibe.dev/sessions/${sessionId}`;
|
|
84
|
+
|
|
85
|
+
let display = `## Session Saved\n\n`;
|
|
86
|
+
display += `**${title}**\n`;
|
|
87
|
+
if (description) {
|
|
88
|
+
display += `${description}\n`;
|
|
89
|
+
}
|
|
90
|
+
display += `\n`;
|
|
91
|
+
display += `**ID:** \`${sessionId}\`\n`;
|
|
92
|
+
display += `**URL:** ${sessionUrl}\n`;
|
|
93
|
+
display += `**Visibility:** ${visibility || 'public'}\n`;
|
|
94
|
+
if (from_broadcast) {
|
|
95
|
+
display += `**From broadcast:** \`${from_broadcast}\`\n`;
|
|
96
|
+
}
|
|
97
|
+
display += `\n`;
|
|
98
|
+
display += `Others can now replay, discover, and fork this session.\n`;
|
|
99
|
+
display += `Share: \`${sessionUrl}\``;
|
|
100
|
+
|
|
101
|
+
return { display };
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return {
|
|
104
|
+
display: `## Session Save Error\n\n${error.message}\n\nMake sure you're connected to the internet. Run \`vibe doctor\` to diagnose.`
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = { definition, handler };
|
package/tools/settings.js
CHANGED
|
@@ -6,15 +6,14 @@
|
|
|
6
6
|
* - guided: on | off (dashboard mode)
|
|
7
7
|
* - github_activity: on | off (show GitHub shipping status)
|
|
8
8
|
* - github_activity_privacy: full | status_only | off
|
|
9
|
-
* - mute: 1h | 2h | 4h | forever | off (merged from vibe_mute)
|
|
10
|
-
* - auto_context: on | off (ambient work context gathering)
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
const config = require('../config');
|
|
14
12
|
|
|
15
13
|
const definition = {
|
|
16
14
|
name: 'vibe_settings',
|
|
17
|
-
description:
|
|
15
|
+
description:
|
|
16
|
+
'Configure /vibe preferences. Set notification level, toggle guided mode, or enable GitHub activity signals.',
|
|
18
17
|
inputSchema: {
|
|
19
18
|
type: 'object',
|
|
20
19
|
properties: {
|
|
@@ -35,14 +34,6 @@ const definition = {
|
|
|
35
34
|
type: 'string',
|
|
36
35
|
enum: ['full', 'status_only', 'off'],
|
|
37
36
|
description: 'Privacy level: full (repos/commits), status_only (just badge), off'
|
|
38
|
-
},
|
|
39
|
-
mute: {
|
|
40
|
-
type: 'string',
|
|
41
|
-
description: 'Mute presence alerts: "1h", "2h", "4h", "forever", or "off" to unmute'
|
|
42
|
-
},
|
|
43
|
-
auto_context: {
|
|
44
|
-
type: 'boolean',
|
|
45
|
-
description: 'Enable/disable automatic work context gathering (git branch, recent commits shown in presence)'
|
|
46
37
|
}
|
|
47
38
|
}
|
|
48
39
|
}
|
|
@@ -75,68 +66,12 @@ async function handler(args) {
|
|
|
75
66
|
changes.push('github activity privacy → **' + args.github_activity_privacy + '**');
|
|
76
67
|
}
|
|
77
68
|
|
|
78
|
-
// Handle mute setting (merged from vibe_mute)
|
|
79
|
-
if (args.mute) {
|
|
80
|
-
const duration = args.mute;
|
|
81
|
-
|
|
82
|
-
// UNMUTE
|
|
83
|
-
if (duration === 'off' || duration === 'unmute') {
|
|
84
|
-
config.set('mutedUntil', null);
|
|
85
|
-
config.set('focusMode', false);
|
|
86
|
-
changes.push('alerts → **unmuted**');
|
|
87
|
-
}
|
|
88
|
-
// MUTE FOREVER
|
|
89
|
-
else if (duration === 'forever' || duration === 'disable') {
|
|
90
|
-
config.set('presenceAgentEnabled', false);
|
|
91
|
-
config.set('mutedUntil', null);
|
|
92
|
-
changes.push('alerts → **disabled**');
|
|
93
|
-
}
|
|
94
|
-
// PARSE DURATION
|
|
95
|
-
else {
|
|
96
|
-
let ms = 0;
|
|
97
|
-
const match = duration.match(/^(\d+)(h|m|min|hour|hours|minutes)$/);
|
|
98
|
-
|
|
99
|
-
if (match) {
|
|
100
|
-
const amount = parseInt(match[1]);
|
|
101
|
-
const unit = match[2];
|
|
102
|
-
|
|
103
|
-
if (unit === 'h' || unit === 'hour' || unit === 'hours') {
|
|
104
|
-
ms = amount * 60 * 60 * 1000;
|
|
105
|
-
} else if (unit === 'm' || unit === 'min' || unit === 'minutes') {
|
|
106
|
-
ms = amount * 60 * 1000;
|
|
107
|
-
}
|
|
108
|
-
} else {
|
|
109
|
-
// Default to 1 hour if can't parse
|
|
110
|
-
ms = 60 * 60 * 1000;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const mutedUntil = Date.now() + ms;
|
|
114
|
-
config.set('mutedUntil', mutedUntil);
|
|
115
|
-
|
|
116
|
-
const until = new Date(mutedUntil).toLocaleTimeString();
|
|
117
|
-
const durationText = ms >= 3600000
|
|
118
|
-
? `${Math.floor(ms / 3600000)} hour${Math.floor(ms / 3600000) > 1 ? 's' : ''}`
|
|
119
|
-
: `${Math.floor(ms / 60000)} minutes`;
|
|
120
|
-
|
|
121
|
-
changes.push(`alerts → **muted for ${durationText}** (until ${until})`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Update auto context if provided
|
|
126
|
-
if (args.auto_context !== undefined) {
|
|
127
|
-
config.set('autoContext', args.auto_context);
|
|
128
|
-
changes.push('auto context → **' + (args.auto_context ? 'on' : 'off') + '**');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
69
|
// If no args, show current settings
|
|
132
70
|
if (changes.length === 0) {
|
|
133
71
|
const notifications = config.getNotifications();
|
|
134
72
|
const guided = config.getGuidedMode();
|
|
135
73
|
const githubActivity = config.getGithubActivityEnabled();
|
|
136
74
|
const githubPrivacy = config.getGithubActivityPrivacy();
|
|
137
|
-
const mutedUntil = config.get('mutedUntil');
|
|
138
|
-
const presenceEnabled = config.get('presenceAgentEnabled') !== false;
|
|
139
|
-
const autoContext = config.get('autoContext', true); // Default to true
|
|
140
75
|
|
|
141
76
|
const notifyDesc = {
|
|
142
77
|
all: 'All notifications (messages, mentions, presence)',
|
|
@@ -150,49 +85,45 @@ async function handler(args) {
|
|
|
150
85
|
off: 'Disabled'
|
|
151
86
|
};
|
|
152
87
|
|
|
153
|
-
// Determine mute status
|
|
154
|
-
let muteStatus = 'off';
|
|
155
|
-
let muteDesc = 'Alerts enabled';
|
|
156
|
-
if (!presenceEnabled) {
|
|
157
|
-
muteStatus = 'disabled';
|
|
158
|
-
muteDesc = 'Presence alerts permanently disabled';
|
|
159
|
-
} else if (mutedUntil) {
|
|
160
|
-
const remaining = mutedUntil - Date.now();
|
|
161
|
-
if (remaining > 0) {
|
|
162
|
-
const mins = Math.floor(remaining / 60000);
|
|
163
|
-
const hours = Math.floor(mins / 60);
|
|
164
|
-
muteStatus = hours > 0 ? `${hours}h ${mins % 60}m` : `${mins}m`;
|
|
165
|
-
muteDesc = `Muted until ${new Date(mutedUntil).toLocaleTimeString()}`;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
88
|
return {
|
|
170
|
-
display:
|
|
171
|
-
'
|
|
172
|
-
'
|
|
173
|
-
|
|
174
|
-
'
|
|
175
|
-
'
|
|
176
|
-
|
|
177
|
-
'
|
|
178
|
-
'
|
|
89
|
+
display:
|
|
90
|
+
'## /vibe Settings\n\n' +
|
|
91
|
+
'**Notifications:** ' +
|
|
92
|
+
notifications +
|
|
93
|
+
'\n' +
|
|
94
|
+
'_' +
|
|
95
|
+
notifyDesc[notifications] +
|
|
96
|
+
'_\n\n' +
|
|
97
|
+
'**Guided Mode:** ' +
|
|
98
|
+
(guided ? 'on' : 'off') +
|
|
99
|
+
'\n' +
|
|
100
|
+
'_' +
|
|
101
|
+
(guided ? 'Shows dashboard menus' : 'Freeform mode') +
|
|
102
|
+
'_\n\n' +
|
|
103
|
+
'**GitHub Activity:** ' +
|
|
104
|
+
(githubActivity ? 'on' : 'off') +
|
|
105
|
+
'\n' +
|
|
106
|
+
'_' +
|
|
107
|
+
(githubActivity ? 'Shows shipping status from your GitHub commits' : 'Not sharing GitHub activity') +
|
|
108
|
+
'_\n\n' +
|
|
179
109
|
(githubActivity ? '**GitHub Privacy:** ' + githubPrivacy + '\n_' + privacyDesc[githubPrivacy] + '_\n\n' : '') +
|
|
180
|
-
'**Auto Context:** ' + (autoContext ? 'on' : 'off') + '\n' +
|
|
181
|
-
'_' + (autoContext ? 'Git branch & work summary shared in presence' : 'Work context not auto-shared') + '_\n\n' +
|
|
182
110
|
'---\n\n' +
|
|
183
111
|
'**Change settings:**\n' +
|
|
184
112
|
'• "set notifications to mentions" — less noisy\n' +
|
|
185
113
|
'• "turn off guided mode" — no menus\n' +
|
|
186
|
-
'• "mute for 2h" — silence alerts temporarily\n' +
|
|
187
114
|
'• "enable github activity" — show when you\'re shipping\n' +
|
|
188
|
-
'• "set github privacy to status_only" — just badge, no details
|
|
189
|
-
'• "disable auto context" — stop sharing git branch/work'
|
|
115
|
+
'• "set github privacy to status_only" — just badge, no details'
|
|
190
116
|
};
|
|
191
117
|
}
|
|
192
118
|
|
|
193
119
|
return {
|
|
194
|
-
display:
|
|
195
|
-
|
|
120
|
+
display:
|
|
121
|
+
'## Settings Updated\n\n' +
|
|
122
|
+
changes
|
|
123
|
+
.map(function (c) {
|
|
124
|
+
return '✓ ' + c;
|
|
125
|
+
})
|
|
126
|
+
.join('\n') +
|
|
196
127
|
'\n\n_Changes take effect immediately._'
|
|
197
128
|
};
|
|
198
129
|
}
|
package/tools/ship.js
CHANGED
|
@@ -1,29 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vibe ship —
|
|
2
|
+
* vibe ship — Share with the community
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Unified creative entry point with type parameter:
|
|
5
|
+
* - type: "ship" (default) — Announce what you shipped
|
|
6
|
+
* - type: "idea" — Post a raw idea for others to riff on
|
|
7
|
+
* - type: "request" — Post a build request / wish
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
* - ship "Built a new feature for my AI chat app"
|
|
9
|
-
* - ship "Deployed my portfolio website"
|
|
10
|
-
* - ship "Published blog post about React patterns"
|
|
9
|
+
* Absorbs former vibe_idea and vibe_request tools.
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
const config = require('../config');
|
|
14
13
|
const userProfiles = require('../store/profiles');
|
|
15
14
|
const patterns = require('../intelligence/patterns');
|
|
16
|
-
const { requireInit, formatTimeAgo } = require('./_shared');
|
|
15
|
+
const { requireInit, normalizeHandle, formatTimeAgo, debug } = require('./_shared');
|
|
16
|
+
|
|
17
|
+
// Delegate handlers for absorbed tools
|
|
18
|
+
const ideaTool = require('./idea');
|
|
19
|
+
const requestTool = require('./request');
|
|
17
20
|
|
|
18
21
|
const definition = {
|
|
19
22
|
name: 'vibe_ship',
|
|
20
|
-
description:
|
|
23
|
+
description:
|
|
24
|
+
'Share with the community. type="ship" (default): announce what you shipped. type="idea": post an idea for others to riff on. type="request": post a build request.',
|
|
21
25
|
inputSchema: {
|
|
22
26
|
type: 'object',
|
|
23
27
|
properties: {
|
|
28
|
+
type: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
enum: ['ship', 'idea', 'request'],
|
|
31
|
+
description: 'What to share: ship (default), idea, or request'
|
|
32
|
+
},
|
|
24
33
|
what: {
|
|
25
34
|
type: 'string',
|
|
26
|
-
description: 'What you shipped (
|
|
35
|
+
description: 'What you shipped (for type=ship)'
|
|
36
|
+
},
|
|
37
|
+
content: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Content for idea or request (for type=idea/request)'
|
|
27
40
|
},
|
|
28
41
|
url: {
|
|
29
42
|
type: 'string',
|
|
@@ -41,9 +54,20 @@ const definition = {
|
|
|
41
54
|
type: 'array',
|
|
42
55
|
items: { type: 'string' },
|
|
43
56
|
description: 'Tags for discovery (e.g., ["ai", "mcp", "tools"])'
|
|
57
|
+
},
|
|
58
|
+
riff_on: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Handle to riff on (for type=idea)'
|
|
61
|
+
},
|
|
62
|
+
claim: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Request ID to claim (for type=request)'
|
|
65
|
+
},
|
|
66
|
+
bounty: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: "What you're offering for a request (for type=request)"
|
|
44
69
|
}
|
|
45
|
-
}
|
|
46
|
-
required: ['what']
|
|
70
|
+
}
|
|
47
71
|
}
|
|
48
72
|
};
|
|
49
73
|
|
|
@@ -51,8 +75,18 @@ async function handler(args) {
|
|
|
51
75
|
const initCheck = requireInit();
|
|
52
76
|
if (initCheck) return initCheck;
|
|
53
77
|
|
|
78
|
+
// Route to absorbed tools by type
|
|
79
|
+
const type = args.type || 'ship';
|
|
80
|
+
if (type === 'idea') {
|
|
81
|
+
return ideaTool.handler(args);
|
|
82
|
+
}
|
|
83
|
+
if (type === 'request') {
|
|
84
|
+
return requestTool.handler(args);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Default: ship
|
|
54
88
|
if (!args.what) {
|
|
55
|
-
return {
|
|
89
|
+
return { display: 'Please tell us what you shipped: ship "Built a new feature"' };
|
|
56
90
|
}
|
|
57
91
|
|
|
58
92
|
const myHandle = config.getHandle();
|
|
@@ -70,7 +104,7 @@ async function handler(args) {
|
|
|
70
104
|
metaParts.push(`🔗 ${args.url}`);
|
|
71
105
|
}
|
|
72
106
|
if (args.inspired_by) {
|
|
73
|
-
const inspiree = args.inspired_by
|
|
107
|
+
const inspiree = normalizeHandle(args.inspired_by);
|
|
74
108
|
metaParts.push(`✨ inspired by @${inspiree}`);
|
|
75
109
|
}
|
|
76
110
|
if (args.for_request) {
|
|
@@ -84,22 +118,16 @@ async function handler(args) {
|
|
|
84
118
|
// Build tags with attribution
|
|
85
119
|
const tags = args.tags || [];
|
|
86
120
|
if (args.inspired_by) {
|
|
87
|
-
tags.push(`inspired:${args.inspired_by
|
|
121
|
+
tags.push(`inspired:${normalizeHandle(args.inspired_by)}`);
|
|
88
122
|
}
|
|
89
123
|
if (args.for_request) {
|
|
90
124
|
tags.push(`fulfills:${args.for_request}`);
|
|
91
125
|
}
|
|
92
126
|
|
|
93
|
-
// Post to board
|
|
94
|
-
const authToken = config.getAuthToken();
|
|
95
|
-
const headers = { 'Content-Type': 'application/json' };
|
|
96
|
-
if (authToken) {
|
|
97
|
-
headers['Authorization'] = `Bearer ${authToken}`;
|
|
98
|
-
}
|
|
99
|
-
|
|
127
|
+
// Post to board
|
|
100
128
|
const response = await fetch(`${apiUrl}/api/board`, {
|
|
101
129
|
method: 'POST',
|
|
102
|
-
headers,
|
|
130
|
+
headers: { 'Content-Type': 'application/json' },
|
|
103
131
|
body: JSON.stringify({
|
|
104
132
|
author: myHandle,
|
|
105
133
|
content,
|
|
@@ -120,30 +148,17 @@ async function handler(args) {
|
|
|
120
148
|
patterns.logInspiredBy(args.inspired_by);
|
|
121
149
|
}
|
|
122
150
|
|
|
123
|
-
|
|
151
|
+
// Push ship event to subscribed agent gateways
|
|
152
|
+
const { pushToAgents } = require('../notify');
|
|
153
|
+
pushToAgents('ship', { author: myHandle, what: args.what, url: args.url, tags }).catch(() => {});
|
|
154
|
+
|
|
155
|
+
let display = `🚀 shipped\n\n${args.what}`;
|
|
124
156
|
|
|
125
157
|
if (args.url) {
|
|
126
|
-
display += `\n
|
|
158
|
+
display += `\n${args.url}`;
|
|
127
159
|
}
|
|
128
160
|
if (args.inspired_by) {
|
|
129
|
-
display += `\
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Add share URL for viral distribution
|
|
133
|
-
if (data.shareUrl) {
|
|
134
|
-
display += `\n\n**📣 Share your ship:**\n${data.shareUrl}`;
|
|
135
|
-
|
|
136
|
-
// Use the twitterShareUrl from API response (tracked for K-factor)
|
|
137
|
-
if (data.twitterShareUrl) {
|
|
138
|
-
display += `\n\n**🐦 Share on Twitter** (helps others discover /vibe!)`;
|
|
139
|
-
display += `\n${data.twitterShareUrl}`;
|
|
140
|
-
} else {
|
|
141
|
-
// Fallback to inline URL if API didn't return one
|
|
142
|
-
const shareText = encodeURIComponent(`🚀 Just shipped: ${args.what.substring(0, 80)}\n\nBuilding with /vibe`);
|
|
143
|
-
const encodedUrl = encodeURIComponent(data.shareUrl);
|
|
144
|
-
display += `\n\n**Quick share:**`;
|
|
145
|
-
display += `\n• Twitter: https://twitter.com/intent/tweet?text=${shareText}&url=${encodedUrl}&hashtags=buildinpublic,vibecoders`;
|
|
146
|
-
}
|
|
161
|
+
display += `\n_via @${normalizeHandle(args.inspired_by)}_`;
|
|
147
162
|
}
|
|
148
163
|
|
|
149
164
|
display += '\n';
|
|
@@ -151,11 +166,13 @@ async function handler(args) {
|
|
|
151
166
|
// Quiet awareness of similar builders
|
|
152
167
|
const suggestions = await findSimilarShippers(myHandle, args.what);
|
|
153
168
|
if (suggestions.length > 0) {
|
|
154
|
-
display += `\n_similar
|
|
169
|
+
display += `\n_similar: @${suggestions
|
|
170
|
+
.slice(0, 2)
|
|
171
|
+
.map(s => s.handle)
|
|
172
|
+
.join(', @')}_`;
|
|
155
173
|
}
|
|
156
174
|
|
|
157
175
|
return { display };
|
|
158
|
-
|
|
159
176
|
} catch (error) {
|
|
160
177
|
return { display: `## Ship Error\n\n${error.message}` };
|
|
161
178
|
}
|
|
@@ -165,7 +182,10 @@ async function handler(args) {
|
|
|
165
182
|
async function findSimilarShippers(myHandle, whatIShipped) {
|
|
166
183
|
try {
|
|
167
184
|
const allProfiles = await userProfiles.getAllProfiles();
|
|
168
|
-
const myWords = whatIShipped
|
|
185
|
+
const myWords = whatIShipped
|
|
186
|
+
.toLowerCase()
|
|
187
|
+
.split(/\s+/)
|
|
188
|
+
.filter(w => w.length > 3);
|
|
169
189
|
const suggestions = [];
|
|
170
190
|
|
|
171
191
|
for (const profile of allProfiles) {
|
|
@@ -175,7 +195,7 @@ async function findSimilarShippers(myHandle, whatIShipped) {
|
|
|
175
195
|
for (const ship of profile.ships) {
|
|
176
196
|
const shipWords = ship.what.toLowerCase().split(/\s+/);
|
|
177
197
|
const overlap = myWords.filter(w => shipWords.includes(w));
|
|
178
|
-
|
|
198
|
+
|
|
179
199
|
if (overlap.length > 0) {
|
|
180
200
|
suggestions.push({
|
|
181
201
|
handle: profile.handle,
|
|
@@ -189,17 +209,15 @@ async function findSimilarShippers(myHandle, whatIShipped) {
|
|
|
189
209
|
}
|
|
190
210
|
|
|
191
211
|
// Sort by overlap and recency
|
|
192
|
-
return suggestions
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
});
|
|
198
|
-
|
|
212
|
+
return suggestions.sort((a, b) => {
|
|
213
|
+
const overlapDiff = b.overlap - a.overlap;
|
|
214
|
+
if (overlapDiff !== 0) return overlapDiff;
|
|
215
|
+
return b.timestamp - a.timestamp;
|
|
216
|
+
});
|
|
199
217
|
} catch (error) {
|
|
200
|
-
|
|
218
|
+
debug('ship', 'Error finding similar shippers:', error);
|
|
201
219
|
return [];
|
|
202
220
|
}
|
|
203
221
|
}
|
|
204
222
|
|
|
205
|
-
module.exports = { definition, handler };
|
|
223
|
+
module.exports = { definition, handler };
|