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.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/data/db.d.ts +49 -0
- package/dist/data/db.d.ts.map +1 -0
- package/dist/data/db.js +109 -0
- package/dist/data/db.js.map +1 -0
- package/dist/data/hearthstone.d.ts +40 -0
- package/dist/data/hearthstone.d.ts.map +1 -0
- package/dist/data/hearthstone.js +58 -0
- package/dist/data/hearthstone.js.map +1 -0
- package/dist/data/pipeline.d.ts +36 -0
- package/dist/data/pipeline.d.ts.map +1 -0
- package/dist/data/pipeline.js +90 -0
- package/dist/data/pipeline.js.map +1 -0
- package/dist/data/schema.sql +111 -0
- package/dist/data/strategy-seed.d.ts +3 -0
- package/dist/data/strategy-seed.d.ts.map +1 -0
- package/dist/data/strategy-seed.js +512 -0
- package/dist/data/strategy-seed.js.map +1 -0
- package/dist/format.d.ts +63 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +331 -0
- package/dist/format.js.map +1 -0
- package/dist/knowledge/archetype-classifier.d.ts +19 -0
- package/dist/knowledge/archetype-classifier.d.ts.map +1 -0
- package/dist/knowledge/archetype-classifier.js +232 -0
- package/dist/knowledge/archetype-classifier.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +269 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/analyze-deck.d.ts +45 -0
- package/dist/tools/analyze-deck.d.ts.map +1 -0
- package/dist/tools/analyze-deck.js +159 -0
- package/dist/tools/analyze-deck.js.map +1 -0
- package/dist/tools/decode-deck.d.ts +30 -0
- package/dist/tools/decode-deck.d.ts.map +1 -0
- package/dist/tools/decode-deck.js +127 -0
- package/dist/tools/decode-deck.js.map +1 -0
- package/dist/tools/explain-concept.d.ts +26 -0
- package/dist/tools/explain-concept.d.ts.map +1 -0
- package/dist/tools/explain-concept.js +34 -0
- package/dist/tools/explain-concept.js.map +1 -0
- package/dist/tools/get-archetype.d.ts +29 -0
- package/dist/tools/get-archetype.d.ts.map +1 -0
- package/dist/tools/get-archetype.js +47 -0
- package/dist/tools/get-archetype.js.map +1 -0
- package/dist/tools/get-card.d.ts +13 -0
- package/dist/tools/get-card.d.ts.map +1 -0
- package/dist/tools/get-card.js +71 -0
- package/dist/tools/get-card.js.map +1 -0
- package/dist/tools/get-class-identity.d.ts +43 -0
- package/dist/tools/get-class-identity.d.ts.map +1 -0
- package/dist/tools/get-class-identity.js +69 -0
- package/dist/tools/get-class-identity.js.map +1 -0
- package/dist/tools/get-keyword.d.ts +30 -0
- package/dist/tools/get-keyword.d.ts.map +1 -0
- package/dist/tools/get-keyword.js +88 -0
- package/dist/tools/get-keyword.js.map +1 -0
- package/dist/tools/get-matchup.d.ts +32 -0
- package/dist/tools/get-matchup.d.ts.map +1 -0
- package/dist/tools/get-matchup.js +41 -0
- package/dist/tools/get-matchup.js.map +1 -0
- package/dist/tools/search-cards.d.ts +43 -0
- package/dist/tools/search-cards.d.ts.map +1 -0
- package/dist/tools/search-cards.js +167 -0
- package/dist/tools/search-cards.js.map +1 -0
- 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":"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"}
|
|
@@ -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"}
|