snowbll-mcp 0.1.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/LICENSE +21 -0
- package/README.md +234 -0
- package/dist/client.js +107 -0
- package/dist/client.js.map +1 -0
- package/dist/communityClient.js +96 -0
- package/dist/communityClient.js.map +1 -0
- package/dist/crossCheckClient.js +83 -0
- package/dist/crossCheckClient.js.map +1 -0
- package/dist/http.js +70 -0
- package/dist/http.js.map +1 -0
- package/dist/index.js +391 -0
- package/dist/index.js.map +1 -0
- package/dist/mockData.js +471 -0
- package/dist/mockData.js.map +1 -0
- package/dist/prompts.js +48 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.js +54 -0
- package/dist/resources.js.map +1 -0
- package/dist/schemas.js +174 -0
- package/dist/schemas.js.map +1 -0
- package/package.json +45 -0
package/dist/mockData.js
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snowbll MCP — mock Gaming Behaviour Intelligence dataset + helpers.
|
|
3
|
+
*
|
|
4
|
+
* This module is the single source of truth for the local/mock dataset. The
|
|
5
|
+
* SnowbllClient (client.ts) calls these helpers when running in mock mode
|
|
6
|
+
* (the default). When SNOWBLL_USE_MOCK=false the client calls the real Snowbll
|
|
7
|
+
* API instead and these helpers are not used.
|
|
8
|
+
*
|
|
9
|
+
* All data here is synthetic and describes ONE example player profile so that
|
|
10
|
+
* agents and integrators can build against stable, realistic shapes before a
|
|
11
|
+
* real backend is wired up.
|
|
12
|
+
*/
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Static profile data (one example player)
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
export const playerOverview = {
|
|
17
|
+
totalGames: 128,
|
|
18
|
+
wishlist: 34,
|
|
19
|
+
posts: 96,
|
|
20
|
+
devFollows: 12,
|
|
21
|
+
personaMatch: 94,
|
|
22
|
+
personaConfidence: "very_high",
|
|
23
|
+
currentObjective: "Find hidden indie gems that match your taste.",
|
|
24
|
+
summary: "Player is a systems-first gamer who prefers optimization, progression, management loops, and short focused sessions.",
|
|
25
|
+
};
|
|
26
|
+
export const playstyleDna = {
|
|
27
|
+
traits: [
|
|
28
|
+
{ name: "Systems Thinking", score: 91, tier: "elite" },
|
|
29
|
+
{ name: "Progression Seeking", score: 84, tier: "elite" },
|
|
30
|
+
{ name: "Exploration", score: 62, tier: "strong" },
|
|
31
|
+
{ name: "Creativity", score: 57, tier: "strong" },
|
|
32
|
+
{ name: "Competition", score: 31, tier: "low" },
|
|
33
|
+
{ name: "Story Driven", score: 22, tier: "low" },
|
|
34
|
+
],
|
|
35
|
+
uniqueEdge: "Player loves deep systems and optimization, but prefers player expression over competition.",
|
|
36
|
+
};
|
|
37
|
+
export const personaCards = {
|
|
38
|
+
personas: [
|
|
39
|
+
{
|
|
40
|
+
name: "Systems Architect",
|
|
41
|
+
rarity: "epic",
|
|
42
|
+
level: 3,
|
|
43
|
+
progress: 75,
|
|
44
|
+
evidence: "Played 10+ management games and shows strong preference for complex systems.",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "Optimization Addict",
|
|
48
|
+
rarity: "rare",
|
|
49
|
+
level: 4,
|
|
50
|
+
progress: 88,
|
|
51
|
+
evidence: "Spent 100+ hours optimizing systems and improving efficiency loops.",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "Early Adopter",
|
|
55
|
+
rarity: "uncommon",
|
|
56
|
+
level: 2,
|
|
57
|
+
progress: 60,
|
|
58
|
+
evidence: "Discovered hidden games before mainstream hype.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "Finisher",
|
|
62
|
+
rarity: "legendary",
|
|
63
|
+
level: 4,
|
|
64
|
+
progress: 90,
|
|
65
|
+
evidence: "Completed 20+ tracked games.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "Hidden Gem Hunter",
|
|
69
|
+
rarity: "epic",
|
|
70
|
+
level: 3,
|
|
71
|
+
progress: 66,
|
|
72
|
+
evidence: "Found 8 games with fewer than 500 reviews.",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "Progression Master",
|
|
76
|
+
rarity: "legendary",
|
|
77
|
+
level: 4,
|
|
78
|
+
progress: 100,
|
|
79
|
+
evidence: "Reached max level in 10+ games.",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
export const activityPatterns = {
|
|
84
|
+
mostActiveHours: {
|
|
85
|
+
peak: "21:37",
|
|
86
|
+
activeDays: "Fri-Sat",
|
|
87
|
+
type: "night_owl",
|
|
88
|
+
insight: "Player is most active in late hours.",
|
|
89
|
+
},
|
|
90
|
+
sessionLength: {
|
|
91
|
+
averageMinutes: 42,
|
|
92
|
+
under30Minutes: 41,
|
|
93
|
+
between30And90Minutes: 37,
|
|
94
|
+
between90And180Minutes: 15,
|
|
95
|
+
over180Minutes: 7,
|
|
96
|
+
sessionPersona: "Focused Player",
|
|
97
|
+
},
|
|
98
|
+
platforms: [
|
|
99
|
+
{ name: "Steam", hours: 1032, share: 52 },
|
|
100
|
+
{ name: "PlayStation", hours: 286, share: 14 },
|
|
101
|
+
{ name: "Xbox", hours: 182, share: 9 },
|
|
102
|
+
{ name: "Switch", hours: 61, share: 3 },
|
|
103
|
+
{ name: "Epic Games", hours: 48, share: 2 },
|
|
104
|
+
],
|
|
105
|
+
totalPlaytimeHours: 1609,
|
|
106
|
+
};
|
|
107
|
+
export const completionBehavior = {
|
|
108
|
+
completionRate: 78,
|
|
109
|
+
insight: "Player finishes management games 3x more often than RPGs.",
|
|
110
|
+
strongCompletionCategories: [
|
|
111
|
+
"Management",
|
|
112
|
+
"Simulation",
|
|
113
|
+
"Automation",
|
|
114
|
+
"Progression-heavy games",
|
|
115
|
+
],
|
|
116
|
+
weakCompletionCategories: [
|
|
117
|
+
"Story-heavy RPG",
|
|
118
|
+
"Long open world",
|
|
119
|
+
"Games with unskippable cutscenes",
|
|
120
|
+
],
|
|
121
|
+
dropOffSignals: [
|
|
122
|
+
"Complexity without measurable progression",
|
|
123
|
+
"Narrative-heavy pacing",
|
|
124
|
+
"Long sessions required to feel progress",
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
const purchaseBehaviorBase = {
|
|
128
|
+
gamesPurchased: 128,
|
|
129
|
+
averageGamePrice: 14.82,
|
|
130
|
+
topInGameCategories: [
|
|
131
|
+
{ category: "Cosmetics", share: 48 },
|
|
132
|
+
{ category: "Battle Pass", share: 27 },
|
|
133
|
+
{ category: "Convenience", share: 15 },
|
|
134
|
+
{ category: "Expansions", share: 10 },
|
|
135
|
+
],
|
|
136
|
+
insight: "Player buys RPGs, but spends more playtime in management games.",
|
|
137
|
+
purchasePlayMismatch: {
|
|
138
|
+
summary: "Player's buying behavior is broader than their actual play behavior.",
|
|
139
|
+
example: "RPG purchases are common, but management and optimization games dominate actual playtime.",
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// Helpers for parameterized tools
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
/** Deterministic 0..range jitter from a string, so per-game scores vary but are reproducible. */
|
|
146
|
+
function hashJitter(input, range) {
|
|
147
|
+
if (range <= 0)
|
|
148
|
+
return 0;
|
|
149
|
+
let h = 0;
|
|
150
|
+
for (let i = 0; i < input.length; i++) {
|
|
151
|
+
h = (h * 31 + input.charCodeAt(i)) >>> 0;
|
|
152
|
+
}
|
|
153
|
+
return h % (range + 1);
|
|
154
|
+
}
|
|
155
|
+
export function getPurchaseBehavior(includeSensitiveSignals = false) {
|
|
156
|
+
if (!includeSensitiveSignals) {
|
|
157
|
+
// Aggregate-only view: no raw / overly specific purchase detail.
|
|
158
|
+
return purchaseBehaviorBase;
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
...purchaseBehaviorBase,
|
|
162
|
+
sensitiveSignals: {
|
|
163
|
+
recentPurchases: [
|
|
164
|
+
{ title: "Starfield", price: 59.99, hoursPlayed: 4.2, refunded: false },
|
|
165
|
+
{ title: "RimWorld", price: 34.99, hoursPlayed: 212.5, refunded: false },
|
|
166
|
+
{
|
|
167
|
+
title: "Baldur's Gate 3",
|
|
168
|
+
price: 59.99,
|
|
169
|
+
hoursPlayed: 11.0,
|
|
170
|
+
refunded: false,
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
note: "Raw purchase-level detail included because includeSensitiveSignals=true. Default tool calls return aggregates only.",
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const MISMATCH_SEEDS = [
|
|
178
|
+
{
|
|
179
|
+
claimedOrPurchased: "RPG",
|
|
180
|
+
observedBehavior: "Management and optimization-heavy games receive more playtime and higher completion.",
|
|
181
|
+
confidence: 0.78,
|
|
182
|
+
completionSignal: "RPG completion rate trails management completion by ~3x.",
|
|
183
|
+
purchaseSignal: "RPG titles are purchased often but accumulate disproportionately low playtime.",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
claimedOrPurchased: "Open-world exploration",
|
|
187
|
+
observedBehavior: "Player prefers directed progression and measurable systems over unstructured exploration.",
|
|
188
|
+
confidence: 0.72,
|
|
189
|
+
completionSignal: "Open-world titles show early drop-off well before completion milestones.",
|
|
190
|
+
purchaseSignal: "Open-world purchases spike during sales but rarely convert to sustained sessions.",
|
|
191
|
+
},
|
|
192
|
+
];
|
|
193
|
+
export function detectGenreMismatch(includePurchaseSignals = false, includeCompletionSignals = true) {
|
|
194
|
+
const mismatches = MISMATCH_SEEDS.map((seed) => {
|
|
195
|
+
const entry = {
|
|
196
|
+
claimedOrPurchased: seed.claimedOrPurchased,
|
|
197
|
+
observedBehavior: seed.observedBehavior,
|
|
198
|
+
confidence: seed.confidence,
|
|
199
|
+
};
|
|
200
|
+
if (includeCompletionSignals)
|
|
201
|
+
entry.completionSignal = seed.completionSignal;
|
|
202
|
+
if (includePurchaseSignals)
|
|
203
|
+
entry.purchaseSignal = seed.purchaseSignal;
|
|
204
|
+
return entry;
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
mismatches,
|
|
208
|
+
summary: "Player appears to be attracted to RPG fantasy and progression themes, but sustained engagement comes from systems, management, and optimization loops.",
|
|
209
|
+
signalsIncluded: {
|
|
210
|
+
purchase: includePurchaseSignals,
|
|
211
|
+
completion: includeCompletionSignals,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const BEHAVIOUR_EVIDENCE = [
|
|
216
|
+
"Systems Thinking is 91%.",
|
|
217
|
+
"Progression Seeking is 84%.",
|
|
218
|
+
"Story Driven is only 22%.",
|
|
219
|
+
"Average session length is 42 minutes.",
|
|
220
|
+
"Player finishes management games 3x more often than RPGs.",
|
|
221
|
+
"Player buys RPGs, but plays management games more.",
|
|
222
|
+
];
|
|
223
|
+
export function analyzePlayerBehaviour(depth = "standard", includeEvidence = true) {
|
|
224
|
+
const summary = "Player is a systems-first gamer who enjoys optimization, progression, management loops, and short focused sessions.";
|
|
225
|
+
const primaryTraits = [
|
|
226
|
+
"Systems Thinking",
|
|
227
|
+
"Progression Seeking",
|
|
228
|
+
"Optimization",
|
|
229
|
+
"Management Preference",
|
|
230
|
+
];
|
|
231
|
+
const interpretation = "The player is likely to enjoy games that provide visible progress, optimization feedback, build crafting, economy management, and meaningful systems mastery. The player may drop games that rely heavily on long narrative pacing, unskippable scenes, or low-feedback exploration.";
|
|
232
|
+
if (depth === "light") {
|
|
233
|
+
const light = {
|
|
234
|
+
summary,
|
|
235
|
+
primaryTraits,
|
|
236
|
+
interpretation: "Systems-first player: rewards progression and optimization; weak on narrative-heavy or low-feedback games.",
|
|
237
|
+
};
|
|
238
|
+
if (includeEvidence)
|
|
239
|
+
light.behavioralEvidence = BEHAVIOUR_EVIDENCE.slice(0, 3);
|
|
240
|
+
return light;
|
|
241
|
+
}
|
|
242
|
+
const result = {
|
|
243
|
+
summary,
|
|
244
|
+
primaryTraits,
|
|
245
|
+
weakSignals: ["Story Driven", "Competition"],
|
|
246
|
+
interpretation,
|
|
247
|
+
};
|
|
248
|
+
if (includeEvidence)
|
|
249
|
+
result.behavioralEvidence = [...BEHAVIOUR_EVIDENCE];
|
|
250
|
+
if (depth === "deep") {
|
|
251
|
+
result.deepDive = {
|
|
252
|
+
traitCorrelations: [
|
|
253
|
+
"Systems Thinking (91) strongly co-occurs with high completion in management/automation titles.",
|
|
254
|
+
"Low Story Driven (22) correlates with early drop-off in narrative-heavy RPGs.",
|
|
255
|
+
"Short session preference correlates with higher completion of roguelite / short-loop systems games.",
|
|
256
|
+
],
|
|
257
|
+
predictedPreferences: [
|
|
258
|
+
"Buildcrafting and economy-management RPGs over story-led RPGs.",
|
|
259
|
+
"Roguelite and short-loop systems games for quick sessions.",
|
|
260
|
+
"Automation and optimization sandboxes with measurable feedback.",
|
|
261
|
+
],
|
|
262
|
+
riskFactors: [
|
|
263
|
+
"Long unskippable cutscenes.",
|
|
264
|
+
"Open-world games without measurable progression.",
|
|
265
|
+
"Mechanics that delay feedback beyond a single session.",
|
|
266
|
+
],
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
export function explainTastePattern(topic) {
|
|
272
|
+
const t = topic.toLowerCase();
|
|
273
|
+
let explanation = "Based on Snowbll behaviour signals, the player is drawn to progression and systems, but may lose momentum when a game requires long narrative commitment or unstructured exploration.";
|
|
274
|
+
if (t.includes("abandon") || t.includes("drop") || t.includes("quit")) {
|
|
275
|
+
explanation =
|
|
276
|
+
"Snowbll signals suggest the player abandons games when progress stops being measurable — narrative-heavy pacing, long unskippable scenes, or open-ended exploration remove the tight feedback loop this player relies on to stay engaged.";
|
|
277
|
+
}
|
|
278
|
+
else if (t.includes("finish") || t.includes("complete")) {
|
|
279
|
+
explanation =
|
|
280
|
+
"Snowbll signals suggest the player finishes games that deliver visible, measurable progress in short sessions — management, simulation, and automation loops convert interest into completion far more reliably than narrative-led titles.";
|
|
281
|
+
}
|
|
282
|
+
else if (t.includes("buy") || t.includes("purchase") || t.includes("spend")) {
|
|
283
|
+
explanation =
|
|
284
|
+
"Snowbll signals show a gap between buying and playing: the player is attracted to RPG fantasy at purchase time, but sustained playtime concentrates in systems and management games.";
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
topic,
|
|
288
|
+
explanation,
|
|
289
|
+
supportingSignals: [
|
|
290
|
+
"High Systems Thinking",
|
|
291
|
+
"High Progression Seeking",
|
|
292
|
+
"Low Story Driven",
|
|
293
|
+
"Short focused session preference",
|
|
294
|
+
"Higher completion rate in management games",
|
|
295
|
+
],
|
|
296
|
+
actionableAdvice: [
|
|
297
|
+
"Prefer RPGs with strong buildcrafting and systems depth.",
|
|
298
|
+
"Avoid games with slow narrative openings or long unskippable cutscenes.",
|
|
299
|
+
"Choose games that provide visible progress within 30-60 minutes.",
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const HIGH_FIT_TITLES = [
|
|
304
|
+
"factorio",
|
|
305
|
+
"rimworld",
|
|
306
|
+
"against the storm",
|
|
307
|
+
"dyson sphere program",
|
|
308
|
+
"satisfactory",
|
|
309
|
+
"oxygen not included",
|
|
310
|
+
"cities skylines",
|
|
311
|
+
"cities: skylines",
|
|
312
|
+
];
|
|
313
|
+
const STORY_HEAVY_TITLES = [
|
|
314
|
+
"baldur",
|
|
315
|
+
"skyrim",
|
|
316
|
+
"witcher",
|
|
317
|
+
"starfield",
|
|
318
|
+
"cyberpunk",
|
|
319
|
+
"dragon age",
|
|
320
|
+
];
|
|
321
|
+
export function predictGameFit(gameTitle, platform = "unknown") {
|
|
322
|
+
const t = gameTitle.toLowerCase();
|
|
323
|
+
const jitter = hashJitter(gameTitle, 4);
|
|
324
|
+
if (HIGH_FIT_TITLES.some((k) => t.includes(k))) {
|
|
325
|
+
return {
|
|
326
|
+
game: gameTitle,
|
|
327
|
+
platform,
|
|
328
|
+
fitScore: 92 + jitter, // 92–96
|
|
329
|
+
finishLikelihood: 85 + (jitter % 6), // 85–90
|
|
330
|
+
dropOffRisk: "low",
|
|
331
|
+
whyItFits: [
|
|
332
|
+
"Deep, optimizable systems match the player's elite Systems Thinking (91).",
|
|
333
|
+
"Tight progression and efficiency loops align with high Progression Seeking (84).",
|
|
334
|
+
"Rewards short, focused sessions with visible, measurable progress.",
|
|
335
|
+
],
|
|
336
|
+
whyItMayNotFit: [
|
|
337
|
+
"Late-game scope can become time-intensive and stretch session length.",
|
|
338
|
+
],
|
|
339
|
+
verdict: "Strong fit — high finish likelihood and low drop-off risk. Recommended.",
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
if (STORY_HEAVY_TITLES.some((k) => t.includes(k))) {
|
|
343
|
+
return {
|
|
344
|
+
game: gameTitle,
|
|
345
|
+
platform,
|
|
346
|
+
fitScore: 58 + jitter, // 58–62
|
|
347
|
+
finishLikelihood: 46 + (jitter % 6), // 46–51
|
|
348
|
+
dropOffRisk: "high",
|
|
349
|
+
whyItFits: [
|
|
350
|
+
"Buildcrafting and character/system progression appeal to the player's optimization streak.",
|
|
351
|
+
"RPG fantasy and progression themes attract strong initial interest.",
|
|
352
|
+
],
|
|
353
|
+
whyItMayNotFit: [
|
|
354
|
+
"Story-heavy pacing and long narrative commitment conflict with low Story Driven (22).",
|
|
355
|
+
"Unskippable cutscenes and slow openings are known drop-off signals for this player.",
|
|
356
|
+
"Meaningful progress often requires long sessions, against a 42-minute average.",
|
|
357
|
+
],
|
|
358
|
+
verdict: "Mixed fit — likely strong start but elevated drop-off risk from narrative pacing. Best played with a buildcraft/systems focus.",
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
game: gameTitle,
|
|
363
|
+
platform,
|
|
364
|
+
fitScore: 64 + jitter, // 64–68
|
|
365
|
+
finishLikelihood: 58 + (jitter % 6), // 58–63
|
|
366
|
+
dropOffRisk: "medium",
|
|
367
|
+
whyItFits: [
|
|
368
|
+
"May offer progression or systems elements that suit the player's core taste.",
|
|
369
|
+
],
|
|
370
|
+
whyItMayNotFit: [
|
|
371
|
+
"Not enough behavioural signal to confirm strong systems or optimization depth.",
|
|
372
|
+
],
|
|
373
|
+
verdict: "General fit — depends on how much measurable progression and systems depth the game offers.",
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
export function compareGames(games) {
|
|
377
|
+
const ranking = games
|
|
378
|
+
.map((g) => {
|
|
379
|
+
const fit = predictGameFit(g);
|
|
380
|
+
return {
|
|
381
|
+
game: fit.game,
|
|
382
|
+
fitScore: fit.fitScore,
|
|
383
|
+
finishLikelihood: fit.finishLikelihood,
|
|
384
|
+
reason: fit.whyItFits[0] ?? fit.verdict,
|
|
385
|
+
};
|
|
386
|
+
})
|
|
387
|
+
.sort((a, b) => b.fitScore - a.fitScore || b.finishLikelihood - a.finishLikelihood);
|
|
388
|
+
const best = ranking[0];
|
|
389
|
+
const worst = ranking[ranking.length - 1];
|
|
390
|
+
const bestPick = best?.game ?? "n/a";
|
|
391
|
+
let summary = best
|
|
392
|
+
? `Best behavioural fit is ${best.game} (fit ${best.fitScore}, finish likelihood ${best.finishLikelihood}).`
|
|
393
|
+
: "No games provided to compare.";
|
|
394
|
+
if (worst && best && worst.game !== best.game) {
|
|
395
|
+
summary += ` ${worst.game} ranks lowest (fit ${worst.fitScore}) for this player's profile.`;
|
|
396
|
+
}
|
|
397
|
+
return { ranking, bestPick, summary };
|
|
398
|
+
}
|
|
399
|
+
const RECOMMENDATIONS = {
|
|
400
|
+
likely_to_finish: [
|
|
401
|
+
"Against the Storm",
|
|
402
|
+
"Factorio",
|
|
403
|
+
"RimWorld",
|
|
404
|
+
"Oxygen Not Included",
|
|
405
|
+
"Dyson Sphere Program",
|
|
406
|
+
],
|
|
407
|
+
hidden_gems: [
|
|
408
|
+
"Desynced",
|
|
409
|
+
"The Last Spell",
|
|
410
|
+
"Songs of Syx",
|
|
411
|
+
"Factory Town",
|
|
412
|
+
"Nova Lands",
|
|
413
|
+
],
|
|
414
|
+
deep_systems: [
|
|
415
|
+
"Factorio",
|
|
416
|
+
"RimWorld",
|
|
417
|
+
"Oxygen Not Included",
|
|
418
|
+
"Satisfactory",
|
|
419
|
+
"Dyson Sphere Program",
|
|
420
|
+
],
|
|
421
|
+
comfort_games: [
|
|
422
|
+
"Dorfromantik",
|
|
423
|
+
"Mini Motorways",
|
|
424
|
+
"Islanders",
|
|
425
|
+
"Townscaper",
|
|
426
|
+
"Terra Nil",
|
|
427
|
+
],
|
|
428
|
+
short_sessions: [
|
|
429
|
+
"Against the Storm",
|
|
430
|
+
"Slay the Spire",
|
|
431
|
+
"Into the Breach",
|
|
432
|
+
"Mini Motorways",
|
|
433
|
+
"Loop Hero",
|
|
434
|
+
],
|
|
435
|
+
high_progression: [
|
|
436
|
+
"Hades",
|
|
437
|
+
"Dead Cells",
|
|
438
|
+
"Monster Hunter Rise",
|
|
439
|
+
"Warframe",
|
|
440
|
+
"Path of Exile",
|
|
441
|
+
],
|
|
442
|
+
};
|
|
443
|
+
const OBJECTIVE_REASON = {
|
|
444
|
+
likely_to_finish: "Matches your completion pattern — management/progression loops you reliably finish.",
|
|
445
|
+
hidden_gems: "Under-the-radar systems game aligned with your Hidden Gem Hunter persona.",
|
|
446
|
+
deep_systems: "Deep, optimizable systems that reward your elite Systems Thinking.",
|
|
447
|
+
comfort_games: "Low-pressure, calming loop suited to short, focused sessions.",
|
|
448
|
+
short_sessions: "Built for 30–60 minute runs with visible progress — fits your 42-minute average session.",
|
|
449
|
+
high_progression: "Heavy progression and reward loops that satisfy your Progression Seeking.",
|
|
450
|
+
};
|
|
451
|
+
export function recommendGames(objective = "likely_to_finish", limit = 5) {
|
|
452
|
+
const titles = RECOMMENDATIONS[objective] ?? RECOMMENDATIONS.likely_to_finish;
|
|
453
|
+
const reason = OBJECTIVE_REASON[objective] ?? OBJECTIVE_REASON.likely_to_finish;
|
|
454
|
+
const recommendations = titles
|
|
455
|
+
.slice(0, limit)
|
|
456
|
+
.map((game) => {
|
|
457
|
+
const fit = predictGameFit(game);
|
|
458
|
+
return {
|
|
459
|
+
game,
|
|
460
|
+
fitScore: fit.fitScore,
|
|
461
|
+
reason,
|
|
462
|
+
risk: fit.dropOffRisk,
|
|
463
|
+
};
|
|
464
|
+
});
|
|
465
|
+
return {
|
|
466
|
+
objective,
|
|
467
|
+
recommendations,
|
|
468
|
+
note: "Recommendations are based on behavioural fit, not genre alone.",
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
//# sourceMappingURL=mockData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mockData.js","sourceRoot":"","sources":["../src/mockData.ts"],"names":[],"mappings":"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"}
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Prompts — ready-made templates.
|
|
3
|
+
*
|
|
4
|
+
* Clients surface these as slash-commands (e.g. in Claude Desktop / Cursor), so
|
|
5
|
+
* a user can run a whole Snowbll workflow without writing the orchestration.
|
|
6
|
+
* Registered separately to keep the main server file small.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
function userPrompt(text) {
|
|
10
|
+
return {
|
|
11
|
+
messages: [
|
|
12
|
+
{ role: "user", content: { type: "text", text } },
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function registerPrompts(server) {
|
|
17
|
+
server.registerPrompt("understand-player", {
|
|
18
|
+
title: "Understand this player",
|
|
19
|
+
description: "Build a full profile of the player from Snowbll behaviour intelligence.",
|
|
20
|
+
}, () => userPrompt('Use the Snowbll tools — get_player_overview, get_playstyle_dna, get_persona_cards, then analyze_player_behaviour with depth "deep" — to build a clear profile of this player. Summarize who they are, their strongest and weakest traits, their session style, and what kinds of games suit them.'));
|
|
21
|
+
server.registerPrompt("what-to-play", {
|
|
22
|
+
title: "What should this player play next?",
|
|
23
|
+
description: "Recommend the player's next game and explain why.",
|
|
24
|
+
argsSchema: {
|
|
25
|
+
objective: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Optional objective: likely_to_finish, hidden_gems, deep_systems, comfort_games, short_sessions, or high_progression."),
|
|
29
|
+
},
|
|
30
|
+
}, ({ objective }) => userPrompt(`Use recommend_games (objective: ${objective ?? "likely_to_finish"}) to suggest what this player should play next, then explain each pick using their persona and playstyle DNA. Call get_player_overview first if you need context.`));
|
|
31
|
+
server.registerPrompt("should-i-play", {
|
|
32
|
+
title: "Will this player enjoy a specific game?",
|
|
33
|
+
description: "Predict fit and finish likelihood for one game.",
|
|
34
|
+
argsSchema: {
|
|
35
|
+
gameTitle: z.string().describe("The game title to evaluate."),
|
|
36
|
+
},
|
|
37
|
+
}, ({ gameTitle }) => userPrompt(`Use predict_game_fit for "${gameTitle}" and tell me whether this player will enjoy and finish it. Give the fit score, finish likelihood, drop-off risk, and the key reasons it fits or may not.`));
|
|
38
|
+
server.registerPrompt("compare-games", {
|
|
39
|
+
title: "Compare games for this player",
|
|
40
|
+
description: "Rank 2–5 games by behavioural fit for the player.",
|
|
41
|
+
argsSchema: {
|
|
42
|
+
games: z
|
|
43
|
+
.string()
|
|
44
|
+
.describe("Comma-separated list of 2–5 game titles to compare."),
|
|
45
|
+
},
|
|
46
|
+
}, ({ games }) => userPrompt(`Use compare_games_for_player to rank these games for this player and explain the best pick: ${games}.`));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO;QACL,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,MAAe,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,EAAE;SACpE;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,cAAc,CACnB,mBAAmB,EACnB;QACE,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EACT,yEAAyE;KAC5E,EACD,GAAG,EAAE,CACH,UAAU,CACR,mSAAmS,CACpS,CACJ,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,cAAc,EACd;QACE,KAAK,EAAE,oCAAoC;QAC3C,WAAW,EAAE,mDAAmD;QAChE,UAAU,EAAE;YACV,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,sHAAsH,CACvH;SACJ;KACF,EACD,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAChB,UAAU,CACR,mCAAmC,SAAS,IAAI,kBAAkB,mKAAmK,CACtO,CACJ,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,eAAe,EACf;QACE,KAAK,EAAE,yCAAyC;QAChD,WAAW,EAAE,iDAAiD;QAC9D,UAAU,EAAE;YACV,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;SAC9D;KACF,EACD,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAChB,UAAU,CACR,6BAA6B,SAAS,2JAA2J,CAClM,CACJ,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,eAAe,EACf;QACE,KAAK,EAAE,+BAA+B;QACtC,WAAW,EAAE,mDAAmD;QAChE,UAAU,EAAE;YACV,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,CAAC,qDAAqD,CAAC;SACnE;KACF,EACD,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACZ,UAAU,CACR,+FAA+F,KAAK,GAAG,CACxG,CACJ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Resources — attachable, read-only player snapshots.
|
|
3
|
+
*
|
|
4
|
+
* Resources let a client attach Snowbll context (a player's profile) directly,
|
|
5
|
+
* without the agent having to call several tools first. Registered separately so
|
|
6
|
+
* the main server file stays small.
|
|
7
|
+
*/
|
|
8
|
+
function jsonResource(uri, data) {
|
|
9
|
+
return {
|
|
10
|
+
contents: [
|
|
11
|
+
{
|
|
12
|
+
uri: uri.href,
|
|
13
|
+
mimeType: "application/json",
|
|
14
|
+
text: JSON.stringify(data, null, 2),
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function registerResources(server, client) {
|
|
20
|
+
server.registerResource("player-profile", "snowbll://player/profile", {
|
|
21
|
+
title: "Player profile snapshot",
|
|
22
|
+
description: "Combined snapshot (overview, playstyle DNA, persona cards, activity) for the current player. Attach as context instead of calling several tools.",
|
|
23
|
+
mimeType: "application/json",
|
|
24
|
+
}, async (uri) => {
|
|
25
|
+
const [overview, playstyleDna, personaCards, activityPatterns] = await Promise.all([
|
|
26
|
+
client.getPlayerOverview(),
|
|
27
|
+
client.getPlaystyleDna(),
|
|
28
|
+
client.getPersonaCards(),
|
|
29
|
+
client.getActivityPatterns(),
|
|
30
|
+
]);
|
|
31
|
+
return jsonResource(uri, {
|
|
32
|
+
overview,
|
|
33
|
+
playstyleDna,
|
|
34
|
+
personaCards,
|
|
35
|
+
activityPatterns,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
server.registerResource("player-overview", "snowbll://player/overview", {
|
|
39
|
+
title: "Player overview",
|
|
40
|
+
description: "High-level identity, totals, and current objective.",
|
|
41
|
+
mimeType: "application/json",
|
|
42
|
+
}, async (uri) => jsonResource(uri, await client.getPlayerOverview()));
|
|
43
|
+
server.registerResource("player-playstyle-dna", "snowbll://player/playstyle-dna", {
|
|
44
|
+
title: "Player playstyle DNA",
|
|
45
|
+
description: "Playstyle traits with scores and tiers.",
|
|
46
|
+
mimeType: "application/json",
|
|
47
|
+
}, async (uri) => jsonResource(uri, await client.getPlaystyleDna()));
|
|
48
|
+
server.registerResource("player-personas", "snowbll://player/personas", {
|
|
49
|
+
title: "Player persona cards",
|
|
50
|
+
description: "Persona cards with rarity, level, progress, and evidence.",
|
|
51
|
+
mimeType: "application/json",
|
|
52
|
+
}, async (uri) => jsonResource(uri, await client.getPersonaCards()));
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,SAAS,YAAY,CAAC,GAAQ,EAAE,IAAa;IAC3C,OAAO;QACL,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,GAAG,CAAC,IAAI;gBACb,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;aACpC;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAiB,EACjB,MAAqB;IAErB,MAAM,CAAC,gBAAgB,CACrB,gBAAgB,EAChB,0BAA0B,EAC1B;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,kJAAkJ;QACpJ,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,CAAC,GAC5D,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,MAAM,CAAC,iBAAiB,EAAE;YAC1B,MAAM,CAAC,eAAe,EAAE;YACxB,MAAM,CAAC,eAAe,EAAE;YACxB,MAAM,CAAC,mBAAmB,EAAE;SAC7B,CAAC,CAAC;QACL,OAAO,YAAY,CAAC,GAAG,EAAE;YACvB,QAAQ;YACR,YAAY;YACZ,YAAY;YACZ,gBAAgB;SACjB,CAAC,CAAC;IACL,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,gBAAgB,CACrB,iBAAiB,EACjB,2BAA2B,EAC3B;QACE,KAAK,EAAE,iBAAiB;QACxB,WAAW,EAAE,qDAAqD;QAClE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC,CACnE,CAAC;IAEF,MAAM,CAAC,gBAAgB,CACrB,sBAAsB,EACtB,gCAAgC,EAChC;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,yCAAyC;QACtD,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC,CACjE,CAAC;IAEF,MAAM,CAAC,gBAAgB,CACrB,iBAAiB,EACjB,2BAA2B,EAC3B;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,2DAA2D;QACxE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC,CACjE,CAAC;AACJ,CAAC"}
|