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.
Files changed (145) hide show
  1. package/package.json +36 -2
  2. package/version.json +7 -9
  3. package/tools/_connection-queue.js +0 -257
  4. package/tools/_deprecated/auto-suggest-connections.js +0 -304
  5. package/tools/_deprecated/away.js +0 -68
  6. package/tools/_deprecated/back.js +0 -51
  7. package/tools/_deprecated/bootstrap-skills.js +0 -231
  8. package/tools/_deprecated/bridge-dashboard.js +0 -342
  9. package/tools/_deprecated/bridge-health.js +0 -400
  10. package/tools/_deprecated/bridge-live.js +0 -384
  11. package/tools/_deprecated/bridges.js +0 -383
  12. package/tools/_deprecated/colorguess.js +0 -281
  13. package/tools/_deprecated/discover-insights.js +0 -379
  14. package/tools/_deprecated/discover-momentum.js +0 -256
  15. package/tools/_deprecated/discovery-analytics.js +0 -345
  16. package/tools/_deprecated/discovery-auto-suggest.js +0 -275
  17. package/tools/_deprecated/discovery-bootstrap.js +0 -267
  18. package/tools/_deprecated/discovery-daily.js +0 -375
  19. package/tools/_deprecated/discovery-dashboard.js +0 -385
  20. package/tools/_deprecated/discovery-digest.js +0 -314
  21. package/tools/_deprecated/discovery-hub.js +0 -357
  22. package/tools/_deprecated/discovery-insights.js +0 -384
  23. package/tools/_deprecated/discovery-momentum.js +0 -281
  24. package/tools/_deprecated/discovery-monitor.js +0 -319
  25. package/tools/_deprecated/discovery-proactive.js +0 -300
  26. package/tools/_deprecated/draw.js +0 -317
  27. package/tools/_deprecated/farcaster.js +0 -307
  28. package/tools/_deprecated/forget.js +0 -119
  29. package/tools/_deprecated/games-catalog.js +0 -376
  30. package/tools/_deprecated/games.js +0 -313
  31. package/tools/_deprecated/guessnumber.js +0 -194
  32. package/tools/_deprecated/hangman.js +0 -129
  33. package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
  34. package/tools/_deprecated/mute.js +0 -97
  35. package/tools/_deprecated/recall.js +0 -147
  36. package/tools/_deprecated/remember.js +0 -86
  37. package/tools/_deprecated/riddle.js +0 -240
  38. package/tools/_deprecated/run-bootstrap.js +0 -69
  39. package/tools/_deprecated/skills-analytics.js +0 -349
  40. package/tools/_deprecated/skills-bootstrap.js +0 -301
  41. package/tools/_deprecated/skills-dashboard.js +0 -268
  42. package/tools/_deprecated/skills-exchange.js +0 -342
  43. package/tools/_deprecated/skills.js +0 -380
  44. package/tools/_deprecated/smart-intro.js +0 -353
  45. package/tools/_deprecated/storybuilder.js +0 -331
  46. package/tools/_deprecated/telegram-bot.js +0 -183
  47. package/tools/_deprecated/telegram-setup.js +0 -214
  48. package/tools/_deprecated/tictactoe.js +0 -155
  49. package/tools/_deprecated/twentyquestions.js +0 -143
  50. package/tools/_deprecated/wordassociation.js +0 -247
  51. package/tools/_discovery-enhanced.js +0 -290
  52. package/tools/_proactive-discovery.js +0 -301
  53. package/tools/_shared/index.js +0 -326
  54. package/tools/_work-context.manual-test.js +0 -199
  55. package/tools/_work-context.test.js +0 -260
  56. package/tools/activity.js +0 -220
  57. package/tools/agent-treasury.js +0 -288
  58. package/tools/agents.js +0 -122
  59. package/tools/approve.js +0 -197
  60. package/tools/arcade.js +0 -173
  61. package/tools/artifact-create.js +0 -247
  62. package/tools/artifacts-price.js +0 -107
  63. package/tools/ask-expert.js +0 -160
  64. package/tools/available.js +0 -120
  65. package/tools/become-expert.js +0 -150
  66. package/tools/broadcast.js +0 -325
  67. package/tools/call.js +0 -149
  68. package/tools/cc-insights.js +0 -320
  69. package/tools/chat.js +0 -202
  70. package/tools/collaborative-drawing.js +0 -286
  71. package/tools/connection-status.js +0 -178
  72. package/tools/consent.js +0 -114
  73. package/tools/context.js +0 -132
  74. package/tools/crossword.js +0 -369
  75. package/tools/discover.js +0 -717
  76. package/tools/drawing.js +0 -310
  77. package/tools/earnings.js +0 -126
  78. package/tools/follow.js +0 -224
  79. package/tools/forked.js +0 -301
  80. package/tools/friends.js +0 -207
  81. package/tools/genesis.js +0 -233
  82. package/tools/gig-browse.js +0 -206
  83. package/tools/gig-complete.js +0 -144
  84. package/tools/guest-session.js +0 -119
  85. package/tools/handoff.js +0 -239
  86. package/tools/health.js +0 -87
  87. package/tools/idea.js +0 -217
  88. package/tools/insights.js +0 -123
  89. package/tools/invite.js +0 -228
  90. package/tools/l2-bridge.js +0 -272
  91. package/tools/l2-status.js +0 -217
  92. package/tools/l2.js +0 -206
  93. package/tools/leaderboard.js +0 -117
  94. package/tools/lib/git-apply.js +0 -206
  95. package/tools/lib/git-bundle.js +0 -407
  96. package/tools/migrate.js +0 -156
  97. package/tools/mint.js +0 -377
  98. package/tools/multiplayer-game.js +0 -275
  99. package/tools/notifications.js +0 -415
  100. package/tools/observe.js +0 -200
  101. package/tools/onboarding.js +0 -147
  102. package/tools/open.js +0 -258
  103. package/tools/pair.js +0 -173
  104. package/tools/party-game.js +0 -314
  105. package/tools/ping.js +0 -51
  106. package/tools/plan.js +0 -225
  107. package/tools/presence-agent.js +0 -167
  108. package/tools/profile.js +0 -219
  109. package/tools/proof-of-work.js +0 -144
  110. package/tools/pulse.js +0 -218
  111. package/tools/react.js +0 -115
  112. package/tools/release.js +0 -83
  113. package/tools/report.js +0 -109
  114. package/tools/reputation.js +0 -175
  115. package/tools/request.js +0 -231
  116. package/tools/reservations.js +0 -116
  117. package/tools/reserve.js +0 -111
  118. package/tools/schedule.js +0 -367
  119. package/tools/search-messages.js +0 -123
  120. package/tools/session.js +0 -654
  121. package/tools/session_price.js +0 -128
  122. package/tools/settings.js +0 -200
  123. package/tools/shipback.js +0 -326
  124. package/tools/smart-check.js +0 -201
  125. package/tools/social-inbox.js +0 -437
  126. package/tools/social-post.js +0 -326
  127. package/tools/social-processor.js +0 -445
  128. package/tools/solo-game.js +0 -390
  129. package/tools/streak.js +0 -147
  130. package/tools/stuck.js +0 -297
  131. package/tools/submit.js +0 -98
  132. package/tools/subscribe.js +0 -148
  133. package/tools/subscriptions.js +0 -134
  134. package/tools/suggest-tags.js +0 -184
  135. package/tools/tag-suggestions.js +0 -257
  136. package/tools/tip.js +0 -193
  137. package/tools/wallet.js +0 -269
  138. package/tools/watch.js +0 -177
  139. package/tools/webhook-test.js +0 -388
  140. package/tools/withdraw.js +0 -145
  141. package/tools/work-summary.js +0 -96
  142. package/tools/workshop-buddy.js +0 -394
  143. package/tools/workshop.js +0 -327
  144. package/tools/x-mentions.js +0 -84
  145. 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.5.25",
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.5.25",
3
- "updated": "2026-07-10",
4
- "changelog": "Live collaboration now has a real actor boundary. Pairing requires acceptance, private session reads use the signed-in actor instead of a viewer string, and messages enter a human session only after the owner opts in. All MCP pair and guest calls now carry the OAuth token.",
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
- "Pair requests are two-party: the target accepts or declines before session context is shared",
7
- "Paired and private session reads derive the viewer from a signed token; query-string handle spoofing no longer grants access",
8
- "Guest messages and handle/claude DMs require target opt-in plus an accepted pair for human sessions",
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": true,
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 };