warhammer-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/README.md +147 -0
- package/dist/data/keywords.d.ts +3 -0
- package/dist/data/keywords.d.ts.map +1 -0
- package/dist/data/keywords.js +193 -0
- package/dist/data/keywords.js.map +1 -0
- package/dist/data/kill-team-operatives.d.ts +3 -0
- package/dist/data/kill-team-operatives.d.ts.map +1 -0
- package/dist/data/kill-team-operatives.js +24956 -0
- package/dist/data/kill-team-operatives.js.map +1 -0
- package/dist/data/kill-team-rules.d.ts +5 -0
- package/dist/data/kill-team-rules.d.ts.map +1 -0
- package/dist/data/kill-team-rules.js +94 -0
- package/dist/data/kill-team-rules.js.map +1 -0
- package/dist/data/phases.d.ts +3 -0
- package/dist/data/phases.d.ts.map +1 -0
- package/dist/data/phases.js +232 -0
- package/dist/data/phases.js.map +1 -0
- package/dist/data/rules.d.ts +5 -0
- package/dist/data/rules.d.ts.map +1 -0
- package/dist/data/rules.js +138 -0
- package/dist/data/rules.js.map +1 -0
- package/dist/data/units.d.ts +3 -0
- package/dist/data/units.d.ts.map +1 -0
- package/dist/data/units.js +222240 -0
- package/dist/data/units.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/search.d.ts +2 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +14 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/xml-parser.d.ts +28 -0
- package/dist/lib/xml-parser.d.ts.map +1 -0
- package/dist/lib/xml-parser.js +411 -0
- package/dist/lib/xml-parser.js.map +1 -0
- package/dist/lib/xml-parser.test.d.ts +2 -0
- package/dist/lib/xml-parser.test.d.ts.map +1 -0
- package/dist/lib/xml-parser.test.js +202 -0
- package/dist/lib/xml-parser.test.js.map +1 -0
- package/dist/register-tools.d.ts +3 -0
- package/dist/register-tools.d.ts.map +1 -0
- package/dist/register-tools.js +15 -0
- package/dist/register-tools.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +11 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/compare-units.d.ts +3 -0
- package/dist/tools/compare-units.d.ts.map +1 -0
- package/dist/tools/compare-units.js +191 -0
- package/dist/tools/compare-units.js.map +1 -0
- package/dist/tools/game-flow.d.ts +3 -0
- package/dist/tools/game-flow.d.ts.map +1 -0
- package/dist/tools/game-flow.js +119 -0
- package/dist/tools/game-flow.js.map +1 -0
- package/dist/tools/lookup-keyword.d.ts +3 -0
- package/dist/tools/lookup-keyword.d.ts.map +1 -0
- package/dist/tools/lookup-keyword.js +84 -0
- package/dist/tools/lookup-keyword.js.map +1 -0
- package/dist/tools/lookup-phase.d.ts +3 -0
- package/dist/tools/lookup-phase.d.ts.map +1 -0
- package/dist/tools/lookup-phase.js +74 -0
- package/dist/tools/lookup-phase.js.map +1 -0
- package/dist/tools/lookup-unit.d.ts +3 -0
- package/dist/tools/lookup-unit.d.ts.map +1 -0
- package/dist/tools/lookup-unit.js +175 -0
- package/dist/tools/lookup-unit.js.map +1 -0
- package/dist/tools/search-units.d.ts +3 -0
- package/dist/tools/search-units.d.ts.map +1 -0
- package/dist/tools/search-units.js +108 -0
- package/dist/tools/search-units.js.map +1 -0
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { KEYWORDS } from "../data/keywords.js";
|
|
3
|
+
import { SHARED_RULES } from "../data/rules.js";
|
|
4
|
+
import { fuzzySearch } from "../lib/search.js";
|
|
5
|
+
function formatCuratedKeyword(kw) {
|
|
6
|
+
const sections = [];
|
|
7
|
+
sections.push(`# ${kw.name}`);
|
|
8
|
+
sections.push(`**Game Modes:** ${kw.gameModes.join(", ")}`);
|
|
9
|
+
sections.push(`## Official Definition\n\n${kw.description}`);
|
|
10
|
+
sections.push(`## Plain English\n\n${kw.plainEnglish}`);
|
|
11
|
+
if (kw.examples && kw.examples.length > 0) {
|
|
12
|
+
const exampleLines = kw.examples.map((e) => `- ${e}`);
|
|
13
|
+
sections.push(`## Examples\n\n${exampleLines.join("\n")}`);
|
|
14
|
+
}
|
|
15
|
+
return sections.join("\n\n");
|
|
16
|
+
}
|
|
17
|
+
function formatSharedRule(rule) {
|
|
18
|
+
const sections = [];
|
|
19
|
+
sections.push(`# ${rule.name}`);
|
|
20
|
+
sections.push(`*Source: rules data (BSData). A curated plain-English explanation is not yet available for this keyword.*`);
|
|
21
|
+
sections.push(`## Definition\n\n${rule.description}`);
|
|
22
|
+
return sections.join("\n\n");
|
|
23
|
+
}
|
|
24
|
+
export function registerLookupKeyword(server) {
|
|
25
|
+
server.tool("lookup_keyword", "Look up a Warhammer 40K keyword or rule. Returns the official definition, a plain English explanation, examples, and applicable game modes.", {
|
|
26
|
+
keyword: z
|
|
27
|
+
.string()
|
|
28
|
+
.describe("Name or partial name of the keyword to look up (e.g. 'Devastating Wounds', 'Feel No Pain')"),
|
|
29
|
+
game_mode: z
|
|
30
|
+
.enum(["40k", "combat_patrol", "kill_team"])
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Optional game mode filter — only show keywords applicable to this mode"),
|
|
33
|
+
}, async ({ keyword, game_mode }) => {
|
|
34
|
+
// 1. Search curated KEYWORDS first (fuzzy match on name)
|
|
35
|
+
const allCuratedMatches = fuzzySearch(KEYWORDS, keyword, ["name"]);
|
|
36
|
+
if (allCuratedMatches.length > 0) {
|
|
37
|
+
// Apply game_mode filter if provided
|
|
38
|
+
const filtered = game_mode
|
|
39
|
+
? allCuratedMatches.filter((kw) => kw.gameModes.includes(game_mode))
|
|
40
|
+
: allCuratedMatches;
|
|
41
|
+
if (filtered.length > 0) {
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: formatCuratedKeyword(filtered[0]),
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Keyword exists in curated list but not for this game mode
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: `Keyword "${keyword}" was found but is not applicable to ${game_mode}.\n\nIt applies to: ${allCuratedMatches[0].gameModes.join(", ")}.`,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// 2. Fall back to SHARED_RULES (no game_mode filter — rules data doesn't have mode info)
|
|
62
|
+
const ruleMatches = fuzzySearch(SHARED_RULES, keyword, ["name"]);
|
|
63
|
+
if (ruleMatches.length > 0) {
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: formatSharedRule(ruleMatches[0]),
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// 3. Not found anywhere
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: "text",
|
|
78
|
+
text: `Keyword "${keyword}" not found in the curated keywords or rules data.\n\nTry a different spelling or a partial name. Some keywords include: Devastating Wounds, Lethal Hits, Feel No Pain, Deep Strike, Invulnerable Save.`,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=lookup-keyword.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup-keyword.js","sourceRoot":"","sources":["../../src/tools/lookup-keyword.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup-phase.d.ts","sourceRoot":"","sources":["../../src/tools/lookup-phase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqDpE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0C3D"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { TURN_SEQUENCES } from "../data/phases.js";
|
|
3
|
+
function findPhase(phaseName, gameMode) {
|
|
4
|
+
const sequence = TURN_SEQUENCES.find((s) => s.gameMode === gameMode);
|
|
5
|
+
if (!sequence)
|
|
6
|
+
return undefined;
|
|
7
|
+
const lowerName = phaseName.toLowerCase();
|
|
8
|
+
// Exact match first (case insensitive)
|
|
9
|
+
const exact = sequence.phases.find((p) => p.name.toLowerCase() === lowerName);
|
|
10
|
+
if (exact)
|
|
11
|
+
return exact;
|
|
12
|
+
// Substring match
|
|
13
|
+
const substring = sequence.phases.find((p) => p.name.toLowerCase().includes(lowerName));
|
|
14
|
+
if (substring)
|
|
15
|
+
return substring;
|
|
16
|
+
// Reverse substring — query contains the phase name
|
|
17
|
+
const reverseSubstring = sequence.phases.find((p) => lowerName.includes(p.name.toLowerCase()));
|
|
18
|
+
return reverseSubstring;
|
|
19
|
+
}
|
|
20
|
+
function getAvailablePhases(gameMode) {
|
|
21
|
+
const sequence = TURN_SEQUENCES.find((s) => s.gameMode === gameMode);
|
|
22
|
+
if (!sequence)
|
|
23
|
+
return [];
|
|
24
|
+
return sequence.phases.map((p) => p.name);
|
|
25
|
+
}
|
|
26
|
+
function formatPhase(phase) {
|
|
27
|
+
const sections = [];
|
|
28
|
+
sections.push(`# ${phase.name} Phase`);
|
|
29
|
+
sections.push(`**Game Mode:** ${phase.gameMode}`);
|
|
30
|
+
// Numbered steps
|
|
31
|
+
const steps = phase.steps.map((s, i) => `${i + 1}. ${s}`);
|
|
32
|
+
sections.push(`## Steps\n\n${steps.join("\n")}`);
|
|
33
|
+
// Tips
|
|
34
|
+
if (phase.tips.length > 0) {
|
|
35
|
+
const tips = phase.tips.map((t) => `- ${t}`);
|
|
36
|
+
sections.push(`## Tips\n\n${tips.join("\n")}`);
|
|
37
|
+
}
|
|
38
|
+
return sections.join("\n\n");
|
|
39
|
+
}
|
|
40
|
+
export function registerLookupPhase(server) {
|
|
41
|
+
server.tool("lookup_phase", "Look up a game phase by name. Returns step-by-step instructions and tips for the phase in the specified game mode.", {
|
|
42
|
+
phase_name: z
|
|
43
|
+
.string()
|
|
44
|
+
.describe("Name or partial name of the phase to look up (e.g. 'Shooting', 'Command', 'Firefight')"),
|
|
45
|
+
game_mode: z
|
|
46
|
+
.enum(["40k", "combat_patrol", "kill_team"])
|
|
47
|
+
.optional()
|
|
48
|
+
.default("40k")
|
|
49
|
+
.describe("Game mode (default: 40k). Use kill_team for Kill Team phases."),
|
|
50
|
+
}, async ({ phase_name, game_mode }) => {
|
|
51
|
+
const mode = game_mode;
|
|
52
|
+
const phase = findPhase(phase_name, mode);
|
|
53
|
+
if (!phase) {
|
|
54
|
+
const available = getAvailablePhases(mode);
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `Phase "${phase_name}" not found for ${mode}.\n\nAvailable phases: ${available.join(", ")}.`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: formatPhase(phase),
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=lookup-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup-phase.js","sourceRoot":"","sources":["../../src/tools/lookup-phase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup-unit.d.ts","sourceRoot":"","sources":["../../src/tools/lookup-unit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoJpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmF1D"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { UNITS } from "../data/units.js";
|
|
3
|
+
import { KILL_TEAM_OPERATIVES } from "../data/kill-team-operatives.js";
|
|
4
|
+
import { fuzzySearch } from "../lib/search.js";
|
|
5
|
+
// === 40K Formatters ===
|
|
6
|
+
function formatStatsTable(profiles) {
|
|
7
|
+
const header = "| Name | M | T | SV | W | LD | OC |";
|
|
8
|
+
const separator = "|---|---|---|---|---|---|---|";
|
|
9
|
+
const rows = profiles.map((p) => `| ${p.name} | ${p.movement} | ${p.toughness} | ${p.save} | ${p.wounds} | ${p.leadership} | ${p.objectiveControl} |`);
|
|
10
|
+
return [header, separator, ...rows].join("\n");
|
|
11
|
+
}
|
|
12
|
+
function formatRangedWeapons(weapons) {
|
|
13
|
+
if (weapons.length === 0)
|
|
14
|
+
return "";
|
|
15
|
+
const header = "| Weapon | Range | A | BS | S | AP | D | Keywords |";
|
|
16
|
+
const separator = "|---|---|---|---|---|---|---|---|";
|
|
17
|
+
const rows = weapons.map((w) => `| ${w.name} | ${w.range} | ${w.attacks} | ${w.ballisticSkill} | ${w.strength} | ${w.armourPenetration} | ${w.damage} | ${w.keywords.join(", ") || "-"} |`);
|
|
18
|
+
return `### Ranged Weapons\n\n${[header, separator, ...rows].join("\n")}`;
|
|
19
|
+
}
|
|
20
|
+
function formatMeleeWeapons(weapons) {
|
|
21
|
+
if (weapons.length === 0)
|
|
22
|
+
return "";
|
|
23
|
+
const header = "| Weapon | Range | A | WS | S | AP | D | Keywords |";
|
|
24
|
+
const separator = "|---|---|---|---|---|---|---|---|";
|
|
25
|
+
const rows = weapons.map((w) => `| ${w.name} | ${w.range} | ${w.attacks} | ${w.weaponSkill} | ${w.strength} | ${w.armourPenetration} | ${w.damage} | ${w.keywords.join(", ") || "-"} |`);
|
|
26
|
+
return `### Melee Weapons\n\n${[header, separator, ...rows].join("\n")}`;
|
|
27
|
+
}
|
|
28
|
+
function formatAbilities(abilities) {
|
|
29
|
+
if (abilities.length === 0)
|
|
30
|
+
return "";
|
|
31
|
+
const lines = abilities.map((a) => `- **${a.name}**: ${a.description}`);
|
|
32
|
+
return `### Abilities\n\n${lines.join("\n")}`;
|
|
33
|
+
}
|
|
34
|
+
function formatUnit(unit) {
|
|
35
|
+
const sections = [];
|
|
36
|
+
// Header
|
|
37
|
+
const pointsStr = unit.points !== null ? ` — ${unit.points} pts` : "";
|
|
38
|
+
sections.push(`# ${unit.name}\n\n**Faction:** ${unit.faction}${pointsStr}`);
|
|
39
|
+
// Stats
|
|
40
|
+
sections.push(`### Unit Profiles\n\n${formatStatsTable(unit.profiles)}`);
|
|
41
|
+
// Weapons
|
|
42
|
+
const ranged = formatRangedWeapons(unit.rangedWeapons);
|
|
43
|
+
if (ranged)
|
|
44
|
+
sections.push(ranged);
|
|
45
|
+
const melee = formatMeleeWeapons(unit.meleeWeapons);
|
|
46
|
+
if (melee)
|
|
47
|
+
sections.push(melee);
|
|
48
|
+
// Abilities
|
|
49
|
+
const abilities = formatAbilities(unit.abilities);
|
|
50
|
+
if (abilities)
|
|
51
|
+
sections.push(abilities);
|
|
52
|
+
// Keywords
|
|
53
|
+
if (unit.keywords.length > 0) {
|
|
54
|
+
sections.push(`### Keywords\n\n${unit.keywords.join(", ")}`);
|
|
55
|
+
}
|
|
56
|
+
return sections.join("\n\n");
|
|
57
|
+
}
|
|
58
|
+
// === Kill Team Formatters ===
|
|
59
|
+
function formatKTProfile(profile) {
|
|
60
|
+
const header = "| Name | APL | Move | Save | Wounds |";
|
|
61
|
+
const separator = "|---|---|---|---|---|";
|
|
62
|
+
const row = `| ${profile.name} | ${profile.apl} | ${profile.movement} | ${profile.save} | ${profile.wounds} |`;
|
|
63
|
+
return [header, separator, row].join("\n");
|
|
64
|
+
}
|
|
65
|
+
function formatKTWeapons(weapons) {
|
|
66
|
+
if (weapons.length === 0)
|
|
67
|
+
return "";
|
|
68
|
+
const ranged = weapons.filter((w) => w.type === "ranged");
|
|
69
|
+
const melee = weapons.filter((w) => w.type === "melee");
|
|
70
|
+
const sections = [];
|
|
71
|
+
if (ranged.length > 0) {
|
|
72
|
+
const header = "| Weapon | ATK | HIT | DMG | WR |";
|
|
73
|
+
const separator = "|---|---|---|---|---|";
|
|
74
|
+
const rows = ranged.map((w) => `| ${w.name} | ${w.attacks} | ${w.hit} | ${w.damage} | ${w.weaponRules || "-"} |`);
|
|
75
|
+
sections.push(`### Ranged Weapons\n\n${[header, separator, ...rows].join("\n")}`);
|
|
76
|
+
}
|
|
77
|
+
if (melee.length > 0) {
|
|
78
|
+
const header = "| Weapon | ATK | HIT | DMG | WR |";
|
|
79
|
+
const separator = "|---|---|---|---|---|";
|
|
80
|
+
const rows = melee.map((w) => `| ${w.name} | ${w.attacks} | ${w.hit} | ${w.damage} | ${w.weaponRules || "-"} |`);
|
|
81
|
+
sections.push(`### Melee Weapons\n\n${[header, separator, ...rows].join("\n")}`);
|
|
82
|
+
}
|
|
83
|
+
return sections.join("\n\n");
|
|
84
|
+
}
|
|
85
|
+
function formatKTOperative(op) {
|
|
86
|
+
const sections = [];
|
|
87
|
+
sections.push(`# ${op.name}\n\n**Faction:** ${op.faction} | **Game:** Kill Team`);
|
|
88
|
+
sections.push(`### Operative Profile\n\n${formatKTProfile(op.profile)}`);
|
|
89
|
+
const weapons = formatKTWeapons(op.weapons);
|
|
90
|
+
if (weapons)
|
|
91
|
+
sections.push(weapons);
|
|
92
|
+
const abilities = formatAbilities(op.abilities);
|
|
93
|
+
if (abilities)
|
|
94
|
+
sections.push(abilities);
|
|
95
|
+
if (op.uniqueActions.length > 0) {
|
|
96
|
+
const lines = op.uniqueActions.map((a) => `- **${a.name}**: ${a.description}`);
|
|
97
|
+
sections.push(`### Unique Actions\n\n${lines.join("\n")}`);
|
|
98
|
+
}
|
|
99
|
+
if (op.keywords.length > 0) {
|
|
100
|
+
sections.push(`### Keywords\n\n${op.keywords.join(", ")}`);
|
|
101
|
+
}
|
|
102
|
+
return sections.join("\n\n");
|
|
103
|
+
}
|
|
104
|
+
// === Tool Registration ===
|
|
105
|
+
export function registerLookupUnit(server) {
|
|
106
|
+
server.tool("lookup_unit", "Look up a Warhammer 40K unit or Kill Team operative datasheet by name. Returns stats, weapons, abilities, and keywords.", {
|
|
107
|
+
unit_name: z.string().describe("Name or partial name of the unit to search for"),
|
|
108
|
+
faction: z
|
|
109
|
+
.string()
|
|
110
|
+
.optional()
|
|
111
|
+
.describe("Optional faction name to narrow results (e.g. 'Chaos Space Marines', 'Astartes')"),
|
|
112
|
+
game_mode: z
|
|
113
|
+
.enum(["40k", "combat_patrol", "kill_team"])
|
|
114
|
+
.optional()
|
|
115
|
+
.describe("Game mode: '40k' (default) searches 40K units, 'kill_team' searches Kill Team operatives"),
|
|
116
|
+
}, async ({ unit_name, faction, game_mode }) => {
|
|
117
|
+
if (game_mode === "kill_team") {
|
|
118
|
+
let candidates = [...KILL_TEAM_OPERATIVES];
|
|
119
|
+
if (faction) {
|
|
120
|
+
candidates = fuzzySearch(candidates, faction, ["faction"]);
|
|
121
|
+
}
|
|
122
|
+
const matches = fuzzySearch(candidates, unit_name, ["name"]);
|
|
123
|
+
if (matches.length === 0) {
|
|
124
|
+
const suggestion = faction
|
|
125
|
+
? `Try a different faction or check the spelling.`
|
|
126
|
+
: `Try a partial name or check the spelling.`;
|
|
127
|
+
return {
|
|
128
|
+
content: [
|
|
129
|
+
{
|
|
130
|
+
type: "text",
|
|
131
|
+
text: `No Kill Team operative found matching "${unit_name}".${faction ? ` (faction filter: "${faction}")` : ""}\n\n${suggestion}`,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
content: [
|
|
138
|
+
{
|
|
139
|
+
type: "text",
|
|
140
|
+
text: formatKTOperative(matches[0]),
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// Default: 40K units
|
|
146
|
+
let candidates = [...UNITS];
|
|
147
|
+
if (faction) {
|
|
148
|
+
candidates = fuzzySearch(candidates, faction, ["faction"]);
|
|
149
|
+
}
|
|
150
|
+
const matches = fuzzySearch(candidates, unit_name, ["name"]);
|
|
151
|
+
if (matches.length === 0) {
|
|
152
|
+
const suggestion = faction
|
|
153
|
+
? `Try a different faction or check the spelling.`
|
|
154
|
+
: `Try a partial name or check the spelling.`;
|
|
155
|
+
return {
|
|
156
|
+
content: [
|
|
157
|
+
{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: `No unit found matching "${unit_name}".${faction ? ` (faction filter: "${faction}")` : ""}\n\n${suggestion}`,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const unit = matches[0];
|
|
165
|
+
return {
|
|
166
|
+
content: [
|
|
167
|
+
{
|
|
168
|
+
type: "text",
|
|
169
|
+
text: formatUnit(unit),
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=lookup-unit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup-unit.js","sourceRoot":"","sources":["../../src/tools/lookup-unit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-units.d.ts","sourceRoot":"","sources":["../../src/tools/search-units.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqBpE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6G3D"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { UNITS } from "../data/units.js";
|
|
3
|
+
import { KILL_TEAM_OPERATIVES } from "../data/kill-team-operatives.js";
|
|
4
|
+
import { fuzzySearch } from "../lib/search.js";
|
|
5
|
+
const MAX_RESULTS = 10;
|
|
6
|
+
function formatCompactUnit(unit) {
|
|
7
|
+
const pointsStr = unit.points !== null ? `${unit.points}pts` : "pts N/A";
|
|
8
|
+
const keywords = unit.keywords.length > 0 ? unit.keywords.join(", ") : "None";
|
|
9
|
+
return `**${unit.name}** (${unit.faction}) — ${pointsStr} — Keywords: ${keywords}`;
|
|
10
|
+
}
|
|
11
|
+
function formatCompactOperative(op) {
|
|
12
|
+
const stats = `APL:${op.profile.apl} Move:${op.profile.movement} Save:${op.profile.save} W:${op.profile.wounds}`;
|
|
13
|
+
const keywords = op.keywords.length > 0 ? op.keywords.join(", ") : "None";
|
|
14
|
+
return `**${op.name}** (${op.faction}) — ${stats} — Keywords: ${keywords}`;
|
|
15
|
+
}
|
|
16
|
+
export function registerSearchUnits(server) {
|
|
17
|
+
server.tool("search_units", "Search Warhammer 40K units or Kill Team operatives by name, faction, or keywords. Returns a compact list of matching results (max 10).", {
|
|
18
|
+
query: z.string().describe("Search query — matches against name, faction, and keywords"),
|
|
19
|
+
faction: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Optional faction filter to narrow results (e.g. 'Necrons', 'Aeldari')"),
|
|
23
|
+
max_points: z
|
|
24
|
+
.number()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Optional max points filter — only return units costing this many points or fewer (40K only)"),
|
|
27
|
+
game_mode: z
|
|
28
|
+
.enum(["40k", "combat_patrol", "kill_team"])
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Game mode: '40k' (default) searches 40K units, 'kill_team' searches Kill Team operatives"),
|
|
31
|
+
}, async ({ query, faction, max_points, game_mode }) => {
|
|
32
|
+
if (game_mode === "kill_team") {
|
|
33
|
+
let candidates = [...KILL_TEAM_OPERATIVES];
|
|
34
|
+
if (faction) {
|
|
35
|
+
candidates = fuzzySearch(candidates, faction, ["faction"]);
|
|
36
|
+
}
|
|
37
|
+
let matches = fuzzySearch(candidates, query, ["name", "faction", "keywords"]);
|
|
38
|
+
if (matches.length === 0) {
|
|
39
|
+
const filters = [];
|
|
40
|
+
if (faction)
|
|
41
|
+
filters.push(`faction: "${faction}"`);
|
|
42
|
+
const filterStr = filters.length > 0 ? ` (filters: ${filters.join(", ")})` : "";
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
text: `No Kill Team operatives found matching "${query}"${filterStr}. Try a broader search term or different filters.`,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const total = matches.length;
|
|
53
|
+
const displayed = matches.slice(0, MAX_RESULTS);
|
|
54
|
+
const lines = displayed.map(formatCompactOperative);
|
|
55
|
+
if (total > MAX_RESULTS) {
|
|
56
|
+
lines.push(`\n_Showing ${MAX_RESULTS} of ${total} results. Narrow your search for more specific results._`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: "text",
|
|
62
|
+
text: lines.join("\n"),
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Default: 40K units
|
|
68
|
+
let candidates = [...UNITS];
|
|
69
|
+
if (faction) {
|
|
70
|
+
candidates = fuzzySearch(candidates, faction, ["faction"]);
|
|
71
|
+
}
|
|
72
|
+
let matches = fuzzySearch(candidates, query, ["name", "faction", "keywords"]);
|
|
73
|
+
if (max_points !== undefined) {
|
|
74
|
+
matches = matches.filter((u) => u.points !== null && u.points <= max_points);
|
|
75
|
+
}
|
|
76
|
+
if (matches.length === 0) {
|
|
77
|
+
const filters = [];
|
|
78
|
+
if (faction)
|
|
79
|
+
filters.push(`faction: "${faction}"`);
|
|
80
|
+
if (max_points !== undefined)
|
|
81
|
+
filters.push(`max points: ${max_points}`);
|
|
82
|
+
const filterStr = filters.length > 0 ? ` (filters: ${filters.join(", ")})` : "";
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: `No units found matching "${query}"${filterStr}. Try a broader search term or different filters.`,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const total = matches.length;
|
|
93
|
+
const displayed = matches.slice(0, MAX_RESULTS);
|
|
94
|
+
const lines = displayed.map(formatCompactUnit);
|
|
95
|
+
if (total > MAX_RESULTS) {
|
|
96
|
+
lines.push(`\n_Showing ${MAX_RESULTS} of ${total} results. Narrow your search for more specific results._`);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
content: [
|
|
100
|
+
{
|
|
101
|
+
type: "text",
|
|
102
|
+
text: lines.join("\n"),
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=search-units.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-units.js","sourceRoot":"","sources":["../../src/tools/search-units.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type GameMode = "40k" | "combat_patrol" | "kill_team";
|
|
2
|
+
export type GameSystem = "wh40k-10e" | "wh40k-killteam";
|
|
3
|
+
export type UnitProfile = {
|
|
4
|
+
name: string;
|
|
5
|
+
movement: string;
|
|
6
|
+
toughness: string;
|
|
7
|
+
save: string;
|
|
8
|
+
wounds: string;
|
|
9
|
+
leadership: string;
|
|
10
|
+
objectiveControl: string;
|
|
11
|
+
};
|
|
12
|
+
export type KillTeamOperativeProfile = {
|
|
13
|
+
name: string;
|
|
14
|
+
apl: string;
|
|
15
|
+
movement: string;
|
|
16
|
+
save: string;
|
|
17
|
+
wounds: string;
|
|
18
|
+
};
|
|
19
|
+
export type RangedWeapon = {
|
|
20
|
+
name: string;
|
|
21
|
+
range: string;
|
|
22
|
+
attacks: string;
|
|
23
|
+
ballisticSkill: string;
|
|
24
|
+
strength: string;
|
|
25
|
+
armourPenetration: string;
|
|
26
|
+
damage: string;
|
|
27
|
+
keywords: string[];
|
|
28
|
+
};
|
|
29
|
+
export type MeleeWeapon = {
|
|
30
|
+
name: string;
|
|
31
|
+
range: string;
|
|
32
|
+
attacks: string;
|
|
33
|
+
weaponSkill: string;
|
|
34
|
+
strength: string;
|
|
35
|
+
armourPenetration: string;
|
|
36
|
+
damage: string;
|
|
37
|
+
keywords: string[];
|
|
38
|
+
};
|
|
39
|
+
export type KillTeamWeapon = {
|
|
40
|
+
name: string;
|
|
41
|
+
attacks: string;
|
|
42
|
+
hit: string;
|
|
43
|
+
damage: string;
|
|
44
|
+
weaponRules: string;
|
|
45
|
+
type: "ranged" | "melee";
|
|
46
|
+
};
|
|
47
|
+
export type Ability = {
|
|
48
|
+
name: string;
|
|
49
|
+
description: string;
|
|
50
|
+
};
|
|
51
|
+
export type Unit = {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
faction: string;
|
|
55
|
+
keywords: string[];
|
|
56
|
+
profiles: UnitProfile[];
|
|
57
|
+
rangedWeapons: RangedWeapon[];
|
|
58
|
+
meleeWeapons: MeleeWeapon[];
|
|
59
|
+
abilities: Ability[];
|
|
60
|
+
points: number | null;
|
|
61
|
+
gameSystem: GameSystem;
|
|
62
|
+
};
|
|
63
|
+
export type KillTeamOperative = {
|
|
64
|
+
id: string;
|
|
65
|
+
name: string;
|
|
66
|
+
faction: string;
|
|
67
|
+
keywords: string[];
|
|
68
|
+
profile: KillTeamOperativeProfile;
|
|
69
|
+
weapons: KillTeamWeapon[];
|
|
70
|
+
abilities: Ability[];
|
|
71
|
+
uniqueActions: Ability[];
|
|
72
|
+
gameSystem: GameSystem;
|
|
73
|
+
};
|
|
74
|
+
export type KeywordDefinition = {
|
|
75
|
+
name: string;
|
|
76
|
+
description: string;
|
|
77
|
+
plainEnglish: string;
|
|
78
|
+
gameModes: GameMode[];
|
|
79
|
+
examples?: string[];
|
|
80
|
+
};
|
|
81
|
+
export type Phase = {
|
|
82
|
+
name: string;
|
|
83
|
+
order: number;
|
|
84
|
+
steps: string[];
|
|
85
|
+
tips: string[];
|
|
86
|
+
gameMode: GameMode;
|
|
87
|
+
};
|
|
88
|
+
export type TurnSequence = {
|
|
89
|
+
gameMode: GameMode;
|
|
90
|
+
phases: Phase[];
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qBAAqB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "warhammer-oracle",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Warhammer 40K and Kill Team rules, stats, and game flow MCP server",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"warhammer-oracle": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc && chmod 755 dist/index.js",
|
|
16
|
+
"dev": "tsx src/index.ts",
|
|
17
|
+
"lint": "tsc --noEmit",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:watch": "vitest",
|
|
20
|
+
"fetch-data": "tsx scripts/fetch-data.ts",
|
|
21
|
+
"inspect": "npx @modelcontextprotocol/inspector node dist/index.js",
|
|
22
|
+
"prepublishOnly": "npm run build && npm test"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.12",
|
|
26
|
+
"fast-xml-parser": "^5.2",
|
|
27
|
+
"zod": "^3.25"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.0.0",
|
|
31
|
+
"tsx": "^4.0.0",
|
|
32
|
+
"typescript": "^5.7.0",
|
|
33
|
+
"vitest": "^3.0.0"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT"
|
|
39
|
+
}
|