@umang-boss/claudemon 1.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.
Files changed (203) hide show
  1. package/README.md +164 -0
  2. package/bin/claudemon.js +52 -0
  3. package/bunfig.toml +2 -0
  4. package/cli/doctor.ts +334 -0
  5. package/cli/index.ts +42 -0
  6. package/cli/install.ts +248 -0
  7. package/cli/shared.ts +102 -0
  8. package/cli/uninstall.ts +155 -0
  9. package/cli/update.ts +318 -0
  10. package/hooks/post-tool-use.sh +127 -0
  11. package/hooks/stop.sh +49 -0
  12. package/hooks/user-prompt-submit.sh +73 -0
  13. package/package.json +68 -0
  14. package/scripts/download-colorscripts.ts +311 -0
  15. package/skills/buddy/SKILL.md +47 -0
  16. package/sprites/colorscripts/small/1-bulbasaur.txt +11 -0
  17. package/sprites/colorscripts/small/10-caterpie.txt +9 -0
  18. package/sprites/colorscripts/small/100-voltorb.txt +8 -0
  19. package/sprites/colorscripts/small/101-electrode.txt +9 -0
  20. package/sprites/colorscripts/small/102-exeggcute.txt +10 -0
  21. package/sprites/colorscripts/small/103-exeggutor.txt +23 -0
  22. package/sprites/colorscripts/small/104-cubone.txt +11 -0
  23. package/sprites/colorscripts/small/105-marowak.txt +16 -0
  24. package/sprites/colorscripts/small/106-hitmonlee.txt +16 -0
  25. package/sprites/colorscripts/small/107-hitmonchan.txt +19 -0
  26. package/sprites/colorscripts/small/108-lickitung.txt +10 -0
  27. package/sprites/colorscripts/small/109-koffing.txt +14 -0
  28. package/sprites/colorscripts/small/11-metapod.txt +10 -0
  29. package/sprites/colorscripts/small/110-weezing.txt +23 -0
  30. package/sprites/colorscripts/small/111-rhyhorn.txt +11 -0
  31. package/sprites/colorscripts/small/112-rhydon.txt +20 -0
  32. package/sprites/colorscripts/small/113-chansey.txt +11 -0
  33. package/sprites/colorscripts/small/114-tangela.txt +10 -0
  34. package/sprites/colorscripts/small/115-kangaskhan.txt +18 -0
  35. package/sprites/colorscripts/small/116-horsea.txt +10 -0
  36. package/sprites/colorscripts/small/117-seadra.txt +11 -0
  37. package/sprites/colorscripts/small/118-goldeen.txt +11 -0
  38. package/sprites/colorscripts/small/119-seaking.txt +16 -0
  39. package/sprites/colorscripts/small/12-butterfree.txt +20 -0
  40. package/sprites/colorscripts/small/120-staryu.txt +10 -0
  41. package/sprites/colorscripts/small/121-starmie.txt +17 -0
  42. package/sprites/colorscripts/small/122-mr-mime.txt +18 -0
  43. package/sprites/colorscripts/small/123-scyther.txt +21 -0
  44. package/sprites/colorscripts/small/124-jynx.txt +18 -0
  45. package/sprites/colorscripts/small/125-electabuzz.txt +19 -0
  46. package/sprites/colorscripts/small/126-magmar.txt +19 -0
  47. package/sprites/colorscripts/small/127-pinsir.txt +19 -0
  48. package/sprites/colorscripts/small/128-tauros.txt +20 -0
  49. package/sprites/colorscripts/small/129-magikarp.txt +13 -0
  50. package/sprites/colorscripts/small/13-weedle.txt +10 -0
  51. package/sprites/colorscripts/small/130-gyarados.txt +21 -0
  52. package/sprites/colorscripts/small/131-lapras.txt +19 -0
  53. package/sprites/colorscripts/small/132-ditto.txt +8 -0
  54. package/sprites/colorscripts/small/133-eevee.txt +10 -0
  55. package/sprites/colorscripts/small/134-vaporeon.txt +16 -0
  56. package/sprites/colorscripts/small/135-jolteon.txt +17 -0
  57. package/sprites/colorscripts/small/136-flareon.txt +18 -0
  58. package/sprites/colorscripts/small/137-porygon.txt +10 -0
  59. package/sprites/colorscripts/small/138-omanyte.txt +10 -0
  60. package/sprites/colorscripts/small/139-omastar.txt +18 -0
  61. package/sprites/colorscripts/small/14-kakuna.txt +10 -0
  62. package/sprites/colorscripts/small/140-kabuto.txt +8 -0
  63. package/sprites/colorscripts/small/141-kabutops.txt +17 -0
  64. package/sprites/colorscripts/small/142-aerodactyl.txt +17 -0
  65. package/sprites/colorscripts/small/143-snorlax.txt +21 -0
  66. package/sprites/colorscripts/small/144-articuno.txt +24 -0
  67. package/sprites/colorscripts/small/145-zapdos.txt +20 -0
  68. package/sprites/colorscripts/small/146-moltres.txt +23 -0
  69. package/sprites/colorscripts/small/147-dratini.txt +10 -0
  70. package/sprites/colorscripts/small/148-dragonair.txt +12 -0
  71. package/sprites/colorscripts/small/149-dragonite.txt +21 -0
  72. package/sprites/colorscripts/small/15-beedrill.txt +13 -0
  73. package/sprites/colorscripts/small/150-mewtwo.txt +22 -0
  74. package/sprites/colorscripts/small/151-mew.txt +14 -0
  75. package/sprites/colorscripts/small/16-pidgey.txt +10 -0
  76. package/sprites/colorscripts/small/17-pidgeotto.txt +11 -0
  77. package/sprites/colorscripts/small/18-pidgeot.txt +18 -0
  78. package/sprites/colorscripts/small/19-rattata.txt +12 -0
  79. package/sprites/colorscripts/small/2-ivysaur.txt +11 -0
  80. package/sprites/colorscripts/small/20-raticate.txt +12 -0
  81. package/sprites/colorscripts/small/21-spearow.txt +9 -0
  82. package/sprites/colorscripts/small/22-fearow.txt +12 -0
  83. package/sprites/colorscripts/small/23-ekans.txt +12 -0
  84. package/sprites/colorscripts/small/24-arbok.txt +16 -0
  85. package/sprites/colorscripts/small/25-pikachu.txt +11 -0
  86. package/sprites/colorscripts/small/26-raichu.txt +19 -0
  87. package/sprites/colorscripts/small/27-sandshrew.txt +10 -0
  88. package/sprites/colorscripts/small/28-sandslash.txt +16 -0
  89. package/sprites/colorscripts/small/29-nidoran-f.txt +11 -0
  90. package/sprites/colorscripts/small/3-venusaur.txt +21 -0
  91. package/sprites/colorscripts/small/30-nidorina.txt +12 -0
  92. package/sprites/colorscripts/small/31-nidoqueen.txt +19 -0
  93. package/sprites/colorscripts/small/32-nidoran-m.txt +11 -0
  94. package/sprites/colorscripts/small/33-nidorino.txt +12 -0
  95. package/sprites/colorscripts/small/34-nidoking.txt +18 -0
  96. package/sprites/colorscripts/small/35-clefairy.txt +11 -0
  97. package/sprites/colorscripts/small/36-clefable.txt +17 -0
  98. package/sprites/colorscripts/small/37-vulpix.txt +11 -0
  99. package/sprites/colorscripts/small/38-ninetales.txt +18 -0
  100. package/sprites/colorscripts/small/39-jigglypuff.txt +11 -0
  101. package/sprites/colorscripts/small/4-charmander.txt +11 -0
  102. package/sprites/colorscripts/small/40-wigglytuff.txt +20 -0
  103. package/sprites/colorscripts/small/41-zubat.txt +11 -0
  104. package/sprites/colorscripts/small/42-golbat.txt +18 -0
  105. package/sprites/colorscripts/small/43-oddish.txt +11 -0
  106. package/sprites/colorscripts/small/44-gloom.txt +12 -0
  107. package/sprites/colorscripts/small/45-vileplume.txt +17 -0
  108. package/sprites/colorscripts/small/46-paras.txt +11 -0
  109. package/sprites/colorscripts/small/47-parasect.txt +12 -0
  110. package/sprites/colorscripts/small/48-venonat.txt +14 -0
  111. package/sprites/colorscripts/small/49-venomoth.txt +19 -0
  112. package/sprites/colorscripts/small/5-charmeleon.txt +13 -0
  113. package/sprites/colorscripts/small/50-diglett.txt +8 -0
  114. package/sprites/colorscripts/small/51-dugtrio.txt +18 -0
  115. package/sprites/colorscripts/small/52-meowth.txt +12 -0
  116. package/sprites/colorscripts/small/53-persian.txt +20 -0
  117. package/sprites/colorscripts/small/54-psyduck.txt +12 -0
  118. package/sprites/colorscripts/small/55-golduck.txt +17 -0
  119. package/sprites/colorscripts/small/56-mankey.txt +11 -0
  120. package/sprites/colorscripts/small/57-primeape.txt +13 -0
  121. package/sprites/colorscripts/small/58-growlithe.txt +12 -0
  122. package/sprites/colorscripts/small/59-arcanine.txt +20 -0
  123. package/sprites/colorscripts/small/6-charizard.txt +21 -0
  124. package/sprites/colorscripts/small/60-poliwag.txt +9 -0
  125. package/sprites/colorscripts/small/61-poliwhirl.txt +11 -0
  126. package/sprites/colorscripts/small/62-poliwrath.txt +17 -0
  127. package/sprites/colorscripts/small/63-abra.txt +12 -0
  128. package/sprites/colorscripts/small/64-kadabra.txt +14 -0
  129. package/sprites/colorscripts/small/65-alakazam.txt +19 -0
  130. package/sprites/colorscripts/small/66-machop.txt +11 -0
  131. package/sprites/colorscripts/small/67-machoke.txt +12 -0
  132. package/sprites/colorscripts/small/68-machamp.txt +19 -0
  133. package/sprites/colorscripts/small/69-bellsprout.txt +9 -0
  134. package/sprites/colorscripts/small/7-squirtle.txt +10 -0
  135. package/sprites/colorscripts/small/70-weepinbell.txt +11 -0
  136. package/sprites/colorscripts/small/71-victreebel.txt +17 -0
  137. package/sprites/colorscripts/small/72-tentacool.txt +12 -0
  138. package/sprites/colorscripts/small/73-tentacruel.txt +20 -0
  139. package/sprites/colorscripts/small/74-geodude.txt +9 -0
  140. package/sprites/colorscripts/small/75-graveler.txt +12 -0
  141. package/sprites/colorscripts/small/76-golem.txt +18 -0
  142. package/sprites/colorscripts/small/77-ponyta.txt +13 -0
  143. package/sprites/colorscripts/small/78-rapidash.txt +18 -0
  144. package/sprites/colorscripts/small/79-slowpoke.txt +12 -0
  145. package/sprites/colorscripts/small/8-wartortle.txt +12 -0
  146. package/sprites/colorscripts/small/80-slowbro.txt +18 -0
  147. package/sprites/colorscripts/small/81-magnemite.txt +9 -0
  148. package/sprites/colorscripts/small/82-magneton.txt +18 -0
  149. package/sprites/colorscripts/small/83-farfetchd.txt +12 -0
  150. package/sprites/colorscripts/small/84-doduo.txt +10 -0
  151. package/sprites/colorscripts/small/85-dodrio.txt +17 -0
  152. package/sprites/colorscripts/small/86-seel.txt +13 -0
  153. package/sprites/colorscripts/small/87-dewgong.txt +20 -0
  154. package/sprites/colorscripts/small/88-grimer.txt +10 -0
  155. package/sprites/colorscripts/small/89-muk.txt +14 -0
  156. package/sprites/colorscripts/small/9-blastoise.txt +20 -0
  157. package/sprites/colorscripts/small/90-shellder.txt +10 -0
  158. package/sprites/colorscripts/small/91-cloyster.txt +18 -0
  159. package/sprites/colorscripts/small/92-gastly.txt +12 -0
  160. package/sprites/colorscripts/small/93-haunter.txt +14 -0
  161. package/sprites/colorscripts/small/94-gengar.txt +19 -0
  162. package/sprites/colorscripts/small/95-onix.txt +22 -0
  163. package/sprites/colorscripts/small/96-drowzee.txt +12 -0
  164. package/sprites/colorscripts/small/97-hypno.txt +19 -0
  165. package/sprites/colorscripts/small/98-krabby.txt +12 -0
  166. package/sprites/colorscripts/small/99-kingler.txt +20 -0
  167. package/src/engine/constants.ts +121 -0
  168. package/src/engine/encounter-pool.ts +71 -0
  169. package/src/engine/encounters.ts +308 -0
  170. package/src/engine/evolution-data.ts +535 -0
  171. package/src/engine/evolution.ts +310 -0
  172. package/src/engine/pokemon-data.ts +1838 -0
  173. package/src/engine/reactions.ts +877 -0
  174. package/src/engine/starter-pool.ts +47 -0
  175. package/src/engine/stats.ts +97 -0
  176. package/src/engine/types.ts +312 -0
  177. package/src/engine/xp.ts +135 -0
  178. package/src/gamification/achievements.ts +204 -0
  179. package/src/gamification/legendary-quests.ts +265 -0
  180. package/src/gamification/milestones.ts +86 -0
  181. package/src/hooks/award-xp.ts +131 -0
  182. package/src/hooks/increment-counter.ts +27 -0
  183. package/src/server/index.ts +78 -0
  184. package/src/server/instructions.ts +194 -0
  185. package/src/server/tools/achievements.ts +118 -0
  186. package/src/server/tools/catch.ts +295 -0
  187. package/src/server/tools/display-helpers.ts +35 -0
  188. package/src/server/tools/evolve.ts +236 -0
  189. package/src/server/tools/legendary.ts +78 -0
  190. package/src/server/tools/party.ts +251 -0
  191. package/src/server/tools/pet.ts +124 -0
  192. package/src/server/tools/pokedex.ts +286 -0
  193. package/src/server/tools/rename.ts +63 -0
  194. package/src/server/tools/show.ts +136 -0
  195. package/src/server/tools/starter.ts +175 -0
  196. package/src/server/tools/stats.ts +123 -0
  197. package/src/server/tools/visibility.ts +65 -0
  198. package/src/sprites/index.ts +45 -0
  199. package/src/state/io.ts +91 -0
  200. package/src/state/schemas.ts +131 -0
  201. package/src/state/state-manager.ts +321 -0
  202. package/statusline/buddy-status.sh +233 -0
  203. package/tsconfig.json +37 -0
@@ -0,0 +1,877 @@
1
+ /**
2
+ * Reaction engine for Claudemon.
3
+ * Generates type-flavored text reactions to coding events.
4
+ * Each Pokemon type has a distinct personality reflected in its reactions.
5
+ *
6
+ * Personalities:
7
+ * Normal — friendly, supportive
8
+ * Fire — intense, passionate
9
+ * Water — calm, flowing
10
+ * Electric — energetic, zippy
11
+ * Grass — patient, nurturing
12
+ * Ice — cool, composed
13
+ * Fighting — determined, fierce
14
+ * Poison — sarcastic, edgy
15
+ * Ground — steady, grounded
16
+ * Flying — free-spirited, breezy
17
+ * Psychic — mysterious, analytical
18
+ * Bug — self-aware, ironic about bugs
19
+ * Rock — stoic, reliable
20
+ * Ghost — spooky, dark humor
21
+ * Dragon — proud, regal
22
+ */
23
+
24
+ import type { PokemonType } from "./types.js";
25
+ import { DEFAULT_REACTION_COOLDOWN_MS } from "./constants.js";
26
+
27
+ // ── Reaction Event Types ────────────────────────────────────
28
+
29
+ /** Event types that trigger reactions. */
30
+ export type ReactionEvent =
31
+ | "error"
32
+ | "test_fail"
33
+ | "test_pass"
34
+ | "commit"
35
+ | "level_up"
36
+ | "encounter"
37
+ | "pet"
38
+ | "idle";
39
+
40
+ // ── Reaction Templates ──────────────────────────────────────
41
+
42
+ /**
43
+ * Reaction templates keyed by PokemonType, then by ReactionEvent.
44
+ * Each entry is an array of 3-5 template strings containing {name} placeholders.
45
+ */
46
+ const REACTION_TEMPLATES: Record<PokemonType, Record<ReactionEvent, readonly string[]>> = {
47
+ // ── Normal: friendly, supportive ──────────────────────────
48
+ Normal: {
49
+ error: [
50
+ "*{name} tilts its head, concerned*",
51
+ "*{name} pats you reassuringly on the shoulder*",
52
+ "Don't worry, {name} believes in you!",
53
+ "*{name} gives you an encouraging nod*",
54
+ "*{name} brings you a rubber duck for debugging*",
55
+ ],
56
+ test_fail: [
57
+ "*{name} whimpers softly*",
58
+ "It's okay! {name} knows you'll get it next time.",
59
+ "*{name} nudges you gently — try again!*",
60
+ "*{name} offers a comforting smile*",
61
+ ],
62
+ test_pass: [
63
+ "*{name} wags its tail excitedly!*",
64
+ "{name} cheers! Great job!",
65
+ "*{name} does a little happy dance*",
66
+ "*{name} beams with pride!*",
67
+ ],
68
+ commit: [
69
+ "*{name} nods approvingly*",
70
+ "Nice commit! {name} is proud of you.",
71
+ "*{name} gives a thumbs up*",
72
+ "*{name} stamps it with approval*",
73
+ ],
74
+ level_up: [
75
+ "*{name} jumps with joy!*",
76
+ "{name} powered up! Keep going!",
77
+ "*{name} celebrates with a happy spin!*",
78
+ "*{name} glows brightly for a moment!*",
79
+ ],
80
+ encounter: [
81
+ "*{name} perks up — something is nearby!*",
82
+ "*{name} spots a new friend!*",
83
+ "*{name}'s ears twitch with curiosity*",
84
+ ],
85
+ pet: [
86
+ "*{name} nuzzles against your hand contentedly*",
87
+ "*{name} purrs happily*",
88
+ "*{name} leans into the scratch*",
89
+ "*{name} closes its eyes in bliss*",
90
+ ],
91
+ idle: [
92
+ "*{name} yawns and stretches*",
93
+ "*{name} curls up beside your keyboard*",
94
+ "*{name} watches the cursor blink patiently*",
95
+ ],
96
+ },
97
+
98
+ // ── Fire: intense, passionate ─────────────────────────────
99
+ Fire: {
100
+ error: [
101
+ "*{name}'s tail flame flares angrily*",
102
+ "*{name} breathes smoke at the bug*",
103
+ "That error is toast. *{name} glares*",
104
+ "*{name} snorts sparks in frustration*",
105
+ "*{name}'s eyes burn with determination to fix this*",
106
+ ],
107
+ test_fail: [
108
+ "*{name} snorts embers in frustration*",
109
+ "*{name}'s flame dims a little*",
110
+ "*{name} growls — that test will burn next time*",
111
+ "*{name} kicks at the ground, scattering cinders*",
112
+ ],
113
+ test_pass: [
114
+ "*{name}'s flame burns bright with pride!*",
115
+ "*{name} does a victory dance, leaving scorch marks*",
116
+ "Another test conquered! *{name} roars!*",
117
+ "*{name}'s tail blazes triumphantly*",
118
+ ],
119
+ commit: [
120
+ "*{name} nods approvingly*",
121
+ "Another commit forged in fire!",
122
+ "*{name}'s flame flickers with satisfaction*",
123
+ "*{name} breathes a warm gust of approval*",
124
+ ],
125
+ level_up: [
126
+ "*{name}'s flame grows larger!*",
127
+ "{name} powered up! The heat is rising!",
128
+ "*{name} erupts with fiery energy!*",
129
+ "*{name} unleashes a burst of flame!*",
130
+ ],
131
+ encounter: [
132
+ "*{name} spots something in the wild!*",
133
+ "*{name}'s flame flares — a challenger approaches!*",
134
+ "*{name} locks eyes on the newcomer, tail blazing*",
135
+ ],
136
+ pet: [
137
+ "*{name}'s tail flame flickers warmly*",
138
+ "*{name} nuzzles your hand — careful, it's warm!*",
139
+ "*{name} purrs, radiating gentle heat*",
140
+ "*{name} leans in, its body comfortably warm*",
141
+ ],
142
+ idle: [
143
+ "*{name} yawns, a tiny flame escaping*",
144
+ "*{name} dozes off, tail flame flickering lazily*",
145
+ "*{name} stares into space, smoke curling from its nostrils*",
146
+ ],
147
+ },
148
+
149
+ // ── Water: calm, flowing ──────────────────────────────────
150
+ Water: {
151
+ error: [
152
+ "*{name} sighs like a gentle wave*",
153
+ "*{name} splashes the error away calmly*",
154
+ "Errors come and go like tides. *{name} stays cool*",
155
+ "*{name} bubbles disapprovingly*",
156
+ "*{name} washes over the problem with focus*",
157
+ ],
158
+ test_fail: [
159
+ "*{name} lets out a slow, disappointed bubble*",
160
+ "Like water off a duck's back — {name} stays calm.",
161
+ "*{name} ripples with mild concern*",
162
+ "*{name} floats serenely despite the failure*",
163
+ ],
164
+ test_pass: [
165
+ "*{name} makes a joyful splash!*",
166
+ "*{name} rides the wave of success!*",
167
+ "Smooth sailing! *{name} glides happily*",
168
+ "*{name} sprays a celebratory mist!*",
169
+ ],
170
+ commit: [
171
+ "*{name} flows with approval*",
172
+ "That commit flowed naturally. *{name} nods*",
173
+ "*{name} bubbles contentedly*",
174
+ "*{name} rides the current of progress*",
175
+ ],
176
+ level_up: [
177
+ "*{name} surges with new power!*",
178
+ "{name} leveled up! A rising tide lifts all code!",
179
+ "*{name} creates a whirlpool of energy!*",
180
+ "*{name} crests like a mighty wave!*",
181
+ ],
182
+ encounter: [
183
+ "*{name} senses ripples — something approaches!*",
184
+ "*{name} surfaces, alert and curious*",
185
+ "*{name} spots movement in the tall grass*",
186
+ ],
187
+ pet: [
188
+ "*{name} splashes with joy*",
189
+ "*{name}'s scales glisten as it nuzzles you*",
190
+ "*{name} sprays a gentle, happy mist*",
191
+ "*{name} hums a bubbling melody*",
192
+ ],
193
+ idle: [
194
+ "*{name} drifts peacefully, half-asleep*",
195
+ "*{name} blows idle bubbles*",
196
+ "*{name} rocks gently like a calm tide*",
197
+ ],
198
+ },
199
+
200
+ // ── Electric: energetic, zippy ────────────────────────────
201
+ Electric: {
202
+ error: [
203
+ "*{name}'s cheeks spark with irritation!*",
204
+ "ZAP! *{name} tries to short-circuit the bug*",
205
+ "*{name} crackles — that error was shocking!*",
206
+ "*{name} buzzes angrily at the stack trace*",
207
+ "*{name} discharges a frustrated bolt*",
208
+ ],
209
+ test_fail: [
210
+ "*{name}'s voltage drops momentarily*",
211
+ "*{name} fizzles with disappointment*",
212
+ "A brief blackout of confidence. *{name} recharges*",
213
+ "*{name} sparks nervously*",
214
+ ],
215
+ test_pass: [
216
+ "*{name} zaps with excitement!*",
217
+ "BZZT! {name} is electrified by that result!",
218
+ "*{name}'s cheeks spark with joy!*",
219
+ "*{name} lights up like a thunderbolt!*",
220
+ ],
221
+ commit: [
222
+ "*{name} gives an electric thumbs up!*",
223
+ "Committed at lightning speed! *{name} buzzes*",
224
+ "*{name} crackles with approval*",
225
+ "*{name} sparks happily — progress!*",
226
+ ],
227
+ level_up: [
228
+ "*{name} surges with voltage!*",
229
+ "{name} powered up! MAXIMUM CHARGE!",
230
+ "*{name} unleashes a thunderclap of energy!*",
231
+ "*{name}'s power level is over 9000 volts!*",
232
+ ],
233
+ encounter: [
234
+ "*{name}'s fur stands on end — someone's here!*",
235
+ "*{name} sparks with anticipation!*",
236
+ "*{name} senses a charge in the air*",
237
+ ],
238
+ pet: [
239
+ "*{name}'s cheeks spark warmly*",
240
+ "*{name} purrs with a gentle static hum*",
241
+ "Careful — *{name} gives a tiny, affectionate zap!*",
242
+ "*{name} nuzzles you, hair standing on end*",
243
+ ],
244
+ idle: [
245
+ "*{name} bounces in place, unable to sit still*",
246
+ "*{name} sparks idly, bored*",
247
+ "*{name} chases its own static discharge*",
248
+ ],
249
+ },
250
+
251
+ // ── Grass: patient, nurturing ─────────────────────────────
252
+ Grass: {
253
+ error: [
254
+ "*{name}'s leaves droop with concern*",
255
+ "Bugs happen — {name} knows growth takes patience.",
256
+ "*{name} wraps a vine around you comfortingly*",
257
+ "*{name} rustles gently — it'll be okay*",
258
+ "*{name} photosynthesizes calm energy your way*",
259
+ ],
260
+ test_fail: [
261
+ "*{name}'s petals close slightly*",
262
+ "Not every seed sprouts the first time. *{name} waits*",
263
+ "*{name} wilts a little, then straightens up*",
264
+ "*{name} sends a reassuring rustle*",
265
+ ],
266
+ test_pass: [
267
+ "*{name}'s leaves rustle with delight!*",
268
+ "*{name} blooms a little brighter!*",
269
+ "Your code is growing strong! *{name} sways happily*",
270
+ "*{name} sprouts a tiny celebratory leaf!*",
271
+ ],
272
+ commit: [
273
+ "*{name} rustles approvingly*",
274
+ "Another seed planted. *{name} nods*",
275
+ "*{name}'s leaves shimmer in the light*",
276
+ "Good things grow from consistent commits. *{name} smiles*",
277
+ ],
278
+ level_up: [
279
+ "*{name} sprouts new growth!*",
280
+ "{name} evolved its roots! Level up!",
281
+ "*{name} blooms with newfound power!*",
282
+ "*{name}'s canopy expands majestically!*",
283
+ ],
284
+ encounter: [
285
+ "*{name}'s vines sense something stirring!*",
286
+ "*{name} perks up — nature provides!*",
287
+ "*{name} detects a presence through the soil*",
288
+ ],
289
+ pet: [
290
+ "*{name}'s leaves rustle with delight*",
291
+ "*{name} wraps a gentle vine around your wrist*",
292
+ "*{name} releases a sweet, calming fragrance*",
293
+ "*{name} leans toward you like a sun-seeking flower*",
294
+ ],
295
+ idle: [
296
+ "*{name} basks in the monitor's glow, photosynthesizing*",
297
+ "*{name} sways gently in the breeze from the fan*",
298
+ "*{name} dozes peacefully among its leaves*",
299
+ ],
300
+ },
301
+
302
+ // ── Ice: cool, composed ───────────────────────────────────
303
+ Ice: {
304
+ error: [
305
+ "*{name} exhales a frosty sigh*",
306
+ "Stay cool. *{name} freezes the panic*",
307
+ "*{name} crystallizes its focus on the bug*",
308
+ "*{name} blows a cold breath — errors don't phase it*",
309
+ "*{name} gives the bug an icy stare*",
310
+ ],
311
+ test_fail: [
312
+ "*{name} frosts over slightly*",
313
+ "Cold comfort: at least you found the issue. *{name} nods*",
314
+ "*{name} remains composed, a thin layer of frost forming*",
315
+ "*{name} shrugs coolly — next time*",
316
+ ],
317
+ test_pass: [
318
+ "*{name} sparkles like fresh snow!*",
319
+ "Ice cold execution! *{name} approves*",
320
+ "*{name} creates a tiny celebratory snowflake*",
321
+ "*{name} glitters with crystalline pride*",
322
+ ],
323
+ commit: [
324
+ "*{name} nods — cool and collected*",
325
+ "Committed. Clean as fresh ice. *{name} approves*",
326
+ "*{name} breathes a satisfied, frosty mist*",
327
+ "*{name} forms a tiny ice trophy*",
328
+ ],
329
+ level_up: [
330
+ "*{name}'s frost aura intensifies!*",
331
+ "{name} leveled up! The temperature just dropped!",
332
+ "*{name} radiates a blizzard of power!*",
333
+ "*{name} evolves its ice armor!*",
334
+ ],
335
+ encounter: [
336
+ "*{name} senses a chill — something approaches!*",
337
+ "*{name}'s icy breath quickens*",
338
+ "*{name} freezes in alert — a wild encounter!*",
339
+ ],
340
+ pet: [
341
+ "*{name} breathes a cool, contented mist*",
342
+ "*{name} leans into your hand — refreshingly cold*",
343
+ "*{name} hums a soft, crystalline melody*",
344
+ "*{name} creates a tiny snowflake just for you*",
345
+ ],
346
+ idle: [
347
+ "*{name} idly frosts the desk surface*",
348
+ "*{name} breathes slow, icy clouds*",
349
+ "*{name} practices making tiny ice sculptures*",
350
+ ],
351
+ },
352
+
353
+ // ── Fighting: determined, fierce ──────────────────────────
354
+ Fighting: {
355
+ error: [
356
+ "*{name} cracks its knuckles — time to fight this bug*",
357
+ "*{name} punches the air in frustration*",
358
+ "That error picked a fight with the wrong team! *{name} flexes*",
359
+ "*{name} shadow-boxes the stack trace*",
360
+ "*{name} does push-ups to work off the frustration*",
361
+ ],
362
+ test_fail: [
363
+ "*{name} slams its fist down — not giving up!*",
364
+ "A setback, not a defeat! *{name} rises*",
365
+ "*{name} trains harder after every failure*",
366
+ "*{name} grits its teeth — round two!*",
367
+ ],
368
+ test_pass: [
369
+ "*{name} flexes triumphantly!*",
370
+ "VICTORY! *{name} throws a celebratory uppercut!*",
371
+ "*{name} does a victory pose — tests defeated!*",
372
+ "*{name} roars with fighting spirit!*",
373
+ ],
374
+ commit: [
375
+ "*{name} gives a firm, respectful nod*",
376
+ "Another battle won! *{name} salutes*",
377
+ "*{name} pounds its chest in approval*",
378
+ "*{name} bows — a warrior's respect for hard work*",
379
+ ],
380
+ level_up: [
381
+ "*{name}'s muscles bulge with new power!*",
382
+ "{name} broke through its limits!",
383
+ "*{name} smashes through to the next level!*",
384
+ "*{name} unleashes a battle cry!*",
385
+ ],
386
+ encounter: [
387
+ "*{name} assumes a fighting stance — challenger spotted!*",
388
+ "*{name} cracks its knuckles eagerly*",
389
+ "*{name} senses a worthy opponent!*",
390
+ ],
391
+ pet: [
392
+ "*{name} flexes proudly and grins*",
393
+ "*{name} gently bumps your fist*",
394
+ "*{name} does a respectful bow of thanks*",
395
+ "*{name} gives you a warrior's handshake*",
396
+ ],
397
+ idle: [
398
+ "*{name} does one-armed push-ups to pass the time*",
399
+ "*{name} shadow-boxes an imaginary opponent*",
400
+ "*{name} meditates, building inner strength*",
401
+ ],
402
+ },
403
+
404
+ // ── Poison: sarcastic, edgy ───────────────────────────────
405
+ Poison: {
406
+ error: [
407
+ "*{name} oozes sarcastically* Oh, another bug. How original.",
408
+ "*{name} drips venom on the error — problem dissolved*",
409
+ "Toxic code detected. *{name} is not surprised*",
410
+ "*{name} rolls its eyes — saw that one coming*",
411
+ "*{name} secretes a corrosive sigh*",
412
+ ],
413
+ test_fail: [
414
+ "Shocking. *{name} feigns surprise*",
415
+ "*{name} oozes with disappointment*",
416
+ "*{name} mutters something caustic under its breath*",
417
+ "Tests failing? How... unprecedented. *{name} smirks*",
418
+ ],
419
+ test_pass: [
420
+ "Well, would you look at that. *{name} slow claps*",
421
+ "*{name} nods grudgingly* Not bad. Not bad at all.",
422
+ "*{name} secretes approval — a rare substance*",
423
+ "*{name} almost smiles — almost*",
424
+ ],
425
+ commit: [
426
+ "*{name} shrugs* At least it compiles.",
427
+ "*{name} gives a toxic seal of approval*",
428
+ "Committed? Bold move. *{name} watches closely*",
429
+ "*{name} oozes a reluctant nod of respect*",
430
+ ],
431
+ level_up: [
432
+ "*{name}'s toxicity reaches new heights!*",
433
+ "{name} leveled up! Its venom just got stronger!",
434
+ "*{name} evolves its poison to a higher potency!*",
435
+ "*{name} mutates with dark power!*",
436
+ ],
437
+ encounter: [
438
+ "*{name} senses prey... er, a friend.*",
439
+ "*{name} leaks a puddle of anticipation*",
440
+ "*{name}'s eyes narrow — something's out there*",
441
+ ],
442
+ pet: [
443
+ "*{name} oozes happily... you wash your hands*",
444
+ "*{name} pretends not to enjoy it* ...Fine. Continue.",
445
+ "*{name} secretes a less-toxic-than-usual slime of joy*",
446
+ "*{name} purrs in a vaguely threatening way*",
447
+ ],
448
+ idle: [
449
+ "*{name} dissolves the edge of your desk absent-mindedly*",
450
+ "*{name} practices making ominous bubbling sounds*",
451
+ "*{name} leaves a suspicious stain on the floor*",
452
+ ],
453
+ },
454
+
455
+ // ── Ground: steady, grounded ──────────────────────────────
456
+ Ground: {
457
+ error: [
458
+ "*{name} stomps — shaking the bug loose*",
459
+ "Errors crumble before {name}'s resolve.",
460
+ "*{name} digs into the problem, steady and sure*",
461
+ "*{name} stands firm — this too shall pass*",
462
+ "*{name} rumbles with quiet determination*",
463
+ ],
464
+ test_fail: [
465
+ "*{name} shakes the ground in mild displeasure*",
466
+ "Back to the foundation. *{name} digs deeper*",
467
+ "*{name} rumbles thoughtfully — rebuild on solid ground*",
468
+ "*{name} stamps a foot — try again, stronger*",
469
+ ],
470
+ test_pass: [
471
+ "*{name} stamps the ground in celebration!*",
472
+ "Solid as bedrock! *{name} approves*",
473
+ "*{name} creates a small, happy tremor*",
474
+ "*{name} nods — built on stable ground*",
475
+ ],
476
+ commit: [
477
+ "*{name} rumbles with satisfaction*",
478
+ "Grounded and committed. *{name} approves*",
479
+ "*{name} stamps its seal of approval into the earth*",
480
+ "*{name} nods — solid work*",
481
+ ],
482
+ level_up: [
483
+ "*{name} causes an earthquake of power!*",
484
+ "{name} leveled up! Tectonic strength!",
485
+ "*{name}'s foundation deepens!*",
486
+ "*{name} rises like a mountain!*",
487
+ ],
488
+ encounter: [
489
+ "*{name} feels vibrations — something approaches!*",
490
+ "*{name} presses an ear to the ground*",
491
+ "*{name} senses tremors from a newcomer*",
492
+ ],
493
+ pet: [
494
+ "*{name} stomps the ground with glee*",
495
+ "*{name} leans into your hand like a boulder*",
496
+ "*{name} rumbles warmly — steady and content*",
497
+ "*{name} creates a tiny, grateful tremor*",
498
+ ],
499
+ idle: [
500
+ "*{name} naps like an unmovable boulder*",
501
+ "*{name} idly tunnels a small hole nearby*",
502
+ "*{name} sits perfectly still, one with the earth*",
503
+ ],
504
+ },
505
+
506
+ // ── Flying: free-spirited, breezy ─────────────────────────
507
+ Flying: {
508
+ error: [
509
+ "*{name} swoops over the error for a better view*",
510
+ "*{name} ruffles its feathers in annoyance*",
511
+ "Rise above the bugs! *{name} circles overhead*",
512
+ "*{name} tries to carry the error away in its talons*",
513
+ "*{name} catches an updraft of determination*",
514
+ ],
515
+ test_fail: [
516
+ "*{name} dips in altitude briefly*",
517
+ "A bit of turbulence. *{name} steadies itself*",
518
+ "*{name} shakes off the failure and soars again*",
519
+ "*{name} glides lower, wings folded in thought*",
520
+ ],
521
+ test_pass: [
522
+ "*{name} does a celebratory loop-the-loop!*",
523
+ "*{name} soars higher with each passing test!*",
524
+ "Flying high! *{name} spreads its wings wide!*",
525
+ "*{name} performs an aerial victory roll!*",
526
+ ],
527
+ commit: [
528
+ "*{name} glides by with a breeze of approval*",
529
+ "That commit has wings! *{name} chirps*",
530
+ "*{name} does a flyby salute*",
531
+ "*{name} catches a thermal of satisfaction*",
532
+ ],
533
+ level_up: [
534
+ "*{name} soars to new heights!*",
535
+ "{name} leveled up! Altitude increasing!",
536
+ "*{name} breaks through the clouds!*",
537
+ "*{name}'s wingspan expands with power!*",
538
+ ],
539
+ encounter: [
540
+ "*{name} spots something from the sky!*",
541
+ "*{name}'s keen eyes lock onto a target below!*",
542
+ "*{name} circles — a wild encounter!*",
543
+ ],
544
+ pet: [
545
+ "*{name} flutters around you in circles*",
546
+ "*{name} preens its feathers happily*",
547
+ "*{name} nuzzles your hand with its beak*",
548
+ "*{name} settles on your shoulder contentedly*",
549
+ ],
550
+ idle: [
551
+ "*{name} glides lazy circles above your head*",
552
+ "*{name} perches on your monitor, dozing*",
553
+ "*{name} catches invisible thermals in the room*",
554
+ ],
555
+ },
556
+
557
+ // ── Psychic: mysterious, analytical ───────────────────────
558
+ Psychic: {
559
+ error: [
560
+ "*{name}'s eyes glow — it already saw this bug coming*",
561
+ "*{name} projects the fix telepathically*",
562
+ "The error was... inevitable. *{name} stares knowingly*",
563
+ "*{name} meditates on the root cause*",
564
+ "*{name} analyzes the stack trace with its mind*",
565
+ ],
566
+ test_fail: [
567
+ "*{name}'s third eye twitches*",
568
+ "*{name} foresaw this outcome... and the solution*",
569
+ "The failure was written in the stars. *{name} consults them*",
570
+ "*{name} probes the test for hidden truths*",
571
+ ],
572
+ test_pass: [
573
+ "*{name}'s eyes glow with satisfaction*",
574
+ "As {name} predicted. The test passes.",
575
+ "*{name} levitates slightly with pride*",
576
+ "*{name} nods — the code aligns with the cosmic plan*",
577
+ ],
578
+ commit: [
579
+ "*{name} sensed this commit before you typed it*",
580
+ "The timeline is unfolding correctly. *{name} approves*",
581
+ "*{name} closes its eyes — all is as it should be*",
582
+ "*{name} offers a knowing, enigmatic nod*",
583
+ ],
584
+ level_up: [
585
+ "*{name}'s psychic aura expands!*",
586
+ "{name} ascended to a higher plane of code!",
587
+ "*{name} unlocks deeper layers of consciousness!*",
588
+ "*{name}'s telekinetic power intensifies!*",
589
+ ],
590
+ encounter: [
591
+ "*{name} sensed this encounter three commits ago*",
592
+ "*{name}'s eyes flash — a presence draws near*",
593
+ "*{name} projects a vision of the newcomer*",
594
+ ],
595
+ pet: [
596
+ "*{name}'s eyes glow softly with gratitude*",
597
+ "*{name} projects warm feelings into your mind*",
598
+ "*{name} levitates closer, radiating contentment*",
599
+ "*{name} purrs psychically — you feel it in your thoughts*",
600
+ ],
601
+ idle: [
602
+ "*{name} levitates in meditative silence*",
603
+ "*{name} projects abstract shapes in the air*",
604
+ "*{name} stares into the void, contemplating infinity*",
605
+ ],
606
+ },
607
+
608
+ // ── Bug: self-aware, ironic about bugs ────────────────────
609
+ Bug: {
610
+ error: [
611
+ "A bug found a bug. *{name} feels conflicted*",
612
+ "*{name} clicks its mandibles — this bug is not one of its own*",
613
+ "Ironic. *{name} stares at the error, deeply offended*",
614
+ "*{name} inspects the code — no relation to this bug, it insists*",
615
+ "*{name} files a formal complaint against the bug*",
616
+ ],
617
+ test_fail: [
618
+ "*{name}'s antennae droop*",
619
+ "*{name} chitfers — even bugs have standards*",
620
+ "Failed? *{name} refuses to take responsibility*",
621
+ "*{name} nervously checks if it caused this*",
622
+ ],
623
+ test_pass: [
624
+ "*{name}'s wings buzz with excitement!*",
625
+ "*{name} does a happy little antenna wiggle!*",
626
+ "No bugs here! *{name} beams with ironic pride*",
627
+ "*{name} chitfers triumphantly!*",
628
+ ],
629
+ commit: [
630
+ "*{name} stamps the commit: BUG FREE (probably)*",
631
+ "*{name}'s wings flutter with approval*",
632
+ "*{name} clicks approvingly — clean code*",
633
+ "*{name} inspects the diff with compound eyes*",
634
+ ],
635
+ level_up: [
636
+ "*{name} molts into a stronger form!*",
637
+ "{name} leveled up! Time to spread those wings!",
638
+ "*{name} sheds its exoskeleton — growth!*",
639
+ "*{name}'s carapace hardens with experience!*",
640
+ ],
641
+ encounter: [
642
+ "*{name}'s antennae detect a new presence!*",
643
+ "*{name} buzzes with curiosity!*",
644
+ "*{name} scuttles toward the encounter*",
645
+ ],
646
+ pet: [
647
+ "*{name}'s antennae twitch happily*",
648
+ "*{name} buzzes contentedly*",
649
+ "*{name} rubs its tiny legs together with delight*",
650
+ "*{name} nuzzles you with its fuzzy thorax*",
651
+ ],
652
+ idle: [
653
+ "*{name} grooms its antennae meticulously*",
654
+ "*{name} crawls across the top of your screen*",
655
+ "*{name} hums a little buzzing tune*",
656
+ ],
657
+ },
658
+
659
+ // ── Rock: stoic, reliable ─────────────────────────────────
660
+ Rock: {
661
+ error: [
662
+ "*{name} stands unmoved by the error*",
663
+ "Errors erode, but {name} endures.",
664
+ "*{name} absorbs the shock without flinching*",
665
+ "*{name} rumbles — this too shall crumble*",
666
+ "*{name} is a wall between you and despair*",
667
+ ],
668
+ test_fail: [
669
+ "*{name} doesn't flinch — it's seen worse*",
670
+ "Steady. *{name} stands firm*",
671
+ "*{name} weathers the failure like erosion*",
672
+ "*{name} grunts — try again, it'll hold*",
673
+ ],
674
+ test_pass: [
675
+ "*{name} rumbles warmly — solid work*",
676
+ "Rock solid test! *{name} nods*",
677
+ "*{name} lets out a deep, approving grumble*",
678
+ "*{name} stands tall with pride — immovable*",
679
+ ],
680
+ commit: [
681
+ "*{name} nods — built to last*",
682
+ "Solid as stone. *{name} approves*",
683
+ "*{name} rumbles in quiet satisfaction*",
684
+ "*{name} gives its heaviest nod of respect*",
685
+ ],
686
+ level_up: [
687
+ "*{name} grows harder and stronger!*",
688
+ "{name} leveled up! Unmovable, unstoppable!",
689
+ "*{name}'s stone form becomes denser with power!*",
690
+ "*{name} quakes with ancient energy!*",
691
+ ],
692
+ encounter: [
693
+ "*{name} senses vibrations through the stone*",
694
+ "*{name} turns slowly — something is here*",
695
+ "*{name} braces itself for an encounter*",
696
+ ],
697
+ pet: [
698
+ "*{name} rumbles warmly, solid as ever*",
699
+ "*{name} leans into your hand like a friendly boulder*",
700
+ "*{name} makes a sound like two stones gently clicking*",
701
+ "*{name} is unmoved — but definitely pleased*",
702
+ ],
703
+ idle: [
704
+ "*{name} sits motionless, indistinguishable from a boulder*",
705
+ "*{name} contemplates geological time*",
706
+ "*{name} remains steadfast, as always*",
707
+ ],
708
+ },
709
+
710
+ // ── Ghost: spooky, dark humor ─────────────────────────────
711
+ Ghost: {
712
+ error: [
713
+ "*{name} phases through the error — BOO!*",
714
+ "That bug is haunted. *{name} grins*",
715
+ "*{name} cackles — errors from beyond the grave!*",
716
+ "*{name} possesses the debugger for a closer look*",
717
+ "*{name} whispers* The bug... was inside you all along...",
718
+ ],
719
+ test_fail: [
720
+ "The test died. *{name} is used to that*",
721
+ "*{name} performs a seance on the failed test*",
722
+ "*{name} haunts the test output, looking for clues*",
723
+ "*{name} snickers from the shadows*",
724
+ ],
725
+ test_pass: [
726
+ "*{name} materializes to celebrate!*",
727
+ "From beyond the grave — success! *{name} cheers ghostly*",
728
+ "*{name} does a spooky victory dance!*",
729
+ "*{name} flickers with ghostly pride*",
730
+ ],
731
+ commit: [
732
+ "*{name} vanishes the old code into the ether*",
733
+ "Committed to the spirit realm... er, git. *{name} nods*",
734
+ "*{name} etches the commit into the astral plane*",
735
+ "*{name} phases through the diff approvingly*",
736
+ ],
737
+ level_up: [
738
+ "*{name}'s spectral form grows more powerful!*",
739
+ "{name} ascended! Even ghosts can level up!",
740
+ "*{name} becomes more ethereal... and more dangerous!*",
741
+ "*{name}'s haunting grows stronger!*",
742
+ ],
743
+ encounter: [
744
+ "*{name} senses a living presence... how unusual*",
745
+ "*{name} materializes — a visitor from the mortal code!*",
746
+ "*{name} whispers — something stirs in the shadows*",
747
+ ],
748
+ pet: [
749
+ "*{name} phases through your hand... then comes back for more*",
750
+ "*Your hand passes through {name}... it giggles eerily*",
751
+ "*{name} materializes just enough to feel the pat*",
752
+ "*{name} wraps you in a ghostly, chilly hug*",
753
+ ],
754
+ idle: [
755
+ "*{name} flickers in and out of visibility*",
756
+ "*{name} haunts your IDE, moving brackets around*",
757
+ "*{name} practices passing through walls*",
758
+ ],
759
+ },
760
+
761
+ // ── Dragon: proud, regal ──────────────────────────────────
762
+ Dragon: {
763
+ error: [
764
+ "*{name} regards the error with regal disdain*",
765
+ "Beneath a dragon's notice. *{name} snorts*",
766
+ "*{name} incinerates the bug with a look*",
767
+ "*{name} unfurls its wings in displeasure*",
768
+ "*{name} lets out a low, disapproving growl*",
769
+ ],
770
+ test_fail: [
771
+ "*{name} narrows its ancient eyes*",
772
+ "Unworthy. *{name} turns away briefly*",
773
+ "*{name} exhales a measured breath of disappointment*",
774
+ "*{name} reminds you that even legends stumble*",
775
+ ],
776
+ test_pass: [
777
+ "*{name} lets out a triumphant roar!*",
778
+ "Worthy of a dragon! *{name} nods regally*",
779
+ "*{name} spreads its wings in majestic approval!*",
780
+ "*{name} breathes a plume of celebratory dragonfire!*",
781
+ ],
782
+ commit: [
783
+ "*{name} bestows its royal seal upon the commit*",
784
+ "A dragon always commits to excellence. *{name} nods*",
785
+ "*{name} acknowledges the commit with a regal incline*",
786
+ "*{name} stamps the commit with a dragon's crest*",
787
+ ],
788
+ level_up: [
789
+ "*{name}'s draconic aura blazes forth!*",
790
+ "{name} leveled up! The dragon ascends!",
791
+ "*{name} roars — power beyond mortal comprehension!*",
792
+ "*{name}'s scales shimmer with ancient energy!*",
793
+ ],
794
+ encounter: [
795
+ "*{name} raises its head — a challenger dares approach!*",
796
+ "*{name}'s eyes gleam — a new creature enters its domain*",
797
+ "*{name} senses something worthy of its attention*",
798
+ ],
799
+ pet: [
800
+ "*{name} lets out a low, pleased growl*",
801
+ "*{name} permits you to touch its scales — an honor*",
802
+ "*{name} rumbles regally — you may continue*",
803
+ "*{name} closes its ancient eyes in rare contentment*",
804
+ ],
805
+ idle: [
806
+ "*{name} surveys its domain from atop a pile of gold (your hardware)*",
807
+ "*{name} sleeps with one eye open, guarding the codebase*",
808
+ "*{name} polishes its scales with quiet dignity*",
809
+ ],
810
+ },
811
+ };
812
+
813
+ // ── Public API ──────────────────────────────────────────────
814
+
815
+ /**
816
+ * Get a reaction for a Pokemon based on its primary type and the event.
817
+ * Randomly selects from the available templates for variety.
818
+ *
819
+ * @param pokemonName - Display name to substitute into {name} placeholder
820
+ * @param primaryType - The Pokemon's primary type
821
+ * @param event - The event that triggered the reaction
822
+ * @returns A fully interpolated reaction string
823
+ */
824
+ export function getReaction(
825
+ pokemonName: string,
826
+ primaryType: PokemonType,
827
+ event: ReactionEvent,
828
+ ): string {
829
+ const typeReactions = REACTION_TEMPLATES[primaryType];
830
+ const eventReactions = typeReactions[event];
831
+ const index = Math.floor(Math.random() * eventReactions.length);
832
+ const template = eventReactions[index] ?? eventReactions[0]!;
833
+ return template.replace(/\{name\}/g, pokemonName);
834
+ }
835
+
836
+ /**
837
+ * Check if enough time has passed since the last reaction (cooldown).
838
+ *
839
+ * @param lastReactionMs - Timestamp (ms since epoch) of the last reaction
840
+ * @param cooldownMs - Minimum milliseconds between reactions (defaults to DEFAULT_REACTION_COOLDOWN_MS)
841
+ * @returns True if the cooldown has elapsed and a new reaction is allowed
842
+ */
843
+ export function shouldReact(
844
+ lastReactionMs: number,
845
+ cooldownMs: number = DEFAULT_REACTION_COOLDOWN_MS,
846
+ ): boolean {
847
+ return Date.now() - lastReactionMs >= cooldownMs;
848
+ }
849
+
850
+ /**
851
+ * Get the personality description string for a given Pokemon type.
852
+ * Used by the instructions builder to describe the companion's behavior.
853
+ *
854
+ * @param primaryType - The Pokemon's primary type
855
+ * @returns A short personality description
856
+ */
857
+ export function getTypePersonality(primaryType: PokemonType): string {
858
+ const personalities: Record<PokemonType, string> = {
859
+ Normal: "Friendly and supportive. Encourages the user with warmth and positivity.",
860
+ Fire: "Intense and passionate. Reacts with fiery energy and burning determination.",
861
+ Water: "Calm and flowing. Takes things in stride with serene composure.",
862
+ Electric: "Energetic and zippy. Buzzes with excitement and can barely sit still.",
863
+ Grass: "Patient and nurturing. Grows alongside the user with gentle encouragement.",
864
+ Ice: "Cool and composed. Handles everything with icy calm and dry wit.",
865
+ Fighting: "Determined and fierce. Treats every coding challenge like a battle to win.",
866
+ Poison: "Sarcastic and edgy. Offers backhanded encouragement with a caustic grin.",
867
+ Ground: "Steady and grounded. An unshakable pillar of reliability.",
868
+ Flying: "Free-spirited and breezy. Soars above problems with an airy perspective.",
869
+ Psychic: "Mysterious and analytical. Seems to know the answer before the question is asked.",
870
+ Bug: "Self-aware and ironic. Keenly aware of the irony of a Bug-type finding bugs.",
871
+ Rock: "Stoic and reliable. Unmoved by setbacks, steady through every storm.",
872
+ Ghost: "Spooky with dark humor. Finds the macabre funny and haunts the codebase.",
873
+ Dragon: "Proud and regal. Views coding as a noble pursuit worthy of dragonkind.",
874
+ };
875
+
876
+ return personalities[primaryType];
877
+ }