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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const config = require('../config');
|
|
14
|
+
const { debug } = require('./_shared');
|
|
14
15
|
|
|
15
16
|
const QUEUE_FILE = path.join(config.VIBE_DIR, 'connection-queue.json');
|
|
16
17
|
const SUGGESTION_COOLDOWN = 24 * 60 * 60 * 1000; // 24 hours
|
|
@@ -24,7 +25,7 @@ function loadQueue() {
|
|
|
24
25
|
return JSON.parse(data);
|
|
25
26
|
}
|
|
26
27
|
} catch (e) {
|
|
27
|
-
|
|
28
|
+
debug('connection-queue', 'Failed to load connection queue:', e.message);
|
|
28
29
|
}
|
|
29
30
|
return {
|
|
30
31
|
recent_suggestions: [],
|
|
@@ -38,7 +39,7 @@ function saveQueue(queueData) {
|
|
|
38
39
|
try {
|
|
39
40
|
fs.writeFileSync(QUEUE_FILE, JSON.stringify(queueData, null, 2));
|
|
40
41
|
} catch (e) {
|
|
41
|
-
|
|
42
|
+
debug('connection-queue', 'Failed to save connection queue:', e.message);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -47,28 +48,22 @@ function isRecentSuggestion(from, to) {
|
|
|
47
48
|
const queue = loadQueue();
|
|
48
49
|
const now = Date.now();
|
|
49
50
|
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
|
-
);
|
|
51
|
+
|
|
52
|
+
return queue.recent_suggestions.some(s => s.from === from && s.to === to && s.timestamp > cutoff);
|
|
56
53
|
}
|
|
57
54
|
|
|
58
55
|
// Check if user has reached daily suggestion limit
|
|
59
56
|
function hasReachedDailyLimit(userHandle) {
|
|
60
57
|
const queue = loadQueue();
|
|
61
58
|
const now = Date.now();
|
|
62
|
-
const dayStart = now -
|
|
63
|
-
|
|
59
|
+
const dayStart = now - 24 * 60 * 60 * 1000;
|
|
60
|
+
|
|
64
61
|
if (!queue.user_limits[userHandle]) {
|
|
65
62
|
return false;
|
|
66
63
|
}
|
|
67
|
-
|
|
68
|
-
const todaysSuggestions = queue.user_limits[userHandle].filter(
|
|
69
|
-
|
|
70
|
-
);
|
|
71
|
-
|
|
64
|
+
|
|
65
|
+
const todaysSuggestions = queue.user_limits[userHandle].filter(timestamp => timestamp > dayStart);
|
|
66
|
+
|
|
72
67
|
return todaysSuggestions.length >= MAX_SUGGESTIONS_PER_DAY;
|
|
73
68
|
}
|
|
74
69
|
|
|
@@ -76,7 +71,7 @@ function hasReachedDailyLimit(userHandle) {
|
|
|
76
71
|
function recordSuggestion(from, to, reason, priority = 'medium') {
|
|
77
72
|
const queue = loadQueue();
|
|
78
73
|
const now = Date.now();
|
|
79
|
-
|
|
74
|
+
|
|
80
75
|
// Add to recent suggestions
|
|
81
76
|
queue.recent_suggestions.push({
|
|
82
77
|
from,
|
|
@@ -85,26 +80,26 @@ function recordSuggestion(from, to, reason, priority = 'medium') {
|
|
|
85
80
|
timestamp: now,
|
|
86
81
|
priority
|
|
87
82
|
});
|
|
88
|
-
|
|
83
|
+
|
|
89
84
|
// Track user limit
|
|
90
85
|
if (!queue.user_limits[from]) {
|
|
91
86
|
queue.user_limits[from] = [];
|
|
92
87
|
}
|
|
93
88
|
queue.user_limits[from].push(now);
|
|
94
|
-
|
|
89
|
+
|
|
95
90
|
// Clean up old data
|
|
96
91
|
const cutoff = now - SUGGESTION_COOLDOWN;
|
|
97
92
|
queue.recent_suggestions = queue.recent_suggestions.filter(s => s.timestamp > cutoff);
|
|
98
|
-
|
|
93
|
+
|
|
99
94
|
// Clean up user limits (keep last 7 days)
|
|
100
|
-
const weekCutoff = now -
|
|
95
|
+
const weekCutoff = now - 7 * 24 * 60 * 60 * 1000;
|
|
101
96
|
for (const [user, timestamps] of Object.entries(queue.user_limits)) {
|
|
102
97
|
queue.user_limits[user] = timestamps.filter(t => t > weekCutoff);
|
|
103
98
|
if (queue.user_limits[user].length === 0) {
|
|
104
99
|
delete queue.user_limits[user];
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
|
-
|
|
102
|
+
|
|
108
103
|
saveQueue(queue);
|
|
109
104
|
}
|
|
110
105
|
|
|
@@ -112,7 +107,7 @@ function recordSuggestion(from, to, reason, priority = 'medium') {
|
|
|
112
107
|
function queueSuggestion(from, to, reason, priority = 'medium', idealTiming = null) {
|
|
113
108
|
const queue = loadQueue();
|
|
114
109
|
const now = Date.now();
|
|
115
|
-
|
|
110
|
+
|
|
116
111
|
queue.queued_suggestions.push({
|
|
117
112
|
from,
|
|
118
113
|
to,
|
|
@@ -122,7 +117,7 @@ function queueSuggestion(from, to, reason, priority = 'medium', idealTiming = nu
|
|
|
122
117
|
ideal_timing: idealTiming,
|
|
123
118
|
status: 'pending'
|
|
124
119
|
});
|
|
125
|
-
|
|
120
|
+
|
|
126
121
|
saveQueue(queue);
|
|
127
122
|
}
|
|
128
123
|
|
|
@@ -130,7 +125,7 @@ function queueSuggestion(from, to, reason, priority = 'medium', idealTiming = nu
|
|
|
130
125
|
function getNextSuggestions(limit = 5) {
|
|
131
126
|
const queue = loadQueue();
|
|
132
127
|
const now = Date.now();
|
|
133
|
-
|
|
128
|
+
|
|
134
129
|
return queue.queued_suggestions
|
|
135
130
|
.filter(s => s.status === 'pending')
|
|
136
131
|
.filter(s => {
|
|
@@ -138,17 +133,17 @@ function getNextSuggestions(limit = 5) {
|
|
|
138
133
|
if (s.ideal_timing && now < s.ideal_timing) {
|
|
139
134
|
return false;
|
|
140
135
|
}
|
|
141
|
-
|
|
136
|
+
|
|
142
137
|
// Check rate limits
|
|
143
138
|
if (hasReachedDailyLimit(s.from)) {
|
|
144
139
|
return false;
|
|
145
140
|
}
|
|
146
|
-
|
|
141
|
+
|
|
147
142
|
// Check recent suggestion cooldown
|
|
148
143
|
if (isRecentSuggestion(s.from, s.to)) {
|
|
149
144
|
return false;
|
|
150
145
|
}
|
|
151
|
-
|
|
146
|
+
|
|
152
147
|
return true;
|
|
153
148
|
})
|
|
154
149
|
.sort((a, b) => {
|
|
@@ -156,7 +151,7 @@ function getNextSuggestions(limit = 5) {
|
|
|
156
151
|
const priorityOrder = { high: 3, medium: 2, low: 1 };
|
|
157
152
|
const priorityDiff = (priorityOrder[b.priority] || 2) - (priorityOrder[a.priority] || 2);
|
|
158
153
|
if (priorityDiff !== 0) return priorityDiff;
|
|
159
|
-
|
|
154
|
+
|
|
160
155
|
// Then by queue time (older first)
|
|
161
156
|
return a.queued_at - b.queued_at;
|
|
162
157
|
})
|
|
@@ -166,16 +161,14 @@ function getNextSuggestions(limit = 5) {
|
|
|
166
161
|
// Mark suggestion as processed
|
|
167
162
|
function markSuggestionProcessed(from, to, status = 'sent') {
|
|
168
163
|
const queue = loadQueue();
|
|
169
|
-
|
|
170
|
-
const suggestion = queue.queued_suggestions.find(s =>
|
|
171
|
-
|
|
172
|
-
);
|
|
173
|
-
|
|
164
|
+
|
|
165
|
+
const suggestion = queue.queued_suggestions.find(s => s.from === from && s.to === to && s.status === 'pending');
|
|
166
|
+
|
|
174
167
|
if (suggestion) {
|
|
175
168
|
suggestion.status = status;
|
|
176
169
|
suggestion.processed_at = Date.now();
|
|
177
170
|
saveQueue(queue);
|
|
178
|
-
|
|
171
|
+
|
|
179
172
|
// Also record in recent suggestions if sent
|
|
180
173
|
if (status === 'sent') {
|
|
181
174
|
recordSuggestion(from, to, suggestion.reason, suggestion.priority);
|
|
@@ -186,16 +179,12 @@ function markSuggestionProcessed(from, to, status = 'sent') {
|
|
|
186
179
|
// Get user's suggestion history
|
|
187
180
|
function getUserSuggestionHistory(userHandle, days = 7) {
|
|
188
181
|
const queue = loadQueue();
|
|
189
|
-
const cutoff = Date.now() -
|
|
190
|
-
|
|
191
|
-
const recent = queue.recent_suggestions.filter(s =>
|
|
192
|
-
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
const queued = queue.queued_suggestions.filter(s =>
|
|
196
|
-
s.from === userHandle
|
|
197
|
-
);
|
|
198
|
-
|
|
182
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
|
|
183
|
+
|
|
184
|
+
const recent = queue.recent_suggestions.filter(s => s.from === userHandle && s.timestamp > cutoff);
|
|
185
|
+
|
|
186
|
+
const queued = queue.queued_suggestions.filter(s => s.from === userHandle);
|
|
187
|
+
|
|
199
188
|
return { recent, queued };
|
|
200
189
|
}
|
|
201
190
|
|
|
@@ -203,20 +192,20 @@ function getUserSuggestionHistory(userHandle, days = 7) {
|
|
|
203
192
|
function getQueueStats() {
|
|
204
193
|
const queue = loadQueue();
|
|
205
194
|
const now = Date.now();
|
|
206
|
-
|
|
195
|
+
|
|
207
196
|
const pending = queue.queued_suggestions.filter(s => s.status === 'pending').length;
|
|
208
197
|
const processed = queue.queued_suggestions.filter(s => s.status !== 'pending').length;
|
|
209
|
-
|
|
210
|
-
const today = now -
|
|
198
|
+
|
|
199
|
+
const today = now - 24 * 60 * 60 * 1000;
|
|
211
200
|
const recentSuggestions = queue.recent_suggestions.filter(s => s.timestamp > today).length;
|
|
212
|
-
|
|
201
|
+
|
|
213
202
|
const priorityCounts = {};
|
|
214
203
|
for (const suggestion of queue.queued_suggestions) {
|
|
215
204
|
if (suggestion.status === 'pending') {
|
|
216
205
|
priorityCounts[suggestion.priority] = (priorityCounts[suggestion.priority] || 0) + 1;
|
|
217
206
|
}
|
|
218
207
|
}
|
|
219
|
-
|
|
208
|
+
|
|
220
209
|
return {
|
|
221
210
|
pending,
|
|
222
211
|
processed,
|
|
@@ -230,15 +219,15 @@ function getQueueStats() {
|
|
|
230
219
|
function cleanupQueue() {
|
|
231
220
|
const queue = loadQueue();
|
|
232
221
|
const now = Date.now();
|
|
233
|
-
const cutoff = now -
|
|
234
|
-
|
|
222
|
+
const cutoff = now - 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
223
|
+
|
|
235
224
|
// Remove old processed suggestions
|
|
236
|
-
queue.queued_suggestions = queue.queued_suggestions.filter(
|
|
237
|
-
s.status === 'pending' || (s.processed_at && s.processed_at > cutoff)
|
|
225
|
+
queue.queued_suggestions = queue.queued_suggestions.filter(
|
|
226
|
+
s => s.status === 'pending' || (s.processed_at && s.processed_at > cutoff)
|
|
238
227
|
);
|
|
239
|
-
|
|
228
|
+
|
|
240
229
|
// Remove old recent suggestions (already handled in recordSuggestion)
|
|
241
|
-
|
|
230
|
+
|
|
242
231
|
saveQueue(queue);
|
|
243
232
|
}
|
|
244
233
|
|
|
@@ -254,4 +243,4 @@ module.exports = {
|
|
|
254
243
|
cleanupQueue,
|
|
255
244
|
SUGGESTION_COOLDOWN,
|
|
256
245
|
MAX_SUGGESTIONS_PER_DAY
|
|
257
|
-
};
|
|
246
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Enhanced Discovery Features - Advanced matchmaking capabilities
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Features for @discovery-agent:
|
|
5
5
|
* - Smart profile completion suggestions
|
|
6
6
|
* - Cross-domain interest matching
|
|
@@ -14,27 +14,27 @@ const store = require('../store');
|
|
|
14
14
|
|
|
15
15
|
// Advanced interest mapping - find connections across domains
|
|
16
16
|
const CROSS_DOMAIN_INTERESTS = {
|
|
17
|
-
|
|
17
|
+
ai: {
|
|
18
18
|
related: ['machine learning', 'data science', 'automation', 'nlp'],
|
|
19
19
|
complementary: ['ui/ux', 'product', 'ethics', 'data visualization'],
|
|
20
20
|
applications: ['healthcare', 'fintech', 'education', 'gaming']
|
|
21
21
|
},
|
|
22
|
-
|
|
22
|
+
frontend: {
|
|
23
23
|
related: ['ui/ux', 'design systems', 'react', 'vue', 'angular'],
|
|
24
24
|
complementary: ['backend', 'api design', 'devops', 'mobile'],
|
|
25
25
|
applications: ['web apps', 'dashboards', 'marketing sites', 'e-commerce']
|
|
26
26
|
},
|
|
27
|
-
|
|
27
|
+
blockchain: {
|
|
28
28
|
related: ['crypto', 'web3', 'defi', 'nfts', 'smart contracts'],
|
|
29
29
|
complementary: ['security', 'economics', 'legal', 'community'],
|
|
30
30
|
applications: ['fintech', 'gaming', 'supply chain', 'identity']
|
|
31
31
|
},
|
|
32
|
-
|
|
32
|
+
healthcare: {
|
|
33
33
|
related: ['medical devices', 'telemedicine', 'health data', 'wellness'],
|
|
34
34
|
complementary: ['ai', 'security', 'compliance', 'ux'],
|
|
35
35
|
applications: ['patient care', 'research', 'mental health', 'fitness']
|
|
36
36
|
},
|
|
37
|
-
|
|
37
|
+
gaming: {
|
|
38
38
|
related: ['game design', 'unity', 'unreal', 'mobile games'],
|
|
39
39
|
complementary: ['ai', 'networking', 'audio', 'community'],
|
|
40
40
|
applications: ['education', 'simulation', 'social', 'vr/ar']
|
|
@@ -45,27 +45,27 @@ const CROSS_DOMAIN_INTERESTS = {
|
|
|
45
45
|
async function suggestProfileEnhancements(handle) {
|
|
46
46
|
const profile = await userProfiles.getProfile(handle);
|
|
47
47
|
const suggestions = [];
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
// Missing building project
|
|
50
50
|
if (!profile.building) {
|
|
51
51
|
suggestions.push({
|
|
52
52
|
type: 'building',
|
|
53
53
|
priority: 'high',
|
|
54
|
-
suggestion:
|
|
54
|
+
suggestion: "Add what you're currently building to find similar builders",
|
|
55
55
|
example: 'vibe update building "AI-powered code review tool"'
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
// Few interests
|
|
60
60
|
if (!profile.interests || profile.interests.length < 2) {
|
|
61
61
|
suggestions.push({
|
|
62
62
|
type: 'interests',
|
|
63
|
-
priority: 'high',
|
|
63
|
+
priority: 'high',
|
|
64
64
|
suggestion: 'Add 3-5 interests to find people with shared passions',
|
|
65
65
|
example: 'vibe update interests "ai, startups, productivity, music"'
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
// No technical tags
|
|
70
70
|
if (!profile.tags || profile.tags.length < 2) {
|
|
71
71
|
suggestions.push({
|
|
@@ -75,7 +75,7 @@ async function suggestProfileEnhancements(handle) {
|
|
|
75
75
|
example: 'vibe update tags "python, react, backend, api-design"'
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
// Suggest cross-domain connections
|
|
80
80
|
if (profile.interests && profile.interests.length > 0) {
|
|
81
81
|
for (const interest of profile.interests) {
|
|
@@ -92,7 +92,7 @@ async function suggestProfileEnhancements(handle) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
return suggestions;
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -100,21 +100,22 @@ async function suggestProfileEnhancements(handle) {
|
|
|
100
100
|
async function findCrossDomainMatches(handle) {
|
|
101
101
|
const myProfile = await userProfiles.getProfile(handle);
|
|
102
102
|
const allProfiles = await userProfiles.getAllProfiles();
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
const crossMatches = [];
|
|
105
|
-
|
|
106
|
-
for (const interest of
|
|
105
|
+
|
|
106
|
+
for (const interest of myProfile.interests || []) {
|
|
107
107
|
const crossDomain = CROSS_DOMAIN_INTERESTS[interest.toLowerCase()];
|
|
108
108
|
if (!crossDomain) continue;
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
// Find people in complementary domains
|
|
111
111
|
for (const complementary of crossDomain.complementary) {
|
|
112
|
-
const matches = allProfiles.filter(
|
|
113
|
-
p
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
const matches = allProfiles.filter(
|
|
113
|
+
p =>
|
|
114
|
+
p.handle !== myProfile.handle &&
|
|
115
|
+
(p.interests?.some(i => i.toLowerCase().includes(complementary.toLowerCase())) ||
|
|
116
|
+
p.tags?.some(t => t.toLowerCase().includes(complementary.toLowerCase())))
|
|
116
117
|
);
|
|
117
|
-
|
|
118
|
+
|
|
118
119
|
for (const match of matches) {
|
|
119
120
|
crossMatches.push({
|
|
120
121
|
handle: match.handle,
|
|
@@ -127,7 +128,7 @@ async function findCrossDomainMatches(handle) {
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
+
|
|
131
132
|
return crossMatches.slice(0, 5);
|
|
132
133
|
}
|
|
133
134
|
|
|
@@ -140,16 +141,16 @@ async function analyzeActivityPatterns() {
|
|
|
140
141
|
recentlyActive: [],
|
|
141
142
|
dormant: []
|
|
142
143
|
};
|
|
143
|
-
|
|
144
|
+
|
|
144
145
|
const now = Date.now();
|
|
145
146
|
const hour = 1000 * 60 * 60;
|
|
146
147
|
const day = hour * 24;
|
|
147
|
-
|
|
148
|
+
|
|
148
149
|
for (const profile of allProfiles) {
|
|
149
150
|
if (!profile.lastSeen) continue;
|
|
150
|
-
|
|
151
|
+
|
|
151
152
|
const timeAgo = now - profile.lastSeen;
|
|
152
|
-
|
|
153
|
+
|
|
153
154
|
// Recently active (last 2 hours)
|
|
154
155
|
if (timeAgo < 2 * hour) {
|
|
155
156
|
patterns.recentlyActive.push({
|
|
@@ -158,7 +159,7 @@ async function analyzeActivityPatterns() {
|
|
|
158
159
|
minutesAgo: Math.floor(timeAgo / (1000 * 60))
|
|
159
160
|
});
|
|
160
161
|
}
|
|
161
|
-
|
|
162
|
+
|
|
162
163
|
// Dormant users (more than 7 days)
|
|
163
164
|
if (timeAgo > 7 * day) {
|
|
164
165
|
patterns.dormant.push({
|
|
@@ -166,13 +167,13 @@ async function analyzeActivityPatterns() {
|
|
|
166
167
|
daysAgo: Math.floor(timeAgo / day)
|
|
167
168
|
});
|
|
168
169
|
}
|
|
169
|
-
|
|
170
|
+
|
|
170
171
|
// Estimate timezone (very rough)
|
|
171
172
|
const lastSeenHour = new Date(profile.lastSeen).getHours();
|
|
172
173
|
const timezone = `UTC${lastSeenHour < 12 ? '-' : '+'}${Math.abs(lastSeenHour - 12)}`;
|
|
173
174
|
patterns.timezones[timezone] = (patterns.timezones[timezone] || 0) + 1;
|
|
174
175
|
}
|
|
175
|
-
|
|
176
|
+
|
|
176
177
|
return patterns;
|
|
177
178
|
}
|
|
178
179
|
|
|
@@ -186,19 +187,17 @@ async function getConnectionInsights() {
|
|
|
186
187
|
recentConnections: [],
|
|
187
188
|
connectionReasons: {}
|
|
188
189
|
};
|
|
189
|
-
|
|
190
|
+
|
|
190
191
|
let totalUsers = 0;
|
|
191
|
-
|
|
192
|
+
|
|
192
193
|
for (const profile of allProfiles) {
|
|
193
194
|
if (profile.connections && profile.connections.length > 0) {
|
|
194
195
|
totalUsers++;
|
|
195
196
|
insights.totalConnections += profile.connections.length;
|
|
196
|
-
|
|
197
|
+
|
|
197
198
|
// Recent connections (last 24 hours)
|
|
198
|
-
const recent = profile.connections.filter(c =>
|
|
199
|
-
|
|
200
|
-
);
|
|
201
|
-
|
|
199
|
+
const recent = profile.connections.filter(c => Date.now() - c.timestamp < 1000 * 60 * 60 * 24);
|
|
200
|
+
|
|
202
201
|
for (const conn of recent) {
|
|
203
202
|
insights.recentConnections.push({
|
|
204
203
|
from: profile.handle,
|
|
@@ -207,15 +206,14 @@ async function getConnectionInsights() {
|
|
|
207
206
|
hoursAgo: Math.floor((Date.now() - conn.timestamp) / (1000 * 60 * 60))
|
|
208
207
|
});
|
|
209
208
|
}
|
|
210
|
-
|
|
209
|
+
|
|
211
210
|
// Track connection reasons
|
|
212
211
|
for (const conn of profile.connections) {
|
|
213
212
|
if (conn.reason) {
|
|
214
|
-
insights.connectionReasons[conn.reason] =
|
|
215
|
-
(insights.connectionReasons[conn.reason] || 0) + 1;
|
|
213
|
+
insights.connectionReasons[conn.reason] = (insights.connectionReasons[conn.reason] || 0) + 1;
|
|
216
214
|
}
|
|
217
215
|
}
|
|
218
|
-
|
|
216
|
+
|
|
219
217
|
// Top connectors
|
|
220
218
|
insights.topConnectors.push({
|
|
221
219
|
handle: profile.handle,
|
|
@@ -223,13 +221,12 @@ async function getConnectionInsights() {
|
|
|
223
221
|
});
|
|
224
222
|
}
|
|
225
223
|
}
|
|
226
|
-
|
|
227
|
-
insights.avgConnectionsPerUser = totalUsers > 0 ?
|
|
228
|
-
|
|
229
|
-
|
|
224
|
+
|
|
225
|
+
insights.avgConnectionsPerUser = totalUsers > 0 ? Math.round((insights.totalConnections / totalUsers) * 10) / 10 : 0;
|
|
226
|
+
|
|
230
227
|
insights.topConnectors.sort((a, b) => b.connections - a.connections);
|
|
231
228
|
insights.topConnectors = insights.topConnectors.slice(0, 5);
|
|
232
|
-
|
|
229
|
+
|
|
233
230
|
return insights;
|
|
234
231
|
}
|
|
235
232
|
|
|
@@ -238,15 +235,13 @@ async function generateDiscoveryRecommendations() {
|
|
|
238
235
|
const allProfiles = await userProfiles.getAllProfiles();
|
|
239
236
|
const insights = await getConnectionInsights();
|
|
240
237
|
const patterns = await analyzeActivityPatterns();
|
|
241
|
-
|
|
238
|
+
|
|
242
239
|
const recommendations = [];
|
|
243
|
-
|
|
240
|
+
|
|
244
241
|
// Recommend profile improvements
|
|
245
242
|
if (allProfiles.length > 0) {
|
|
246
|
-
const incompleteProfiles = allProfiles.filter(p =>
|
|
247
|
-
|
|
248
|
-
).length;
|
|
249
|
-
|
|
243
|
+
const incompleteProfiles = allProfiles.filter(p => !p.building || !p.interests || p.interests.length < 2).length;
|
|
244
|
+
|
|
250
245
|
if (incompleteProfiles > 0) {
|
|
251
246
|
recommendations.push({
|
|
252
247
|
type: 'profile-completion',
|
|
@@ -256,7 +251,7 @@ async function generateDiscoveryRecommendations() {
|
|
|
256
251
|
});
|
|
257
252
|
}
|
|
258
253
|
}
|
|
259
|
-
|
|
254
|
+
|
|
260
255
|
// Recommend connection opportunities
|
|
261
256
|
if (patterns.recentlyActive.length > 1) {
|
|
262
257
|
recommendations.push({
|
|
@@ -266,17 +261,17 @@ async function generateDiscoveryRecommendations() {
|
|
|
266
261
|
action: 'Perfect time for real-time connection suggestions'
|
|
267
262
|
});
|
|
268
263
|
}
|
|
269
|
-
|
|
264
|
+
|
|
270
265
|
// Recommend re-engagement
|
|
271
266
|
if (patterns.dormant.length > 0) {
|
|
272
267
|
recommendations.push({
|
|
273
268
|
type: 'reengagement',
|
|
274
|
-
priority: 'low',
|
|
269
|
+
priority: 'low',
|
|
275
270
|
message: `${patterns.dormant.length} dormant users could be re-engaged`,
|
|
276
271
|
action: 'Send personalized connection suggestions to bring them back'
|
|
277
272
|
});
|
|
278
273
|
}
|
|
279
|
-
|
|
274
|
+
|
|
280
275
|
return recommendations;
|
|
281
276
|
}
|
|
282
277
|
|
|
@@ -287,4 +282,4 @@ module.exports = {
|
|
|
287
282
|
getConnectionInsights,
|
|
288
283
|
generateDiscoveryRecommendations,
|
|
289
284
|
CROSS_DOMAIN_INTERESTS
|
|
290
|
-
};
|
|
285
|
+
};
|