getcompetitive 4.5.1 → 5.0.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/README.md +21 -62
- package/dist/evaluator.js +200 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/prompts.js +19 -19
- package/dist/prompts.js.map +1 -1
- package/dist/server.js +2 -24
- package/dist/server.js.map +1 -1
- package/dist/tools/analyze.js +33 -0
- package/dist/tools/analyze.js.map +1 -1
- package/dist/tools/compound.js +161 -0
- package/dist/tools/compound.js.map +1 -0
- package/dist/tools/doctor.js +58 -4
- package/dist/tools/doctor.js.map +1 -1
- package/dist/tools/matchup.js +110 -25
- package/dist/tools/matchup.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,8 +17,8 @@ Smogon-tier and archetype surface that used to sit alongside it is gone.
|
|
|
17
17
|
|
|
18
18
|
## What it provides
|
|
19
19
|
|
|
20
|
-
- **
|
|
21
|
-
- **Six workflow prompts** — `/team-doctor`, `/matchup-prep`, `/build-around`, `/tournament-prep`, `/learn-my-team`, `/meta-report` — server-provided templates that chain the
|
|
20
|
+
- **8 compound tools**: `lookup`, `calculate`, `analyze_team`, `optimize_team`, `prepare_matchup`, `analyze_battle`, `analyze_meta`, `team_io` — intent-level entrypoints that dispatch on a `mode`, so the model picks an intent and the server does the orchestration
|
|
21
|
+
- **Six workflow prompts** — `/team-doctor`, `/matchup-prep`, `/build-around`, `/tournament-prep`, `/learn-my-team`, `/meta-report` — server-provided templates that chain the eight tools, so compound workflows stay discoverable without widening the surface
|
|
22
22
|
- **Structured, agent-first definitions** — every tool declares MCP annotations and an output schema, returns `structuredContent` alongside JSON text, and documents all of its parameters; the deterministic half of the [TDQS](https://tdqs.dev) checklist is linted in CI
|
|
23
23
|
- Full **Pokémon Showdown** dataset — species, alternate forms, stats, moves, items, abilities, natures, learnsets, types
|
|
24
24
|
- **Battle math** from Smogon's calculator — stat calculation and full damage calculation (weather, terrain, boosts, items)
|
|
@@ -30,59 +30,18 @@ Built on [`@pkmn/dex`](https://github.com/pkmn/EPOKe) (Showdown data) and
|
|
|
30
30
|
|
|
31
31
|
## Tools
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
| Tool | Purpose |
|
|
35
|
-
| --- | --- |
|
|
36
|
-
| `get_pokemon` | Types, base stats, BST, abilities, forms, weight, gender, evolutions |
|
|
37
|
-
| `list_forms` | All forms of a species (alternate, cosmetic, battle-only) |
|
|
38
|
-
| `get_sprites` | Sprite URLs for a whole team in one call (artwork or icon), from a committed PokéAPI id table — URLs only, the server does no network I/O |
|
|
39
|
-
| `search_dex` | Fuzzy name search across species / moves / items / abilities / natures |
|
|
40
|
-
| `get_move` | Type, category, power, accuracy, PP, priority, target, secondary effects |
|
|
41
|
-
| `get_item` | Effect, flags, mega stone, Z-move, Fling, boosts |
|
|
42
|
-
| `get_ability` | Effect description, flags |
|
|
43
|
-
| `get_nature` | Boosts / lowers which stat |
|
|
44
|
-
| `get_learnset` | All learnable moves grouped by method (level-up, TM, egg, tutor, event) |
|
|
45
|
-
| `get_type` | Defensive weaknesses, resistances, immunities |
|
|
46
|
-
| `get_type_matchup` | Matchup multiplier, offensive coverage, or defensive chart (defender can be a species) |
|
|
47
|
-
|
|
48
|
-
### Team analysis
|
|
49
|
-
| Tool | Purpose |
|
|
50
|
-
| --- | --- |
|
|
51
|
-
| `analyze_team` | Team synergy: stacked defensive weaknesses, offensive coverage gaps, speed placement, a heuristic score, and — with a regulation — coverage against the meta's real sets |
|
|
52
|
-
|
|
53
|
-
### Team workflows
|
|
54
|
-
| Tool | Purpose |
|
|
55
|
-
| --- | --- |
|
|
56
|
-
| `parse_team` | Turn a Showdown/Pokepaste block (or a `species @ item \| ability \| nature \| EVs \| moves` one-liner) into the canonical team every tool takes; unknown names become warnings, not errors |
|
|
57
|
-
| `format_team` | Render a canonical team back into paste text, round-tripping through `parse_team` |
|
|
58
|
-
| `diagnose_team` | "Fix my team": weaknesses with evidence, then concrete spread, move, item and member changes, each backed by exact math or usage data |
|
|
59
|
-
| `prepare_matchup` | "Prepare me": their likely sets by usage, speed races with margins, key damage rolls, bring-four, leads, and win/loss conditions |
|
|
60
|
-
| `analyze_replay` | Post-match read of a battle log: teams, KOs with causes, observed Speed order, damage percentages, and a type-coverage read |
|
|
61
|
-
| `infer_set` | Reverse constraint solving: battle observations (who moved first, damage dealt/taken) narrow the opponent's likely set, ranked against the meta |
|
|
62
|
-
| `optimize_team` | Fill open team slots against constraints — cover these types, answer these threats — with reasons for every recommendation |
|
|
63
|
-
|
|
64
|
-
### Meta (usage-derived)
|
|
65
|
-
| Tool | Purpose |
|
|
66
|
-
| --- | --- |
|
|
67
|
-
| `list_threats` | Most-used Pokemon of a regulation, ranked by measured usage (role, tier, usage share) with the sample and sources behind it |
|
|
68
|
-
| `compare_meta` | What is changing: last 7 days of usage vs the 7 before, per species and per two-species core, from a committed build-time aggregation |
|
|
69
|
-
| `get_set` | Most-played set for one or several species (item, ability, nature, EVs, 4 moves), with the Mega form and ability where relevant; covers each regulation's ranked species, which `list_threats` lists |
|
|
70
|
-
|
|
71
|
-
### Regulations (Pokémon Champions / VGC)
|
|
72
|
-
| Tool | Purpose |
|
|
73
|
-
| --- | --- |
|
|
74
|
-
| `list_regulations` | Official Regulation Sets with dates, status, roster size, and how many species have usage-derived sets |
|
|
75
|
-
| `get_regulation` | Full set rules: battle rules, clauses, Mega rules, and roster sizes; the name rosters come back with `includeRoster` |
|
|
76
|
-
| `check_legality` | Validate a team against a set: illegal species, Species/Item Clause, illegal moves, team size, Mega eligibility |
|
|
33
|
+
Eight compound tools; each dispatches on a `mode` field where the name alone is ambiguous.
|
|
77
34
|
|
|
78
|
-
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
35
|
+
| Tool | Purpose | Modes |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| `lookup` | One data lookup | species, forms, search, move, item, ability, nature, learnset, type, matchup, sprites |
|
|
38
|
+
| `calculate` | One battle calc | stats, damage, matchups, speed, optimize_evs |
|
|
39
|
+
| `analyze_team` | Team analysis | synergy, diagnose |
|
|
40
|
+
| `optimize_team` | Fill open team slots against constraints | — |
|
|
41
|
+
| `prepare_matchup` | Pre-game dossier: likely sets, speed races, damage rolls, exhaustive bring-four with alternates, scored leads, win/loss conditions | — |
|
|
42
|
+
| `analyze_battle` | Post-game and scouting | replay, infer |
|
|
43
|
+
| `analyze_meta` | The meta, measured | threats, compare, set |
|
|
44
|
+
| `team_io` | Team import/export and validation | parse, format, legality, regulation, regulations |
|
|
86
45
|
|
|
87
46
|
## Install
|
|
88
47
|
|
|
@@ -179,14 +138,14 @@ npm test # builds and drives every tool over real MCP stdio, plus the HTTP ent
|
|
|
179
138
|
|
|
180
139
|
## Example queries
|
|
181
140
|
|
|
182
|
-
- `
|
|
183
|
-
- `
|
|
184
|
-
- `
|
|
185
|
-
- `
|
|
186
|
-
- `
|
|
187
|
-
- `analyze_team` `{ "team": [ { "species": "Garchomp", "moves": ["Earthquake", "Dragon Claw", "Rock Slide"] } ], "regulation": "m-c" }`
|
|
188
|
-
- `
|
|
189
|
-
- `
|
|
141
|
+
- `lookup` `{ "mode": "species", "species": "Ogerpon-Wellspring" }`
|
|
142
|
+
- `lookup` `{ "mode": "matchup", "attacker": "Ice", "defender": "Garchomp" }` → 4x super effective
|
|
143
|
+
- `calculate` `{ "mode": "stats", "species": "Garchomp", "level": 50, "nature": "Jolly", "evs": { "atk": 252, "spe": 252 } }`
|
|
144
|
+
- `calculate` `{ "mode": "damage", "attacker": { "species": "Garchomp", "level": 50, "nature": "Jolly", "evs": { "atk": 252, "spe": 252 }, "item": "Choice Band" }, "defender": { "species": "Corviknight", "level": 50, "nature": "Impish", "evs": { "hp": 252, "def": 252 } }, "move": "Dragon Claw" }`
|
|
145
|
+
- `team_io` `{ "mode": "legality", "regulation": "m-c", "team": [ { "species": "Garchomp", "item": "Choice Band" } ] }`
|
|
146
|
+
- `analyze_team` `{ "mode": "synergy", "team": [ { "species": "Garchomp", "moves": ["Earthquake", "Dragon Claw", "Rock Slide"] } ], "regulation": "m-c" }`
|
|
147
|
+
- `team_io` `{ "mode": "parse", "text": "Garchomp @ Choice Scarf | Rough Skin | Jolly | 252 Atk / 252 Spe | Earthquake / Dragon Claw" }`
|
|
148
|
+
- `analyze_team` `{ "mode": "diagnose", "team": [ { "species": "Garchomp", "nature": "Jolly", "evs": { "atk": 252, "spe": 252 } } ], "goal": "improve against the current meta" }`
|
|
190
149
|
- `prepare_matchup` `{ "team": [ { "species": "Garchomp" } ], "opponent": ["Sneasler", "Salamence-Mega", "Gholdengo"] }`
|
|
191
150
|
|
|
192
151
|
## Data freshness
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MatchupEvaluator: one reusable definition of what constitutes an actual
|
|
3
|
+
* competitive answer. "Has a super-effective move" is not an answer; this
|
|
4
|
+
* engine runs the real math both directions — each side's hardest hit and
|
|
5
|
+
* damage range, level-50 Speed with priority taken into account, and a
|
|
6
|
+
* conservative turn simulation — and classifies the matchup.
|
|
7
|
+
*
|
|
8
|
+
* Determinism contract: the classification never consults a random roll. Our
|
|
9
|
+
* side is always simulated with its minimum roll and their side with its
|
|
10
|
+
* maximum, so a classification of HARD_ANSWER or SOFT_ANSWER is a worst-case
|
|
11
|
+
* guarantee, and SPEED_DEPENDENT/TRADE mean exactly that order or rolls can
|
|
12
|
+
* flip the result.
|
|
13
|
+
*/
|
|
14
|
+
import { getChampionsDex } from './champions.js';
|
|
15
|
+
import { damageResult, finalStat, typeEffectiveness } from './dex.js';
|
|
16
|
+
/** Better answers rank lower; shared by every consumer that picks the best member. */
|
|
17
|
+
export const ANSWER_CLASS_RANK = {
|
|
18
|
+
HARD_ANSWER: 0,
|
|
19
|
+
SOFT_ANSWER: 1,
|
|
20
|
+
REVENGE: 2,
|
|
21
|
+
SPEED_DEPENDENT: 3,
|
|
22
|
+
TRADE: 4,
|
|
23
|
+
UNFAVORABLE: 5,
|
|
24
|
+
UNKNOWN: 6,
|
|
25
|
+
};
|
|
26
|
+
/** Strongest hit one side has into the other's typing, by eff x power x STAB. */
|
|
27
|
+
function bestMove(dex, side, targetTypes) {
|
|
28
|
+
let best = null;
|
|
29
|
+
for (const mv of side.moves ?? []) {
|
|
30
|
+
const m = dex.moves.get(mv);
|
|
31
|
+
if (!m.exists || !(m.basePower || 0))
|
|
32
|
+
continue;
|
|
33
|
+
const eff = typeEffectiveness(m.type, targetTypes, 9);
|
|
34
|
+
if (eff === 0)
|
|
35
|
+
continue;
|
|
36
|
+
const stab = dex.species.get(side.species).types.includes(m.type) ? 1.5 : 1;
|
|
37
|
+
const score = eff * m.basePower * stab;
|
|
38
|
+
if (!best || score > best.score)
|
|
39
|
+
best = { name: m.name, score, priority: m.priority ?? 0 };
|
|
40
|
+
}
|
|
41
|
+
return best ? { name: best.name, priority: best.priority } : null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Conservative two-hit race simulation: our minimum roll against their maximum,
|
|
45
|
+
* alternating by Speed unless priority intervenes. Returns whether we win and
|
|
46
|
+
* the share of our HP left in the worst case.
|
|
47
|
+
*/
|
|
48
|
+
function simulateRace(ourMove, theirMove, ourRange, theirRange, ourHp, theirHp, ourPriority, theirPriority, weMoveFirst) {
|
|
49
|
+
let usHp = ourHp;
|
|
50
|
+
let themHp = theirHp;
|
|
51
|
+
// Conservative rolls: our worst, their best.
|
|
52
|
+
const ourHit = ourRange[0];
|
|
53
|
+
const theirHit = theirRange[1];
|
|
54
|
+
let turn = 0;
|
|
55
|
+
while (usHp > 0 && themHp > 0 && turn < 12) {
|
|
56
|
+
turn++;
|
|
57
|
+
const ourTurn = ourPriority !== theirPriority
|
|
58
|
+
? ourPriority > theirPriority
|
|
59
|
+
: weMoveFirst
|
|
60
|
+
? turn % 2 === 1
|
|
61
|
+
: turn % 2 === 0;
|
|
62
|
+
if (ourTurn) {
|
|
63
|
+
themHp -= ourHit;
|
|
64
|
+
if (themHp <= 0)
|
|
65
|
+
return { weWin: true, hpLeftPct: (usHp / ourHp) * 100 };
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
usHp -= theirHit;
|
|
69
|
+
if (usHp <= 0)
|
|
70
|
+
return { weWin: false, hpLeftPct: (usHp / ourHp) * 100 };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 12 turns without a faint: effectively unwinnable by damage.
|
|
74
|
+
return { weWin: false, hpLeftPct: (usHp / ourHp) * 100 };
|
|
75
|
+
}
|
|
76
|
+
/** True when the side has at least one damaging move that is not fully resisted or immune into the target. */
|
|
77
|
+
function canHit(dex, side, targetTypes) {
|
|
78
|
+
for (const mv of side.moves ?? []) {
|
|
79
|
+
const m = dex.moves.get(mv);
|
|
80
|
+
if (m.exists && (m.basePower || 0) && typeEffectiveness(m.type, targetTypes, 9) > 0)
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Classify the matchup between two sets. Both sides must carry at least one
|
|
87
|
+
* usable damaging move, else the class is UNKNOWN — a type chart is not a
|
|
88
|
+
* battle.
|
|
89
|
+
*/
|
|
90
|
+
export function evaluateMatchup(us, them) {
|
|
91
|
+
const dex = getChampionsDex();
|
|
92
|
+
const usSp = dex.species.get(us.species);
|
|
93
|
+
const themSp = dex.species.get(them.species);
|
|
94
|
+
const ourMove = bestMove(dex, us, themSp.types);
|
|
95
|
+
const theirMove = bestMove(dex, them, usSp.types);
|
|
96
|
+
const speed = (side, sp) => {
|
|
97
|
+
const nature = side.nature ?? 'Serious';
|
|
98
|
+
const evs = side.championsPoints
|
|
99
|
+
? Object.fromEntries(Object.entries(side.championsPoints).map(([k, v]) => [k, v * 8]))
|
|
100
|
+
: (side.evs ?? {});
|
|
101
|
+
let s = finalStat(9, 'spe', sp.baseStats.spe, 31, evs.spe ?? 0, 50, nature);
|
|
102
|
+
if (side.item === 'Choice Scarf')
|
|
103
|
+
s = Math.floor(s * 1.5);
|
|
104
|
+
return s;
|
|
105
|
+
};
|
|
106
|
+
const ourSpeed = speed(us, usSp);
|
|
107
|
+
const theirSpeed = speed(them, themSp);
|
|
108
|
+
const weMoveFirst = ourSpeed >= theirSpeed;
|
|
109
|
+
const empty = {
|
|
110
|
+
ourBest: null,
|
|
111
|
+
theirBest: null,
|
|
112
|
+
speed: { ours: ourSpeed, theirs: theirSpeed, weMoveFirst },
|
|
113
|
+
};
|
|
114
|
+
if (!ourMove || !theirMove) {
|
|
115
|
+
const weBlocked = !ourMove && !!us.moves?.length && !canHit(dex, us, themSp.types);
|
|
116
|
+
const theyBlocked = !theirMove && !!them.moves?.length && !canHit(dex, them, usSp.types);
|
|
117
|
+
if (weBlocked || theyBlocked) {
|
|
118
|
+
return {
|
|
119
|
+
...empty,
|
|
120
|
+
answerClass: 'UNFAVORABLE',
|
|
121
|
+
reason: weBlocked
|
|
122
|
+
? `every damaging move ${us.species} knows is resisted or immune into ${them.species}\u2019s typing.`
|
|
123
|
+
: `every damaging move ${them.species} knows is resisted or immune into ${us.species}\u2019s typing.`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
...empty,
|
|
128
|
+
answerClass: 'UNKNOWN',
|
|
129
|
+
reason: !ourMove ? `no damaging move known for ${us.species}` : `no damaging move known for ${them.species}`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const ourRes = damageResult(9, { species: us.species, level: 50, nature: us.nature, evs: us.evs, championsPoints: us.championsPoints, item: us.item, ability: us.ability, moves: [ourMove.name] }, { species: them.species, level: 50, nature: them.nature, evs: them.evs, championsPoints: them.championsPoints, item: them.item, ability: them.ability, moves: them.moves }, ourMove.name);
|
|
133
|
+
const theirRes = damageResult(9, { species: them.species, level: 50, nature: them.nature, evs: them.evs, championsPoints: them.championsPoints, item: them.item, ability: them.ability, moves: [theirMove.name] }, { species: us.species, level: 50, nature: us.nature, evs: us.evs, championsPoints: us.championsPoints, item: us.item, ability: us.ability, moves: us.moves }, theirMove.name);
|
|
134
|
+
const ourHp = ourRes.attacker.stats.hp;
|
|
135
|
+
const theirHp = theirRes.attacker.stats.hp;
|
|
136
|
+
const ourRange = ourRes.damageRange;
|
|
137
|
+
const theirRange = theirRes.damageRange;
|
|
138
|
+
const base = {
|
|
139
|
+
ourBest: { move: ourMove.name, damageRange: ourRange, koChance: ourRes.koChance },
|
|
140
|
+
theirBest: { move: theirMove.name, damageRange: theirRange, koChance: theirRes.koChance },
|
|
141
|
+
speed: { ours: ourSpeed, theirs: theirSpeed, weMoveFirst },
|
|
142
|
+
};
|
|
143
|
+
const ourReliableKO = ourRange[0] >= theirHp;
|
|
144
|
+
const theirReliableKO = theirRange[0] >= ourHp;
|
|
145
|
+
const theirPossibleKO = theirRange[1] >= ourHp;
|
|
146
|
+
if (ourReliableKO && theirReliableKO) {
|
|
147
|
+
return {
|
|
148
|
+
...base,
|
|
149
|
+
answerClass: weMoveFirst ? 'REVENGE' : 'UNFAVORABLE',
|
|
150
|
+
reason: `both sides one-shot the other; ${weMoveFirst ? `we move first (${ourSpeed} vs ${theirSpeed}), so we win on initiative only and cannot switch in` : `they move first (${theirSpeed} vs ${ourSpeed})`}.`,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (ourReliableKO) {
|
|
154
|
+
if (theirPossibleKO && !weMoveFirst) {
|
|
155
|
+
return {
|
|
156
|
+
...base,
|
|
157
|
+
answerClass: 'TRADE',
|
|
158
|
+
reason: `we one-shot reliably but move second; their best roll (${theirRange[1]} of ${ourHp}) can one-shot us, so the result rides on their roll.`,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
...base,
|
|
163
|
+
answerClass: 'HARD_ANSWER',
|
|
164
|
+
reason: `we one-shot (${ourRange[0]}-${ourRange[1]} of ${theirHp})${theirPossibleKO ? ' and move first' : ' and survive their best hit'}.`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (theirReliableKO) {
|
|
168
|
+
return {
|
|
169
|
+
...base,
|
|
170
|
+
answerClass: 'UNFAVORABLE',
|
|
171
|
+
reason: `they one-shot us (${theirRange[0]}-${theirRange[1]} of ${ourHp}) and our best hit does not one-shot back.`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// Neither side one-shots: the two-hit race, simulated conservatively, and
|
|
175
|
+
// re-simulated with the order flipped to see whether speed decides it.
|
|
176
|
+
const worstCase = simulateRace(ourMove.name, theirMove.name, ourRange, theirRange, ourHp, theirHp, ourMove.priority, theirMove.priority, weMoveFirst);
|
|
177
|
+
const flipped = simulateRace(ourMove.name, theirMove.name, ourRange, theirRange, ourHp, theirHp, ourMove.priority, theirMove.priority, !weMoveFirst);
|
|
178
|
+
if (worstCase.weWin && flipped.weWin) {
|
|
179
|
+
return {
|
|
180
|
+
...base,
|
|
181
|
+
answerClass: worstCase.hpLeftPct >= 50 ? 'HARD_ANSWER' : 'SOFT_ANSWER',
|
|
182
|
+
reason: worstCase.hpLeftPct >= 50
|
|
183
|
+
? `we win the exchange regardless of turn order, finishing above half HP (${worstCase.hpLeftPct.toFixed(0)}%).`
|
|
184
|
+
: `we win the exchange regardless of turn order, but finish at ${worstCase.hpLeftPct.toFixed(0)}% HP against their best rolls.`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (worstCase.weWin !== flipped.weWin) {
|
|
188
|
+
return {
|
|
189
|
+
...base,
|
|
190
|
+
answerClass: 'SPEED_DEPENDENT',
|
|
191
|
+
reason: `the winner flips with turn order: both sides need at least two hits, and ${weMoveFirst ? `we move first (${ourSpeed} vs ${theirSpeed})` : `they move first (${theirSpeed} vs ${ourSpeed})`}.`,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
...base,
|
|
196
|
+
answerClass: 'UNFAVORABLE',
|
|
197
|
+
reason: `they win the exchange on both orderings; our best is ${ourRange[0]}-${ourRange[1]} of ${theirHp}, theirs ${theirRange[0]}-${theirRange[1]} of ${ourHp}.`,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../src/evaluator.ts"],"names":[],"mappings":"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"}
|
package/dist/prompts.js
CHANGED
|
@@ -15,7 +15,7 @@ const teamArg = z
|
|
|
15
15
|
.string()
|
|
16
16
|
.optional()
|
|
17
17
|
.describe('The team as paste text (Showdown format, or plain lines); omitted, the workflow asks for it.');
|
|
18
|
-
const goalArg = z.string().optional().describe('What the player wants out of the change, carried into
|
|
18
|
+
const goalArg = z.string().optional().describe('What the player wants out of the change, carried into analyze_team mode "diagnose".');
|
|
19
19
|
export function registerPrompts(server) {
|
|
20
20
|
server.registerPrompt('team-doctor', {
|
|
21
21
|
title: 'Team Doctor',
|
|
@@ -32,10 +32,10 @@ export function registerPrompts(server) {
|
|
|
32
32
|
${args.team ? `Their team (paste text):\n\n${args.team}\n` : 'Ask the user to paste their team first.'}
|
|
33
33
|
|
|
34
34
|
Then, in order:
|
|
35
|
-
1. Run
|
|
36
|
-
2. Run
|
|
37
|
-
3. Walk through the problems with their evidence, then the candidate changes with their math. Say plainly which changes are exact (spread, move) and which are typing-only heuristics (member swaps) —
|
|
38
|
-
4. If you propose a changed team, run
|
|
35
|
+
1. Run team_io with mode "parse" on the paste (with the regulation) and surface every warning it returns — a name that did not resolve is a fixable typo, not a dead end.
|
|
36
|
+
2. Run analyze_team with mode "synergy" with mode "diagnose" on the parsed team, passing the goal and any members the user wants kept.
|
|
37
|
+
3. Walk through the problems with their evidence, then the candidate changes with their math. Say plainly which changes are exact (spread, move) and which are typing-only heuristics (member swaps) — analyze_team with mode "synergy" with mode "diagnose" labels the confidence, repeat it.
|
|
38
|
+
4. If you propose a changed team, run team_io with mode "format" on it so the user can copy the paste straight into the game.
|
|
39
39
|
|
|
40
40
|
Every claim must come from the tools\u2019 output. You explain; getcompetitive proves.`,
|
|
41
41
|
},
|
|
@@ -64,7 +64,7 @@ ${args.team ? `Their team:\n\n${args.team}\n` : 'Ask the user for their team fir
|
|
|
64
64
|
${args.opponent ? `What they know about the opponent:\n\n${args.opponent}\n` : 'Ask the user what they know about the opponent (species at minimum).'}
|
|
65
65
|
|
|
66
66
|
Then, in order:
|
|
67
|
-
1.
|
|
67
|
+
1. team_io with mode "parse" on any paste text. If the opponent is just species names, that is fine — pass them to prepare_matchup as the opponent array; it estimates what it cannot know and says so.
|
|
68
68
|
2. Run prepare_matchup with the team, the opponent, and ${args.regulation ?? 'the current regulation'}.
|
|
69
69
|
3. Deliver the dossier in plain language: their likely sets ordered by usage, the speed races that matter, the key damage rolls (quote the description lines), the recommended bring-four and why, leads to open with and watch for, win/loss conditions, and which of the user\u2019s members to preserve.
|
|
70
70
|
4. End with the matchupConfidence read and what it can and cannot see.
|
|
@@ -93,10 +93,10 @@ Every number comes from prepare_matchup\u2019s output — you explain; getcompet
|
|
|
93
93
|
text: `Act as a Pokémon Champions teambuilder. Build a team around ${args.core ?? 'the species the user names (ask them first)'} for ${args.regulation ?? 'the current regulation set'}.
|
|
94
94
|
|
|
95
95
|
Workflow:
|
|
96
|
-
1.
|
|
97
|
-
2. Run analyze_team on the partial team to see the defensive weaknesses and the types nothing hits super-effectively — those are the gaps the remaining slots must fill.
|
|
98
|
-
3. Run
|
|
99
|
-
4. Assemble six members, run
|
|
96
|
+
1. analyze_meta with mode "set" on the core species (batched if several) so the core is built from what the meta actually plays.
|
|
97
|
+
2. Run analyze_team with mode "synergy" on the partial team to see the defensive weaknesses and the types nothing hits super-effectively — those are the gaps the remaining slots must fill.
|
|
98
|
+
3. Run analyze_team with mode "diagnose" on the partial team and mine its candidate changes (member swaps and move changes) for gap-filling partners; prefer partners the meta has usage data for (analyze_meta with mode "threats"), and say when a pick is typing-only.
|
|
99
|
+
4. Assemble six members, run team_io with mode "legality" against the regulation, then team_io with mode "format" the finished squad so the user can paste it.
|
|
100
100
|
|
|
101
101
|
Explain each pick with its evidence (coverage, speed, or usage). You design; getcompetitive proves the picks.`,
|
|
102
102
|
},
|
|
@@ -116,11 +116,11 @@ Explain each pick with its evidence (coverage, speed, or usage). You design; get
|
|
|
116
116
|
text: `Act as a Pokémon Champions tournament coach. Prepare the user for an event under ${args.regulation ?? 'the current regulation set'}.
|
|
117
117
|
|
|
118
118
|
Workflow:
|
|
119
|
-
1.
|
|
120
|
-
2.
|
|
119
|
+
1. team_io with mode "regulation" for the rules that shape the format: clauses, timers, bring 4 of 6, Mega rules. (Skip includeRoster unless a full legal list is actually wanted.)
|
|
120
|
+
2. analyze_meta with mode "threats" for the regulation and analyze_meta with mode "set" (batched) on the top threats so their real sets are in front of you.
|
|
121
121
|
3. Produce a tournament-prep briefing: the meta snapshot (top threats with usage, tier bands), what each top threat does, and a preparation checklist — answers for the top threats, a speed plan, and a bring-four habit.
|
|
122
122
|
|
|
123
|
-
Numbers only from the tools; the sample size and sourceAsOf from
|
|
123
|
+
Numbers only from the tools; the sample size and sourceAsOf from analyze_meta with mode "threats" are part of the briefing, not an afterthought.`,
|
|
124
124
|
},
|
|
125
125
|
},
|
|
126
126
|
],
|
|
@@ -139,10 +139,10 @@ Numbers only from the tools; the sample size and sourceAsOf from list_threats ar
|
|
|
139
139
|
${args.team ? `Their team:\n\n${args.team}\n` : 'Ask the user to paste their team first.'}
|
|
140
140
|
|
|
141
141
|
Workflow:
|
|
142
|
-
1.
|
|
143
|
-
2. analyze_team for the synergy read: stacked weaknesses, coverage gaps, speed placement, and the score.
|
|
144
|
-
3.
|
|
145
|
-
4. For each member:
|
|
142
|
+
1. team_io with mode "parse" on the paste.
|
|
143
|
+
2. analyze_team with mode "synergy" for the synergy read: stacked weaknesses, coverage gaps, speed placement, and the score.
|
|
144
|
+
3. analyze_team with mode "synergy" with mode "diagnose" for what it would change, so the guide includes the holes.
|
|
145
|
+
4. For each member: analyze_meta with mode "set" if the species is ranked (batched across the team), else lookup with mode "species" plus lookup with mode "learnset" highlights.
|
|
146
146
|
|
|
147
147
|
Deliver a team guide: each member\u2019s role, the pairs and synergies between them, the holes a future change should fill, and a one-paragraph game plan. Every factual claim cites a tool\u2019s output.`,
|
|
148
148
|
},
|
|
@@ -162,8 +162,8 @@ Deliver a team guide: each member\u2019s role, the pairs and synergies between t
|
|
|
162
162
|
text: `Act as a Pokémon Champions metagame reporter. Produce the meta report for ${args.regulation ?? 'the current regulation set'}.
|
|
163
163
|
|
|
164
164
|
Workflow:
|
|
165
|
-
1.
|
|
166
|
-
2.
|
|
165
|
+
1. analyze_meta with mode "threats" for the usage ranking, tiers and the sample behind it.
|
|
166
|
+
2. analyze_meta with mode "set" (batched) on the top five threats for their real sets.
|
|
167
167
|
3. Write the report: the tier bands with usage shares, each top threat\u2019s standard set and what it does, and a closing read of what the meta rewards. State the list\u2019s sourceAsOf and sample size so the reader knows how current the numbers are.
|
|
168
168
|
|
|
169
169
|
The report is data journalism: every figure quoted comes from the tools, and the data date travels with it.`,
|
package/dist/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,aAAa,GAAG,CAAC;KACpB,MAAM,EAAE;KACR,QAAQ,EAAE;KACV,QAAQ,CAAC,sFAAsF,CAAC,CAAC;AACpG,MAAM,OAAO,GAAG,CAAC;KACd,MAAM,EAAE;KACR,QAAQ,EAAE;KACV,QAAQ,CAAC,8FAA8F,CAAC,CAAC;AAC5G,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -5,37 +5,15 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync } from 'node:fs';
|
|
7
7
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
-
import { registerDataTools } from './tools/data.js';
|
|
9
|
-
import { registerCalcTools } from './tools/calc.js';
|
|
10
|
-
import { registerRegulationTools } from './tools/regulations.js';
|
|
11
|
-
import { registerAnalyzeTools } from './tools/analyze.js';
|
|
12
|
-
import { registerMetaTools } from './tools/meta.js';
|
|
13
|
-
import { registerTeamTools } from './tools/team.js';
|
|
14
|
-
import { registerDoctorTool } from './tools/doctor.js';
|
|
15
|
-
import { registerMatchupTool } from './tools/matchup.js';
|
|
16
|
-
import { registerSpritesTool } from './tools/sprites.js';
|
|
17
|
-
import { registerReplayTool } from './tools/replay.js';
|
|
18
|
-
import { registerInferTool } from './tools/infer.js';
|
|
19
|
-
import { registerOptimizeTeamTool } from './tools/optimize.js';
|
|
20
8
|
import { registerPrompts } from './prompts.js';
|
|
9
|
+
import { registerCompoundTools } from './tools/compound.js';
|
|
21
10
|
export const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
22
11
|
export function buildServer() {
|
|
23
12
|
const server = new McpServer({
|
|
24
13
|
name: 'getcompetitive',
|
|
25
14
|
version: VERSION,
|
|
26
15
|
});
|
|
27
|
-
|
|
28
|
-
registerCalcTools(server);
|
|
29
|
-
registerRegulationTools(server);
|
|
30
|
-
registerAnalyzeTools(server);
|
|
31
|
-
registerMetaTools(server);
|
|
32
|
-
registerTeamTools(server);
|
|
33
|
-
registerDoctorTool(server);
|
|
34
|
-
registerMatchupTool(server);
|
|
35
|
-
registerSpritesTool(server);
|
|
36
|
-
registerReplayTool(server);
|
|
37
|
-
registerInferTool(server);
|
|
38
|
-
registerOptimizeTeamTool(server);
|
|
16
|
+
registerCompoundTools(server);
|
|
39
17
|
registerPrompts(server);
|
|
40
18
|
return server;
|
|
41
19
|
}
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,CAAC,MAAM,OAAO,GAClB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC7E,CAAC,OAAO,CAAC;AAEV,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/tools/analyze.js
CHANGED
|
@@ -9,6 +9,7 @@ import { getChampionsDex } from '../champions.js';
|
|
|
9
9
|
import { getRegulationSet } from '../regulations.js';
|
|
10
10
|
import { getThreatList } from '../threats.js';
|
|
11
11
|
import { ok, wrap, requireExists, READ_ONLY_ANNOTATIONS } from '../result.js';
|
|
12
|
+
import { evaluateMatchup, ANSWER_CLASS_RANK } from '../evaluator.js';
|
|
12
13
|
import { evMap, championsPointsMap } from './schemas.js';
|
|
13
14
|
/** One member's score against a known opponent; shared by `picks` and `leftBehind`. */
|
|
14
15
|
const bringCandidate = z.object({
|
|
@@ -192,6 +193,11 @@ export function registerAnalyzeTools(server) {
|
|
|
192
193
|
hitBy: z.string().optional().describe('The member providing that best hit; absent when nothing hits it super-effectively.'),
|
|
193
194
|
hitVia: z.string().optional().describe('The attacking type providing it; absent when nothing hits it super-effectively.'),
|
|
194
195
|
answered: z.boolean().describe('True when the team has a super-effective (\u22652x) hit on it.'),
|
|
196
|
+
answerClass: z
|
|
197
|
+
.enum(['HARD_ANSWER', 'SOFT_ANSWER', 'REVENGE', 'SPEED_DEPENDENT', 'TRADE', 'UNFAVORABLE', 'UNKNOWN'])
|
|
198
|
+
.optional()
|
|
199
|
+
.describe('The shared MatchupEvaluator\u2019s verdict from real damage ranges and Speed, when at least one member supplied moves: HARD_ANSWER and SOFT_ANSWER win the exchange, REVENGE wins only on initiative, SPEED_DEPENDENT and TRADE ride on order or rolls, UNFAVORABLE loses it. Absent when no member listed moves \u2014 the type-based fields above are all there is.'),
|
|
200
|
+
answerBy: z.string().optional().describe('The member that earns the best `answerClass`; present with it.'),
|
|
195
201
|
})).describe('One entry per threat in the regulation\u2019s list, most used first.'),
|
|
196
202
|
unanswered: z.array(z.string()).describe('Threats with no super-effective hit from this team \u2014 the coverage holes to fix first.'),
|
|
197
203
|
unansweredCount: z.number().int().describe('How many threats are unanswered.'),
|
|
@@ -338,6 +344,32 @@ export function registerAnalyzeTools(server) {
|
|
|
338
344
|
}
|
|
339
345
|
}
|
|
340
346
|
const multiplier = best?.multiplier ?? 0;
|
|
347
|
+
// Where a member supplied real moves, run the shared MatchupEvaluator:
|
|
348
|
+
// damage ranges and Speed decide what an answer actually is, instead
|
|
349
|
+
// of the type multiplier alone.
|
|
350
|
+
let answerClass;
|
|
351
|
+
let answerBy;
|
|
352
|
+
for (const entry of args.team.filter((e) => e.moves?.length)) {
|
|
353
|
+
const result = evaluateMatchup({
|
|
354
|
+
species: entry.species,
|
|
355
|
+
...(entry.item ? { item: entry.item } : {}),
|
|
356
|
+
...(entry.nature ? { nature: entry.nature } : {}),
|
|
357
|
+
...(entry.evs ? { evs: entry.evs } : {}),
|
|
358
|
+
...(entry.championsPoints ? { championsPoints: entry.championsPoints } : {}),
|
|
359
|
+
moves: entry.moves,
|
|
360
|
+
}, {
|
|
361
|
+
species: form,
|
|
362
|
+
item: threat.item,
|
|
363
|
+
ability: threat.ability,
|
|
364
|
+
nature: threat.nature,
|
|
365
|
+
...(threat.evs ? { evs: threat.evs } : {}),
|
|
366
|
+
moves: threat.moves,
|
|
367
|
+
});
|
|
368
|
+
if (!answerClass || ANSWER_CLASS_RANK[result.answerClass] < ANSWER_CLASS_RANK[answerClass]) {
|
|
369
|
+
answerClass = result.answerClass;
|
|
370
|
+
answerBy = entry.species;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
341
373
|
return {
|
|
342
374
|
species: form,
|
|
343
375
|
usage: threat.usage,
|
|
@@ -346,6 +378,7 @@ export function registerAnalyzeTools(server) {
|
|
|
346
378
|
hitMultiplier: multiplier,
|
|
347
379
|
...(multiplier > 1 && best ? { hitBy: best.member, hitVia: best.via } : {}),
|
|
348
380
|
answered: multiplier >= 2,
|
|
381
|
+
...(answerClass ? { answerClass, answerBy } : {}),
|
|
349
382
|
};
|
|
350
383
|
});
|
|
351
384
|
const unanswered = threatCoverage?.filter((t) => !t.answered).map((t) => t.species) ?? [];
|