@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.
- package/README.md +219 -0
- package/dist/config/claude-config.d.ts +7 -0
- package/dist/config/claude-config.d.ts.map +1 -0
- package/dist/config/claude-config.js +107 -0
- package/dist/config/claude-config.js.map +1 -0
- package/dist/config/hooks.d.ts +22 -0
- package/dist/config/hooks.d.ts.map +1 -0
- package/dist/config/hooks.js +58 -0
- package/dist/config/hooks.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/pet-config.d.ts +12 -0
- package/dist/config/pet-config.d.ts.map +1 -0
- package/dist/config/pet-config.js +150 -0
- package/dist/config/pet-config.js.map +1 -0
- package/dist/constants.d.ts +24 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +94 -0
- package/dist/constants.js.map +1 -0
- package/dist/finder/estimator.d.ts +3 -0
- package/dist/finder/estimator.d.ts.map +1 -0
- package/dist/finder/estimator.js +27 -0
- package/dist/finder/estimator.js.map +1 -0
- package/dist/finder/index.d.ts +3 -0
- package/dist/finder/index.d.ts.map +1 -0
- package/dist/finder/index.js +3 -0
- package/dist/finder/index.js.map +1 -0
- package/dist/finder/orchestrator.d.ts +8 -0
- package/dist/finder/orchestrator.d.ts.map +1 -0
- package/dist/finder/orchestrator.js +163 -0
- package/dist/finder/orchestrator.js.map +1 -0
- package/dist/finder/worker.d.ts +3 -0
- package/dist/finder/worker.d.ts.map +1 -0
- package/dist/finder/worker.js +130 -0
- package/dist/finder/worker.js.map +1 -0
- package/dist/generation/hash.d.ts +5 -0
- package/dist/generation/hash.d.ts.map +1 -0
- package/dist/generation/hash.js +37 -0
- package/dist/generation/hash.js.map +1 -0
- package/dist/generation/index.d.ts +4 -0
- package/dist/generation/index.d.ts.map +1 -0
- package/dist/generation/index.js +4 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/generation/rng.d.ts +4 -0
- package/dist/generation/rng.d.ts.map +1 -0
- package/dist/generation/rng.js +14 -0
- package/dist/generation/rng.js.map +1 -0
- package/dist/generation/roll.d.ts +7 -0
- package/dist/generation/roll.d.ts.map +1 -0
- package/dist/generation/roll.js +51 -0
- package/dist/generation/roll.js.map +1 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +273 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/persistence.d.ts +6 -0
- package/dist/mcp/persistence.d.ts.map +1 -0
- package/dist/mcp/persistence.js +129 -0
- package/dist/mcp/persistence.js.map +1 -0
- package/dist/mcp/state.d.ts +74 -0
- package/dist/mcp/state.d.ts.map +1 -0
- package/dist/mcp/state.js +20 -0
- package/dist/mcp/state.js.map +1 -0
- package/dist/mcp/tools/auto.d.ts +4 -0
- package/dist/mcp/tools/auto.d.ts.map +1 -0
- package/dist/mcp/tools/auto.js +15 -0
- package/dist/mcp/tools/auto.js.map +1 -0
- package/dist/mcp/tools/core.d.ts +2 -0
- package/dist/mcp/tools/core.d.ts.map +1 -0
- package/dist/mcp/tools/core.js +350 -0
- package/dist/mcp/tools/core.js.map +1 -0
- package/dist/mcp/tools/export.d.ts +2 -0
- package/dist/mcp/tools/export.d.ts.map +1 -0
- package/dist/mcp/tools/export.js +161 -0
- package/dist/mcp/tools/export.js.map +1 -0
- package/dist/mcp/tools/interact.d.ts +2 -0
- package/dist/mcp/tools/interact.d.ts.map +1 -0
- package/dist/mcp/tools/interact.js +56 -0
- package/dist/mcp/tools/interact.js.map +1 -0
- package/dist/mcp/tools/stats.d.ts +4 -0
- package/dist/mcp/tools/stats.d.ts.map +1 -0
- package/dist/mcp/tools/stats.js +87 -0
- package/dist/mcp/tools/stats.js.map +1 -0
- package/dist/mcp/watcher.d.ts +3 -0
- package/dist/mcp/watcher.d.ts.map +1 -0
- package/dist/mcp/watcher.js +117 -0
- package/dist/mcp/watcher.js.map +1 -0
- package/dist/patcher/binary-finder.d.ts +3 -0
- package/dist/patcher/binary-finder.d.ts.map +1 -0
- package/dist/patcher/binary-finder.js +169 -0
- package/dist/patcher/binary-finder.js.map +1 -0
- package/dist/patcher/index.d.ts +5 -0
- package/dist/patcher/index.d.ts.map +1 -0
- package/dist/patcher/index.js +5 -0
- package/dist/patcher/index.js.map +1 -0
- package/dist/patcher/patch.d.ts +5 -0
- package/dist/patcher/patch.d.ts.map +1 -0
- package/dist/patcher/patch.js +148 -0
- package/dist/patcher/patch.js.map +1 -0
- package/dist/patcher/preflight.d.ts +5 -0
- package/dist/patcher/preflight.d.ts.map +1 -0
- package/dist/patcher/preflight.js +145 -0
- package/dist/patcher/preflight.js.map +1 -0
- package/dist/patcher/salt-ops.d.ts +18 -0
- package/dist/patcher/salt-ops.d.ts.map +1 -0
- package/dist/patcher/salt-ops.js +93 -0
- package/dist/patcher/salt-ops.js.map +1 -0
- package/dist/personalities.d.ts +10 -0
- package/dist/personalities.d.ts.map +1 -0
- package/dist/personalities.js +295 -0
- package/dist/personalities.js.map +1 -0
- package/dist/presets.d.ts +11 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +207 -0
- package/dist/presets.js.map +1 -0
- package/dist/sprites/data.d.ts +4 -0
- package/dist/sprites/data.d.ts.map +1 -0
- package/dist/sprites/data.js +103 -0
- package/dist/sprites/data.js.map +1 -0
- package/dist/sprites/index.d.ts +3 -0
- package/dist/sprites/index.d.ts.map +1 -0
- package/dist/sprites/index.js +3 -0
- package/dist/sprites/index.js.map +1 -0
- package/dist/sprites/render.d.ts +15 -0
- package/dist/sprites/render.d.ts.map +1 -0
- package/dist/sprites/render.js +77 -0
- package/dist/sprites/render.js.map +1 -0
- package/dist/tui/animator.d.ts +13 -0
- package/dist/tui/animator.d.ts.map +1 -0
- package/dist/tui/animator.js +39 -0
- package/dist/tui/animator.js.map +1 -0
- package/dist/tui/apply/index.d.ts +9 -0
- package/dist/tui/apply/index.d.ts.map +1 -0
- package/dist/tui/apply/index.js +553 -0
- package/dist/tui/apply/index.js.map +1 -0
- package/dist/tui/builder/colors.d.ts +15 -0
- package/dist/tui/builder/colors.d.ts.map +1 -0
- package/dist/tui/builder/colors.js +20 -0
- package/dist/tui/builder/colors.js.map +1 -0
- package/dist/tui/builder/index.d.ts +6 -0
- package/dist/tui/builder/index.d.ts.map +1 -0
- package/dist/tui/builder/index.js +172 -0
- package/dist/tui/builder/index.js.map +1 -0
- package/dist/tui/builder/keyboard.d.ts +17 -0
- package/dist/tui/builder/keyboard.d.ts.map +1 -0
- package/dist/tui/builder/keyboard.js +76 -0
- package/dist/tui/builder/keyboard.js.map +1 -0
- package/dist/tui/builder/preview-panel.d.ts +9 -0
- package/dist/tui/builder/preview-panel.d.ts.map +1 -0
- package/dist/tui/builder/preview-panel.js +103 -0
- package/dist/tui/builder/preview-panel.js.map +1 -0
- package/dist/tui/builder/selection-panel.d.ts +11 -0
- package/dist/tui/builder/selection-panel.d.ts.map +1 -0
- package/dist/tui/builder/selection-panel.js +446 -0
- package/dist/tui/builder/selection-panel.js.map +1 -0
- package/dist/tui/builder/stat-bars.d.ts +4 -0
- package/dist/tui/builder/stat-bars.d.ts.map +1 -0
- package/dist/tui/builder/stat-bars.js +46 -0
- package/dist/tui/builder/stat-bars.js.map +1 -0
- package/dist/tui/builder/state.d.ts +22 -0
- package/dist/tui/builder/state.d.ts.map +1 -0
- package/dist/tui/builder/state.js +92 -0
- package/dist/tui/builder/state.js.map +1 -0
- package/dist/tui/cli.d.ts +3 -0
- package/dist/tui/cli.d.ts.map +1 -0
- package/dist/tui/cli.js +26 -0
- package/dist/tui/cli.js.map +1 -0
- package/dist/tui/commands/buddies.d.ts +2 -0
- package/dist/tui/commands/buddies.d.ts.map +1 -0
- package/dist/tui/commands/buddies.js +172 -0
- package/dist/tui/commands/buddies.js.map +1 -0
- package/dist/tui/commands/current.d.ts +2 -0
- package/dist/tui/commands/current.d.ts.map +1 -0
- package/dist/tui/commands/current.js +35 -0
- package/dist/tui/commands/current.js.map +1 -0
- package/dist/tui/commands/interactive.d.ts +6 -0
- package/dist/tui/commands/interactive.d.ts.map +1 -0
- package/dist/tui/commands/interactive.js +385 -0
- package/dist/tui/commands/interactive.js.map +1 -0
- package/dist/tui/commands/preview.d.ts +3 -0
- package/dist/tui/commands/preview.d.ts.map +1 -0
- package/dist/tui/commands/preview.js +94 -0
- package/dist/tui/commands/preview.js.map +1 -0
- package/dist/tui/commands/rehatch.d.ts +2 -0
- package/dist/tui/commands/rehatch.d.ts.map +1 -0
- package/dist/tui/commands/rehatch.js +30 -0
- package/dist/tui/commands/rehatch.js.map +1 -0
- package/dist/tui/commands/restore.d.ts +2 -0
- package/dist/tui/commands/restore.d.ts.map +1 -0
- package/dist/tui/commands/restore.js +52 -0
- package/dist/tui/commands/restore.js.map +1 -0
- package/dist/tui/commands/share.d.ts +2 -0
- package/dist/tui/commands/share.d.ts.map +1 -0
- package/dist/tui/commands/share.js +105 -0
- package/dist/tui/commands/share.js.map +1 -0
- package/dist/tui/commands/start-screen.d.ts +3 -0
- package/dist/tui/commands/start-screen.d.ts.map +1 -0
- package/dist/tui/commands/start-screen.js +93 -0
- package/dist/tui/commands/start-screen.js.map +1 -0
- package/dist/tui/display.d.ts +5 -0
- package/dist/tui/display.d.ts.map +1 -0
- package/dist/tui/display.js +33 -0
- package/dist/tui/display.js.map +1 -0
- package/dist/tui/format.d.ts +5 -0
- package/dist/tui/format.d.ts.map +1 -0
- package/dist/tui/format.js +21 -0
- package/dist/tui/format.js.map +1 -0
- package/dist/tui/gallery/index.d.ts +12 -0
- package/dist/tui/gallery/index.d.ts.map +1 -0
- package/dist/tui/gallery/index.js +153 -0
- package/dist/tui/gallery/index.js.map +1 -0
- package/dist/tui/gallery/keyboard.d.ts +15 -0
- package/dist/tui/gallery/keyboard.d.ts.map +1 -0
- package/dist/tui/gallery/keyboard.js +41 -0
- package/dist/tui/gallery/keyboard.js.map +1 -0
- package/dist/tui/gallery/profile-list-panel.d.ts +10 -0
- package/dist/tui/gallery/profile-list-panel.d.ts.map +1 -0
- package/dist/tui/gallery/profile-list-panel.js +66 -0
- package/dist/tui/gallery/profile-list-panel.js.map +1 -0
- package/dist/tui/gallery/profile-preview-panel.d.ts +9 -0
- package/dist/tui/gallery/profile-preview-panel.d.ts.map +1 -0
- package/dist/tui/gallery/profile-preview-panel.js +121 -0
- package/dist/tui/gallery/profile-preview-panel.js.map +1 -0
- package/dist/tui/gallery/state.d.ts +13 -0
- package/dist/tui/gallery/state.d.ts.map +1 -0
- package/dist/tui/gallery/state.js +33 -0
- package/dist/tui/gallery/state.js.map +1 -0
- package/dist/tui/index.d.ts +9 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +9 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/launcher.d.ts +3 -0
- package/dist/tui/launcher.d.ts.map +1 -0
- package/dist/tui/launcher.js +24 -0
- package/dist/tui/launcher.js.map +1 -0
- package/dist/tui/presets/index.d.ts +3 -0
- package/dist/tui/presets/index.d.ts.map +1 -0
- package/dist/tui/presets/index.js +202 -0
- package/dist/tui/presets/index.js.map +1 -0
- package/dist/tui/presets/preset-list-panel.d.ts +9 -0
- package/dist/tui/presets/preset-list-panel.d.ts.map +1 -0
- package/dist/tui/presets/preset-list-panel.js +52 -0
- package/dist/tui/presets/preset-list-panel.js.map +1 -0
- package/dist/tui/prompts.d.ts +13 -0
- package/dist/tui/prompts.d.ts.map +1 -0
- package/dist/tui/prompts.js +126 -0
- package/dist/tui/prompts.js.map +1 -0
- package/dist/tui/start/index.d.ts +3 -0
- package/dist/tui/start/index.d.ts.map +1 -0
- package/dist/tui/start/index.js +170 -0
- package/dist/tui/start/index.js.map +1 -0
- package/dist/types.d.ts +113 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- 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
|