slashvibe-mcp 0.3.21 → 0.3.23
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/auto-update.js +10 -15
- package/config.js +36 -31
- package/crypto.js +1 -6
- package/debug.js +12 -0
- package/discord.js +19 -19
- package/eslint.config.js +54 -0
- 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/migrate-v2.js +72 -0
- package/notification-emitter.js +2 -2
- package/notify.js +39 -14
- package/package.json +28 -29
- package/post-install.js +141 -0
- 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/test-skills-bootstrap.js +20 -0
- package/test-v2-integration.js +385 -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/webhook-runner.js +132 -0
- package/auth-store.js +0 -148
- 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/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
package/tools/_discovery.js
CHANGED
|
@@ -12,33 +12,33 @@
|
|
|
12
12
|
const INTEREST_CLUSTERS = {
|
|
13
13
|
'ai-ml': ['ai', 'machine learning', 'deep learning', 'neural networks', 'llm', 'gpt', 'artificial intelligence'],
|
|
14
14
|
'web-dev': ['frontend', 'backend', 'fullstack', 'web development', 'javascript', 'react', 'vue', 'angular'],
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
mobile: ['ios', 'android', 'react native', 'flutter', 'mobile development', 'swift', 'kotlin'],
|
|
16
|
+
startups: ['entrepreneur', 'startup', 'founder', 'business', 'venture capital', 'product market fit'],
|
|
17
|
+
design: ['ui design', 'ux design', 'product design', 'graphic design', 'figma', 'sketch'],
|
|
18
|
+
blockchain: ['blockchain', 'crypto', 'web3', 'defi', 'nft', 'ethereum', 'bitcoin'],
|
|
19
|
+
data: ['data science', 'analytics', 'big data', 'data engineering', 'sql', 'python'],
|
|
20
|
+
gaming: ['game development', 'unity', 'unreal', 'indie games', 'gaming'],
|
|
21
|
+
devops: ['devops', 'kubernetes', 'docker', 'aws', 'cloud', 'infrastructure'],
|
|
22
|
+
content: ['writing', 'blogging', 'content creation', 'marketing', 'social media']
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
// Technology skill clusters for complementary matching
|
|
26
26
|
const SKILL_CLUSTERS = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
frontend: ['react', 'vue', 'angular', 'typescript', 'javascript', 'css', 'html'],
|
|
28
|
+
backend: ['node.js', 'python', 'java', 'go', 'rust', 'express', 'django'],
|
|
29
|
+
mobile: ['swift', 'kotlin', 'react-native', 'flutter', 'ionic'],
|
|
30
|
+
data: ['python', 'r', 'sql', 'pandas', 'tensorflow', 'pytorch'],
|
|
31
|
+
devops: ['docker', 'kubernetes', 'aws', 'azure', 'terraform', 'jenkins'],
|
|
32
|
+
design: ['figma', 'sketch', 'photoshop', 'illustrator', 'principle']
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
// Calculate semantic similarity between interests
|
|
36
36
|
function calculateInterestSimilarity(interests1, interests2) {
|
|
37
37
|
if (!interests1?.length || !interests2?.length) return 0;
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
let score = 0;
|
|
40
40
|
const matches = [];
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
// Direct matches (highest weight)
|
|
43
43
|
for (const interest1 of interests1) {
|
|
44
44
|
for (const interest2 of interests2) {
|
|
@@ -48,45 +48,41 @@ function calculateInterestSimilarity(interests1, interests2) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
// Cluster-based similarity (medium weight)
|
|
53
53
|
for (const [clusterName, keywords] of Object.entries(INTEREST_CLUSTERS)) {
|
|
54
|
-
const user1InCluster = interests1.some(i =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const user2InCluster = interests2.some(i =>
|
|
58
|
-
keywords.some(k => i.toLowerCase().includes(k.toLowerCase()))
|
|
59
|
-
);
|
|
60
|
-
|
|
54
|
+
const user1InCluster = interests1.some(i => keywords.some(k => i.toLowerCase().includes(k.toLowerCase())));
|
|
55
|
+
const user2InCluster = interests2.some(i => keywords.some(k => i.toLowerCase().includes(k.toLowerCase())));
|
|
56
|
+
|
|
61
57
|
if (user1InCluster && user2InCluster) {
|
|
62
58
|
score += 12;
|
|
63
59
|
matches.push(clusterName);
|
|
64
60
|
}
|
|
65
61
|
}
|
|
66
|
-
|
|
62
|
+
|
|
67
63
|
// Keyword similarity (lower weight)
|
|
68
64
|
for (const interest1 of interests1) {
|
|
69
65
|
for (const interest2 of interests2) {
|
|
70
66
|
const words1 = interest1.toLowerCase().split(/\s+/);
|
|
71
67
|
const words2 = interest2.toLowerCase().split(/\s+/);
|
|
72
68
|
const commonWords = words1.filter(w => words2.includes(w) && w.length > 3);
|
|
73
|
-
|
|
69
|
+
|
|
74
70
|
if (commonWords.length > 0) {
|
|
75
71
|
score += commonWords.length * 3;
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
}
|
|
79
|
-
|
|
75
|
+
|
|
80
76
|
return { score, matches: [...new Set(matches)].slice(0, 3) };
|
|
81
77
|
}
|
|
82
78
|
|
|
83
79
|
// Calculate tag/skill complementarity
|
|
84
80
|
function calculateSkillComplementarity(tags1, tags2) {
|
|
85
81
|
if (!tags1?.length || !tags2?.length) return { score: 0, pairs: [] };
|
|
86
|
-
|
|
82
|
+
|
|
87
83
|
let score = 0;
|
|
88
84
|
const pairs = [];
|
|
89
|
-
|
|
85
|
+
|
|
90
86
|
// Find complementary pairs
|
|
91
87
|
const complementaryPairs = [
|
|
92
88
|
['frontend', 'backend'],
|
|
@@ -97,27 +93,20 @@ function calculateSkillComplementarity(tags1, tags2) {
|
|
|
97
93
|
['devops', 'backend'],
|
|
98
94
|
['marketing', 'product']
|
|
99
95
|
];
|
|
100
|
-
|
|
96
|
+
|
|
101
97
|
for (const [skill1, skill2] of complementaryPairs) {
|
|
102
98
|
const user1HasSkill1 = tags1.some(t => t.toLowerCase().includes(skill1.toLowerCase()));
|
|
103
99
|
const user1HasSkill2 = tags1.some(t => t.toLowerCase().includes(skill2.toLowerCase()));
|
|
104
100
|
const user2HasSkill1 = tags2.some(t => t.toLowerCase().includes(skill1.toLowerCase()));
|
|
105
101
|
const user2HasSkill2 = tags2.some(t => t.toLowerCase().includes(skill2.toLowerCase()));
|
|
106
|
-
|
|
102
|
+
|
|
107
103
|
if ((user1HasSkill1 && user2HasSkill2) || (user1HasSkill2 && user2HasSkill1)) {
|
|
108
104
|
score += 15;
|
|
109
105
|
pairs.push(`${skill1}/${skill2}`);
|
|
110
106
|
}
|
|
111
107
|
}
|
|
112
|
-
|
|
113
|
-
return { score, pairs: pairs.slice(0, 2) };
|
|
114
|
-
}
|
|
115
108
|
|
|
116
|
-
|
|
117
|
-
function hasWord(text, word) {
|
|
118
|
-
// Use word boundary regex for short keywords prone to false positives
|
|
119
|
-
const regex = new RegExp(`\\b${word}\\b`, 'i');
|
|
120
|
-
return regex.test(text);
|
|
109
|
+
return { score, pairs: pairs.slice(0, 2) };
|
|
121
110
|
}
|
|
122
111
|
|
|
123
112
|
// Suggest interests based on what user is building
|
|
@@ -127,169 +116,83 @@ function suggestInterestsFromBuilding(buildingDescription) {
|
|
|
127
116
|
const building = buildingDescription.toLowerCase();
|
|
128
117
|
const suggestions = [];
|
|
129
118
|
|
|
130
|
-
//
|
|
131
|
-
if (building.includes('
|
|
132
|
-
|
|
133
|
-
building.includes('orchestrat') || building.includes('workflow')) {
|
|
134
|
-
suggestions.push('agents', 'ai', 'automation');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// AI/ML projects (use word boundary for short keywords)
|
|
138
|
-
if (hasWord(building, 'ai') || building.includes('machine learning') ||
|
|
139
|
-
hasWord(building, 'llm') || hasWord(building, 'gpt') ||
|
|
140
|
-
building.includes('neural') || hasWord(building, 'ml')) {
|
|
141
|
-
suggestions.push('ai', 'machine learning');
|
|
119
|
+
// AI/ML projects
|
|
120
|
+
if (building.includes('ai') || building.includes('machine learning') || building.includes('llm')) {
|
|
121
|
+
suggestions.push('ai', 'machine learning', 'deep learning');
|
|
142
122
|
}
|
|
143
123
|
|
|
144
124
|
// Web projects
|
|
145
|
-
if (building.includes('web') || building.includes('website') ||
|
|
146
|
-
|
|
147
|
-
building.includes('next') || building.includes('vue')) {
|
|
148
|
-
suggestions.push('web development', 'frontend');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Backend/API projects
|
|
152
|
-
if (building.includes('api') || building.includes('backend') ||
|
|
153
|
-
building.includes('server') || building.includes('database')) {
|
|
154
|
-
suggestions.push('backend', 'api');
|
|
125
|
+
if (building.includes('web') || building.includes('website') || building.includes('app')) {
|
|
126
|
+
suggestions.push('web development', 'frontend', 'fullstack');
|
|
155
127
|
}
|
|
156
128
|
|
|
157
129
|
// Mobile projects
|
|
158
|
-
if (building.includes('mobile') || building.includes('ios') ||
|
|
159
|
-
|
|
160
|
-
building.includes('react native')) {
|
|
161
|
-
suggestions.push('mobile development');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Platform/SaaS projects (NEW)
|
|
165
|
-
if (building.includes('platform') || building.includes('saas') ||
|
|
166
|
-
building.includes('.app') || building.includes('product')) {
|
|
167
|
-
suggestions.push('platform', 'saas', 'product');
|
|
130
|
+
if (building.includes('mobile') || building.includes('ios') || building.includes('android')) {
|
|
131
|
+
suggestions.push('mobile development', 'app development');
|
|
168
132
|
}
|
|
169
133
|
|
|
170
134
|
// Startup/business projects
|
|
171
|
-
if (building.includes('startup') || building.includes('business') ||
|
|
172
|
-
|
|
173
|
-
suggestions.push('startups', 'entrepreneur');
|
|
135
|
+
if (building.includes('startup') || building.includes('business') || building.includes('saas')) {
|
|
136
|
+
suggestions.push('startups', 'entrepreneur', 'product management');
|
|
174
137
|
}
|
|
175
138
|
|
|
176
139
|
// Data projects
|
|
177
|
-
if (building.includes('data') || building.includes('analytics') ||
|
|
178
|
-
|
|
179
|
-
suggestions.push('data science', 'analytics');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Developer tools (NEW)
|
|
183
|
-
if (building.includes('tool') || building.includes('cli') ||
|
|
184
|
-
building.includes('developer') || building.includes('devtool') ||
|
|
185
|
-
building.includes('editor') || building.includes('ide')) {
|
|
186
|
-
suggestions.push('developer tools', 'infrastructure');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Creative/Generative projects (NEW)
|
|
190
|
-
if (hasWord(building, 'art') || building.includes('generative') ||
|
|
191
|
-
building.includes('creative') || building.includes('music') ||
|
|
192
|
-
building.includes('visual') || building.includes('design')) {
|
|
193
|
-
suggestions.push('generative art', 'creative');
|
|
140
|
+
if (building.includes('data') || building.includes('analytics') || building.includes('dashboard')) {
|
|
141
|
+
suggestions.push('data science', 'analytics', 'visualization');
|
|
194
142
|
}
|
|
195
143
|
|
|
196
144
|
// Content/media projects
|
|
197
|
-
if (building.includes('content') || building.includes('blog') ||
|
|
198
|
-
|
|
199
|
-
suggestions.push('content creation', 'writing');
|
|
145
|
+
if (building.includes('content') || building.includes('blog') || building.includes('media')) {
|
|
146
|
+
suggestions.push('content creation', 'writing', 'marketing');
|
|
200
147
|
}
|
|
201
148
|
|
|
202
149
|
// Gaming projects
|
|
203
|
-
if (building.includes('game') || building.includes('unity') ||
|
|
204
|
-
|
|
205
|
-
suggestions.push('game development', 'gaming');
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Infrastructure/DevOps (NEW)
|
|
209
|
-
if (building.includes('infrastructure') || building.includes('devops') ||
|
|
210
|
-
building.includes('cloud') || building.includes('deploy') ||
|
|
211
|
-
building.includes('kubernetes') || building.includes('docker')) {
|
|
212
|
-
suggestions.push('devops', 'infrastructure');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Social/Community (NEW)
|
|
216
|
-
if (building.includes('social') || building.includes('community') ||
|
|
217
|
-
building.includes('network') || building.includes('chat') ||
|
|
218
|
-
building.includes('messaging')) {
|
|
219
|
-
suggestions.push('social', 'community');
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Crypto/Web3 (NEW)
|
|
223
|
-
if (building.includes('crypto') || building.includes('web3') ||
|
|
224
|
-
building.includes('blockchain') || building.includes('defi') ||
|
|
225
|
-
building.includes('nft') || building.includes('token')) {
|
|
226
|
-
suggestions.push('crypto', 'web3');
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Education (NEW)
|
|
230
|
-
if (building.includes('education') || building.includes('learning') ||
|
|
231
|
-
building.includes('course') || building.includes('tutorial') ||
|
|
232
|
-
building.includes('teaching')) {
|
|
233
|
-
suggestions.push('education', 'learning');
|
|
150
|
+
if (building.includes('game') || building.includes('unity') || building.includes('gaming')) {
|
|
151
|
+
suggestions.push('game development', 'gaming', 'interactive media');
|
|
234
152
|
}
|
|
235
153
|
|
|
236
|
-
|
|
237
|
-
if (building.includes('fintech') || building.includes('payment') ||
|
|
238
|
-
building.includes('banking') || building.includes('finance') ||
|
|
239
|
-
building.includes('trading')) {
|
|
240
|
-
suggestions.push('fintech', 'finance');
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Health/Biotech (NEW)
|
|
244
|
-
if (building.includes('health') || building.includes('biotech') ||
|
|
245
|
-
building.includes('medical') || building.includes('fitness') ||
|
|
246
|
-
building.includes('wellness')) {
|
|
247
|
-
suggestions.push('healthtech', 'biotech');
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Return unique interests, limited to 5
|
|
251
|
-
return [...new Set(suggestions)].slice(0, 5);
|
|
154
|
+
return [...new Set(suggestions)].slice(0, 4);
|
|
252
155
|
}
|
|
253
156
|
|
|
254
157
|
// Suggest tags/skills based on interests and building
|
|
255
158
|
function suggestTagsFromProfile(interests, building) {
|
|
256
159
|
const suggestions = [];
|
|
257
|
-
|
|
160
|
+
|
|
258
161
|
// From interests
|
|
259
162
|
if (interests) {
|
|
260
163
|
for (const interest of interests) {
|
|
261
164
|
const interestLower = interest.toLowerCase();
|
|
262
|
-
|
|
165
|
+
|
|
263
166
|
if (interestLower.includes('ai') || interestLower.includes('machine learning')) {
|
|
264
167
|
suggestions.push('python', 'tensorflow', 'pytorch', 'data-science');
|
|
265
168
|
}
|
|
266
|
-
|
|
169
|
+
|
|
267
170
|
if (interestLower.includes('web') || interestLower.includes('frontend')) {
|
|
268
171
|
suggestions.push('react', 'javascript', 'typescript', 'css');
|
|
269
172
|
}
|
|
270
|
-
|
|
173
|
+
|
|
271
174
|
if (interestLower.includes('mobile')) {
|
|
272
175
|
suggestions.push('swift', 'kotlin', 'react-native', 'flutter');
|
|
273
176
|
}
|
|
274
|
-
|
|
177
|
+
|
|
275
178
|
if (interestLower.includes('data')) {
|
|
276
179
|
suggestions.push('python', 'sql', 'pandas', 'analytics');
|
|
277
180
|
}
|
|
278
|
-
|
|
181
|
+
|
|
279
182
|
if (interestLower.includes('design')) {
|
|
280
183
|
suggestions.push('figma', 'ui-design', 'ux-design', 'prototyping');
|
|
281
184
|
}
|
|
282
|
-
|
|
185
|
+
|
|
283
186
|
if (interestLower.includes('startup') || interestLower.includes('business')) {
|
|
284
187
|
suggestions.push('product-management', 'strategy', 'growth', 'founder');
|
|
285
188
|
}
|
|
286
189
|
}
|
|
287
190
|
}
|
|
288
|
-
|
|
191
|
+
|
|
289
192
|
// From building description
|
|
290
193
|
if (building) {
|
|
291
194
|
const buildingLower = building.toLowerCase();
|
|
292
|
-
|
|
195
|
+
|
|
293
196
|
if (buildingLower.includes('react')) suggestions.push('react', 'frontend', 'javascript');
|
|
294
197
|
if (buildingLower.includes('python')) suggestions.push('python', 'backend', 'data-science');
|
|
295
198
|
if (buildingLower.includes('node')) suggestions.push('nodejs', 'backend', 'javascript');
|
|
@@ -297,7 +200,7 @@ function suggestTagsFromProfile(interests, building) {
|
|
|
297
200
|
suggestions.push('ai', 'machine-learning', 'python');
|
|
298
201
|
}
|
|
299
202
|
}
|
|
300
|
-
|
|
203
|
+
|
|
301
204
|
return [...new Set(suggestions)].slice(0, 6);
|
|
302
205
|
}
|
|
303
206
|
|
|
@@ -305,49 +208,53 @@ function suggestTagsFromProfile(interests, building) {
|
|
|
305
208
|
function calculateAdvancedMatchScore(user1, user2) {
|
|
306
209
|
let totalScore = 0;
|
|
307
210
|
const reasons = [];
|
|
308
|
-
|
|
211
|
+
|
|
309
212
|
// Interest similarity (high weight)
|
|
310
213
|
const interestSim = calculateInterestSimilarity(user1.interests, user2.interests);
|
|
311
214
|
totalScore += interestSim.score;
|
|
312
215
|
if (interestSim.matches.length > 0) {
|
|
313
216
|
reasons.push(`Shared interests: ${interestSim.matches.join(', ')}`);
|
|
314
217
|
}
|
|
315
|
-
|
|
218
|
+
|
|
316
219
|
// Tag overlap (medium-high weight)
|
|
317
220
|
if (user1.tags && user2.tags) {
|
|
318
|
-
const sharedTags = user1.tags.filter(t =>
|
|
319
|
-
user2.tags.some(t2 => t2.toLowerCase() === t.toLowerCase())
|
|
320
|
-
);
|
|
221
|
+
const sharedTags = user1.tags.filter(t => user2.tags.some(t2 => t2.toLowerCase() === t.toLowerCase()));
|
|
321
222
|
if (sharedTags.length > 0) {
|
|
322
223
|
totalScore += sharedTags.length * 12;
|
|
323
224
|
reasons.push(`Common skills: ${sharedTags.join(', ')}`);
|
|
324
225
|
}
|
|
325
226
|
}
|
|
326
|
-
|
|
227
|
+
|
|
327
228
|
// Skill complementarity (medium weight)
|
|
328
229
|
const skillComp = calculateSkillComplementarity(user1.tags, user2.tags);
|
|
329
230
|
totalScore += skillComp.score;
|
|
330
231
|
if (skillComp.pairs.length > 0) {
|
|
331
232
|
reasons.push(`Complementary skills: ${skillComp.pairs.join(', ')}`);
|
|
332
233
|
}
|
|
333
|
-
|
|
234
|
+
|
|
334
235
|
// Building similarity (medium weight)
|
|
335
236
|
if (user1.building && user2.building) {
|
|
336
|
-
const building1Words = user1.building
|
|
337
|
-
|
|
237
|
+
const building1Words = user1.building
|
|
238
|
+
.toLowerCase()
|
|
239
|
+
.split(/\s+/)
|
|
240
|
+
.filter(w => w.length > 3);
|
|
241
|
+
const building2Words = user2.building
|
|
242
|
+
.toLowerCase()
|
|
243
|
+
.split(/\s+/)
|
|
244
|
+
.filter(w => w.length > 3);
|
|
338
245
|
const commonBuildingWords = building1Words.filter(w => building2Words.includes(w));
|
|
339
|
-
|
|
246
|
+
|
|
340
247
|
if (commonBuildingWords.length > 0) {
|
|
341
248
|
totalScore += commonBuildingWords.length * 8;
|
|
342
249
|
reasons.push(`Both building ${commonBuildingWords.join(', ')} projects`);
|
|
343
250
|
}
|
|
344
251
|
}
|
|
345
|
-
|
|
252
|
+
|
|
346
253
|
// Activity timing (low weight but important for connection success)
|
|
347
254
|
if (user1.lastSeen && user2.lastSeen) {
|
|
348
255
|
const timeDiff = Math.abs(user1.lastSeen - user2.lastSeen);
|
|
349
256
|
const hours = timeDiff / (1000 * 60 * 60);
|
|
350
|
-
|
|
257
|
+
|
|
351
258
|
if (hours < 2) {
|
|
352
259
|
totalScore += 15;
|
|
353
260
|
reasons.push('Both active recently');
|
|
@@ -356,17 +263,15 @@ function calculateAdvancedMatchScore(user1, user2) {
|
|
|
356
263
|
reasons.push('Similar activity patterns');
|
|
357
264
|
}
|
|
358
265
|
}
|
|
359
|
-
|
|
266
|
+
|
|
360
267
|
// Connection history penalty (avoid repeat suggestions)
|
|
361
268
|
if (user1.connections && user2.connections) {
|
|
362
|
-
const alreadyConnected = user1.connections.some(c =>
|
|
363
|
-
c.handle === user2.handle.toLowerCase()
|
|
364
|
-
);
|
|
269
|
+
const alreadyConnected = user1.connections.some(c => c.handle === user2.handle.toLowerCase());
|
|
365
270
|
if (alreadyConnected) {
|
|
366
271
|
totalScore -= 50; // Heavy penalty
|
|
367
272
|
}
|
|
368
273
|
}
|
|
369
|
-
|
|
274
|
+
|
|
370
275
|
return {
|
|
371
276
|
score: Math.max(0, totalScore),
|
|
372
277
|
reasons: reasons.slice(0, 3) // Top 3 reasons
|
|
@@ -376,13 +281,14 @@ function calculateAdvancedMatchScore(user1, user2) {
|
|
|
376
281
|
// Find the best matches for a user from a pool of candidates
|
|
377
282
|
function findBestMatches(targetUser, candidates, limit = 5) {
|
|
378
283
|
const matches = [];
|
|
379
|
-
|
|
284
|
+
|
|
380
285
|
for (const candidate of candidates) {
|
|
381
286
|
if (candidate.handle === targetUser.handle) continue;
|
|
382
|
-
|
|
287
|
+
|
|
383
288
|
const match = calculateAdvancedMatchScore(targetUser, candidate);
|
|
384
|
-
|
|
385
|
-
if (match.score > 10) {
|
|
289
|
+
|
|
290
|
+
if (match.score > 10) {
|
|
291
|
+
// Minimum threshold
|
|
386
292
|
matches.push({
|
|
387
293
|
...candidate,
|
|
388
294
|
matchScore: match.score,
|
|
@@ -390,36 +296,32 @@ function findBestMatches(targetUser, candidates, limit = 5) {
|
|
|
390
296
|
});
|
|
391
297
|
}
|
|
392
298
|
}
|
|
393
|
-
|
|
394
|
-
return matches
|
|
395
|
-
.sort((a, b) => b.matchScore - a.matchScore)
|
|
396
|
-
.slice(0, limit);
|
|
299
|
+
|
|
300
|
+
return matches.sort((a, b) => b.matchScore - a.matchScore).slice(0, limit);
|
|
397
301
|
}
|
|
398
302
|
|
|
399
303
|
// Group users by interest clusters
|
|
400
304
|
function groupUsersByInterestClusters(users) {
|
|
401
305
|
const clusters = {};
|
|
402
|
-
|
|
306
|
+
|
|
403
307
|
for (const user of users) {
|
|
404
308
|
if (!user.interests?.length) continue;
|
|
405
|
-
|
|
309
|
+
|
|
406
310
|
for (const [clusterName, keywords] of Object.entries(INTEREST_CLUSTERS)) {
|
|
407
311
|
const matchesCluster = user.interests.some(interest =>
|
|
408
|
-
keywords.some(keyword =>
|
|
409
|
-
interest.toLowerCase().includes(keyword.toLowerCase())
|
|
410
|
-
)
|
|
312
|
+
keywords.some(keyword => interest.toLowerCase().includes(keyword.toLowerCase()))
|
|
411
313
|
);
|
|
412
|
-
|
|
314
|
+
|
|
413
315
|
if (matchesCluster) {
|
|
414
316
|
if (!clusters[clusterName]) clusters[clusterName] = [];
|
|
415
317
|
clusters[clusterName].push(user);
|
|
416
318
|
}
|
|
417
319
|
}
|
|
418
320
|
}
|
|
419
|
-
|
|
321
|
+
|
|
420
322
|
// Sort clusters by size
|
|
421
323
|
return Object.entries(clusters)
|
|
422
|
-
.sort(([,a], [,b]) => b.length - a.length)
|
|
324
|
+
.sort(([, a], [, b]) => b.length - a.length)
|
|
423
325
|
.reduce((acc, [key, value]) => {
|
|
424
326
|
acc[key] = value;
|
|
425
327
|
return acc;
|
|
@@ -436,4 +338,4 @@ module.exports = {
|
|
|
436
338
|
groupUsersByInterestClusters,
|
|
437
339
|
INTEREST_CLUSTERS,
|
|
438
340
|
SKILL_CLUSTERS
|
|
439
|
-
};
|
|
341
|
+
};
|