@iamjameslennon/ddb-mcp 2.8.0 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/browser.d.ts.map +1 -1
  2. package/dist/browser.js +19 -4
  3. package/dist/browser.js.map +1 -1
  4. package/dist/index.js +10 -18
  5. package/dist/index.js.map +1 -1
  6. package/dist/tools/campaign.js +1 -1
  7. package/dist/tools/campaign.js.map +1 -1
  8. package/dist/tools/character/ac.d.ts +20 -0
  9. package/dist/tools/character/ac.d.ts.map +1 -0
  10. package/dist/tools/character/ac.js +83 -0
  11. package/dist/tools/character/ac.js.map +1 -0
  12. package/dist/tools/character/actions.d.ts +22 -0
  13. package/dist/tools/character/actions.d.ts.map +1 -0
  14. package/dist/tools/character/actions.js +110 -0
  15. package/dist/tools/character/actions.js.map +1 -0
  16. package/dist/tools/character/core.d.ts +15 -0
  17. package/dist/tools/character/core.d.ts.map +1 -0
  18. package/dist/tools/character/core.js +156 -0
  19. package/dist/tools/character/core.js.map +1 -0
  20. package/dist/tools/character/defenses.d.ts +16 -0
  21. package/dist/tools/character/defenses.d.ts.map +1 -0
  22. package/dist/tools/character/defenses.js +27 -0
  23. package/dist/tools/character/defenses.js.map +1 -0
  24. package/dist/tools/character/definition.d.ts +14 -0
  25. package/dist/tools/character/definition.d.ts.map +1 -0
  26. package/dist/tools/character/definition.js +205 -0
  27. package/dist/tools/character/definition.js.map +1 -0
  28. package/dist/tools/character/features.d.ts +26 -0
  29. package/dist/tools/character/features.d.ts.map +1 -0
  30. package/dist/tools/character/features.js +107 -0
  31. package/dist/tools/character/features.js.map +1 -0
  32. package/dist/tools/character/helpers.d.ts +57 -0
  33. package/dist/tools/character/helpers.d.ts.map +1 -0
  34. package/dist/tools/character/helpers.js +80 -0
  35. package/dist/tools/character/helpers.js.map +1 -0
  36. package/dist/tools/character/identity.d.ts +19 -0
  37. package/dist/tools/character/identity.d.ts.map +1 -0
  38. package/dist/tools/character/identity.js +84 -0
  39. package/dist/tools/character/identity.js.map +1 -0
  40. package/dist/tools/character/inventory.d.ts +21 -0
  41. package/dist/tools/character/inventory.d.ts.map +1 -0
  42. package/dist/tools/character/inventory.js +61 -0
  43. package/dist/tools/character/inventory.js.map +1 -0
  44. package/dist/tools/character/notes.d.ts +20 -0
  45. package/dist/tools/character/notes.d.ts.map +1 -0
  46. package/dist/tools/character/notes.js +63 -0
  47. package/dist/tools/character/notes.js.map +1 -0
  48. package/dist/tools/character/parse.d.ts +13 -0
  49. package/dist/tools/character/parse.d.ts.map +1 -0
  50. package/dist/tools/character/parse.js +82 -0
  51. package/dist/tools/character/parse.js.map +1 -0
  52. package/dist/tools/character/spells.d.ts +26 -0
  53. package/dist/tools/character/spells.d.ts.map +1 -0
  54. package/dist/tools/character/spells.js +237 -0
  55. package/dist/tools/character/spells.js.map +1 -0
  56. package/dist/tools/character/stats.d.ts +33 -0
  57. package/dist/tools/character/stats.d.ts.map +1 -0
  58. package/dist/tools/character/stats.js +372 -0
  59. package/dist/tools/character/stats.js.map +1 -0
  60. package/dist/tools/character/templates.d.ts +22 -0
  61. package/dist/tools/character/templates.d.ts.map +1 -0
  62. package/dist/tools/character/templates.js +61 -0
  63. package/dist/tools/character/templates.js.map +1 -0
  64. package/dist/tools/character/types.d.ts +133 -0
  65. package/dist/tools/character/types.d.ts.map +1 -0
  66. package/dist/tools/character/types.js +12 -0
  67. package/dist/tools/character/types.js.map +1 -0
  68. package/dist/tools/character/vitals.d.ts +34 -0
  69. package/dist/tools/character/vitals.d.ts.map +1 -0
  70. package/dist/tools/character/vitals.js +198 -0
  71. package/dist/tools/character/vitals.js.map +1 -0
  72. package/dist/tools/character/weapons.d.ts +13 -0
  73. package/dist/tools/character/weapons.d.ts.map +1 -0
  74. package/dist/tools/character/weapons.js +79 -0
  75. package/dist/tools/character/weapons.js.map +1 -0
  76. package/dist/tools/character.d.ts +13 -3
  77. package/dist/tools/character.d.ts.map +1 -1
  78. package/dist/tools/character.js +18 -1181
  79. package/dist/tools/character.js.map +1 -1
  80. package/dist/tools/library.d.ts +32 -4
  81. package/dist/tools/library.d.ts.map +1 -1
  82. package/dist/tools/library.js +181 -86
  83. package/dist/tools/library.js.map +1 -1
  84. package/dist/tools/search.d.ts +1 -2
  85. package/dist/tools/search.d.ts.map +1 -1
  86. package/dist/tools/search.js +36 -59
  87. package/dist/tools/search.js.map +1 -1
  88. package/package.json +2 -1
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Actions domain — ACTIONS / BONUS ACTIONS / REACTIONS / LIMITED USE.
3
+ * Owns the combat block.
4
+ *
5
+ * Phase 6b of the character.ts refactor — see docs/character-refactor.md.
6
+ *
7
+ * Filters Circle Spell entries (Dark Bargain campaign leak), surfaces
8
+ * activationType 3/4 spells into bonus-action and reaction lists (with the
9
+ * spellbook prepared/ritual gate applied), and computes "X used / Y max"
10
+ * for limited-use features (including stat-mod-keyed uses like Bardic
11
+ * Inspiration). Output is pre-formatted lines.
12
+ */
13
+ import { arr, num, obj, signed, str } from "./helpers.js";
14
+ import { computeWeaponAttacks } from "./weapons.js";
15
+ // ── Action source extraction ─────────────────────────────────────────────────
16
+ function getAllActions(char) {
17
+ // activation.activationType: 1=action, 3=bonus action, 4=reaction, 8=special (skip)
18
+ // Filter Circle Spell entries — these leak from the Dark Bargain campaign feature
19
+ // and don't represent real character abilities on the website.
20
+ return Object.values(obj(char.actions))
21
+ .flatMap(v => arr(v))
22
+ .filter(a => a != null && !str(a.name).startsWith("Circle Spell") && str(a.name) !== "Initiate a Circle Spell");
23
+ }
24
+ const activationType = (a) => num(obj(a.activation).activationType);
25
+ // ── Bonus-action and reaction spells ─────────────────────────────────────────
26
+ function getCharSpellsForActions(char, classes) {
27
+ // Bonus-action and reaction spells — activationType 3=bonus action, 4=reaction.
28
+ // Apply the same prepared/ritual filter used in the main SPELLS section for spellbook
29
+ // classes (Wizards) so unprepared non-ritual spells don't bleed into these sections.
30
+ return [
31
+ ...arr(char.classSpells).flatMap(cs => {
32
+ const classEntry = classes.find(c => c.id === cs.characterClassId);
33
+ const isSpellbook = str(obj(classEntry?.definition ?? {}).name) === "Wizard";
34
+ return arr(cs.spells).filter(s => !isSpellbook || s.prepared === true || obj(s.definition).ritual === true);
35
+ }),
36
+ ...Object.values(obj(char.spells)).flatMap(v => arr(v)),
37
+ ].filter(Boolean);
38
+ }
39
+ const spellActivationType = (s) => num(obj(obj(s.definition).activation).activationType);
40
+ function formatSpellAction(s) {
41
+ const def = obj(s.definition);
42
+ const lvl = num(def.level);
43
+ const slotStr = lvl === 0 ? "cantrip" : `${lvl === 1 ? "1st" : lvl === 2 ? "2nd" : lvl === 3 ? "3rd" : `${lvl}th`}-level slot`;
44
+ return `• ${str(def.name)} (spell, ${slotStr})`;
45
+ }
46
+ // ── Limited-use features ─────────────────────────────────────────────────────
47
+ function buildLimitedUseLines(allActions, statMods) {
48
+ return allActions
49
+ .filter(a => {
50
+ const lu = obj(a.limitedUse);
51
+ // maxUses=0 with statModifierUsesId means uses = that stat modifier (e.g. CHA for Bardic Inspiration)
52
+ return lu.maxUses !== undefined && (num(lu.maxUses) > 0 || lu.statModifierUsesId != null);
53
+ })
54
+ .map(a => {
55
+ const lu = obj(a.limitedUse);
56
+ const resetLabels = { 1: "Short Rest", 2: "Long Rest" };
57
+ const reset = resetLabels[num(lu.resetType)] ?? "Rest";
58
+ let maxStr = num(lu.maxUses) > 0
59
+ ? String(num(lu.maxUses))
60
+ : lu.statModifierUsesId != null
61
+ ? `${signed(statMods[num(lu.statModifierUsesId) - 1])} (stat)`
62
+ : "?";
63
+ const used = num(lu.numberUsed);
64
+ return `• ${str(a.name)} ${used} used / ${maxStr} max (${reset})`;
65
+ });
66
+ }
67
+ // ── Public API ───────────────────────────────────────────────────────────────
68
+ export function computeActions(core) {
69
+ const { char, classes, statMods } = core;
70
+ const allActions = getAllActions(char);
71
+ const allCharSpells = getCharSpellsForActions(char, classes);
72
+ // Spell activationTypes (from rule-data): 1=Action, 2=No Action, 3=Bonus Action, 4=Reaction, 8=Special
73
+ const bonusActionSpells = allCharSpells.filter(s => spellActivationType(s) === 3).map(formatSpellAction);
74
+ const reactionSpells = allCharSpells.filter(s => spellActivationType(s) === 4).map(formatSpellAction);
75
+ // activationType 3 = bonus action in class actions, 4 = reaction
76
+ // activationType 1 = action (weapon masteries — skip, shown in ACTIONS already)
77
+ // activationType 8 = special/passive — skip
78
+ const bonusActions = [
79
+ ...allActions.filter(a => activationType(a) === 3).map(a => `• ${str(a.name)}`),
80
+ ...bonusActionSpells,
81
+ ];
82
+ // Reactions: Opportunity Attack is universal, then class reactions, then reaction spells
83
+ const reactions = [
84
+ "• Opportunity Attack",
85
+ ...allActions.filter(a => activationType(a) === 4).map(a => `• ${str(a.name)}`),
86
+ ...reactionSpells,
87
+ ];
88
+ const limitedUseFeatures = buildLimitedUseLines(allActions, statMods);
89
+ return {
90
+ weaponAttacks: computeWeaponAttacks(core),
91
+ bonusActions,
92
+ reactions,
93
+ limitedUseFeatures,
94
+ };
95
+ }
96
+ export function formatCombatBlock(a) {
97
+ return [
98
+ `ACTIONS`,
99
+ ...(a.weaponAttacks.length ? a.weaponAttacks : [" (none)"]),
100
+ ``,
101
+ `BONUS ACTIONS`,
102
+ ...(a.bonusActions.length ? a.bonusActions : [" (none)"]),
103
+ ``,
104
+ `REACTIONS`,
105
+ ...(a.reactions.length ? a.reactions : [" (none)"]),
106
+ ``,
107
+ ...(a.limitedUseFeatures.length ? [`LIMITED USE`, ...a.limitedUseFeatures, ``] : []),
108
+ ];
109
+ }
110
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/tools/character/actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `computeCoreStats(char)` — the foundation context object for the character
3
+ * module.
4
+ *
5
+ * Phase 2 of the character.ts refactor — see docs/character-refactor.md.
6
+ *
7
+ * Computes the values that every per-domain module (vitals, stats, ac,
8
+ * weapons, spells, …) needs: flattened modifiers, classes, total level,
9
+ * proficiency bonus, ability scores + mods, inventory, and the template
10
+ * resolver. Computed once at the top of `parseCharacterData` and threaded
11
+ * downstream.
12
+ */
13
+ import type { CharData, CoreStats } from "./types.js";
14
+ export declare function computeCoreStats(char: CharData): CoreStats;
15
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/tools/character/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAc,SAAS,EAAsB,MAAM,YAAY,CAAC;AAEtF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,CA4I1D"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * `computeCoreStats(char)` — the foundation context object for the character
3
+ * module.
4
+ *
5
+ * Phase 2 of the character.ts refactor — see docs/character-refactor.md.
6
+ *
7
+ * Computes the values that every per-domain module (vitals, stats, ac,
8
+ * weapons, spells, …) needs: flattened modifiers, classes, total level,
9
+ * proficiency bonus, ability scores + mods, inventory, and the template
10
+ * resolver. Computed once at the top of `parseCharacterData` and threaded
11
+ * downstream.
12
+ */
13
+ import { arr, isBonusMod, isSetMod, num, modOf, obj, statKeys, statNames } from "./helpers.js";
14
+ import { makeResolveTemplates } from "./templates.js";
15
+ export function computeCoreStats(char) {
16
+ const classes = arr(char.classes);
17
+ const totalLevel = classes.reduce((s, c) => s + num(c.level), 0);
18
+ const profBonus = Math.floor((totalLevel - 1) / 4) + 2;
19
+ // PHB multiclass rule: only the *starting* class grants saving-throw
20
+ // proficiencies. DDB still hoists every class's Proficiencies-feature
21
+ // modifiers into modifiers.class regardless, so we drop the non-starting
22
+ // save-prof entries here at the source. Collect the starting class's
23
+ // classFeature + subclassFeature ids; a save-prof mod whose componentId
24
+ // is in that set is from the starting class and stays.
25
+ const startingClass = classes.find(c => c.isStartingClass === true) ?? classes[0];
26
+ const startingClassFeatureIds = new Set();
27
+ if (startingClass) {
28
+ for (const cf of arr(startingClass.classFeatures)) {
29
+ const id = num(obj(cf.definition).id);
30
+ if (id)
31
+ startingClassFeatureIds.add(id);
32
+ }
33
+ for (const cf of arr(obj(startingClass.subclassDefinition).classFeatures)) {
34
+ const id = num(obj(cf.definition).id);
35
+ if (id)
36
+ startingClassFeatureIds.add(id);
37
+ }
38
+ }
39
+ const isStartingClassSaveProf = (m) => {
40
+ if (m.type !== "proficiency")
41
+ return true;
42
+ if (typeof m.subType !== "string" || !m.subType.includes("saving-throws"))
43
+ return true;
44
+ const cid = num(m.componentId);
45
+ // cid === 0 means no componentId (hand-built fixtures, older DDB data) —
46
+ // keep, since we can't disprove it's from the starting class.
47
+ return cid === 0 || startingClassFeatureIds.has(cid);
48
+ };
49
+ const allMods = Object.entries(obj(char.modifiers)).flatMap(([source, list]) => {
50
+ const mods = arr(list);
51
+ return source === "class" || source === "subclass"
52
+ ? mods.filter(isStartingClassSaveProf)
53
+ : mods;
54
+ });
55
+ // ── Ability Scores ─────────────────────────────────────────────────────────
56
+ const baseStats = arr(char.stats);
57
+ const bonusStats = arr(char.bonusStats);
58
+ const overrideStats = arr(char.overrideStats);
59
+ // Sum ability-score `bonus` modifiers, but iterate per-source so we can
60
+ // gate race-sourced bonuses on `isGranted`. In the 2024 rules ability
61
+ // score increases come from the character's background (origin feat),
62
+ // not from race — DDB still emits the race-categorized ASI modifiers in
63
+ // the JSON, but they carry `isGranted: false` and the website ignores
64
+ // them. We must too, or the race ASI gets double-counted against
65
+ // char.stats (which already includes it).
66
+ //
67
+ // EXCEPTION: 2014 Half-Elf grants +2 CHA fixed plus two player-chosen +1s.
68
+ // The chosen ones are ALSO emitted as race mods with `isGranted: false` —
69
+ // same flag the 2024 declined-ASIs use. Discriminator: 2014 Half-Elf pairs
70
+ // each chosen +1 with a `choices.race` entry whose `optionValue` is in the
71
+ // 3520..3525 range (STR..CHA) and whose `componentId` matches the mod's.
72
+ // Build a multiset of (componentId, abilityIdx) picks and consume one per
73
+ // matching mod so duplicate picks (Danyr's STR+STR) stack correctly.
74
+ const ABILITY_OPTION_BASE = 3520;
75
+ const playerRaceAbilityPicks = [];
76
+ for (const ch of arr(obj(char.choices).race)) {
77
+ const opt = num(ch.optionValue);
78
+ if (opt < ABILITY_OPTION_BASE || opt > ABILITY_OPTION_BASE + 5)
79
+ continue;
80
+ playerRaceAbilityPicks.push({
81
+ componentId: num(ch.componentId),
82
+ abilityIdx: opt - ABILITY_OPTION_BASE,
83
+ });
84
+ }
85
+ const consumeMatchingRacePick = (componentId, abilityIdx) => {
86
+ const i = playerRaceAbilityPicks.findIndex(p => p.componentId === componentId && p.abilityIdx === abilityIdx);
87
+ if (i < 0)
88
+ return false;
89
+ playerRaceAbilityPicks.splice(i, 1);
90
+ return true;
91
+ };
92
+ const scoreBonuses = {};
93
+ for (const [source, list] of Object.entries(obj(char.modifiers))) {
94
+ for (const m of arr(list)) {
95
+ if (!isBonusMod(m))
96
+ continue;
97
+ if (!m.subType.endsWith("-score"))
98
+ continue;
99
+ const idx = statKeys.indexOf(m.subType.replace("-score", ""));
100
+ if (idx < 0)
101
+ continue;
102
+ if (source === "race" && m.isGranted === false) {
103
+ // Allow through only if the player has a matching race-ability pick
104
+ // (2014 Half-Elf shape). Otherwise this is a declined 2024-style ASI.
105
+ if (!consumeMatchingRacePick(num(m.componentId), idx))
106
+ continue;
107
+ }
108
+ scoreBonuses[idx + 1] = (scoreBonuses[idx + 1] ?? 0) + num(m.fixedValue);
109
+ }
110
+ }
111
+ const scoreSetValues = {};
112
+ for (const m of allMods) {
113
+ if (isSetMod(m) && m.subType.endsWith("-score")) {
114
+ const idx = statKeys.indexOf(m.subType.replace("-score", ""));
115
+ if (idx >= 0) {
116
+ const setVal = num(m.fixedValue ?? m.value);
117
+ if (setVal > 0)
118
+ scoreSetValues[idx + 1] = Math.max(scoreSetValues[idx + 1] ?? 0, setVal);
119
+ }
120
+ }
121
+ }
122
+ // PHB cap: ability scores from race/class/feat/background ASI sources max
123
+ // out at 20 (both 2014 and 2024 PHB). Two sources are explicitly allowed
124
+ // to exceed: manual overrides via `overrideStats` and `type:"set"` item
125
+ // modifiers (Belt of Giant Strength, Manual of Bodily Health, etc.).
126
+ // Without this cap, characters like Calderax (base 18 + multiple +1 ASIs)
127
+ // display as 21 (+5) while the DDB website shows 20 (+5).
128
+ const ABILITY_SCORE_CAP = 20;
129
+ const statTotals = statNames.map((_, i) => {
130
+ const id = i + 1;
131
+ const base = baseStats.find(s => num(s.id) === id);
132
+ const bonus = bonusStats.find(s => num(s.id) === id);
133
+ const override = overrideStats.find(s => num(s.id) === id);
134
+ const baseVal = num(base?.value ?? 0);
135
+ const bonusVal = num(bonus?.value ?? 0);
136
+ const overrideVal = override?.value != null ? num(override.value) : null;
137
+ const calculated = overrideVal != null ? overrideVal : baseVal + bonusVal + (scoreBonuses[id] ?? 0);
138
+ const capped = overrideVal != null ? calculated : Math.min(calculated, ABILITY_SCORE_CAP);
139
+ return scoreSetValues[id] != null ? Math.max(capped, scoreSetValues[id]) : capped;
140
+ });
141
+ const statMods = statTotals.map(modOf);
142
+ const inventory = arr(char.inventory);
143
+ const resolveTemplates = makeResolveTemplates(profBonus, totalLevel);
144
+ return {
145
+ char,
146
+ allMods,
147
+ statTotals,
148
+ statMods,
149
+ profBonus,
150
+ totalLevel,
151
+ classes,
152
+ inventory,
153
+ resolveTemplates,
154
+ };
155
+ }
156
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/tools/character/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Defenses domain — damage resistances / immunities / vulnerabilities and
3
+ * active conditions. Owns the defenses block.
4
+ *
5
+ * Phase 5b of the character.ts refactor — see docs/character-refactor.md.
6
+ */
7
+ import type { CoreStats } from "./types.js";
8
+ export interface Defenses {
9
+ resistances: string[];
10
+ immunities: string[];
11
+ vulnerabilities: string[];
12
+ conditions: string[];
13
+ }
14
+ export declare function computeDefenses(core: CoreStats): Defenses;
15
+ export declare function formatDefensesBlock(d: Defenses): string[];
16
+ //# sourceMappingURL=defenses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defenses.d.ts","sourceRoot":"","sources":["../../../src/tools/character/defenses.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAczD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,CASzD"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Defenses domain — damage resistances / immunities / vulnerabilities and
3
+ * active conditions. Owns the defenses block.
4
+ *
5
+ * Phase 5b of the character.ts refactor — see docs/character-refactor.md.
6
+ */
7
+ import { arr, capitalize, isImmunityMod, isResistanceMod, isVulnerabilityMod, str } from "./helpers.js";
8
+ export function computeDefenses(core) {
9
+ const { char, allMods } = core;
10
+ return {
11
+ resistances: [...new Set(allMods.filter(isResistanceMod).map(m => capitalize(m.subType)))],
12
+ immunities: [...new Set(allMods.filter(isImmunityMod).map(m => capitalize(m.subType)))],
13
+ vulnerabilities: [...new Set(allMods.filter(isVulnerabilityMod).map(m => capitalize(m.subType)))],
14
+ conditions: arr(char.conditions).map(c => str(c.id)),
15
+ };
16
+ }
17
+ export function formatDefensesBlock(d) {
18
+ return [
19
+ `DEFENSES`,
20
+ ` Resistances: ${d.resistances.length ? d.resistances.join(", ") : "(none)"}`,
21
+ ` Immunities: ${d.immunities.length ? d.immunities.join(", ") : "(none)"}`,
22
+ ` Vulnerabilities: ${d.vulnerabilities.length ? d.vulnerabilities.join(", ") : "(none)"}`,
23
+ `CONDITIONS: ${d.conditions.length ? d.conditions.join(", ") : "(none)"}`,
24
+ ``,
25
+ ];
26
+ }
27
+ //# sourceMappingURL=defenses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defenses.js","sourceRoot":"","sources":["../../../src/tools/character/defenses.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAUxG,MAAM,UAAU,eAAe,CAAC,IAAe;IAC7C,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,OAAO;QACL,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,CACtB,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAChE,CAAC;QACF,UAAU,EAAE,CAAC,GAAG,IAAI,GAAG,CACrB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAC9D,CAAC;QACF,eAAe,EAAE,CAAC,GAAG,IAAI,GAAG,CAC1B,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CACnE,CAAC;QACF,UAAU,EAAE,GAAG,CAA0B,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;KAC9E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAW;IAC7C,OAAO;QACL,UAAU;QACV,kBAAkB,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QAC9E,iBAAiB,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QAC3E,sBAAsB,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QAC1F,eAAe,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QACzE,EAAE;KACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Definition lookup — searches a character's known spells, feats, class &
3
+ * subclass features, racial traits, background feature, and equipped items
4
+ * for a name match, and returns formatted definitions for the hits.
5
+ *
6
+ * Phase 9 of the character.ts refactor — see docs/character-refactor.md.
7
+ *
8
+ * `getDefinition` is the public entry point (re-exported from character.ts).
9
+ * It depends on `getCharacter` from the network/IO layer in character.ts
10
+ * — that import is intentionally one-way (definition consumes IO, not
11
+ * the other way around).
12
+ */
13
+ export declare function getDefinition(characterId: string, query: string): Promise<string>;
14
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../src/tools/character/definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA+MH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Definition lookup — searches a character's known spells, feats, class &
3
+ * subclass features, racial traits, background feature, and equipped items
4
+ * for a name match, and returns formatted definitions for the hits.
5
+ *
6
+ * Phase 9 of the character.ts refactor — see docs/character-refactor.md.
7
+ *
8
+ * `getDefinition` is the public entry point (re-exported from character.ts).
9
+ * It depends on `getCharacter` from the network/IO layer in character.ts
10
+ * — that import is intentionally one-way (definition consumes IO, not
11
+ * the other way around).
12
+ */
13
+ import { stripHtml as stripHtmlFull } from "../../utils.js";
14
+ import { getCharacter } from "../character.js";
15
+ import { levenshteinDistance } from "./helpers.js";
16
+ function matchesDefinitionQuery(name, query) {
17
+ const n = name.toLowerCase();
18
+ const q = query.toLowerCase();
19
+ if (n.includes(q))
20
+ return true;
21
+ return name.split(/\s+/).some(w => levenshteinDistance(q, w.toLowerCase()) <= 2);
22
+ }
23
+ function formatSpellResult(spell) {
24
+ const d = (spell.definition ?? spell);
25
+ const name = String(d.name ?? "Unknown");
26
+ const level = Number(d.level ?? 0);
27
+ const school = String(d.school ?? "");
28
+ const levelLabel = level === 0 ? "Cantrip" : `Level ${level}`;
29
+ const ACTIVATION_TYPES = { 1: "Action", 3: "Bonus Action", 6: "Reaction" };
30
+ const act = d.activation;
31
+ const castingTime = act
32
+ ? `${act.activationTime} ${ACTIVATION_TYPES[Number(act.activationType)] ?? "Action"}`
33
+ : "1 Action";
34
+ const rng = d.range;
35
+ let range = "Self";
36
+ if (rng) {
37
+ if (rng.rangeValue && rng.origin !== "Self")
38
+ range = `${rng.rangeValue} ft`;
39
+ else
40
+ range = String(rng.origin ?? "Self");
41
+ if (rng.aoeType && rng.aoeValue)
42
+ range += ` (${rng.aoeValue}-ft ${rng.aoeType})`;
43
+ }
44
+ const dur = d.duration;
45
+ let duration = "Instantaneous";
46
+ if (dur) {
47
+ const isConc = dur.durationType === "Concentration";
48
+ if (dur.durationInterval && dur.durationUnit) {
49
+ duration = `${isConc ? "Concentration, up to " : ""}${dur.durationInterval} ${dur.durationUnit}${Number(dur.durationInterval) > 1 ? "s" : ""}`;
50
+ }
51
+ else if (isConc) {
52
+ duration = "Concentration";
53
+ }
54
+ }
55
+ const components = (Array.isArray(d.components) ? d.components : [])
56
+ .map((c) => ({ 1: "V", 2: "S", 3: "M" })[c])
57
+ .filter(Boolean)
58
+ .join(", ");
59
+ const matNote = d.componentsDescription ? ` (${d.componentsDescription})` : "";
60
+ const lines = [
61
+ `${name} (${levelLabel} ${school})`,
62
+ `Casting Time: ${castingTime}`,
63
+ `Range: ${range}`,
64
+ `Components: ${components || "None"}${matNote}`,
65
+ `Duration: ${duration}`,
66
+ ];
67
+ if (d.ritual)
68
+ lines.push("Ritual: Yes");
69
+ lines.push("", stripHtmlFull(String(d.description ?? "")));
70
+ return lines.join("\n");
71
+ }
72
+ function formatFeatResult(feat) {
73
+ const d = (feat.definition ?? feat);
74
+ const lines = [String(d.name ?? "Unknown")];
75
+ if (d.prerequisite)
76
+ lines.push(`Prerequisite: ${d.prerequisite}`);
77
+ lines.push("", stripHtmlFull(String(d.description ?? d.snippet ?? "")));
78
+ return lines.join("\n");
79
+ }
80
+ function formatClassFeatureResult(feature, className, level) {
81
+ const d = (feature.definition ?? feature);
82
+ const name = String(d.name ?? feature.name ?? "Unknown");
83
+ const desc = stripHtmlFull(String(d.description ?? d.snippet ?? ""));
84
+ return `${name} (${className}, Level ${level})\n\n${desc}`;
85
+ }
86
+ function formatRacialTraitResult(trait, raceName) {
87
+ const d = (trait.definition ?? trait);
88
+ const name = String(d.name ?? "Unknown");
89
+ const desc = stripHtmlFull(String(d.description ?? d.snippet ?? ""));
90
+ return `${name} (${raceName})\n\n${desc}`;
91
+ }
92
+ function formatItemResult(item) {
93
+ const d = (item.definition ?? item);
94
+ const name = String(d.name ?? "Unknown");
95
+ const type = String(d.type ?? "Item");
96
+ const rarity = String(d.rarity ?? "Common");
97
+ const weight = d.weight != null ? `Weight: ${d.weight} lb\n` : "";
98
+ const desc = stripHtmlFull(String(d.description ?? ""));
99
+ return `${name} (${type}, ${rarity})\n${weight}\n${desc}`;
100
+ }
101
+ function searchDefinitions(char, query) {
102
+ const results = [];
103
+ // searchDefinitions intentionally keeps these as locals (not the shared
104
+ // helpers) — its tolerance for unexpected shapes differs slightly (e.g.
105
+ // it accepts `spell.name` as a fallback for `spell.definition.name`).
106
+ const arr = (v) => (Array.isArray(v) ? v : []);
107
+ const obj = (v) => v != null && typeof v === "object" && !Array.isArray(v) ? v : {};
108
+ const str = (v) => (typeof v === "string" ? v : "");
109
+ const num = (v) => (typeof v === "number" ? v : 0);
110
+ // ── Spells ────────────────────────────────────────────────────────────────
111
+ const allSpells = [
112
+ ...arr(char.classSpells).flatMap(cs => arr(cs.spells)),
113
+ ...Object.values(obj(char.spells)).flatMap(v => arr(v)),
114
+ ];
115
+ for (const spell of allSpells) {
116
+ const name = str(obj(spell.definition).name || spell.name);
117
+ if (name && matchesDefinitionQuery(name, query)) {
118
+ results.push({ type: "Spell", text: formatSpellResult(spell) });
119
+ }
120
+ }
121
+ // ── Feats ─────────────────────────────────────────────────────────────────
122
+ for (const feat of arr(char.feats)) {
123
+ const name = str(obj(feat.definition).name);
124
+ if (name && matchesDefinitionQuery(name, query)) {
125
+ results.push({ type: "Feat", text: formatFeatResult(feat) });
126
+ }
127
+ }
128
+ // ── Class & Subclass Features ─────────────────────────────────────────────
129
+ const seen = new Set();
130
+ for (const cls of arr(char.classes)) {
131
+ const charLevel = num(cls.level);
132
+ const className = str(obj(cls.definition).name);
133
+ for (const cf of arr(cls.classFeatures)) {
134
+ const d = obj(cf.definition);
135
+ const name = str(d.name);
136
+ const requiredLevel = num(d.requiredLevel || 1);
137
+ if (requiredLevel <= charLevel && name && matchesDefinitionQuery(name, query) && !seen.has(name)) {
138
+ seen.add(name);
139
+ results.push({
140
+ type: "Class Feature",
141
+ text: formatClassFeatureResult(cf, className, requiredLevel),
142
+ });
143
+ }
144
+ }
145
+ const subDef = obj(cls.subclassDefinition);
146
+ const subName = str(subDef.name);
147
+ for (const cf of arr(subDef.classFeatures)) {
148
+ const d = obj(cf.definition);
149
+ const name = str(d.name);
150
+ const requiredLevel = num(d.requiredLevel || 1);
151
+ const label = subName ? `${className} / ${subName}` : className;
152
+ if (requiredLevel <= charLevel && name && matchesDefinitionQuery(name, query) && !seen.has(name)) {
153
+ seen.add(name);
154
+ results.push({
155
+ type: "Subclass Feature",
156
+ text: formatClassFeatureResult(cf, label, requiredLevel),
157
+ });
158
+ }
159
+ }
160
+ }
161
+ // ── Racial Traits ─────────────────────────────────────────────────────────
162
+ const raceName = str(obj(char.race).fullName || obj(char.race).baseName);
163
+ for (const trait of arr(obj(char.race).racialTraits)) {
164
+ const name = str(obj(trait.definition).name);
165
+ if (name && matchesDefinitionQuery(name, query)) {
166
+ results.push({ type: "Racial Trait", text: formatRacialTraitResult(trait, raceName) });
167
+ }
168
+ }
169
+ // ── Background Feature ────────────────────────────────────────────────────
170
+ const bgDef = obj(obj(char.background).definition);
171
+ const bgFeatureName = str(bgDef.featureName);
172
+ if (bgFeatureName && matchesDefinitionQuery(bgFeatureName, query)) {
173
+ const bgName = str(bgDef.name);
174
+ const bgDesc = stripHtmlFull(str(bgDef.featureDescription));
175
+ results.push({
176
+ type: "Background Feature",
177
+ text: `${bgFeatureName} (${bgName})\n\n${bgDesc}`,
178
+ });
179
+ }
180
+ // ── Equipped Items ────────────────────────────────────────────────────────
181
+ for (const item of arr(char.inventory)) {
182
+ if (!item.equipped)
183
+ continue;
184
+ const name = str(obj(item.definition).name);
185
+ if (name && matchesDefinitionQuery(name, query)) {
186
+ results.push({ type: "Item", text: formatItemResult(item) });
187
+ }
188
+ }
189
+ return results;
190
+ }
191
+ export async function getDefinition(characterId, query) {
192
+ const jsonData = await getCharacter(characterId);
193
+ const raw = JSON.parse(jsonData);
194
+ const char = (raw?.data ?? raw);
195
+ const hits = searchDefinitions(char, query);
196
+ if (hits.length === 0) {
197
+ return `No definition found matching "${query}" on this character. Try a partial name like "hunter" for Hunter's Mark.`;
198
+ }
199
+ if (hits.length > 3) {
200
+ const list = hits.map((h, i) => `${i + 1}. [${h.type}] ${h.text.split("\n")[0]}`).join("\n");
201
+ return `Found ${hits.length} matches for "${query}". Be more specific, or here are the matches:\n\n${list}`;
202
+ }
203
+ return hits.map(h => `[${h.type}]\n${h.text}`).join("\n\n===\n\n");
204
+ }
205
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../src/tools/character/definition.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Features domain — feats (real + disguised), class features, racial traits,
3
+ * background feature. Owns the features block.
4
+ *
5
+ * Phase 5c of the character.ts refactor — see docs/character-refactor.md.
6
+ *
7
+ * Output strings are pre-formatted (e.g. featLines = ["• Great Weapon Master: …"])
8
+ * to preserve byte-for-byte parity with the original inline code.
9
+ */
10
+ import type { CoreStats } from "./types.js";
11
+ export interface BackgroundFeature {
12
+ name: string;
13
+ isFeat: boolean;
14
+ descSnippet: string;
15
+ }
16
+ export interface Features {
17
+ featLines: string[];
18
+ disguisedFeatLines: string[];
19
+ realFeatCount: number;
20
+ classFeatureLines: string[];
21
+ racialTraitLines: string[];
22
+ background: BackgroundFeature;
23
+ }
24
+ export declare function computeFeatures(core: CoreStats): Features;
25
+ export declare function formatFeaturesBlock(f: Features): string[];
26
+ //# sourceMappingURL=features.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../../src/tools/character/features.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAwB,SAAS,EAAO,MAAM,YAAY,CAAC;AAGvE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,iBAAiB,CAAC;CAC/B;AAqED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAWzD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,CA0BzD"}