@lyellr88/buddy-mcp 1.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.
Files changed (258) hide show
  1. package/README.md +219 -0
  2. package/dist/config/claude-config.d.ts +7 -0
  3. package/dist/config/claude-config.d.ts.map +1 -0
  4. package/dist/config/claude-config.js +107 -0
  5. package/dist/config/claude-config.js.map +1 -0
  6. package/dist/config/hooks.d.ts +22 -0
  7. package/dist/config/hooks.d.ts.map +1 -0
  8. package/dist/config/hooks.js +58 -0
  9. package/dist/config/hooks.js.map +1 -0
  10. package/dist/config/index.d.ts +4 -0
  11. package/dist/config/index.d.ts.map +1 -0
  12. package/dist/config/index.js +6 -0
  13. package/dist/config/index.js.map +1 -0
  14. package/dist/config/pet-config.d.ts +12 -0
  15. package/dist/config/pet-config.d.ts.map +1 -0
  16. package/dist/config/pet-config.js +150 -0
  17. package/dist/config/pet-config.js.map +1 -0
  18. package/dist/constants.d.ts +24 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +94 -0
  21. package/dist/constants.js.map +1 -0
  22. package/dist/finder/estimator.d.ts +3 -0
  23. package/dist/finder/estimator.d.ts.map +1 -0
  24. package/dist/finder/estimator.js +27 -0
  25. package/dist/finder/estimator.js.map +1 -0
  26. package/dist/finder/index.d.ts +3 -0
  27. package/dist/finder/index.d.ts.map +1 -0
  28. package/dist/finder/index.js +3 -0
  29. package/dist/finder/index.js.map +1 -0
  30. package/dist/finder/orchestrator.d.ts +8 -0
  31. package/dist/finder/orchestrator.d.ts.map +1 -0
  32. package/dist/finder/orchestrator.js +163 -0
  33. package/dist/finder/orchestrator.js.map +1 -0
  34. package/dist/finder/worker.d.ts +3 -0
  35. package/dist/finder/worker.d.ts.map +1 -0
  36. package/dist/finder/worker.js +130 -0
  37. package/dist/finder/worker.js.map +1 -0
  38. package/dist/generation/hash.d.ts +5 -0
  39. package/dist/generation/hash.d.ts.map +1 -0
  40. package/dist/generation/hash.js +37 -0
  41. package/dist/generation/hash.js.map +1 -0
  42. package/dist/generation/index.d.ts +4 -0
  43. package/dist/generation/index.d.ts.map +1 -0
  44. package/dist/generation/index.js +4 -0
  45. package/dist/generation/index.js.map +1 -0
  46. package/dist/generation/rng.d.ts +4 -0
  47. package/dist/generation/rng.d.ts.map +1 -0
  48. package/dist/generation/rng.js +14 -0
  49. package/dist/generation/rng.js.map +1 -0
  50. package/dist/generation/roll.d.ts +7 -0
  51. package/dist/generation/roll.d.ts.map +1 -0
  52. package/dist/generation/roll.js +51 -0
  53. package/dist/generation/roll.js.map +1 -0
  54. package/dist/mcp/index.d.ts +5 -0
  55. package/dist/mcp/index.d.ts.map +1 -0
  56. package/dist/mcp/index.js +273 -0
  57. package/dist/mcp/index.js.map +1 -0
  58. package/dist/mcp/persistence.d.ts +6 -0
  59. package/dist/mcp/persistence.d.ts.map +1 -0
  60. package/dist/mcp/persistence.js +129 -0
  61. package/dist/mcp/persistence.js.map +1 -0
  62. package/dist/mcp/state.d.ts +74 -0
  63. package/dist/mcp/state.d.ts.map +1 -0
  64. package/dist/mcp/state.js +20 -0
  65. package/dist/mcp/state.js.map +1 -0
  66. package/dist/mcp/tools/auto.d.ts +4 -0
  67. package/dist/mcp/tools/auto.d.ts.map +1 -0
  68. package/dist/mcp/tools/auto.js +15 -0
  69. package/dist/mcp/tools/auto.js.map +1 -0
  70. package/dist/mcp/tools/core.d.ts +2 -0
  71. package/dist/mcp/tools/core.d.ts.map +1 -0
  72. package/dist/mcp/tools/core.js +350 -0
  73. package/dist/mcp/tools/core.js.map +1 -0
  74. package/dist/mcp/tools/export.d.ts +2 -0
  75. package/dist/mcp/tools/export.d.ts.map +1 -0
  76. package/dist/mcp/tools/export.js +161 -0
  77. package/dist/mcp/tools/export.js.map +1 -0
  78. package/dist/mcp/tools/interact.d.ts +2 -0
  79. package/dist/mcp/tools/interact.d.ts.map +1 -0
  80. package/dist/mcp/tools/interact.js +56 -0
  81. package/dist/mcp/tools/interact.js.map +1 -0
  82. package/dist/mcp/tools/stats.d.ts +4 -0
  83. package/dist/mcp/tools/stats.d.ts.map +1 -0
  84. package/dist/mcp/tools/stats.js +87 -0
  85. package/dist/mcp/tools/stats.js.map +1 -0
  86. package/dist/mcp/watcher.d.ts +3 -0
  87. package/dist/mcp/watcher.d.ts.map +1 -0
  88. package/dist/mcp/watcher.js +117 -0
  89. package/dist/mcp/watcher.js.map +1 -0
  90. package/dist/patcher/binary-finder.d.ts +3 -0
  91. package/dist/patcher/binary-finder.d.ts.map +1 -0
  92. package/dist/patcher/binary-finder.js +169 -0
  93. package/dist/patcher/binary-finder.js.map +1 -0
  94. package/dist/patcher/index.d.ts +5 -0
  95. package/dist/patcher/index.d.ts.map +1 -0
  96. package/dist/patcher/index.js +5 -0
  97. package/dist/patcher/index.js.map +1 -0
  98. package/dist/patcher/patch.d.ts +5 -0
  99. package/dist/patcher/patch.d.ts.map +1 -0
  100. package/dist/patcher/patch.js +148 -0
  101. package/dist/patcher/patch.js.map +1 -0
  102. package/dist/patcher/preflight.d.ts +5 -0
  103. package/dist/patcher/preflight.d.ts.map +1 -0
  104. package/dist/patcher/preflight.js +145 -0
  105. package/dist/patcher/preflight.js.map +1 -0
  106. package/dist/patcher/salt-ops.d.ts +18 -0
  107. package/dist/patcher/salt-ops.d.ts.map +1 -0
  108. package/dist/patcher/salt-ops.js +93 -0
  109. package/dist/patcher/salt-ops.js.map +1 -0
  110. package/dist/personalities.d.ts +10 -0
  111. package/dist/personalities.d.ts.map +1 -0
  112. package/dist/personalities.js +295 -0
  113. package/dist/personalities.js.map +1 -0
  114. package/dist/presets.d.ts +11 -0
  115. package/dist/presets.d.ts.map +1 -0
  116. package/dist/presets.js +207 -0
  117. package/dist/presets.js.map +1 -0
  118. package/dist/sprites/data.d.ts +4 -0
  119. package/dist/sprites/data.d.ts.map +1 -0
  120. package/dist/sprites/data.js +103 -0
  121. package/dist/sprites/data.js.map +1 -0
  122. package/dist/sprites/index.d.ts +3 -0
  123. package/dist/sprites/index.d.ts.map +1 -0
  124. package/dist/sprites/index.js +3 -0
  125. package/dist/sprites/index.js.map +1 -0
  126. package/dist/sprites/render.d.ts +15 -0
  127. package/dist/sprites/render.d.ts.map +1 -0
  128. package/dist/sprites/render.js +77 -0
  129. package/dist/sprites/render.js.map +1 -0
  130. package/dist/tui/animator.d.ts +13 -0
  131. package/dist/tui/animator.d.ts.map +1 -0
  132. package/dist/tui/animator.js +39 -0
  133. package/dist/tui/animator.js.map +1 -0
  134. package/dist/tui/apply/index.d.ts +9 -0
  135. package/dist/tui/apply/index.d.ts.map +1 -0
  136. package/dist/tui/apply/index.js +553 -0
  137. package/dist/tui/apply/index.js.map +1 -0
  138. package/dist/tui/builder/colors.d.ts +15 -0
  139. package/dist/tui/builder/colors.d.ts.map +1 -0
  140. package/dist/tui/builder/colors.js +20 -0
  141. package/dist/tui/builder/colors.js.map +1 -0
  142. package/dist/tui/builder/index.d.ts +6 -0
  143. package/dist/tui/builder/index.d.ts.map +1 -0
  144. package/dist/tui/builder/index.js +172 -0
  145. package/dist/tui/builder/index.js.map +1 -0
  146. package/dist/tui/builder/keyboard.d.ts +17 -0
  147. package/dist/tui/builder/keyboard.d.ts.map +1 -0
  148. package/dist/tui/builder/keyboard.js +76 -0
  149. package/dist/tui/builder/keyboard.js.map +1 -0
  150. package/dist/tui/builder/preview-panel.d.ts +9 -0
  151. package/dist/tui/builder/preview-panel.d.ts.map +1 -0
  152. package/dist/tui/builder/preview-panel.js +103 -0
  153. package/dist/tui/builder/preview-panel.js.map +1 -0
  154. package/dist/tui/builder/selection-panel.d.ts +11 -0
  155. package/dist/tui/builder/selection-panel.d.ts.map +1 -0
  156. package/dist/tui/builder/selection-panel.js +446 -0
  157. package/dist/tui/builder/selection-panel.js.map +1 -0
  158. package/dist/tui/builder/stat-bars.d.ts +4 -0
  159. package/dist/tui/builder/stat-bars.d.ts.map +1 -0
  160. package/dist/tui/builder/stat-bars.js +46 -0
  161. package/dist/tui/builder/stat-bars.js.map +1 -0
  162. package/dist/tui/builder/state.d.ts +22 -0
  163. package/dist/tui/builder/state.d.ts.map +1 -0
  164. package/dist/tui/builder/state.js +92 -0
  165. package/dist/tui/builder/state.js.map +1 -0
  166. package/dist/tui/cli.d.ts +3 -0
  167. package/dist/tui/cli.d.ts.map +1 -0
  168. package/dist/tui/cli.js +26 -0
  169. package/dist/tui/cli.js.map +1 -0
  170. package/dist/tui/commands/buddies.d.ts +2 -0
  171. package/dist/tui/commands/buddies.d.ts.map +1 -0
  172. package/dist/tui/commands/buddies.js +172 -0
  173. package/dist/tui/commands/buddies.js.map +1 -0
  174. package/dist/tui/commands/current.d.ts +2 -0
  175. package/dist/tui/commands/current.d.ts.map +1 -0
  176. package/dist/tui/commands/current.js +35 -0
  177. package/dist/tui/commands/current.js.map +1 -0
  178. package/dist/tui/commands/interactive.d.ts +6 -0
  179. package/dist/tui/commands/interactive.d.ts.map +1 -0
  180. package/dist/tui/commands/interactive.js +385 -0
  181. package/dist/tui/commands/interactive.js.map +1 -0
  182. package/dist/tui/commands/preview.d.ts +3 -0
  183. package/dist/tui/commands/preview.d.ts.map +1 -0
  184. package/dist/tui/commands/preview.js +94 -0
  185. package/dist/tui/commands/preview.js.map +1 -0
  186. package/dist/tui/commands/rehatch.d.ts +2 -0
  187. package/dist/tui/commands/rehatch.d.ts.map +1 -0
  188. package/dist/tui/commands/rehatch.js +30 -0
  189. package/dist/tui/commands/rehatch.js.map +1 -0
  190. package/dist/tui/commands/restore.d.ts +2 -0
  191. package/dist/tui/commands/restore.d.ts.map +1 -0
  192. package/dist/tui/commands/restore.js +52 -0
  193. package/dist/tui/commands/restore.js.map +1 -0
  194. package/dist/tui/commands/share.d.ts +2 -0
  195. package/dist/tui/commands/share.d.ts.map +1 -0
  196. package/dist/tui/commands/share.js +105 -0
  197. package/dist/tui/commands/share.js.map +1 -0
  198. package/dist/tui/commands/start-screen.d.ts +3 -0
  199. package/dist/tui/commands/start-screen.d.ts.map +1 -0
  200. package/dist/tui/commands/start-screen.js +93 -0
  201. package/dist/tui/commands/start-screen.js.map +1 -0
  202. package/dist/tui/display.d.ts +5 -0
  203. package/dist/tui/display.d.ts.map +1 -0
  204. package/dist/tui/display.js +33 -0
  205. package/dist/tui/display.js.map +1 -0
  206. package/dist/tui/format.d.ts +5 -0
  207. package/dist/tui/format.d.ts.map +1 -0
  208. package/dist/tui/format.js +21 -0
  209. package/dist/tui/format.js.map +1 -0
  210. package/dist/tui/gallery/index.d.ts +12 -0
  211. package/dist/tui/gallery/index.d.ts.map +1 -0
  212. package/dist/tui/gallery/index.js +153 -0
  213. package/dist/tui/gallery/index.js.map +1 -0
  214. package/dist/tui/gallery/keyboard.d.ts +15 -0
  215. package/dist/tui/gallery/keyboard.d.ts.map +1 -0
  216. package/dist/tui/gallery/keyboard.js +41 -0
  217. package/dist/tui/gallery/keyboard.js.map +1 -0
  218. package/dist/tui/gallery/profile-list-panel.d.ts +10 -0
  219. package/dist/tui/gallery/profile-list-panel.d.ts.map +1 -0
  220. package/dist/tui/gallery/profile-list-panel.js +66 -0
  221. package/dist/tui/gallery/profile-list-panel.js.map +1 -0
  222. package/dist/tui/gallery/profile-preview-panel.d.ts +9 -0
  223. package/dist/tui/gallery/profile-preview-panel.d.ts.map +1 -0
  224. package/dist/tui/gallery/profile-preview-panel.js +121 -0
  225. package/dist/tui/gallery/profile-preview-panel.js.map +1 -0
  226. package/dist/tui/gallery/state.d.ts +13 -0
  227. package/dist/tui/gallery/state.d.ts.map +1 -0
  228. package/dist/tui/gallery/state.js +33 -0
  229. package/dist/tui/gallery/state.js.map +1 -0
  230. package/dist/tui/index.d.ts +9 -0
  231. package/dist/tui/index.d.ts.map +1 -0
  232. package/dist/tui/index.js +9 -0
  233. package/dist/tui/index.js.map +1 -0
  234. package/dist/tui/launcher.d.ts +3 -0
  235. package/dist/tui/launcher.d.ts.map +1 -0
  236. package/dist/tui/launcher.js +24 -0
  237. package/dist/tui/launcher.js.map +1 -0
  238. package/dist/tui/presets/index.d.ts +3 -0
  239. package/dist/tui/presets/index.d.ts.map +1 -0
  240. package/dist/tui/presets/index.js +202 -0
  241. package/dist/tui/presets/index.js.map +1 -0
  242. package/dist/tui/presets/preset-list-panel.d.ts +9 -0
  243. package/dist/tui/presets/preset-list-panel.d.ts.map +1 -0
  244. package/dist/tui/presets/preset-list-panel.js +52 -0
  245. package/dist/tui/presets/preset-list-panel.js.map +1 -0
  246. package/dist/tui/prompts.d.ts +13 -0
  247. package/dist/tui/prompts.d.ts.map +1 -0
  248. package/dist/tui/prompts.js +126 -0
  249. package/dist/tui/prompts.js.map +1 -0
  250. package/dist/tui/start/index.d.ts +3 -0
  251. package/dist/tui/start/index.d.ts.map +1 -0
  252. package/dist/tui/start/index.js +170 -0
  253. package/dist/tui/start/index.js.map +1 -0
  254. package/dist/types.d.ts +113 -0
  255. package/dist/types.d.ts.map +1 -0
  256. package/dist/types.js +2 -0
  257. package/dist/types.js.map +1 -0
  258. package/package.json +82 -0
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # buddy-mcp
2
+
3
+ A break from long code sessions. Stuck on a bug? Reroll a buddy, talk with them, or pet them to build affection and improve your odds at higher-tier buddies on the next roll. If enough people want it, I'll build out Battle-Buddies where you can pit your buddy against others and unlock exclusive species that sync back into your local pool.
4
+
5
+ > A gacha companion system for Claude Code. Roll for a rare buddy, patch it directly into the binary, collect 'em all. Buddy-mcp is an MCP server that replaces Claude Code's built-in companion with one you actually rolled for. Reroll, get lucky, close Claude, reopen. Your new buddy is waiting. Legendary drop rates apply.
6
+
7
+ ---
8
+
9
+ ## How It Works
10
+
11
+ Claude Code's companion is generated from a salt string baked into the binary. buddy-mcp:
12
+
13
+ 1. Rolls random desired traits (species, rarity, eye, hat)
14
+ 2. Brute-forces a salt that hashes to those traits (multi-worker, runs fast)
15
+ 3. Patches the binary in place, or queues the patch for when you close Claude
16
+ 4. Saves your full buddy profile with stats, name, and personality
17
+ 5. Tracks every species you've ever rolled in your BuddyDex
18
+
19
+ No companion server. No cloud. Just you, your binary, and the gacha gods.
20
+
21
+ ---
22
+
23
+ ## TUI Builder (`buddy-mcp-build`)
24
+
25
+ Want more control? Use the interactive builder:
26
+
27
+ ```bash
28
+ node dist/tui/cli.js
29
+ ```
30
+
31
+ | Command | What it does |
32
+ |---------|-------------|
33
+ | `build your own` | Pick species, rarity, eye, hat — brute-forces a matching salt and patches |
34
+ | `browse presets` | Pick from curated preset buddies |
35
+ | `saved buddies` | Switch between previously saved buddy profiles |
36
+ | `current` | Display current buddy info |
37
+ | `preview` | Preview ASCII art for any species |
38
+ | `share` | Copy your buddy's ASCII card to clipboard |
39
+ | `restore` | Restore binary from the best available backup |
40
+ | `rehatch` | Delete current buddy and start fresh |
41
+
42
+ > Bun optional but recommended — install [bun.sh](https://bun.sh) for the full animated TUI. Falls back to sequential prompts without it.
43
+
44
+ ---
45
+
46
+ ## Quick Start
47
+
48
+ > **Try me:** run `reroll_buddy` → close Claude Code → reopen → your new buddy is live.
49
+
50
+ ### 1. Prerequisites
51
+
52
+ - [Claude Code CLI](https://claude.ai/download) installed
53
+ - [Node.js](https://nodejs.org/) v20+ — required for everything
54
+ - [Bun](https://bun.sh/) — required for salt brute-forcing (rerolling) + full animated TUI
55
+
56
+ ### 2. Install via npm
57
+
58
+ ```bash
59
+ npm install -g buddy-mcp
60
+ ```
61
+
62
+ This installs both commands globally:
63
+ - `buddy-mcp` — the MCP server (Claude Code runs this)
64
+ - `buddy-mcp-build` — the interactive TUI builder (you run this)
65
+
66
+ ### 3. Register with Claude
67
+
68
+ ```bash
69
+ claude mcp add buddy-mcp buddy-mcp
70
+ ```
71
+
72
+ Claude will auto-detect the installed binary and connect it.
73
+
74
+ ### 4. Verify
75
+
76
+ Open Claude Code and ask: **"show me my buddy card"**
77
+
78
+ You should see a card with your current companion's species, rarity, and stats. You're in.
79
+
80
+ ### 5. Launch the TUI Builder (optional)
81
+
82
+ For the full interactive builder with live preview:
83
+
84
+ ```bash
85
+ buddy-mcp-build
86
+ ```
87
+
88
+ Auto-detects Bun for animated TUI. Falls back to basic prompts without it.
89
+
90
+ ---
91
+
92
+ ## The Gacha System
93
+
94
+ Every reroll is a random pull from the pool. Rarity affects stat floors. Legendaries hit different.
95
+
96
+ | Rarity | Drop Rate | Stat Floor |
97
+ |-----------|-----------|------------|
98
+ | Common | 60% | 5 |
99
+ | Uncommon | 25% | 15 |
100
+ | Rare | 10% | 25 |
101
+ | Epic | 4% | 35 |
102
+ | Legendary | 1% | 50 |
103
+
104
+ **18 species:** duck · goose · blob · cat · dragon · octopus · owl · penguin · turtle · snail · ghost · axolotl · capybara · cactus · robot · rabbit · mushroom · chonk
105
+
106
+ Each buddy has 5 stats: **Debugging, Patience, Chaos, Wisdom, Snark**. A peak stat is boosted high and a dump stat is kept humble. Personality shapes how `buddy_speak` and `pet_buddy` respond. A high-Chaos dragon hits different than a patient turtle.
107
+
108
+ ---
109
+
110
+ | Tool | What it does |
111
+ |------|-------------|
112
+ | `reroll_buddy` | 🎲 Spin the wheel. Brute-forces a salt matching a random rare+ outcome and patches your binary. Close Claude and reopen to see it. |
113
+ | `get_buddy_card` | 🪪 Display your current buddy card. Species, rarity, stats, name, ASCII art, everything. |
114
+ | `pet_buddy` | 🤚 Poke your buddy. Builds affection. Every pet counts toward better reroll odds, with 25/50/75 pet milestones unlocking rarity bonuses. |
115
+ | `buddy_speak` | 💬 Ask your buddy to say something. Personality-aligned, stat-influenced. Output shown verbatim. |
116
+ | `view_buddy_dex` | 📖 Browse every species you've ever rolled. Gotta catch 'em all. |
117
+ | `export_buddy_card` | 🖼️ Export your full buddy card as an SVG image file. |
118
+ | `export_buddy_sprite` | 🎨 Export just the buddy ASCII sprite as an SVG image file. |
119
+ | `activate_buddy_interact` | 👁️ Start buddy observation mode. Your buddy will react to session events based on personality. |
120
+ | `deactivate_buddy_interact` | 🔕 Stop observation mode. Your buddy goes quiet. |
121
+
122
+ ### Stat Personality Tools
123
+
124
+ **20 baked-in tools.** Only **2 are visible** at a time: 1 randomly picked from each of your buddy's **top 2 stats by raw value**. The other 18 stay hidden. The visible pair is **locked per roll**. It doesn't change until you reroll. Every buddy shows a different pair.
125
+
126
+ | Tool | Stat | What it does |
127
+ |------|------|-------------|
128
+ | `deep_trace` | Debugging | Focused bug hunting. Curt, clinical, slightly haunted. |
129
+ | `trace_nightmare` | Debugging | When the trace stops making sense. Surreal debugging perspective |
130
+ | `null_hunt` | Debugging | Hunt for null refs. Clinical. Relentless |
131
+ | `stack_dive` | Debugging | Dive into the callstack. The bug is always deeper than you think |
132
+ | `patience_check` | Patience | Check if your buddy is still willing to help |
133
+ | `wait_wisdom` | Patience | Slow down. Receive patience-encoded insight |
134
+ | `vibe_check` | Patience | The mystery action. Your buddy reads the vibe. 5% cosmic event |
135
+ | `still_point` | Patience | Stop. Be still. Let the answer come to you |
136
+ | `chaos_audit` | Chaos | Unpredictable. Might help. Might not. Science |
137
+ | `chaos_roulette` | Chaos | Spin the chaos wheel. Receive a wildly lateral suggestion |
138
+ | `chaos_spark` | Chaos | Ignite a lateral idea. May or may not be relevant |
139
+ | `entropy_roll` | Chaos | Roll against entropy. The universe responds |
140
+ | `zen_consult` | Wisdom | Philosophical insight into your architecture |
141
+ | `zen_mirror` | Wisdom | Turn the question inward. A reflection, not an answer |
142
+ | `oracle_seek` | Wisdom | Seek the oracle. The answer is already inside you |
143
+ | `deep_thought` | Wisdom | Think slower. The answer requires depth |
144
+ | `snark_roast` | Snark | Light sarcastic critique of your current work |
145
+ | `snark_savage` | Snark | No mercy. Full roast. For when you need the unfiltered truth |
146
+ | `side_eye` | Snark | Your buddy looks at your code. Then at you. Then back at the code |
147
+ | `snark_verdict` | Snark | Final ruling from the bench. The buddy has reviewed and judged |
148
+
149
+ ---
150
+
151
+ ## Patch Flow
152
+
153
+ buddy-mcp patches the Claude binary directly. Here's what happens when you hit `reroll_buddy`:
154
+
155
+ ```
156
+ reroll_buddy
157
+
158
+ ├─ Roll random traits (species, rarity, eye, hat, shiny chance)
159
+
160
+ ├─ Multi-worker salt search (up to 8 parallel Bun workers)
161
+ │ └─ Each worker brute-forces salts using wyhash until traits match
162
+
163
+ ├─ Try to patch binary immediately
164
+ │ ├─ Success → "Close Claude and reopen"
165
+ │ └─ EPERM (Claude is running) → Save pending patch + start background watcher
166
+ │ └─ Watcher polls every 2s, applies patch the moment Claude closes
167
+
168
+ └─ Profile saved: species, rarity, stats, name, personality
169
+
170
+ On next session start (hook fires):
171
+
172
+ ├─ Salt still valid → no-op (fast path)
173
+
174
+ ├─ Pending patch found → apply it
175
+
176
+ └─ Salt mismatch (Claude auto-updated)
177
+ ├─ Try .buddy-mcp-bak (only if it contains original salt)
178
+ ├─ Try .anybuddy-bak (fallback for prior patcher users)
179
+ └─ Restore + re-patch automatically — no reinstall required
180
+ ```
181
+
182
+
183
+ ---
184
+
185
+ ## State Files
186
+
187
+ buddy-mcp stores everything in your home directory:
188
+
189
+ | File | Purpose |
190
+ |------|---------|
191
+ | `~/.buddy-mcp.json` | Your buddy profiles (species, rarity, stats, name, salt) |
192
+ | `~/.buddy_mcp_gacha.json` | Gacha extras: shiny count, BuddyDex, manifested tools |
193
+ | `~/.buddy_mcp_pending.json` | Queued patch waiting for Claude to close |
194
+
195
+ ---
196
+
197
+ ## Manual Apply (Fallback)
198
+
199
+ If the background watcher didn't fire for some reason, you can apply a pending patch manually:
200
+
201
+ ```bash
202
+ npm run apply
203
+ ```
204
+
205
+ Then restart Claude Code.
206
+
207
+ ---
208
+
209
+ ## Personality
210
+
211
+ Each buddy gets a name and a personality derived from their species. Personality shapes how `buddy_speak`, `pet_buddy`, and stat tools respond. A high-Chaos dragon hits different than a patient turtle.
212
+
213
+ ---
214
+
215
+ ## Credits
216
+
217
+ Forked and extended from [any-buddy](https://github.com/cpaczek/any-buddy) by cpaczek.
218
+
219
+ Licensed under [WTFPL](http://www.wtfpl.net/).
@@ -0,0 +1,7 @@
1
+ export declare function getClaudeUserId(): string;
2
+ export declare function getCompanionName(): string | null;
3
+ export declare function renameCompanion(newName: string): void;
4
+ export declare function getCompanionPersonality(): string | null;
5
+ export declare function setCompanionPersonality(personality: string): void;
6
+ export declare function deleteCompanion(): boolean;
7
+ //# sourceMappingURL=claude-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-config.d.ts","sourceRoot":"","sources":["../../src/config/claude-config.ts"],"names":[],"mappings":"AAYA,wBAAgB,eAAe,IAAI,MAAM,CAexC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAShD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAiBrD;AAED,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CASvD;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAiBjE;AAED,wBAAgB,eAAe,IAAI,OAAO,CAczC"}
@@ -0,0 +1,107 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ function getClaudeConfigPath() {
5
+ const paths = [join(homedir(), '.claude.json'), join(homedir(), '.claude', '.config.json')];
6
+ for (const p of paths) {
7
+ if (existsSync(p))
8
+ return p;
9
+ }
10
+ return paths[0];
11
+ }
12
+ export function getClaudeUserId() {
13
+ const paths = [join(homedir(), '.claude.json'), join(homedir(), '.claude', '.config.json')];
14
+ for (const p of paths) {
15
+ if (existsSync(p)) {
16
+ try {
17
+ const config = JSON.parse(readFileSync(p, 'utf-8'));
18
+ return config.oauthAccount?.accountUuid ?? config.userID ?? 'anon';
19
+ }
20
+ catch {
21
+ continue;
22
+ }
23
+ }
24
+ }
25
+ return 'anon';
26
+ }
27
+ export function getCompanionName() {
28
+ const configPath = getClaudeConfigPath();
29
+ if (!existsSync(configPath))
30
+ return null;
31
+ try {
32
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
33
+ return config.companion?.name ?? null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ export function renameCompanion(newName) {
40
+ const configPath = getClaudeConfigPath();
41
+ if (!existsSync(configPath)) {
42
+ throw new Error(`Claude config not found at ${configPath}`);
43
+ }
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ let config;
46
+ try {
47
+ config = JSON.parse(readFileSync(configPath, 'utf-8'));
48
+ }
49
+ catch {
50
+ throw new Error(`Failed to parse Claude config at ${configPath}`);
51
+ }
52
+ if (!config.companion) {
53
+ throw new Error('No companion found in config. Run /buddy in Claude Code first to hatch one.');
54
+ }
55
+ config.companion.name = newName;
56
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
57
+ }
58
+ export function getCompanionPersonality() {
59
+ const configPath = getClaudeConfigPath();
60
+ if (!existsSync(configPath))
61
+ return null;
62
+ try {
63
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
64
+ return config.companion?.personality ?? null;
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
70
+ export function setCompanionPersonality(personality) {
71
+ const configPath = getClaudeConfigPath();
72
+ if (!existsSync(configPath)) {
73
+ throw new Error(`Claude config not found at ${configPath}`);
74
+ }
75
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
+ let config;
77
+ try {
78
+ config = JSON.parse(readFileSync(configPath, 'utf-8'));
79
+ }
80
+ catch {
81
+ throw new Error(`Failed to parse Claude config at ${configPath}`);
82
+ }
83
+ if (!config.companion) {
84
+ throw new Error('No companion found in config. Run /buddy in Claude Code first to hatch one.');
85
+ }
86
+ config.companion.personality = personality;
87
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
88
+ }
89
+ export function deleteCompanion() {
90
+ const configPath = getClaudeConfigPath();
91
+ if (!existsSync(configPath))
92
+ return false;
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ let config;
95
+ try {
96
+ config = JSON.parse(readFileSync(configPath, 'utf-8'));
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ if (!config.companion)
102
+ return false;
103
+ delete config.companion;
104
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
105
+ return true;
106
+ }
107
+ //# sourceMappingURL=claude-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-config.js","sourceRoot":"","sources":["../../src/config/claude-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ interface HookEntry {
2
+ type: string;
3
+ command: string;
4
+ }
5
+ interface MatcherEntry {
6
+ matcher: string;
7
+ hooks: HookEntry[];
8
+ }
9
+ interface ClaudeSettings {
10
+ hooks?: {
11
+ SessionStart?: MatcherEntry[];
12
+ [key: string]: MatcherEntry[] | undefined;
13
+ };
14
+ [key: string]: unknown;
15
+ }
16
+ export declare function getClaudeSettings(): ClaudeSettings;
17
+ export declare function saveClaudeSettings(settings: ClaudeSettings): void;
18
+ export declare function isHookInstalled(): boolean;
19
+ export declare function installHook(scriptPath: string): void;
20
+ export declare function removeHook(): void;
21
+ export {};
22
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/config/hooks.ts"],"names":[],"mappings":"AAUA,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;QAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,SAAS,CAAC;KAC3C,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAOlD;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAIjE;AAWD,wBAAgB,eAAe,IAAI,OAAO,CAGzC;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAapD;AAED,wBAAgB,UAAU,IAAI,IAAI,CASjC"}
@@ -0,0 +1,58 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ const SETTINGS_PATH = join(homedir(), '.claude', 'settings.json');
5
+ function buildHookCommand(scriptPath) {
6
+ return `node "${scriptPath}" apply --silent`;
7
+ }
8
+ export function getClaudeSettings() {
9
+ if (!existsSync(SETTINGS_PATH))
10
+ return {};
11
+ try {
12
+ return JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8'));
13
+ }
14
+ catch {
15
+ return {};
16
+ }
17
+ }
18
+ export function saveClaudeSettings(settings) {
19
+ const dir = join(homedir(), '.claude');
20
+ if (!existsSync(dir))
21
+ mkdirSync(dir, { recursive: true });
22
+ writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\n', { mode: 0o600 });
23
+ }
24
+ function findHookEntry(matchers) {
25
+ if (!Array.isArray(matchers))
26
+ return null;
27
+ return (matchers.find((m) => Array.isArray(m.hooks) && m.hooks.some((h) => h.command.includes('apply --silent') && h.command.includes('index.js'))) ?? null);
28
+ }
29
+ export function isHookInstalled() {
30
+ const settings = getClaudeSettings();
31
+ return findHookEntry(settings.hooks?.SessionStart) !== null;
32
+ }
33
+ export function installHook(scriptPath) {
34
+ const settings = getClaudeSettings();
35
+ if (!settings.hooks)
36
+ settings.hooks = {};
37
+ if (!Array.isArray(settings.hooks.SessionStart))
38
+ settings.hooks.SessionStart = [];
39
+ if (!findHookEntry(settings.hooks.SessionStart)) {
40
+ settings.hooks.SessionStart.push({
41
+ matcher: '',
42
+ hooks: [{ type: 'command', command: buildHookCommand(scriptPath) }],
43
+ });
44
+ }
45
+ saveClaudeSettings(settings);
46
+ }
47
+ export function removeHook() {
48
+ const settings = getClaudeSettings();
49
+ if (!settings.hooks?.SessionStart)
50
+ return;
51
+ settings.hooks.SessionStart = settings.hooks.SessionStart.filter((m) => !Array.isArray(m.hooks) || !m.hooks.some((h) => h.command.includes('apply --silent') && h.command.includes('index.js')));
52
+ if (settings.hooks.SessionStart.length === 0)
53
+ delete settings.hooks.SessionStart;
54
+ if (Object.keys(settings.hooks).length === 0)
55
+ delete settings.hooks;
56
+ saveClaudeSettings(settings);
57
+ }
58
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/config/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { savePetConfig, loadPetConfig, loadPetConfigV2, savePetConfigV2, saveProfile, getProfiles, switchToProfile, deleteProfile, } from './pet-config.ts';
2
+ export { getClaudeUserId, getCompanionName, renameCompanion, getCompanionPersonality, setCompanionPersonality, deleteCompanion, } from './claude-config.ts';
3
+ export { getClaudeSettings, saveClaudeSettings, isHookInstalled, installHook, removeHook, } from './hooks.ts';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,EACX,WAAW,EACX,eAAe,EACf,aAAa,GACd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { savePetConfig, loadPetConfig, loadPetConfigV2, savePetConfigV2, saveProfile, getProfiles, switchToProfile, deleteProfile, } from "./pet-config.js";
2
+ // Note: saveProfile(profile) keys by profile.salt
3
+ // switchToProfile(salt) and deleteProfile(salt) take salt, not name
4
+ export { getClaudeUserId, getCompanionName, renameCompanion, getCompanionPersonality, setCompanionPersonality, deleteCompanion, } from "./claude-config.js";
5
+ export { getClaudeSettings, saveClaudeSettings, isHookInstalled, installHook, removeHook, } from "./hooks.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,EACX,WAAW,EACX,eAAe,EACf,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,kDAAkD;AAClD,oEAAoE;AACpE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { PetConfig, PetConfigV2, ProfileData } from '../types.js';
2
+ export declare function savePetConfig(data: PetConfig): void;
3
+ export declare function loadPetConfig(): PetConfig | null;
4
+ export declare function loadPetConfigV2(): PetConfigV2 | null;
5
+ export declare function savePetConfigV2(data: PetConfigV2): void;
6
+ export declare function saveProfile(profile: ProfileData, { activate }?: {
7
+ activate?: boolean;
8
+ }): void;
9
+ export declare function getProfiles(): Record<string, ProfileData>;
10
+ export declare function switchToProfile(salt: string): PetConfigV2;
11
+ export declare function deleteProfile(salt: string): void;
12
+ //# sourceMappingURL=pet-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pet-config.d.ts","sourceRoot":"","sources":["../../src/config/pet-config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAQtE,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAEnD;AAED,wBAAgB,aAAa,IAAI,SAAS,GAAG,IAAI,CAOhD;AAqED,wBAAgB,eAAe,IAAI,WAAW,GAAG,IAAI,CAiBpD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAEvD;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,WAAW,EACpB,EAAE,QAAgB,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GAChD,IAAI,CAmBN;AAED,wBAAgB,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAGzD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAazD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAWhD"}
@@ -0,0 +1,150 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ import { ORIGINAL_SALT } from '../constants.js';
5
+ import { getCompanionName, getCompanionPersonality } from "./claude-config.js";
6
+ const OUR_CONFIG = join(homedir(), '.buddy-mcp.json');
7
+ // --- v1 compat (used by apply --silent fast path) ---
8
+ export function savePetConfig(data) {
9
+ writeFileSync(OUR_CONFIG, JSON.stringify(data, null, 2) + '\n');
10
+ }
11
+ export function loadPetConfig() {
12
+ if (!existsSync(OUR_CONFIG))
13
+ return null;
14
+ try {
15
+ return JSON.parse(readFileSync(OUR_CONFIG, 'utf-8'));
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ // --- v2 with profiles (keyed by salt) ---
22
+ function migrateV1(v1) {
23
+ const migrated = {
24
+ version: 2,
25
+ activeProfile: null,
26
+ salt: v1.salt,
27
+ previousSalt: v1.previousSalt,
28
+ profiles: {},
29
+ appliedTo: v1.appliedTo,
30
+ appliedAt: v1.appliedAt,
31
+ };
32
+ if (v1.salt && v1.salt !== ORIGINAL_SALT && !v1.restored) {
33
+ migrated.activeProfile = v1.salt;
34
+ migrated.profiles[v1.salt] = {
35
+ salt: v1.salt,
36
+ species: v1.species ?? 'duck',
37
+ rarity: v1.rarity ?? 'common',
38
+ eye: v1.eye ?? '·',
39
+ hat: v1.hat ?? 'none',
40
+ shiny: false,
41
+ stats: {},
42
+ name: getCompanionName(),
43
+ personality: getCompanionPersonality(),
44
+ createdAt: v1.appliedAt ?? new Date().toISOString(),
45
+ };
46
+ }
47
+ return migrated;
48
+ }
49
+ /**
50
+ * Migrate v2 configs that were keyed by display name to salt-keyed.
51
+ * Detects the old format by checking if any key is NOT a valid salt
52
+ * (salts are exactly 15 chars from the charset [a-zA-Z0-9_-]).
53
+ */
54
+ function migrateNameKeyedProfiles(config) {
55
+ const saltPattern = /^[a-zA-Z0-9_-]{15}$/;
56
+ const entries = Object.entries(config.profiles);
57
+ if (entries.length === 0)
58
+ return false;
59
+ // If all keys already look like salts, no migration needed
60
+ if (entries.every(([key]) => saltPattern.test(key)))
61
+ return false;
62
+ const newProfiles = {};
63
+ for (const [key, profile] of entries) {
64
+ if (saltPattern.test(key)) {
65
+ // Already salt-keyed
66
+ newProfiles[key] = profile;
67
+ }
68
+ else {
69
+ // Old name-keyed entry — re-key by salt, store old key as display name
70
+ newProfiles[profile.salt] = {
71
+ ...profile,
72
+ name: profile.name ?? key,
73
+ };
74
+ // Fix activeProfile if it pointed to the old name
75
+ if (config.activeProfile === key) {
76
+ config.activeProfile = profile.salt;
77
+ }
78
+ }
79
+ }
80
+ config.profiles = newProfiles;
81
+ return true;
82
+ }
83
+ export function loadPetConfigV2() {
84
+ if (!existsSync(OUR_CONFIG))
85
+ return null;
86
+ try {
87
+ const raw = JSON.parse(readFileSync(OUR_CONFIG, 'utf-8'));
88
+ if (raw.version === 2) {
89
+ const config = raw;
90
+ if (migrateNameKeyedProfiles(config)) {
91
+ savePetConfigV2(config);
92
+ }
93
+ return config;
94
+ }
95
+ const migrated = migrateV1(raw);
96
+ savePetConfigV2(migrated);
97
+ return migrated;
98
+ }
99
+ catch {
100
+ return null;
101
+ }
102
+ }
103
+ export function savePetConfigV2(data) {
104
+ writeFileSync(OUR_CONFIG, JSON.stringify(data, null, 2) + '\n');
105
+ }
106
+ export function saveProfile(profile, { activate = false } = {}) {
107
+ const config = loadPetConfigV2() ?? {
108
+ version: 2,
109
+ activeProfile: null,
110
+ salt: ORIGINAL_SALT,
111
+ profiles: {},
112
+ };
113
+ config.profiles[profile.salt] = profile;
114
+ if (activate) {
115
+ config.activeProfile = profile.salt;
116
+ if (config.salt && config.salt !== profile.salt) {
117
+ config.previousSalt = config.salt;
118
+ }
119
+ config.salt = profile.salt;
120
+ }
121
+ savePetConfigV2(config);
122
+ }
123
+ export function getProfiles() {
124
+ const config = loadPetConfigV2();
125
+ return config?.profiles ?? {};
126
+ }
127
+ export function switchToProfile(salt) {
128
+ const config = loadPetConfigV2();
129
+ if (!config?.profiles[salt]) {
130
+ throw new Error(`Buddy not found (salt: ${salt.slice(0, 6)}...)`);
131
+ }
132
+ config.previousSalt = config.salt;
133
+ config.activeProfile = salt;
134
+ config.salt = config.profiles[salt].salt;
135
+ config.appliedAt = new Date().toISOString();
136
+ savePetConfigV2(config);
137
+ return config;
138
+ }
139
+ export function deleteProfile(salt) {
140
+ const config = loadPetConfigV2();
141
+ if (!config?.profiles[salt])
142
+ return;
143
+ if (config.activeProfile === salt) {
144
+ const name = config.profiles[salt].name ?? salt.slice(0, 6);
145
+ throw new Error(`Cannot delete the active buddy "${name}". Switch to another first.`);
146
+ }
147
+ config.profiles = Object.fromEntries(Object.entries(config.profiles).filter(([key]) => key !== salt));
148
+ savePetConfigV2(config);
149
+ }
150
+ //# sourceMappingURL=pet-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pet-config.js","sourceRoot":"","sources":["../../src/config/pet-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { Rarity, Species, Eye, Hat, StatName } from './types.ts';
2
+ export declare const ISSUE_URL = "https://github.com/lyellr88/buddy-mcp/issues";
3
+ export declare const ORIGINAL_SALT = "friend-2026-401";
4
+ export declare function diagnostics(extra?: Record<string, string>): string;
5
+ export declare const RARITIES: readonly Rarity[];
6
+ export declare const RARITY_WEIGHTS: Record<Rarity, number>;
7
+ export declare const RARITY_STARS: Record<Rarity, string>;
8
+ export declare const SPECIES: readonly Species[];
9
+ export declare const EYES: readonly Eye[];
10
+ export declare const HATS: readonly Hat[];
11
+ export declare const STAT_NAMES: readonly StatName[];
12
+ export declare const RARITY_FLOOR: Record<Rarity, number>;
13
+ export declare const PET_MILESTONES: readonly [{
14
+ readonly threshold: 75;
15
+ readonly label: "🌟 Epic/Legendary heavily favoured — don't waste it!";
16
+ }, {
17
+ readonly threshold: 50;
18
+ readonly label: "⭐ Rare+ guaranteed on next reroll!";
19
+ }, {
20
+ readonly threshold: 25;
21
+ readonly label: "⭐ Uncommon+ guaranteed on next reroll!";
22
+ }];
23
+ export declare function getAffectionWeights(petCount: number): Record<Rarity, number>;
24
+ //# sourceMappingURL=constants.d.ts.map