hearthstone-oracle 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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/data/db.d.ts +49 -0
  4. package/dist/data/db.d.ts.map +1 -0
  5. package/dist/data/db.js +109 -0
  6. package/dist/data/db.js.map +1 -0
  7. package/dist/data/hearthstone.d.ts +40 -0
  8. package/dist/data/hearthstone.d.ts.map +1 -0
  9. package/dist/data/hearthstone.js +58 -0
  10. package/dist/data/hearthstone.js.map +1 -0
  11. package/dist/data/pipeline.d.ts +36 -0
  12. package/dist/data/pipeline.d.ts.map +1 -0
  13. package/dist/data/pipeline.js +90 -0
  14. package/dist/data/pipeline.js.map +1 -0
  15. package/dist/data/schema.sql +111 -0
  16. package/dist/data/strategy-seed.d.ts +3 -0
  17. package/dist/data/strategy-seed.d.ts.map +1 -0
  18. package/dist/data/strategy-seed.js +512 -0
  19. package/dist/data/strategy-seed.js.map +1 -0
  20. package/dist/format.d.ts +63 -0
  21. package/dist/format.d.ts.map +1 -0
  22. package/dist/format.js +331 -0
  23. package/dist/format.js.map +1 -0
  24. package/dist/knowledge/archetype-classifier.d.ts +19 -0
  25. package/dist/knowledge/archetype-classifier.d.ts.map +1 -0
  26. package/dist/knowledge/archetype-classifier.js +232 -0
  27. package/dist/knowledge/archetype-classifier.js.map +1 -0
  28. package/dist/server.d.ts +5 -0
  29. package/dist/server.d.ts.map +1 -0
  30. package/dist/server.js +269 -0
  31. package/dist/server.js.map +1 -0
  32. package/dist/tools/analyze-deck.d.ts +45 -0
  33. package/dist/tools/analyze-deck.d.ts.map +1 -0
  34. package/dist/tools/analyze-deck.js +159 -0
  35. package/dist/tools/analyze-deck.js.map +1 -0
  36. package/dist/tools/decode-deck.d.ts +30 -0
  37. package/dist/tools/decode-deck.d.ts.map +1 -0
  38. package/dist/tools/decode-deck.js +127 -0
  39. package/dist/tools/decode-deck.js.map +1 -0
  40. package/dist/tools/explain-concept.d.ts +26 -0
  41. package/dist/tools/explain-concept.d.ts.map +1 -0
  42. package/dist/tools/explain-concept.js +34 -0
  43. package/dist/tools/explain-concept.js.map +1 -0
  44. package/dist/tools/get-archetype.d.ts +29 -0
  45. package/dist/tools/get-archetype.d.ts.map +1 -0
  46. package/dist/tools/get-archetype.js +47 -0
  47. package/dist/tools/get-archetype.js.map +1 -0
  48. package/dist/tools/get-card.d.ts +13 -0
  49. package/dist/tools/get-card.d.ts.map +1 -0
  50. package/dist/tools/get-card.js +71 -0
  51. package/dist/tools/get-card.js.map +1 -0
  52. package/dist/tools/get-class-identity.d.ts +43 -0
  53. package/dist/tools/get-class-identity.d.ts.map +1 -0
  54. package/dist/tools/get-class-identity.js +69 -0
  55. package/dist/tools/get-class-identity.js.map +1 -0
  56. package/dist/tools/get-keyword.d.ts +30 -0
  57. package/dist/tools/get-keyword.d.ts.map +1 -0
  58. package/dist/tools/get-keyword.js +88 -0
  59. package/dist/tools/get-keyword.js.map +1 -0
  60. package/dist/tools/get-matchup.d.ts +32 -0
  61. package/dist/tools/get-matchup.d.ts.map +1 -0
  62. package/dist/tools/get-matchup.js +41 -0
  63. package/dist/tools/get-matchup.js.map +1 -0
  64. package/dist/tools/search-cards.d.ts +43 -0
  65. package/dist/tools/search-cards.d.ts.map +1 -0
  66. package/dist/tools/search-cards.js +167 -0
  67. package/dist/tools/search-cards.js.map +1 -0
  68. package/package.json +50 -0
@@ -0,0 +1,232 @@
1
+ // --- Types ---
2
+ // --- Signal helpers ---
3
+ function countCardsMatching(cards, test) {
4
+ return cards.filter(test).length;
5
+ }
6
+ function textContains(text, ...terms) {
7
+ if (!text)
8
+ return false;
9
+ const lower = text.toLowerCase();
10
+ return terms.some((t) => lower.includes(t.toLowerCase()));
11
+ }
12
+ function keywordsContain(keywords, term) {
13
+ if (!keywords)
14
+ return false;
15
+ const lower = keywords.toLowerCase();
16
+ return lower.includes(term.toLowerCase());
17
+ }
18
+ // --- Score calculators ---
19
+ function scoreAggro(profile) {
20
+ let score = 0;
21
+ const signals = [];
22
+ // Low average cost (<3.0): +3
23
+ if (profile.avg_cost < 3.0) {
24
+ score += 3;
25
+ signals.push(`Low average mana cost (${profile.avg_cost.toFixed(1)})`);
26
+ }
27
+ // Many 1-2 cost cards (>40% of deck): +2
28
+ const lowCostCount = (profile.mana_curve['1'] ?? 0) + (profile.mana_curve['2'] ?? 0);
29
+ if (profile.total_cards > 0 && lowCostCount / profile.total_cards > 0.4) {
30
+ score += 2;
31
+ signals.push(`${lowCostCount} cards costing 1-2 (${Math.round((lowCostCount / profile.total_cards) * 100)}% of deck)`);
32
+ }
33
+ // Cards with face damage / Charge / Rush: +1 each
34
+ const chargeCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'Charge') || keywordsContain(c.keywords, 'CHARGE'));
35
+ if (chargeCount > 0) {
36
+ score += Math.min(chargeCount, 3);
37
+ signals.push(`${chargeCount} card(s) with Charge`);
38
+ }
39
+ const faceDamageCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'deal damage to the enemy hero', 'face damage'));
40
+ if (faceDamageCount > 0) {
41
+ score += Math.min(faceDamageCount, 3);
42
+ signals.push(`${faceDamageCount} card(s) with face damage effects`);
43
+ }
44
+ const rushCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'Rush') || keywordsContain(c.keywords, 'RUSH'));
45
+ if (rushCount > 0) {
46
+ score += Math.min(rushCount, 2);
47
+ signals.push(`${rushCount} card(s) with Rush`);
48
+ }
49
+ // Few cards costing 6+: +1
50
+ const expensiveCount = (profile.mana_curve['6'] ?? 0) + (profile.mana_curve['7+'] ?? 0);
51
+ if (expensiveCount <= 2) {
52
+ score += 1;
53
+ signals.push('Few expensive cards');
54
+ }
55
+ return { score, signals };
56
+ }
57
+ function scoreControl(profile) {
58
+ let score = 0;
59
+ const signals = [];
60
+ // High average cost (>4.0): +3
61
+ if (profile.avg_cost > 4.0) {
62
+ score += 3;
63
+ signals.push(`High average mana cost (${profile.avg_cost.toFixed(1)})`);
64
+ }
65
+ // Cards with "destroy" / "remove" / "clear" text: +2
66
+ const removalCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'destroy', 'remove', 'clear'));
67
+ if (removalCount > 0) {
68
+ score += 2;
69
+ signals.push(`${removalCount} removal card(s)`);
70
+ }
71
+ // Cards with "heal" / "restore" / "armor": +2
72
+ const healCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'heal', 'restore', 'armor'));
73
+ if (healCount > 0) {
74
+ score += 2;
75
+ signals.push(`${healCount} healing/armor card(s)`);
76
+ }
77
+ // Cards costing 7+: +1 per card (max 3)
78
+ const sevenPlus = profile.mana_curve['7+'] ?? 0;
79
+ if (sevenPlus > 0) {
80
+ const bonus = Math.min(sevenPlus, 3);
81
+ score += bonus;
82
+ signals.push(`${sevenPlus} card(s) costing 7+`);
83
+ }
84
+ return { score, signals };
85
+ }
86
+ function scoreCombo(profile) {
87
+ let score = 0;
88
+ const signals = [];
89
+ // Many spells (>50% spells): +2
90
+ const spellCount = profile.type_distribution['SPELL'] ?? 0;
91
+ if (profile.total_cards > 0 && spellCount / profile.total_cards > 0.5) {
92
+ score += 2;
93
+ signals.push(`Spell-heavy deck (${Math.round((spellCount / profile.total_cards) * 100)}% spells)`);
94
+ }
95
+ // Cards with "draw" text: +1 per card (max 3)
96
+ const drawCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'draw'));
97
+ if (drawCount > 0) {
98
+ const bonus = Math.min(drawCount, 3);
99
+ score += bonus;
100
+ signals.push(`${drawCount} card draw effect(s)`);
101
+ }
102
+ // Low minion count (<10): +2
103
+ const minionCount = profile.type_distribution['MINION'] ?? 0;
104
+ if (minionCount < 10) {
105
+ score += 2;
106
+ signals.push(`Low minion count (${minionCount})`);
107
+ }
108
+ // Cards with COMBO mechanic: +2
109
+ const comboCount = countCardsMatching(profile.cards, (c) => keywordsContain(c.keywords, 'COMBO'));
110
+ if (comboCount > 0) {
111
+ score += 2;
112
+ signals.push(`${comboCount} card(s) with Combo keyword`);
113
+ }
114
+ return { score, signals };
115
+ }
116
+ function scoreMidrange(profile) {
117
+ let score = 0;
118
+ const signals = [];
119
+ // Average cost 3.0-4.5: +3
120
+ if (profile.avg_cost >= 3.0 && profile.avg_cost <= 4.5) {
121
+ score += 3;
122
+ signals.push(`Balanced average mana cost (${profile.avg_cost.toFixed(1)})`);
123
+ }
124
+ // Balanced curve (significant cards at 3, 4, 5 cost): +2
125
+ const midCards = (profile.mana_curve['3'] ?? 0) + (profile.mana_curve['4'] ?? 0) + (profile.mana_curve['5'] ?? 0);
126
+ if (midCards >= 10) {
127
+ score += 2;
128
+ signals.push(`Strong mid-game curve (${midCards} cards at 3-5 cost)`);
129
+ }
130
+ // Good mix of minions and spells (40-70% minions): +2
131
+ const minionCount = profile.type_distribution['MINION'] ?? 0;
132
+ if (profile.total_cards > 0) {
133
+ const minionPct = minionCount / profile.total_cards;
134
+ if (minionPct >= 0.4 && minionPct <= 0.7) {
135
+ score += 2;
136
+ signals.push(`Balanced minion/spell mix (${Math.round(minionPct * 100)}% minions)`);
137
+ }
138
+ }
139
+ return { score, signals };
140
+ }
141
+ function scoreTempo(profile) {
142
+ let score = 0;
143
+ const signals = [];
144
+ // Average cost 2.5-3.5: +2
145
+ if (profile.avg_cost >= 2.5 && profile.avg_cost <= 3.5) {
146
+ score += 2;
147
+ signals.push(`Tempo-friendly average cost (${profile.avg_cost.toFixed(1)})`);
148
+ }
149
+ // Weapons: +2
150
+ const weaponCount = profile.type_distribution['WEAPON'] ?? 0;
151
+ if (weaponCount > 0) {
152
+ score += 2;
153
+ signals.push(`${weaponCount} weapon(s)`);
154
+ }
155
+ // Cards with Rush: +1 each (max 2)
156
+ const rushCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'Rush') || keywordsContain(c.keywords, 'RUSH'));
157
+ if (rushCount > 0) {
158
+ const bonus = Math.min(rushCount, 2);
159
+ score += bonus;
160
+ signals.push(`${rushCount} Rush card(s)`);
161
+ }
162
+ // Good 1-3 curve: +2
163
+ const earlyCurve = (profile.mana_curve['1'] ?? 0) + (profile.mana_curve['2'] ?? 0) + (profile.mana_curve['3'] ?? 0);
164
+ if (earlyCurve >= 12) {
165
+ score += 2;
166
+ signals.push(`Strong early curve (${earlyCurve} cards at 1-3 cost)`);
167
+ }
168
+ return { score, signals };
169
+ }
170
+ function scoreValue(profile) {
171
+ let score = 0;
172
+ const signals = [];
173
+ // Cards with "Discover" / "generate" / "add.*to your hand" text: +2 per card (max 4)
174
+ const generateCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'Discover', 'generate', 'add') && textContains(c.text, 'hand'));
175
+ const discoverOnly = countCardsMatching(profile.cards, (c) => textContains(c.text, 'Discover') || keywordsContain(c.keywords, 'DISCOVER'));
176
+ const totalGen = Math.max(generateCount, discoverOnly);
177
+ if (totalGen > 0) {
178
+ const bonus = Math.min(totalGen * 2, 4);
179
+ score += bonus;
180
+ signals.push(`${totalGen} resource generation card(s)`);
181
+ }
182
+ // Cards with "copy" text: +1
183
+ const copyCount = countCardsMatching(profile.cards, (c) => textContains(c.text, 'copy'));
184
+ if (copyCount > 0) {
185
+ score += 1;
186
+ signals.push(`${copyCount} copy effect(s)`);
187
+ }
188
+ // High card count at 5+ cost: +1
189
+ const fivePlus = (profile.mana_curve['5'] ?? 0) + (profile.mana_curve['6'] ?? 0) + (profile.mana_curve['7+'] ?? 0);
190
+ if (fivePlus >= 8) {
191
+ score += 1;
192
+ signals.push(`${fivePlus} cards costing 5+`);
193
+ }
194
+ return { score, signals };
195
+ }
196
+ // --- Main classifier ---
197
+ export function classifyArchetype(profile) {
198
+ const scores = [
199
+ { archetype: 'aggro', ...scoreAggro(profile) },
200
+ { archetype: 'control', ...scoreControl(profile) },
201
+ { archetype: 'combo', ...scoreCombo(profile) },
202
+ { archetype: 'midrange', ...scoreMidrange(profile) },
203
+ { archetype: 'tempo', ...scoreTempo(profile) },
204
+ { archetype: 'value', ...scoreValue(profile) },
205
+ ];
206
+ // Sort descending by score
207
+ scores.sort((a, b) => b.score - a.score);
208
+ const top = scores[0];
209
+ const second = scores[1];
210
+ const gap = top.score - second.score;
211
+ // Confidence based on gap
212
+ let confidence;
213
+ if (gap > 3) {
214
+ confidence = Math.min(0.8 + gap * 0.03, 1.0);
215
+ }
216
+ else if (gap >= 1) {
217
+ confidence = 0.5 + (gap - 1) * 0.1;
218
+ }
219
+ else {
220
+ confidence = Math.max(0.3, 0.5 - (1 - gap) * 0.2);
221
+ }
222
+ // Build reasoning from top archetype signals
223
+ const reasoning = top.signals.length > 0
224
+ ? top.signals.join(', ') + ` suggest ${top.archetype === 'aggro' ? 'an aggressive' : `a ${top.archetype}`} strategy.`
225
+ : `Classified as ${top.archetype} based on overall deck composition.`;
226
+ return {
227
+ archetype: top.archetype,
228
+ confidence: Math.round(confidence * 100) / 100,
229
+ reasoning,
230
+ };
231
+ }
232
+ //# sourceMappingURL=archetype-classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archetype-classifier.js","sourceRoot":"","sources":["../../src/knowledge/archetype-classifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import type Database from 'better-sqlite3';
4
+ export declare function createServer(db: Database.Database): McpServer;
5
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AA4C3C,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,aAgQjD"}
package/dist/server.js ADDED
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { createRequire } from 'node:module';
5
+ import { SearchCardsInput, searchCards } from './tools/search-cards.js';
6
+ import { GetCardInput, getCard } from './tools/get-card.js';
7
+ import { GetKeywordInput, getKeyword } from './tools/get-keyword.js';
8
+ import { DecodeDeckInput, decodeDeck } from './tools/decode-deck.js';
9
+ import { AnalyzeDeckInput, analyzeDeck } from './tools/analyze-deck.js';
10
+ import { GetArchetypeInput, getArchetype } from './tools/get-archetype.js';
11
+ import { GetClassIdentityInput, getClassIdentity, } from './tools/get-class-identity.js';
12
+ import { GetMatchupInput, getMatchup } from './tools/get-matchup.js';
13
+ import { ExplainConceptInput, explainConcept, } from './tools/explain-concept.js';
14
+ import { formatSearchCards, formatGetCard, formatGetKeyword, formatDecodeDeck, formatAnalyzeDeck, formatGetArchetype, formatGetClassIdentity, formatGetMatchup, formatExplainConcept, } from './format.js';
15
+ import { getDatabase } from './data/db.js';
16
+ import { runPipeline } from './data/pipeline.js';
17
+ import { seedStrategyKnowledge } from './data/strategy-seed.js';
18
+ function getVersion() {
19
+ try {
20
+ const require = createRequire(import.meta.url);
21
+ const pkg = require('../package.json');
22
+ return pkg.version;
23
+ }
24
+ catch {
25
+ return '0.0.0';
26
+ }
27
+ }
28
+ export function createServer(db) {
29
+ const server = new McpServer({ name: 'hearthstone-oracle', version: getVersion() }, { capabilities: { tools: {} } });
30
+ // 1. search_cards
31
+ server.tool('search_cards', 'Search for Hearthstone cards by name, text, class, mana cost, type, rarity, set, or keyword. Use this when you need to find cards matching specific criteria. Returns a summary list — use get_card for full details on a specific card.', SearchCardsInput.shape, async (params) => {
32
+ try {
33
+ const result = searchCards(db, params);
34
+ return {
35
+ content: [
36
+ { type: 'text', text: formatSearchCards(result) },
37
+ ],
38
+ };
39
+ }
40
+ catch (err) {
41
+ return {
42
+ content: [
43
+ {
44
+ type: 'text',
45
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
46
+ },
47
+ ],
48
+ isError: true,
49
+ };
50
+ }
51
+ });
52
+ // 2. get_card
53
+ server.tool('get_card', 'Get complete details for a specific Hearthstone card including stats, text, keywords, and type. Use this when you know the card name (or close to it) and need full information. Supports fuzzy matching.', GetCardInput.shape, async (params) => {
54
+ try {
55
+ const result = getCard(db, params);
56
+ return {
57
+ content: [
58
+ { type: 'text', text: formatGetCard(result) },
59
+ ],
60
+ };
61
+ }
62
+ catch (err) {
63
+ return {
64
+ content: [
65
+ {
66
+ type: 'text',
67
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
68
+ },
69
+ ],
70
+ isError: true,
71
+ };
72
+ }
73
+ });
74
+ // 3. get_keyword
75
+ server.tool('get_keyword', 'Look up a Hearthstone keyword or mechanic (e.g., Battlecry, Deathrattle, Discover) and see all cards that have it. Use this to explain what a keyword does or find all cards with a specific mechanic.', GetKeywordInput.shape, async (params) => {
76
+ try {
77
+ const result = getKeyword(db, params);
78
+ return {
79
+ content: [
80
+ { type: 'text', text: formatGetKeyword(result) },
81
+ ],
82
+ };
83
+ }
84
+ catch (err) {
85
+ return {
86
+ content: [
87
+ {
88
+ type: 'text',
89
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
90
+ },
91
+ ],
92
+ isError: true,
93
+ };
94
+ }
95
+ });
96
+ // 4. decode_deck
97
+ server.tool('decode_deck', 'Decode a Hearthstone deck code into its full card list with mana curve and card type breakdown. Use this when a user shares a deck code and wants to see what\'s in it.', DecodeDeckInput.shape, async (params) => {
98
+ try {
99
+ const result = decodeDeck(db, params);
100
+ return {
101
+ content: [
102
+ { type: 'text', text: formatDecodeDeck(result) },
103
+ ],
104
+ };
105
+ }
106
+ catch (err) {
107
+ return {
108
+ content: [
109
+ {
110
+ type: 'text',
111
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
112
+ },
113
+ ],
114
+ isError: true,
115
+ };
116
+ }
117
+ });
118
+ // 5. analyze_deck
119
+ server.tool('analyze_deck', 'Analyze a Hearthstone deck code to classify its archetype, explain its gameplan, identify strengths and weaknesses, and predict matchup dynamics. Use this for strategic deck coaching — it combines card data with strategy knowledge.', AnalyzeDeckInput.shape, async (params) => {
120
+ try {
121
+ const result = analyzeDeck(db, params);
122
+ return {
123
+ content: [
124
+ { type: 'text', text: formatAnalyzeDeck(result) },
125
+ ],
126
+ };
127
+ }
128
+ catch (err) {
129
+ return {
130
+ content: [
131
+ {
132
+ type: 'text',
133
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
134
+ },
135
+ ],
136
+ isError: true,
137
+ };
138
+ }
139
+ });
140
+ // 6. get_archetype
141
+ server.tool('get_archetype', 'Get a detailed explanation of a Hearthstone deck archetype (aggro, control, combo, midrange, tempo, value). Includes gameplan, win conditions, strengths, weaknesses, and example decks. Use this when explaining deck building strategy.', GetArchetypeInput.shape, async (params) => {
142
+ try {
143
+ const result = getArchetype(db, params);
144
+ return {
145
+ content: [
146
+ { type: 'text', text: formatGetArchetype(result) },
147
+ ],
148
+ };
149
+ }
150
+ catch (err) {
151
+ return {
152
+ content: [
153
+ {
154
+ type: 'text',
155
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
156
+ },
157
+ ],
158
+ isError: true,
159
+ };
160
+ }
161
+ });
162
+ // 7. get_class_identity
163
+ server.tool('get_class_identity', 'Get the strategic identity of a Hearthstone class — hero power implications, historical archetypes, strengths, weaknesses, and how the class approaches each game phase. Omit the class name to get an overview of all 11 classes.', GetClassIdentityInput.shape, async (params) => {
164
+ try {
165
+ const result = getClassIdentity(db, params);
166
+ return {
167
+ content: [
168
+ {
169
+ type: 'text',
170
+ text: formatGetClassIdentity(result),
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ catch (err) {
176
+ return {
177
+ content: [
178
+ {
179
+ type: 'text',
180
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
181
+ },
182
+ ],
183
+ isError: true,
184
+ };
185
+ }
186
+ });
187
+ // 8. get_matchup
188
+ server.tool('get_matchup', 'Get the theoretical matchup dynamics between two Hearthstone archetypes. Explains who is favoured, why, the key strategic tension, and what each side should prioritise.', GetMatchupInput.shape, async (params) => {
189
+ try {
190
+ const result = getMatchup(db, params);
191
+ return {
192
+ content: [
193
+ { type: 'text', text: formatGetMatchup(result) },
194
+ ],
195
+ };
196
+ }
197
+ catch (err) {
198
+ return {
199
+ content: [
200
+ {
201
+ type: 'text',
202
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
203
+ },
204
+ ],
205
+ isError: true,
206
+ };
207
+ }
208
+ });
209
+ // 9. explain_concept
210
+ server.tool('explain_concept', 'Explain a fundamental Hearthstone game concept like card advantage, tempo, value, board control, or mana curve. Includes how the concept applies specifically to Hearthstone.', ExplainConceptInput.shape, async (params) => {
211
+ try {
212
+ const result = explainConcept(db, params);
213
+ return {
214
+ content: [
215
+ {
216
+ type: 'text',
217
+ text: formatExplainConcept(result),
218
+ },
219
+ ],
220
+ };
221
+ }
222
+ catch (err) {
223
+ return {
224
+ content: [
225
+ {
226
+ type: 'text',
227
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
228
+ },
229
+ ],
230
+ isError: true,
231
+ };
232
+ }
233
+ });
234
+ return server;
235
+ }
236
+ async function main() {
237
+ const version = getVersion();
238
+ const db = getDatabase();
239
+ // Run data pipeline
240
+ try {
241
+ console.error('[hearthstone-oracle] Starting data pipeline...');
242
+ const cardCount = await runPipeline(db);
243
+ console.error(`[hearthstone-oracle] Pipeline: ok (${cardCount} cards)`);
244
+ }
245
+ catch (err) {
246
+ console.error(`[hearthstone-oracle] Pipeline error: ${err instanceof Error ? err.message : String(err)}`);
247
+ console.error('[hearthstone-oracle] Continuing with existing data (if any)...');
248
+ }
249
+ // Seed strategy knowledge
250
+ seedStrategyKnowledge(db);
251
+ const server = createServer(db);
252
+ const transport = new StdioServerTransport();
253
+ console.error(`[hearthstone-oracle] v${version} starting on stdio...`);
254
+ await server.connect(transport);
255
+ console.error('[hearthstone-oracle] Server running — 9 tools registered');
256
+ process.on('SIGINT', async () => {
257
+ await server.close();
258
+ process.exit(0);
259
+ });
260
+ process.on('SIGTERM', async () => {
261
+ await server.close();
262
+ process.exit(0);
263
+ });
264
+ }
265
+ main().catch((err) => {
266
+ console.error(`[hearthstone-oracle] Fatal: ${err instanceof Error ? err.message : String(err)}`);
267
+ process.exit(1);
268
+ });
269
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type Database from 'better-sqlite3';
2
+ import { z } from 'zod';
3
+ import { type ClassificationResult } from '../knowledge/archetype-classifier.js';
4
+ export declare const AnalyzeDeckInput: z.ZodObject<{
5
+ deck_code: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ deck_code: string;
8
+ }, {
9
+ deck_code: string;
10
+ }>;
11
+ export type AnalyzeDeckInputType = z.infer<typeof AnalyzeDeckInput>;
12
+ export interface AnalyzeDeckSuccess {
13
+ success: true;
14
+ deck: {
15
+ format: string;
16
+ hero_class: string;
17
+ cards: Array<{
18
+ name: string;
19
+ mana_cost: number | null;
20
+ count: number;
21
+ }>;
22
+ total_cards: number;
23
+ mana_curve: Record<string, number>;
24
+ type_distribution: Record<string, number>;
25
+ };
26
+ classification: ClassificationResult;
27
+ archetype_info?: {
28
+ description: string;
29
+ gameplan: string;
30
+ strengths: string[];
31
+ weaknesses: string[];
32
+ };
33
+ matchups?: Array<{
34
+ vs_archetype: string;
35
+ favoured: string;
36
+ key_tension: string;
37
+ }>;
38
+ }
39
+ export interface AnalyzeDeckError {
40
+ success: false;
41
+ message: string;
42
+ }
43
+ export type AnalyzeDeckResult = AnalyzeDeckSuccess | AnalyzeDeckError;
44
+ export declare function analyzeDeck(db: Database.Database, input: AnalyzeDeckInputType): AnalyzeDeckResult;
45
+ //# sourceMappingURL=analyze-deck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-deck.d.ts","sourceRoot":"","sources":["../../src/tools/analyze-deck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAqB,KAAK,oBAAoB,EAAoB,MAAM,sCAAsC,CAAC;AAItH,eAAO,MAAM,gBAAgB;;;;;;EAE3B,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAIpE,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE;QACJ,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACxE,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC3C,CAAC;IACF,cAAc,EAAE,oBAAoB,CAAC;IACrC,cAAc,CAAC,EAAE;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;IACF,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,gBAAgB,CAAC;AAkDtE,wBAAgB,WAAW,CACzB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,oBAAoB,GAC1B,iBAAiB,CA4InB"}