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,159 @@
1
+ import { z } from 'zod';
2
+ import { decode } from 'deckstrings';
3
+ import { classifyArchetype } from '../knowledge/archetype-classifier.js';
4
+ // --- Input Schema ---
5
+ export const AnalyzeDeckInput = z.object({
6
+ deck_code: z.string().describe('Hearthstone deck code (base64 deckstring)'),
7
+ });
8
+ // --- Helpers ---
9
+ const HERO_CLASS_MAP = {
10
+ 7: 'WARRIOR',
11
+ 274: 'MAGE',
12
+ 31: 'HUNTER',
13
+ 637: 'PRIEST',
14
+ 930: 'ROGUE',
15
+ 1066: 'PALADIN',
16
+ 671: 'WARLOCK',
17
+ 813: 'SHAMAN',
18
+ 893: 'DRUID',
19
+ 56550: 'DEMON_HUNTER',
20
+ 78065: 'DEATH_KNIGHT',
21
+ };
22
+ function manaCurveBucket(cost) {
23
+ if (cost == null)
24
+ return '0';
25
+ if (cost >= 7)
26
+ return '7+';
27
+ return String(cost);
28
+ }
29
+ function parseJson(raw) {
30
+ if (!raw)
31
+ return [];
32
+ try {
33
+ return JSON.parse(raw);
34
+ }
35
+ catch {
36
+ return [];
37
+ }
38
+ }
39
+ export function analyzeDeck(db, input) {
40
+ // 1. Decode the deck
41
+ let decoded;
42
+ try {
43
+ decoded = decode(input.deck_code);
44
+ }
45
+ catch (err) {
46
+ return {
47
+ success: false,
48
+ message: `Invalid deck code: ${err instanceof Error ? err.message : String(err)}`,
49
+ };
50
+ }
51
+ // 2. Format
52
+ const format = decoded.format === 1 ? 'Wild' : 'Standard';
53
+ // 3. Hero class
54
+ let heroClass = 'UNKNOWN';
55
+ if (decoded.heroes.length > 0) {
56
+ const heroDbfId = decoded.heroes[0];
57
+ const heroRow = db
58
+ .prepare('SELECT player_class FROM cards WHERE id = ?')
59
+ .get(String(heroDbfId));
60
+ if (heroRow?.player_class) {
61
+ heroClass = heroRow.player_class;
62
+ }
63
+ else if (HERO_CLASS_MAP[heroDbfId]) {
64
+ heroClass = HERO_CLASS_MAP[heroDbfId];
65
+ }
66
+ }
67
+ // 4. Build card list and profile data
68
+ const deckCards = [];
69
+ const profileCards = [];
70
+ const manaCurve = {};
71
+ const typeDistribution = {};
72
+ let totalCards = 0;
73
+ let totalCost = 0;
74
+ let cardsWithCost = 0;
75
+ for (const [dbfId, count] of decoded.cards) {
76
+ const row = db
77
+ .prepare('SELECT * FROM cards WHERE id = ?')
78
+ .get(String(dbfId));
79
+ const name = row ? row.name : `Unknown Card (${dbfId})`;
80
+ const manaCost = row?.mana_cost ?? null;
81
+ const type = row?.type ?? null;
82
+ const text = row?.text ?? null;
83
+ const keywords = row?.keywords ?? null;
84
+ deckCards.push({ name, mana_cost: manaCost, count });
85
+ // Add profile cards (expand by count for classification)
86
+ for (let i = 0; i < count; i++) {
87
+ profileCards.push({ mana_cost: manaCost, type, text, keywords });
88
+ }
89
+ totalCards += count;
90
+ // Mana curve
91
+ const bucket = manaCurveBucket(manaCost);
92
+ manaCurve[bucket] = (manaCurve[bucket] ?? 0) + count;
93
+ // Type distribution
94
+ const cardType = type ?? 'UNKNOWN';
95
+ typeDistribution[cardType] = (typeDistribution[cardType] ?? 0) + count;
96
+ // Average cost tracking
97
+ if (manaCost != null) {
98
+ totalCost += manaCost * count;
99
+ cardsWithCost += count;
100
+ }
101
+ }
102
+ const avgCost = cardsWithCost > 0 ? totalCost / cardsWithCost : 0;
103
+ // 5. Build DeckProfile and classify
104
+ const profile = {
105
+ avg_cost: avgCost,
106
+ cards: profileCards,
107
+ total_cards: totalCards,
108
+ mana_curve: manaCurve,
109
+ type_distribution: typeDistribution,
110
+ };
111
+ const classification = classifyArchetype(profile);
112
+ // 6. Look up archetype info from strategy tables
113
+ let archetypeInfo;
114
+ const archetypeRow = db
115
+ .prepare('SELECT * FROM archetypes WHERE LOWER(name) = LOWER(?)')
116
+ .get(classification.archetype);
117
+ if (archetypeRow) {
118
+ archetypeInfo = {
119
+ description: archetypeRow.description,
120
+ gameplan: archetypeRow.gameplan,
121
+ strengths: parseJson(archetypeRow.strengths),
122
+ weaknesses: parseJson(archetypeRow.weaknesses),
123
+ };
124
+ }
125
+ // 7. Look up matchup expectations
126
+ let matchups;
127
+ const matchupRows = db
128
+ .prepare(`SELECT archetype_a, archetype_b, favoured, key_tension FROM matchup_framework
129
+ WHERE LOWER(archetype_a) = LOWER(?) OR LOWER(archetype_b) = LOWER(?)`)
130
+ .all(classification.archetype, classification.archetype);
131
+ if (matchupRows.length > 0) {
132
+ matchups = matchupRows
133
+ .filter((m) => m.archetype_a.toLowerCase() !== m.archetype_b.toLowerCase() ||
134
+ m.archetype_a.toLowerCase() !== classification.archetype.toLowerCase())
135
+ .map((m) => {
136
+ const isA = m.archetype_a.toLowerCase() === classification.archetype.toLowerCase();
137
+ return {
138
+ vs_archetype: isA ? m.archetype_b : m.archetype_a,
139
+ favoured: m.favoured,
140
+ key_tension: m.key_tension,
141
+ };
142
+ });
143
+ }
144
+ return {
145
+ success: true,
146
+ deck: {
147
+ format,
148
+ hero_class: heroClass,
149
+ cards: deckCards,
150
+ total_cards: totalCards,
151
+ mana_curve: manaCurve,
152
+ type_distribution: typeDistribution,
153
+ },
154
+ classification,
155
+ archetype_info: archetypeInfo,
156
+ matchups: matchups && matchups.length > 0 ? matchups : undefined,
157
+ };
158
+ }
159
+ //# sourceMappingURL=analyze-deck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-deck.js","sourceRoot":"","sources":["../../src/tools/analyze-deck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,iBAAiB,EAA+C,MAAM,sCAAsC,CAAC;AAEtH,uBAAuB;AAEvB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;CAC5E,CAAC,CAAC;AAqCH,kBAAkB;AAElB,MAAM,cAAc,GAA2B;IAC7C,CAAC,EAAE,SAAS;IACZ,GAAG,EAAE,MAAM;IACX,EAAE,EAAE,QAAQ;IACZ,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,OAAO;IACZ,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,OAAO;IACZ,KAAK,EAAE,cAAc;IACrB,KAAK,EAAE,cAAc;CACtB,CAAC;AAEF,SAAS,eAAe,CAAC,IAAmB;IAC1C,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC;IAC7B,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,SAAS,CAAC,GAAkB;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAmBD,MAAM,UAAU,WAAW,CACzB,EAAqB,EACrB,KAA2B;IAE3B,qBAAqB;IACrB,IAAI,OAA6E,CAAC;IAElF,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,sBAAsB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;SAClF,CAAC;IACJ,CAAC;IAED,YAAY;IACZ,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;IAE1D,gBAAgB;IAChB,IAAI,SAAS,GAAG,SAAS,CAAC;IAC1B,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,EAAE;aACf,OAAO,CAAC,6CAA6C,CAAC;aACtD,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAgD,CAAC;QAEzE,IAAI,OAAO,EAAE,YAAY,EAAE,CAAC;YAC1B,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;QACnC,CAAC;aAAM,IAAI,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,sCAAsC;IACtC,MAAM,SAAS,GAAqE,EAAE,CAAC;IACvF,MAAM,YAAY,GAAyB,EAAE,CAAC;IAC9C,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,MAAM,gBAAgB,GAA2B,EAAE,CAAC;IACpD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,EAAE;aACX,OAAO,CAAC,kCAAkC,CAAC;aAC3C,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAwB,CAAC;QAE7C,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,KAAK,GAAG,CAAC;QACxD,MAAM,QAAQ,GAAG,GAAG,EAAE,SAAS,IAAI,IAAI,CAAC;QACxC,MAAM,IAAI,GAAG,GAAG,EAAE,IAAI,IAAI,IAAI,CAAC;QAC/B,MAAM,IAAI,GAAG,GAAG,EAAE,IAAI,IAAI,IAAI,CAAC;QAC/B,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,IAAI,IAAI,CAAC;QAEvC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAErD,yDAAyD;QACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,YAAY,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;QAED,UAAU,IAAI,KAAK,CAAC;QAEpB,aAAa;QACb,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QACzC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;QAErD,oBAAoB;QACpB,MAAM,QAAQ,GAAG,IAAI,IAAI,SAAS,CAAC;QACnC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;QAEvE,wBAAwB;QACxB,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,SAAS,IAAI,QAAQ,GAAG,KAAK,CAAC;YAC9B,aAAa,IAAI,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAElE,oCAAoC;IACpC,MAAM,OAAO,GAAgB;QAC3B,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,UAAU;QACvB,UAAU,EAAE,SAAS;QACrB,iBAAiB,EAAE,gBAAgB;KACpC,CAAC;IAEF,MAAM,cAAc,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAElD,iDAAiD;IACjD,IAAI,aAA+D,CAAC;IACpE,MAAM,YAAY,GAAG,EAAE;SACpB,OAAO,CAAC,uDAAuD,CAAC;SAChE,GAAG,CAAC,cAAc,CAAC,SAAS,CAA6B,CAAC;IAE7D,IAAI,YAAY,EAAE,CAAC;QACjB,aAAa,GAAG;YACd,WAAW,EAAE,YAAY,CAAC,WAAW;YACrC,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,SAAS,EAAE,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC;YAC5C,UAAU,EAAE,SAAS,CAAC,YAAY,CAAC,UAAU,CAAC;SAC/C,CAAC;IACJ,CAAC;IAED,kCAAkC;IAClC,IAAI,QAAoD,CAAC;IACzD,MAAM,WAAW,GAAG,EAAE;SACnB,OAAO,CACN;4EACsE,CACvE;SACA,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC,SAAS,CAAiB,CAAC;IAE3E,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,QAAQ,GAAG,WAAW;aACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE;YACxE,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;aACxE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YACnF,OAAO;gBACL,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW;gBACjD,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,WAAW,EAAE,CAAC,CAAC,WAAW;aAC3B,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE;YACJ,MAAM;YACN,UAAU,EAAE,SAAS;YACrB,KAAK,EAAE,SAAS;YAChB,WAAW,EAAE,UAAU;YACvB,UAAU,EAAE,SAAS;YACrB,iBAAiB,EAAE,gBAAgB;SACpC;QACD,cAAc;QACd,cAAc,EAAE,aAAa;QAC7B,QAAQ,EAAE,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;KACjE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type Database from 'better-sqlite3';
2
+ import { z } from 'zod';
3
+ import type { CardSummary } from '../format.js';
4
+ export declare const DecodeDeckInput: z.ZodObject<{
5
+ deck_code: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ deck_code: string;
8
+ }, {
9
+ deck_code: string;
10
+ }>;
11
+ export type DecodeDeckInputType = z.infer<typeof DecodeDeckInput>;
12
+ export interface DecodeDeckSuccess {
13
+ success: true;
14
+ format: string;
15
+ hero_class: string;
16
+ cards: Array<{
17
+ card: CardSummary;
18
+ count: number;
19
+ }>;
20
+ total_cards: number;
21
+ mana_curve: Record<string, number>;
22
+ type_distribution: Record<string, number>;
23
+ }
24
+ export interface DecodeDeckError {
25
+ success: false;
26
+ message: string;
27
+ }
28
+ export type DecodeDeckResult = DecodeDeckSuccess | DecodeDeckError;
29
+ export declare function decodeDeck(db: Database.Database, input: DecodeDeckInputType): DecodeDeckResult;
30
+ //# sourceMappingURL=decode-deck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-deck.d.ts","sourceRoot":"","sources":["../../src/tools/decode-deck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhD,eAAO,MAAM,eAAe;;;;;;EAE1B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAIlE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,eAAe,CAAC;AAmDnE,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,mBAAmB,GACzB,gBAAgB,CAiFlB"}
@@ -0,0 +1,127 @@
1
+ import { z } from 'zod';
2
+ import { decode } from 'deckstrings';
3
+ // --- Input Schema ---
4
+ export const DecodeDeckInput = z.object({
5
+ deck_code: z.string().describe('Hearthstone deck code (base64 deckstring)'),
6
+ });
7
+ // --- Helpers ---
8
+ function parseJson(raw) {
9
+ if (!raw)
10
+ return [];
11
+ try {
12
+ return JSON.parse(raw);
13
+ }
14
+ catch {
15
+ return [];
16
+ }
17
+ }
18
+ function toCardSummary(row) {
19
+ return {
20
+ name: row.name,
21
+ mana_cost: row.mana_cost,
22
+ type: row.type,
23
+ player_class: row.player_class,
24
+ rarity: row.rarity,
25
+ text: row.text ? row.text.split('\n')[0] : null,
26
+ attack: row.attack,
27
+ health: row.health,
28
+ keywords: parseJson(row.keywords),
29
+ };
30
+ }
31
+ function manaCurveBucket(cost) {
32
+ if (cost == null)
33
+ return '0';
34
+ if (cost >= 7)
35
+ return '7+';
36
+ return String(cost);
37
+ }
38
+ // --- Hero dbfId to class mapping (common heroes) ---
39
+ const HERO_CLASS_MAP = {
40
+ 7: 'WARRIOR', // Garrosh Hellscream
41
+ 274: 'MAGE', // Jaina Proudmoore
42
+ 31: 'HUNTER', // Rexxar
43
+ 637: 'PRIEST', // Anduin Wrynn
44
+ 930: 'ROGUE', // Valeera Sanguinar
45
+ 1066: 'PALADIN', // Uther Lightbringer
46
+ 671: 'WARLOCK', // Gul'dan
47
+ 813: 'SHAMAN', // Thrall
48
+ 893: 'DRUID', // Malfurion Stormrage
49
+ 56550: 'DEMON_HUNTER', // Illidan Stormrage
50
+ 78065: 'DEATH_KNIGHT', // The Lich King
51
+ };
52
+ // --- Handler ---
53
+ export function decodeDeck(db, input) {
54
+ let decoded;
55
+ try {
56
+ decoded = decode(input.deck_code);
57
+ }
58
+ catch (err) {
59
+ return {
60
+ success: false,
61
+ message: `Invalid deck code: ${err instanceof Error ? err.message : String(err)}`,
62
+ };
63
+ }
64
+ // Format
65
+ const format = decoded.format === 1 ? 'Wild' : 'Standard';
66
+ // Hero class — try to look up hero in DB first, then fall back to map
67
+ let heroClass = 'UNKNOWN';
68
+ if (decoded.heroes.length > 0) {
69
+ const heroDbfId = decoded.heroes[0];
70
+ // Try DB lookup
71
+ const heroRow = db
72
+ .prepare('SELECT player_class FROM cards WHERE id = ?')
73
+ .get(String(heroDbfId));
74
+ if (heroRow?.player_class) {
75
+ heroClass = heroRow.player_class;
76
+ }
77
+ else if (HERO_CLASS_MAP[heroDbfId]) {
78
+ heroClass = HERO_CLASS_MAP[heroDbfId];
79
+ }
80
+ }
81
+ // Cards
82
+ const cards = [];
83
+ const manaCurve = {};
84
+ const typeDistribution = {};
85
+ let totalCards = 0;
86
+ for (const [dbfId, count] of decoded.cards) {
87
+ const row = db
88
+ .prepare('SELECT * FROM cards WHERE id = ?')
89
+ .get(String(dbfId));
90
+ let cardSummary;
91
+ if (row) {
92
+ cardSummary = toCardSummary(row);
93
+ }
94
+ else {
95
+ // Unknown card — create placeholder
96
+ cardSummary = {
97
+ name: `Unknown Card (${dbfId})`,
98
+ mana_cost: null,
99
+ type: null,
100
+ player_class: null,
101
+ rarity: null,
102
+ text: null,
103
+ attack: null,
104
+ health: null,
105
+ keywords: [],
106
+ };
107
+ }
108
+ cards.push({ card: cardSummary, count });
109
+ totalCards += count;
110
+ // Mana curve
111
+ const bucket = manaCurveBucket(cardSummary.mana_cost);
112
+ manaCurve[bucket] = (manaCurve[bucket] ?? 0) + count;
113
+ // Type distribution
114
+ const cardType = cardSummary.type ?? 'UNKNOWN';
115
+ typeDistribution[cardType] = (typeDistribution[cardType] ?? 0) + count;
116
+ }
117
+ return {
118
+ success: true,
119
+ format,
120
+ hero_class: heroClass,
121
+ cards,
122
+ total_cards: totalCards,
123
+ mana_curve: manaCurve,
124
+ type_distribution: typeDistribution,
125
+ };
126
+ }
127
+ //# sourceMappingURL=decode-deck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-deck.js","sourceRoot":"","sources":["../../src/tools/decode-deck.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type Database from 'better-sqlite3';
2
+ import { z } from 'zod';
3
+ export declare const ExplainConceptInput: z.ZodObject<{
4
+ name: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ name: string;
7
+ }, {
8
+ name: string;
9
+ }>;
10
+ export type ExplainConceptInputType = z.infer<typeof ExplainConceptInput>;
11
+ export interface ConceptInfo {
12
+ name: string;
13
+ category: string;
14
+ description: string;
15
+ hearthstone_application: string;
16
+ }
17
+ export type ExplainConceptResult = {
18
+ found: true;
19
+ concept: ConceptInfo;
20
+ } | {
21
+ found: false;
22
+ message: string;
23
+ suggestions?: string[];
24
+ };
25
+ export declare function explainConcept(db: Database.Database, input: ExplainConceptInputType): ExplainConceptResult;
26
+ //# sourceMappingURL=explain-concept.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain-concept.d.ts","sourceRoot":"","sources":["../../src/tools/explain-concept.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,mBAAmB;;;;;;EAE9B,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAI1E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAI9D,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,uBAAuB,GAC7B,oBAAoB,CA8BtB"}
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ // --- Input Schema ---
3
+ export const ExplainConceptInput = z.object({
4
+ name: z.string().describe('Game concept name (e.g. "tempo", "card advantage", "mana curve")'),
5
+ });
6
+ // --- Handler ---
7
+ export function explainConcept(db, input) {
8
+ // Exact match (case-insensitive)
9
+ const row = db
10
+ .prepare('SELECT * FROM game_concepts WHERE LOWER(name) = LOWER(?)')
11
+ .get(input.name);
12
+ if (row) {
13
+ return {
14
+ found: true,
15
+ concept: {
16
+ name: row.name,
17
+ category: row.category,
18
+ description: row.description,
19
+ hearthstone_application: row.hearthstone_application,
20
+ },
21
+ };
22
+ }
23
+ // Not found — suggest similar entries via LIKE
24
+ const suggestions = db
25
+ .prepare('SELECT name FROM game_concepts WHERE LOWER(name) LIKE LOWER(?) LIMIT 5')
26
+ .all(`%${input.name}%`);
27
+ const suggestionNames = suggestions.map((s) => s.name);
28
+ return {
29
+ found: false,
30
+ message: `No game concept found matching "${input.name}".`,
31
+ suggestions: suggestionNames.length > 0 ? suggestionNames : undefined,
32
+ };
33
+ }
34
+ //# sourceMappingURL=explain-concept.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain-concept.js","sourceRoot":"","sources":["../../src/tools/explain-concept.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,uBAAuB;AAEvB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kEAAkE,CAAC;CAC9F,CAAC,CAAC;AAiBH,kBAAkB;AAElB,MAAM,UAAU,cAAc,CAC5B,EAAqB,EACrB,KAA8B;IAE9B,iCAAiC;IACjC,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,0DAA0D,CAAC;SACnE,GAAG,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;IAE9C,IAAI,GAAG,EAAE,CAAC;QACR,OAAO;YACL,KAAK,EAAE,IAAI;YACX,OAAO,EAAE;gBACP,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,uBAAuB,EAAE,GAAG,CAAC,uBAAuB;aACrD;SACF,CAAC;IACJ,CAAC;IAED,+CAA+C;IAC/C,MAAM,WAAW,GAAG,EAAE;SACnB,OAAO,CAAC,wEAAwE,CAAC;SACjF,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAA4B,CAAC;IAErD,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEvD,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,mCAAmC,KAAK,CAAC,IAAI,IAAI;QAC1D,WAAW,EAAE,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;KACtE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type Database from 'better-sqlite3';
2
+ import { z } from 'zod';
3
+ export declare const GetArchetypeInput: z.ZodObject<{
4
+ name: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ name: string;
7
+ }, {
8
+ name: string;
9
+ }>;
10
+ export type GetArchetypeInputType = z.infer<typeof GetArchetypeInput>;
11
+ export interface ArchetypeInfo {
12
+ name: string;
13
+ description: string;
14
+ gameplan: string;
15
+ win_conditions: string[];
16
+ strengths: string[];
17
+ weaknesses: string[];
18
+ example_decks: string[];
19
+ }
20
+ export type GetArchetypeResult = {
21
+ found: true;
22
+ archetype: ArchetypeInfo;
23
+ } | {
24
+ found: false;
25
+ message: string;
26
+ suggestions?: string[];
27
+ };
28
+ export declare function getArchetype(db: Database.Database, input: GetArchetypeInputType): GetArchetypeResult;
29
+ //# sourceMappingURL=get-archetype.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-archetype.d.ts","sourceRoot":"","sources":["../../src/tools/get-archetype.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,iBAAiB;;;;;;EAE5B,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAItE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,aAAa,CAAA;CAAE,GACzC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAyB9D,wBAAgB,YAAY,CAC1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,qBAAqB,GAC3B,kBAAkB,CAiCpB"}
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod';
2
+ // --- Input Schema ---
3
+ export const GetArchetypeInput = z.object({
4
+ name: z.string().describe('Archetype name (e.g. "aggro", "control", "combo", "midrange", "tempo", "value")'),
5
+ });
6
+ // --- Helpers ---
7
+ function parseJson(raw) {
8
+ if (!raw)
9
+ return [];
10
+ try {
11
+ return JSON.parse(raw);
12
+ }
13
+ catch {
14
+ return [];
15
+ }
16
+ }
17
+ export function getArchetype(db, input) {
18
+ // 1. Exact match (case-insensitive)
19
+ const row = db
20
+ .prepare('SELECT * FROM archetypes WHERE LOWER(name) = LOWER(?)')
21
+ .get(input.name);
22
+ if (row) {
23
+ return {
24
+ found: true,
25
+ archetype: {
26
+ name: row.name,
27
+ description: row.description,
28
+ gameplan: row.gameplan,
29
+ win_conditions: parseJson(row.win_conditions),
30
+ strengths: parseJson(row.strengths),
31
+ weaknesses: parseJson(row.weaknesses),
32
+ example_decks: parseJson(row.example_decks),
33
+ },
34
+ };
35
+ }
36
+ // 2. Not found — suggest similar entries via LIKE
37
+ const suggestions = db
38
+ .prepare('SELECT name FROM archetypes WHERE LOWER(name) LIKE LOWER(?) LIMIT 5')
39
+ .all(`%${input.name}%`);
40
+ const suggestionNames = suggestions.map((s) => s.name);
41
+ return {
42
+ found: false,
43
+ message: `No archetype found matching "${input.name}".`,
44
+ suggestions: suggestionNames.length > 0 ? suggestionNames : undefined,
45
+ };
46
+ }
47
+ //# sourceMappingURL=get-archetype.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-archetype.js","sourceRoot":"","sources":["../../src/tools/get-archetype.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,uBAAuB;AAEvB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iFAAiF,CAAC;CAC7G,CAAC,CAAC;AAoBH,kBAAkB;AAElB,SAAS,SAAS,CAAC,GAAkB;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAcD,MAAM,UAAU,YAAY,CAC1B,EAAqB,EACrB,KAA4B;IAE5B,oCAAoC;IACpC,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,uDAAuD,CAAC;SAChE,GAAG,CAAC,KAAK,CAAC,IAAI,CAA6B,CAAC;IAE/C,IAAI,GAAG,EAAE,CAAC;QACR,OAAO;YACL,KAAK,EAAE,IAAI;YACX,SAAS,EAAE;gBACT,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,cAAc,EAAE,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC;gBAC7C,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;gBACnC,UAAU,EAAE,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC;gBACrC,aAAa,EAAE,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC;aAC5C;SACF,CAAC;IACJ,CAAC;IAED,kDAAkD;IAClD,MAAM,WAAW,GAAG,EAAE;SACnB,OAAO,CAAC,qEAAqE,CAAC;SAC9E,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAA4B,CAAC;IAErD,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEvD,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,gCAAgC,KAAK,CAAC,IAAI,IAAI;QACvD,WAAW,EAAE,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;KACtE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type Database from 'better-sqlite3';
2
+ import { z } from 'zod';
3
+ import type { GetCardResult } from '../format.js';
4
+ export declare const GetCardInput: z.ZodObject<{
5
+ name: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ name: string;
8
+ }, {
9
+ name: string;
10
+ }>;
11
+ export type GetCardInputType = z.infer<typeof GetCardInput>;
12
+ export declare function getCard(db: Database.Database, input: GetCardInputType): GetCardResult;
13
+ //# sourceMappingURL=get-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-card.d.ts","sourceRoot":"","sources":["../../src/tools/get-card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAc,aAAa,EAAE,MAAM,cAAc,CAAC;AAI9D,eAAO,MAAM,YAAY;;;;;;EAEvB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AA2C5D,wBAAgB,OAAO,CACrB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,gBAAgB,GACtB,aAAa,CAgCf"}
@@ -0,0 +1,71 @@
1
+ import { z } from 'zod';
2
+ // --- Input Schema ---
3
+ export const GetCardInput = z.object({
4
+ name: z.string().describe('Card name to look up (exact or partial match)'),
5
+ });
6
+ // --- Helper: parse keywords JSON ---
7
+ function parseKeywords(raw) {
8
+ if (!raw)
9
+ return [];
10
+ try {
11
+ return JSON.parse(raw);
12
+ }
13
+ catch {
14
+ return [];
15
+ }
16
+ }
17
+ // --- Helper: CardRow to CardDetail ---
18
+ function toCardDetail(row) {
19
+ return {
20
+ id: row.id,
21
+ card_id: row.card_id,
22
+ name: row.name,
23
+ mana_cost: row.mana_cost,
24
+ type: row.type,
25
+ card_set: row.card_set,
26
+ set_name: row.set_name,
27
+ player_class: row.player_class,
28
+ rarity: row.rarity,
29
+ attack: row.attack,
30
+ health: row.health,
31
+ durability: row.durability,
32
+ armor: row.armor,
33
+ text: row.text,
34
+ flavor: row.flavor,
35
+ artist: row.artist,
36
+ collectible: row.collectible,
37
+ elite: row.elite,
38
+ race: row.race,
39
+ spell_school: row.spell_school,
40
+ keywords: parseKeywords(row.keywords),
41
+ };
42
+ }
43
+ // --- Handler ---
44
+ export function getCard(db, input) {
45
+ // 1. Exact match (case-insensitive)
46
+ const exact = db
47
+ .prepare('SELECT * FROM cards WHERE LOWER(name) = LOWER(?)')
48
+ .get(input.name);
49
+ if (exact) {
50
+ return { found: true, card: toCardDetail(exact) };
51
+ }
52
+ // 2. Fuzzy match via LIKE
53
+ const fuzzy = db
54
+ .prepare('SELECT * FROM cards WHERE LOWER(name) LIKE LOWER(?)')
55
+ .get(`%${input.name}%`);
56
+ if (fuzzy) {
57
+ return { found: true, card: toCardDetail(fuzzy) };
58
+ }
59
+ // 3. Not found — provide suggestions based on first word
60
+ const firstWord = input.name.split(/\s+/)[0];
61
+ const suggestions = db
62
+ .prepare('SELECT name FROM cards WHERE LOWER(name) LIKE LOWER(?) LIMIT 5')
63
+ .all(`%${firstWord}%`);
64
+ const suggestionNames = suggestions.map((s) => s.name);
65
+ return {
66
+ found: false,
67
+ message: `No card found matching "${input.name}".`,
68
+ suggestions: suggestionNames.length > 0 ? suggestionNames : undefined,
69
+ };
70
+ }
71
+ //# sourceMappingURL=get-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-card.js","sourceRoot":"","sources":["../../src/tools/get-card.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type Database from 'better-sqlite3';
2
+ import { z } from 'zod';
3
+ export declare const GetClassIdentityInput: z.ZodObject<{
4
+ class_name: z.ZodOptional<z.ZodString>;
5
+ }, "strip", z.ZodTypeAny, {
6
+ class_name?: string | undefined;
7
+ }, {
8
+ class_name?: string | undefined;
9
+ }>;
10
+ export type GetClassIdentityInputType = z.infer<typeof GetClassIdentityInput>;
11
+ export interface ClassIdentityInfo {
12
+ class: string;
13
+ identity: string;
14
+ hero_power_name: string;
15
+ hero_power_cost: number;
16
+ hero_power_effect: string;
17
+ hero_power_implications: string;
18
+ historical_archetypes: string[];
19
+ strengths: string[];
20
+ weaknesses: string[];
21
+ early_game: string;
22
+ mid_game: string;
23
+ late_game: string;
24
+ }
25
+ export interface ClassOverviewEntry {
26
+ class: string;
27
+ identity: string;
28
+ hero_power_name: string;
29
+ }
30
+ export type GetClassIdentityResult = {
31
+ found: true;
32
+ identity: ClassIdentityInfo;
33
+ } | {
34
+ found: true;
35
+ overview: true;
36
+ classes: ClassOverviewEntry[];
37
+ } | {
38
+ found: false;
39
+ message: string;
40
+ suggestions?: string[];
41
+ };
42
+ export declare function getClassIdentity(db: Database.Database, input: GetClassIdentityInputType): GetClassIdentityResult;
43
+ //# sourceMappingURL=get-class-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-class-identity.d.ts","sourceRoot":"","sources":["../../src/tools/get-class-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,qBAAqB;;;;;;EAKhC,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAI9E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;IAChC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,GAC5C;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAAE,GAC9D;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA+C9D,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,yBAAyB,GAC/B,sBAAsB,CAsCxB"}