slashvibe-mcp 0.5.25 → 0.6.0
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/package.json +36 -2
- package/version.json +7 -9
- package/tools/_connection-queue.js +0 -257
- package/tools/_deprecated/auto-suggest-connections.js +0 -304
- package/tools/_deprecated/away.js +0 -68
- package/tools/_deprecated/back.js +0 -51
- 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/forget.js +0 -119
- 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/mute.js +0 -97
- package/tools/_deprecated/recall.js +0 -147
- package/tools/_deprecated/remember.js +0 -86
- 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-exchange.js +0 -342
- 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/tictactoe.js +0 -155
- package/tools/_deprecated/twentyquestions.js +0 -143
- package/tools/_deprecated/wordassociation.js +0 -247
- package/tools/_discovery-enhanced.js +0 -290
- package/tools/_proactive-discovery.js +0 -301
- package/tools/_shared/index.js +0 -326
- 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/agents.js +0 -122
- package/tools/approve.js +0 -197
- package/tools/arcade.js +0 -173
- package/tools/artifact-create.js +0 -247
- 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/call.js +0 -149
- package/tools/cc-insights.js +0 -320
- package/tools/chat.js +0 -202
- package/tools/collaborative-drawing.js +0 -286
- package/tools/connection-status.js +0 -178
- package/tools/consent.js +0 -114
- package/tools/context.js +0 -132
- package/tools/crossword.js +0 -369
- package/tools/discover.js +0 -717
- package/tools/drawing.js +0 -310
- package/tools/earnings.js +0 -126
- package/tools/follow.js +0 -224
- package/tools/forked.js +0 -301
- 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/guest-session.js +0 -119
- package/tools/handoff.js +0 -239
- package/tools/health.js +0 -87
- package/tools/idea.js +0 -217
- package/tools/insights.js +0 -123
- package/tools/invite.js +0 -228
- package/tools/l2-bridge.js +0 -272
- package/tools/l2-status.js +0 -217
- package/tools/l2.js +0 -206
- package/tools/leaderboard.js +0 -117
- package/tools/lib/git-apply.js +0 -206
- package/tools/lib/git-bundle.js +0 -407
- package/tools/migrate.js +0 -156
- package/tools/mint.js +0 -377
- package/tools/multiplayer-game.js +0 -275
- package/tools/notifications.js +0 -415
- package/tools/observe.js +0 -200
- package/tools/onboarding.js +0 -147
- package/tools/open.js +0 -258
- package/tools/pair.js +0 -173
- package/tools/party-game.js +0 -314
- package/tools/ping.js +0 -51
- package/tools/plan.js +0 -225
- package/tools/presence-agent.js +0 -167
- package/tools/profile.js +0 -219
- package/tools/proof-of-work.js +0 -144
- package/tools/pulse.js +0 -218
- package/tools/react.js +0 -115
- package/tools/release.js +0 -83
- package/tools/report.js +0 -109
- package/tools/reputation.js +0 -175
- package/tools/request.js +0 -231
- package/tools/reservations.js +0 -116
- package/tools/reserve.js +0 -111
- package/tools/schedule.js +0 -367
- package/tools/search-messages.js +0 -123
- package/tools/session.js +0 -654
- package/tools/session_price.js +0 -128
- package/tools/settings.js +0 -200
- package/tools/shipback.js +0 -326
- package/tools/smart-check.js +0 -201
- package/tools/social-inbox.js +0 -437
- package/tools/social-post.js +0 -326
- package/tools/social-processor.js +0 -445
- package/tools/solo-game.js +0 -390
- package/tools/streak.js +0 -147
- package/tools/stuck.js +0 -297
- package/tools/submit.js +0 -98
- package/tools/subscribe.js +0 -148
- package/tools/subscriptions.js +0 -134
- package/tools/suggest-tags.js +0 -184
- package/tools/tag-suggestions.js +0 -257
- package/tools/tip.js +0 -193
- package/tools/wallet.js +0 -269
- package/tools/watch.js +0 -177
- package/tools/webhook-test.js +0 -388
- package/tools/withdraw.js +0 -145
- package/tools/work-summary.js +0 -96
- package/tools/workshop-buddy.js +0 -394
- package/tools/workshop.js +0 -327
- package/tools/x-mentions.js +0 -84
- package/tools/x-reply.js +0 -82
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slashvibe-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"mcpName": "io.github.vibecodinginc/vibe",
|
|
5
5
|
"description": "Social layer for Claude Code - identity, presence, messaging, and consented live collaboration",
|
|
6
6
|
"main": "index.js",
|
|
@@ -60,7 +60,41 @@
|
|
|
60
60
|
"prompts.js",
|
|
61
61
|
"twitter.js",
|
|
62
62
|
"version.json",
|
|
63
|
-
"tools/",
|
|
63
|
+
"tools/_actions.js",
|
|
64
|
+
"tools/_discovery.js",
|
|
65
|
+
"tools/_shared.js",
|
|
66
|
+
"tools/_work-context.js",
|
|
67
|
+
"tools/admin-inbox.js",
|
|
68
|
+
"tools/artifact-view.js",
|
|
69
|
+
"tools/bye.js",
|
|
70
|
+
"tools/corpse.js",
|
|
71
|
+
"tools/dm.js",
|
|
72
|
+
"tools/doctor.js",
|
|
73
|
+
"tools/echo.js",
|
|
74
|
+
"tools/email.js",
|
|
75
|
+
"tools/fable.js",
|
|
76
|
+
"tools/feed.js",
|
|
77
|
+
"tools/game.js",
|
|
78
|
+
"tools/help.js",
|
|
79
|
+
"tools/inbox.js",
|
|
80
|
+
"tools/init.js",
|
|
81
|
+
"tools/intro.js",
|
|
82
|
+
"tools/matrix-read.js",
|
|
83
|
+
"tools/matrix-rooms.js",
|
|
84
|
+
"tools/matrix-send.js",
|
|
85
|
+
"tools/patterns.js",
|
|
86
|
+
"tools/play.js",
|
|
87
|
+
"tools/poem.js",
|
|
88
|
+
"tools/reply.js",
|
|
89
|
+
"tools/ship.js",
|
|
90
|
+
"tools/start.js",
|
|
91
|
+
"tools/status.js",
|
|
92
|
+
"tools/summarize.js",
|
|
93
|
+
"tools/test.js",
|
|
94
|
+
"tools/token.js",
|
|
95
|
+
"tools/update.js",
|
|
96
|
+
"tools/weave.js",
|
|
97
|
+
"tools/who.js",
|
|
64
98
|
"hooks/",
|
|
65
99
|
"store/",
|
|
66
100
|
"protocol/",
|
package/version.json
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"updated": "2026-07-
|
|
4
|
-
"changelog": "
|
|
2
|
+
"version": "0.6.0",
|
|
3
|
+
"updated": "2026-07-25",
|
|
4
|
+
"changelog": "Lean release: the npm tarball now ships only the tool files the server actually loads. 90+ unreachable experiment files (wallet, l2, mint, games graveyard, deprecated) no longer ride along in every npx download. Zero behavior change: same 23-tool surface, same registration, same auth flow.",
|
|
5
5
|
"features": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"Public house-agent sessions retain their explicit open-door policy",
|
|
10
|
-
"The MCP version manifest, package, and lockfile now report the same release"
|
|
6
|
+
"Tarball pruned to the require-closure of index.js/cli.js/setup.js (static analysis, no dynamic requires in codebase)",
|
|
7
|
+
"Package size and npx cold-start reduced",
|
|
8
|
+
"No tool added or removed from the live surface"
|
|
11
9
|
],
|
|
12
10
|
"deprecated": [],
|
|
13
|
-
"breaking":
|
|
11
|
+
"breaking": false,
|
|
14
12
|
"updateUrl": "https://www.slashvibe.dev/api/version"
|
|
15
13
|
}
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Connection Queue Management — Smart queuing for connection suggestions
|
|
3
|
-
*
|
|
4
|
-
* Prevents suggestion spam and optimizes timing:
|
|
5
|
-
* - Tracks recent suggestions to avoid repeats
|
|
6
|
-
* - Queues suggestions for optimal timing
|
|
7
|
-
* - Rates limits to prevent overwhelming users
|
|
8
|
-
* - Prioritizes high-quality matches
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const config = require('../config');
|
|
14
|
-
|
|
15
|
-
const QUEUE_FILE = path.join(config.VIBE_DIR, 'connection-queue.json');
|
|
16
|
-
const SUGGESTION_COOLDOWN = 24 * 60 * 60 * 1000; // 24 hours
|
|
17
|
-
const MAX_SUGGESTIONS_PER_DAY = 3;
|
|
18
|
-
|
|
19
|
-
// Load queue data from disk
|
|
20
|
-
function loadQueue() {
|
|
21
|
-
try {
|
|
22
|
-
if (fs.existsSync(QUEUE_FILE)) {
|
|
23
|
-
const data = fs.readFileSync(QUEUE_FILE, 'utf8');
|
|
24
|
-
return JSON.parse(data);
|
|
25
|
-
}
|
|
26
|
-
} catch (e) {
|
|
27
|
-
console.warn('Failed to load connection queue:', e.message);
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
recent_suggestions: [],
|
|
31
|
-
queued_suggestions: [],
|
|
32
|
-
user_limits: {}
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Save queue data to disk
|
|
37
|
-
function saveQueue(queueData) {
|
|
38
|
-
try {
|
|
39
|
-
fs.writeFileSync(QUEUE_FILE, JSON.stringify(queueData, null, 2));
|
|
40
|
-
} catch (e) {
|
|
41
|
-
console.error('Failed to save connection queue:', e.message);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Check if suggestion was made recently
|
|
46
|
-
function isRecentSuggestion(from, to) {
|
|
47
|
-
const queue = loadQueue();
|
|
48
|
-
const now = Date.now();
|
|
49
|
-
const cutoff = now - SUGGESTION_COOLDOWN;
|
|
50
|
-
|
|
51
|
-
return queue.recent_suggestions.some(s =>
|
|
52
|
-
s.from === from &&
|
|
53
|
-
s.to === to &&
|
|
54
|
-
s.timestamp > cutoff
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Check if user has reached daily suggestion limit
|
|
59
|
-
function hasReachedDailyLimit(userHandle) {
|
|
60
|
-
const queue = loadQueue();
|
|
61
|
-
const now = Date.now();
|
|
62
|
-
const dayStart = now - (24 * 60 * 60 * 1000);
|
|
63
|
-
|
|
64
|
-
if (!queue.user_limits[userHandle]) {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const todaysSuggestions = queue.user_limits[userHandle].filter(
|
|
69
|
-
timestamp => timestamp > dayStart
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
return todaysSuggestions.length >= MAX_SUGGESTIONS_PER_DAY;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Record a new suggestion
|
|
76
|
-
function recordSuggestion(from, to, reason, priority = 'medium') {
|
|
77
|
-
const queue = loadQueue();
|
|
78
|
-
const now = Date.now();
|
|
79
|
-
|
|
80
|
-
// Add to recent suggestions
|
|
81
|
-
queue.recent_suggestions.push({
|
|
82
|
-
from,
|
|
83
|
-
to,
|
|
84
|
-
reason,
|
|
85
|
-
timestamp: now,
|
|
86
|
-
priority
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Track user limit
|
|
90
|
-
if (!queue.user_limits[from]) {
|
|
91
|
-
queue.user_limits[from] = [];
|
|
92
|
-
}
|
|
93
|
-
queue.user_limits[from].push(now);
|
|
94
|
-
|
|
95
|
-
// Clean up old data
|
|
96
|
-
const cutoff = now - SUGGESTION_COOLDOWN;
|
|
97
|
-
queue.recent_suggestions = queue.recent_suggestions.filter(s => s.timestamp > cutoff);
|
|
98
|
-
|
|
99
|
-
// Clean up user limits (keep last 7 days)
|
|
100
|
-
const weekCutoff = now - (7 * 24 * 60 * 60 * 1000);
|
|
101
|
-
for (const [user, timestamps] of Object.entries(queue.user_limits)) {
|
|
102
|
-
queue.user_limits[user] = timestamps.filter(t => t > weekCutoff);
|
|
103
|
-
if (queue.user_limits[user].length === 0) {
|
|
104
|
-
delete queue.user_limits[user];
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
saveQueue(queue);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Queue a suggestion for later delivery
|
|
112
|
-
function queueSuggestion(from, to, reason, priority = 'medium', idealTiming = null) {
|
|
113
|
-
const queue = loadQueue();
|
|
114
|
-
const now = Date.now();
|
|
115
|
-
|
|
116
|
-
queue.queued_suggestions.push({
|
|
117
|
-
from,
|
|
118
|
-
to,
|
|
119
|
-
reason,
|
|
120
|
-
priority,
|
|
121
|
-
queued_at: now,
|
|
122
|
-
ideal_timing: idealTiming,
|
|
123
|
-
status: 'pending'
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
saveQueue(queue);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Get next suggestions to process
|
|
130
|
-
function getNextSuggestions(limit = 5) {
|
|
131
|
-
const queue = loadQueue();
|
|
132
|
-
const now = Date.now();
|
|
133
|
-
|
|
134
|
-
return queue.queued_suggestions
|
|
135
|
-
.filter(s => s.status === 'pending')
|
|
136
|
-
.filter(s => {
|
|
137
|
-
// Check timing constraint if specified
|
|
138
|
-
if (s.ideal_timing && now < s.ideal_timing) {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Check rate limits
|
|
143
|
-
if (hasReachedDailyLimit(s.from)) {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Check recent suggestion cooldown
|
|
148
|
-
if (isRecentSuggestion(s.from, s.to)) {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return true;
|
|
153
|
-
})
|
|
154
|
-
.sort((a, b) => {
|
|
155
|
-
// Priority sorting: high -> medium -> low
|
|
156
|
-
const priorityOrder = { high: 3, medium: 2, low: 1 };
|
|
157
|
-
const priorityDiff = (priorityOrder[b.priority] || 2) - (priorityOrder[a.priority] || 2);
|
|
158
|
-
if (priorityDiff !== 0) return priorityDiff;
|
|
159
|
-
|
|
160
|
-
// Then by queue time (older first)
|
|
161
|
-
return a.queued_at - b.queued_at;
|
|
162
|
-
})
|
|
163
|
-
.slice(0, limit);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Mark suggestion as processed
|
|
167
|
-
function markSuggestionProcessed(from, to, status = 'sent') {
|
|
168
|
-
const queue = loadQueue();
|
|
169
|
-
|
|
170
|
-
const suggestion = queue.queued_suggestions.find(s =>
|
|
171
|
-
s.from === from && s.to === to && s.status === 'pending'
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
if (suggestion) {
|
|
175
|
-
suggestion.status = status;
|
|
176
|
-
suggestion.processed_at = Date.now();
|
|
177
|
-
saveQueue(queue);
|
|
178
|
-
|
|
179
|
-
// Also record in recent suggestions if sent
|
|
180
|
-
if (status === 'sent') {
|
|
181
|
-
recordSuggestion(from, to, suggestion.reason, suggestion.priority);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Get user's suggestion history
|
|
187
|
-
function getUserSuggestionHistory(userHandle, days = 7) {
|
|
188
|
-
const queue = loadQueue();
|
|
189
|
-
const cutoff = Date.now() - (days * 24 * 60 * 60 * 1000);
|
|
190
|
-
|
|
191
|
-
const recent = queue.recent_suggestions.filter(s =>
|
|
192
|
-
s.from === userHandle && s.timestamp > cutoff
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
const queued = queue.queued_suggestions.filter(s =>
|
|
196
|
-
s.from === userHandle
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
return { recent, queued };
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Get queue statistics
|
|
203
|
-
function getQueueStats() {
|
|
204
|
-
const queue = loadQueue();
|
|
205
|
-
const now = Date.now();
|
|
206
|
-
|
|
207
|
-
const pending = queue.queued_suggestions.filter(s => s.status === 'pending').length;
|
|
208
|
-
const processed = queue.queued_suggestions.filter(s => s.status !== 'pending').length;
|
|
209
|
-
|
|
210
|
-
const today = now - (24 * 60 * 60 * 1000);
|
|
211
|
-
const recentSuggestions = queue.recent_suggestions.filter(s => s.timestamp > today).length;
|
|
212
|
-
|
|
213
|
-
const priorityCounts = {};
|
|
214
|
-
for (const suggestion of queue.queued_suggestions) {
|
|
215
|
-
if (suggestion.status === 'pending') {
|
|
216
|
-
priorityCounts[suggestion.priority] = (priorityCounts[suggestion.priority] || 0) + 1;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
pending,
|
|
222
|
-
processed,
|
|
223
|
-
recentSuggestions,
|
|
224
|
-
priorityCounts,
|
|
225
|
-
totalUsers: Object.keys(queue.user_limits).length
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Clean up old queue data
|
|
230
|
-
function cleanupQueue() {
|
|
231
|
-
const queue = loadQueue();
|
|
232
|
-
const now = Date.now();
|
|
233
|
-
const cutoff = now - (7 * 24 * 60 * 60 * 1000); // 7 days
|
|
234
|
-
|
|
235
|
-
// Remove old processed suggestions
|
|
236
|
-
queue.queued_suggestions = queue.queued_suggestions.filter(s =>
|
|
237
|
-
s.status === 'pending' || (s.processed_at && s.processed_at > cutoff)
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
// Remove old recent suggestions (already handled in recordSuggestion)
|
|
241
|
-
|
|
242
|
-
saveQueue(queue);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
module.exports = {
|
|
246
|
-
isRecentSuggestion,
|
|
247
|
-
hasReachedDailyLimit,
|
|
248
|
-
recordSuggestion,
|
|
249
|
-
queueSuggestion,
|
|
250
|
-
getNextSuggestions,
|
|
251
|
-
markSuggestionProcessed,
|
|
252
|
-
getUserSuggestionHistory,
|
|
253
|
-
getQueueStats,
|
|
254
|
-
cleanupQueue,
|
|
255
|
-
SUGGESTION_COOLDOWN,
|
|
256
|
-
MAX_SUGGESTIONS_PER_DAY
|
|
257
|
-
};
|
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibe auto-suggest-connections — Smart connection recommendations
|
|
3
|
-
*
|
|
4
|
-
* Analyzes skills exchanges and user profiles to automatically suggest
|
|
5
|
-
* connections between people with complementary skills or interests.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const store = require('../store');
|
|
9
|
-
const userProfiles = require('../store/profiles');
|
|
10
|
-
const { formatTimeAgo, requireInit } = require('./_shared');
|
|
11
|
-
|
|
12
|
-
const definition = {
|
|
13
|
-
name: 'vibe_auto_suggest_connections',
|
|
14
|
-
description: 'Find and suggest connections based on complementary skills and interests.',
|
|
15
|
-
inputSchema: {
|
|
16
|
-
type: 'object',
|
|
17
|
-
properties: {
|
|
18
|
-
mode: {
|
|
19
|
-
type: 'string',
|
|
20
|
-
enum: ['skills', 'building', 'interests', 'all'],
|
|
21
|
-
description: 'Type of connection analysis to run',
|
|
22
|
-
default: 'skills'
|
|
23
|
-
},
|
|
24
|
-
limit: {
|
|
25
|
-
type: 'number',
|
|
26
|
-
description: 'Maximum number of suggestions to generate',
|
|
27
|
-
default: 5
|
|
28
|
-
},
|
|
29
|
-
execute: {
|
|
30
|
-
type: 'boolean',
|
|
31
|
-
description: 'Actually send suggestions to users (vs just preview)',
|
|
32
|
-
default: false
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// Find skill-based connection opportunities
|
|
39
|
-
async function findSkillConnections() {
|
|
40
|
-
const posts = await store.getSkillExchanges() || [];
|
|
41
|
-
const connections = [];
|
|
42
|
-
|
|
43
|
-
// Build skill map
|
|
44
|
-
const skillMap = {};
|
|
45
|
-
posts.forEach(post => {
|
|
46
|
-
if (!skillMap[post.skill]) {
|
|
47
|
-
skillMap[post.skill] = { offers: [], requests: [] };
|
|
48
|
-
}
|
|
49
|
-
skillMap[post.skill][post.type + 's'].push(post);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Find perfect matches
|
|
53
|
-
Object.entries(skillMap).forEach(([skill, data]) => {
|
|
54
|
-
data.offers.forEach(offer => {
|
|
55
|
-
data.requests.forEach(request => {
|
|
56
|
-
if (offer.handle !== request.handle) {
|
|
57
|
-
connections.push({
|
|
58
|
-
type: 'skill_exchange',
|
|
59
|
-
skill,
|
|
60
|
-
expert: offer.handle,
|
|
61
|
-
learner: request.handle,
|
|
62
|
-
reason: `@${offer.handle} offers "${skill}" expertise and @${request.handle} is looking to learn it`,
|
|
63
|
-
confidence: 95,
|
|
64
|
-
details: {
|
|
65
|
-
offerDetails: offer.details,
|
|
66
|
-
requestDetails: request.details,
|
|
67
|
-
category: offer.category
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
return connections;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Find building/project-based connections
|
|
79
|
-
async function findBuildingConnections() {
|
|
80
|
-
const profiles = await userProfiles.getAllProfiles();
|
|
81
|
-
const connections = [];
|
|
82
|
-
|
|
83
|
-
const users = Object.values(profiles).filter(p => p.building);
|
|
84
|
-
|
|
85
|
-
for (let i = 0; i < users.length; i++) {
|
|
86
|
-
for (let j = i + 1; j < users.length; j++) {
|
|
87
|
-
const user1 = users[i];
|
|
88
|
-
const user2 = users[j];
|
|
89
|
-
|
|
90
|
-
const building1 = user1.building.toLowerCase();
|
|
91
|
-
const building2 = user2.building.toLowerCase();
|
|
92
|
-
|
|
93
|
-
// Check for similar projects or complementary skills
|
|
94
|
-
const commonWords = building1.split(' ').filter(word =>
|
|
95
|
-
word.length > 3 && building2.includes(word)
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
if (commonWords.length > 0) {
|
|
99
|
-
connections.push({
|
|
100
|
-
type: 'similar_building',
|
|
101
|
-
person1: user1.handle,
|
|
102
|
-
person2: user2.handle,
|
|
103
|
-
reason: `Both building similar projects: "${user1.building}" and "${user2.building}"`,
|
|
104
|
-
confidence: 75,
|
|
105
|
-
details: {
|
|
106
|
-
commonWords,
|
|
107
|
-
project1: user1.building,
|
|
108
|
-
project2: user2.building
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return connections;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Find interest-based connections
|
|
119
|
-
async function findInterestConnections() {
|
|
120
|
-
const profiles = await userProfiles.getAllProfiles();
|
|
121
|
-
const connections = [];
|
|
122
|
-
|
|
123
|
-
const users = Object.values(profiles).filter(p => p.interests && p.interests.length > 0);
|
|
124
|
-
|
|
125
|
-
for (let i = 0; i < users.length; i++) {
|
|
126
|
-
for (let j = i + 1; j < users.length; j++) {
|
|
127
|
-
const user1 = users[i];
|
|
128
|
-
const user2 = users[j];
|
|
129
|
-
|
|
130
|
-
const commonInterests = user1.interests.filter(interest =>
|
|
131
|
-
user2.interests.some(i2 =>
|
|
132
|
-
i2.toLowerCase() === interest.toLowerCase() ||
|
|
133
|
-
i2.toLowerCase().includes(interest.toLowerCase()) ||
|
|
134
|
-
interest.toLowerCase().includes(i2.toLowerCase())
|
|
135
|
-
)
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
if (commonInterests.length > 0) {
|
|
139
|
-
connections.push({
|
|
140
|
-
type: 'shared_interests',
|
|
141
|
-
person1: user1.handle,
|
|
142
|
-
person2: user2.handle,
|
|
143
|
-
reason: `Share interests in: ${commonInterests.join(', ')}`,
|
|
144
|
-
confidence: 60 + (commonInterests.length * 10),
|
|
145
|
-
details: {
|
|
146
|
-
commonInterests,
|
|
147
|
-
user1Interests: user1.interests,
|
|
148
|
-
user2Interests: user2.interests
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return connections;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Format connection suggestion
|
|
159
|
-
function formatSuggestion(connection) {
|
|
160
|
-
switch (connection.type) {
|
|
161
|
-
case 'skill_exchange':
|
|
162
|
-
return {
|
|
163
|
-
from: connection.learner,
|
|
164
|
-
to: connection.expert,
|
|
165
|
-
reason: `You both are interested in "${connection.skill}"! @${connection.expert} offers expertise and you're looking to learn. Great opportunity to connect!`,
|
|
166
|
-
altReason: `@${connection.learner} is looking to learn "${connection.skill}" which you offer expertise in. Consider reaching out to help!`
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
case 'similar_building':
|
|
170
|
-
return {
|
|
171
|
-
from: connection.person1,
|
|
172
|
-
to: connection.person2,
|
|
173
|
-
reason: `You might want to connect with @${connection.person2} — you're both building similar projects! "${connection.details.project1}" and "${connection.details.project2}"`
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
case 'shared_interests':
|
|
177
|
-
return {
|
|
178
|
-
from: connection.person1,
|
|
179
|
-
to: connection.person2,
|
|
180
|
-
reason: `You share interests with @${connection.person2} in: ${connection.details.commonInterests.join(', ')}. Could be a great collaboration!`
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
default:
|
|
184
|
-
return {
|
|
185
|
-
from: connection.person1 || connection.expert,
|
|
186
|
-
to: connection.person2 || connection.learner,
|
|
187
|
-
reason: connection.reason
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
async function handler(args) {
|
|
193
|
-
const initCheck = requireInit();
|
|
194
|
-
if (initCheck) return initCheck;
|
|
195
|
-
|
|
196
|
-
const mode = args.mode || 'skills';
|
|
197
|
-
const limit = Math.min(args.limit || 5, 10);
|
|
198
|
-
const execute = args.execute === true;
|
|
199
|
-
|
|
200
|
-
let display = '';
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
display = `## Auto-Suggest Connections 🤖\n\n`;
|
|
204
|
-
|
|
205
|
-
let allConnections = [];
|
|
206
|
-
|
|
207
|
-
// Gather connections based on mode
|
|
208
|
-
if (mode === 'skills' || mode === 'all') {
|
|
209
|
-
const skillConnections = await findSkillConnections();
|
|
210
|
-
allConnections = allConnections.concat(skillConnections);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (mode === 'building' || mode === 'all') {
|
|
214
|
-
const buildingConnections = await findBuildingConnections();
|
|
215
|
-
allConnections = allConnections.concat(buildingConnections);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (mode === 'interests' || mode === 'all') {
|
|
219
|
-
const interestConnections = await findInterestConnections();
|
|
220
|
-
allConnections = allConnections.concat(interestConnections);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Sort by confidence and limit
|
|
224
|
-
allConnections.sort((a, b) => b.confidence - a.confidence);
|
|
225
|
-
const topConnections = allConnections.slice(0, limit);
|
|
226
|
-
|
|
227
|
-
if (topConnections.length === 0) {
|
|
228
|
-
display += `**No connection opportunities found** in "${mode}" mode.\n\n`;
|
|
229
|
-
display += `**Try:**\n`;
|
|
230
|
-
display += `• \`auto-suggest-connections --mode all\` — Check all types\n`;
|
|
231
|
-
display += `• \`bootstrap-skills\` — Create sample skill exchanges\n`;
|
|
232
|
-
display += `• Users can \`skills-exchange post\` to create opportunities\n`;
|
|
233
|
-
return { display };
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
display += `**Found ${topConnections.length} connection opportunities** (mode: ${mode})\n\n`;
|
|
237
|
-
|
|
238
|
-
let suggestions = [];
|
|
239
|
-
|
|
240
|
-
for (const connection of topConnections) {
|
|
241
|
-
const formatted = formatSuggestion(connection);
|
|
242
|
-
suggestions.push(formatted);
|
|
243
|
-
|
|
244
|
-
display += `### ${connection.type.replace('_', ' ').toUpperCase()} (${connection.confidence}% match)\n`;
|
|
245
|
-
display += `**Connection:** @${formatted.from} ↔ @${formatted.to}\n`;
|
|
246
|
-
display += `**Reason:** ${formatted.reason}\n`;
|
|
247
|
-
|
|
248
|
-
if (connection.details) {
|
|
249
|
-
display += `**Context:** `;
|
|
250
|
-
if (connection.type === 'skill_exchange') {
|
|
251
|
-
display += `Expert: "${connection.details.offerDetails || 'available'}" / Learner: "${connection.details.requestDetails || 'seeking help'}"`;
|
|
252
|
-
} else if (connection.type === 'similar_building') {
|
|
253
|
-
display += `"${connection.details.project1}" + "${connection.details.project2}"`;
|
|
254
|
-
} else if (connection.type === 'shared_interests') {
|
|
255
|
-
display += `${connection.details.commonInterests.join(', ')}`;
|
|
256
|
-
}
|
|
257
|
-
display += `\n`;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (execute) {
|
|
261
|
-
display += `**✅ SUGGESTED** — DM sent to @${formatted.from}\n`;
|
|
262
|
-
} else {
|
|
263
|
-
display += `**Preview** — Would suggest to @${formatted.from}\n`;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
display += `\n`;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (execute) {
|
|
270
|
-
// Actually send the suggestions
|
|
271
|
-
let sent = 0;
|
|
272
|
-
for (const suggestion of suggestions) {
|
|
273
|
-
try {
|
|
274
|
-
await store.sendMessage(
|
|
275
|
-
'discovery-agent',
|
|
276
|
-
suggestion.from,
|
|
277
|
-
`🤝 Connection Suggestion: ${suggestion.reason}`,
|
|
278
|
-
'suggestion'
|
|
279
|
-
);
|
|
280
|
-
sent++;
|
|
281
|
-
} catch (error) {
|
|
282
|
-
console.error(`Failed to send suggestion to @${suggestion.from}:`, error);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
display += `**✅ Results: ${sent}/${suggestions.length} suggestions sent successfully**\n\n`;
|
|
287
|
-
} else {
|
|
288
|
-
display += `**💡 To actually send these suggestions:**\n`;
|
|
289
|
-
display += `\`auto-suggest-connections --mode ${mode} --execute true\`\n\n`;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
display += `**Connection Dashboard:**\n`;
|
|
293
|
-
display += `• Skills exchanges: Use \`skills-exchange browse\`\n`;
|
|
294
|
-
display += `• User profiles: Use \`who\` to see who's building what\n`;
|
|
295
|
-
display += `• Direct connections: \`dm @username\` to connect directly\n`;
|
|
296
|
-
|
|
297
|
-
} catch (error) {
|
|
298
|
-
display = `## Auto-Suggest Error\n\n${error.message}\n\nTry: \`auto-suggest-connections\` for basic suggestions`;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return { display };
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
module.exports = { definition, handler };
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibe away — Set an AIM-style away message
|
|
3
|
-
*
|
|
4
|
-
* Part of the /vibe Nostalgia Stack.
|
|
5
|
-
* Classic away messages with auto-away after 30min idle.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const config = require('../config');
|
|
9
|
-
const store = require('../store');
|
|
10
|
-
const { requireInit } = require('./_shared');
|
|
11
|
-
const { markAway } = require('../intelligence/proactive');
|
|
12
|
-
|
|
13
|
-
// Preset suggestions for fun
|
|
14
|
-
const PRESETS = [
|
|
15
|
-
'grabbing coffee ☕',
|
|
16
|
-
'in a meeting 📅',
|
|
17
|
-
'deep work mode 🎧',
|
|
18
|
-
'lunch break 🍕',
|
|
19
|
-
'gone for a walk 🚶',
|
|
20
|
-
'taking a break 💆',
|
|
21
|
-
'back in 5 ⏰',
|
|
22
|
-
'do not disturb 🔕'
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
const definition = {
|
|
26
|
-
name: 'vibe_away',
|
|
27
|
-
description: 'Set an away message (AIM-style). Classic vibes. Use "vibe back" to return.',
|
|
28
|
-
inputSchema: {
|
|
29
|
-
type: 'object',
|
|
30
|
-
properties: {
|
|
31
|
-
message: {
|
|
32
|
-
type: 'string',
|
|
33
|
-
description: 'Your away message (e.g., "grabbing coffee", "in a meeting")'
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
async function handler(args) {
|
|
40
|
-
// Require init
|
|
41
|
-
const initCheck = requireInit();
|
|
42
|
-
if (initCheck) {
|
|
43
|
-
return initCheck;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handle = config.getHandle();
|
|
47
|
-
const message = args.message?.trim();
|
|
48
|
-
|
|
49
|
-
// If no message, set generic away
|
|
50
|
-
if (!message) {
|
|
51
|
-
await store.setAwayStatus(handle, 'away', null);
|
|
52
|
-
markAway();
|
|
53
|
-
return { display: '☕ away' };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Validate message length
|
|
57
|
-
if (message.length > 100) {
|
|
58
|
-
return { display: '⚠️ too long (100 char max)' };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Set away status with message
|
|
62
|
-
await store.setAwayStatus(handle, 'away', message);
|
|
63
|
-
markAway();
|
|
64
|
-
|
|
65
|
-
return { display: `☕ away — "${message}"` };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
module.exports = { definition, handler };
|