@umang-boss/claudemon 1.2.0 → 1.3.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 CHANGED
@@ -24,22 +24,31 @@ fill your Pokedex -- all while you code.
24
24
 
25
25
  ## Install
26
26
 
27
+ **Recommended (global install — persistent):**
28
+ ```bash
29
+ npm install -g @umang-boss/claudemon
30
+ claudemon install
31
+ ```
32
+
33
+ **Or quick try (npx — may need reinstall after cache clear):**
27
34
  ```bash
28
35
  npx @umang-boss/claudemon install
29
36
  ```
30
37
 
31
- That's it! Start a new Claude Code session and type `/buddy`.
38
+ Start a new Claude Code session and type `/buddy` to begin!
32
39
 
33
40
  **Requirements:** Node.js 18+ (Bun optional, auto-detected for faster startup)
34
41
 
35
42
  ### Other CLI Commands
36
43
 
37
44
  ```bash
38
- npx @umang-boss/claudemon doctor # Check installation health
39
- npx @umang-boss/claudemon update # Re-register after updates
40
- npx @umang-boss/claudemon uninstall # Remove (preserves save data)
45
+ claudemon doctor # Check installation health
46
+ claudemon update # Re-register after updates
47
+ claudemon uninstall # Remove (preserves save data)
41
48
  ```
42
49
 
50
+ > **Note:** `npm install -g` is recommended over `npx` because the MCP server path needs to persist. With `npx`, the path points to a temporary cache that may be cleaned up.
51
+
43
52
  ## Commands
44
53
 
45
54
  Once installed, use `/buddy` in Claude Code:
@@ -47,10 +47,9 @@ export function registerAchievementsTool(server) {
47
47
  content: [
48
48
  {
49
49
  type: "text",
50
- text: "You don't have a Pokemon yet! Use buddy_starter to begin your journey.",
50
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start earning achievements!",
51
51
  },
52
52
  ],
53
- isError: true,
54
53
  };
55
54
  }
56
55
  const unlockedIds = new Set(state.achievements.map((a) => a.achievementId));
@@ -43,10 +43,9 @@ export function registerCatchTool(server) {
43
43
  content: [
44
44
  {
45
45
  type: "text",
46
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
46
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before catching wild Pokemon!",
47
47
  },
48
48
  ],
49
- isError: true,
50
49
  };
51
50
  }
52
51
  const encounter = state.pendingEncounter;
@@ -79,10 +78,9 @@ export function registerCatchTool(server) {
79
78
  content: [
80
79
  {
81
80
  type: "text",
82
- text: "No active Pokemon found in your party.",
81
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before catching wild Pokemon!",
83
82
  },
84
83
  ],
85
- isError: true,
86
84
  };
87
85
  }
88
86
  const typeStr = formatTypes(species.types);
@@ -36,10 +36,9 @@ export function registerEvolveTool(server) {
36
36
  content: [
37
37
  {
38
38
  type: "text",
39
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
39
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before evolving!",
40
40
  },
41
41
  ],
42
- isError: true,
43
42
  };
44
43
  }
45
44
  const active = stateManager.getActivePokemon();
@@ -48,10 +47,9 @@ export function registerEvolveTool(server) {
48
47
  content: [
49
48
  {
50
49
  type: "text",
51
- text: "No active Pokemon found in your party.",
50
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before evolving!",
52
51
  },
53
52
  ],
54
- isError: true,
55
53
  };
56
54
  }
57
55
  const species = POKEMON_BY_ID.get(active.pokemonId);
@@ -16,10 +16,9 @@ export function registerLegendaryTool(server) {
16
16
  content: [
17
17
  {
18
18
  type: "text",
19
- text: "You don't have a Pokemon yet! Use buddy_starter to begin your journey.",
19
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and begin your legendary quests!",
20
20
  },
21
21
  ],
22
- isError: true,
23
22
  };
24
23
  }
25
24
  const progress = getQuestProgress(state);
@@ -20,10 +20,9 @@ export function registerPartyTool(server) {
20
20
  content: [
21
21
  {
22
22
  type: "text",
23
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
23
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and build your party!",
24
24
  },
25
25
  ],
26
- isError: true,
27
26
  };
28
27
  }
29
28
  const action = params.action ?? "list";
@@ -41,10 +41,9 @@ export function registerPetTool(server) {
41
41
  content: [
42
42
  {
43
43
  type: "text",
44
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
44
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can pet them!",
45
45
  },
46
46
  ],
47
- isError: true,
48
47
  };
49
48
  }
50
49
  const active = stateManager.getActivePokemon();
@@ -53,10 +52,9 @@ export function registerPetTool(server) {
53
52
  content: [
54
53
  {
55
54
  type: "text",
56
- text: "No active Pokemon found in your party.",
55
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can pet them!",
57
56
  },
58
57
  ],
59
- isError: true,
60
58
  };
61
59
  }
62
60
  const species = POKEMON_BY_ID.get(active.pokemonId);
@@ -23,10 +23,9 @@ export function registerPokedexTool(server) {
23
23
  content: [
24
24
  {
25
25
  type: "text",
26
- text: "You don't have a Pokemon yet! Use buddy_starter to begin your journey.",
26
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start filling your Pokedex!",
27
27
  },
28
28
  ],
29
- isError: true,
30
29
  };
31
30
  }
32
31
  // ── Specific Pokemon lookup ────────────────────────────
@@ -11,15 +11,23 @@ export function registerRenameTool(server) {
11
11
  const state = await stateManager.load();
12
12
  if (!state || state.party.length === 0) {
13
13
  return {
14
- content: [{ type: "text", text: "No Pokemon to rename! Pick a starter first." }],
15
- isError: true,
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can give them a nickname!",
18
+ },
19
+ ],
16
20
  };
17
21
  }
18
22
  const active = stateManager.getActivePokemon();
19
23
  if (!active) {
20
24
  return {
21
- content: [{ type: "text", text: "No active Pokemon found." }],
22
- isError: true,
25
+ content: [
26
+ {
27
+ type: "text",
28
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can give them a nickname!",
29
+ },
30
+ ],
23
31
  };
24
32
  }
25
33
  const species = POKEMON_BY_ID.get(active.pokemonId);
@@ -21,10 +21,9 @@ export function registerShowTool(server) {
21
21
  content: [
22
22
  {
23
23
  type: "text",
24
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
24
+ text: "Welcome to Claudemon! You don't have a Pokemon yet. Use /buddy starter to pick your first companion!",
25
25
  },
26
26
  ],
27
- isError: true,
28
27
  };
29
28
  }
30
29
  const active = stateManager.getActivePokemon();
@@ -56,10 +56,32 @@ async function getStarters() {
56
56
  catch {
57
57
  // No saved options or expired — generate new ones
58
58
  }
59
- // Generate fresh random 3
59
+ // Generate fresh random 3 with different primary types
60
60
  const seed = hashString(`claudemon-${Date.now()}-${Math.random()}`);
61
61
  const shuffled = seededShuffle(STARTER_POOL, seed);
62
- const starters = [shuffled[0], shuffled[1], shuffled[2]];
62
+ const starters = [];
63
+ const usedTypes = new Set();
64
+ for (const id of shuffled) {
65
+ if (starters.length >= 3)
66
+ break;
67
+ const pokemon = POKEMON_BY_ID.get(id);
68
+ if (!pokemon)
69
+ continue;
70
+ const primaryType = pokemon.types[0];
71
+ if (usedTypes.has(primaryType))
72
+ continue;
73
+ usedTypes.add(primaryType);
74
+ starters.push(id);
75
+ }
76
+ // Fallback if not enough unique types (shouldn't happen with 39 starters)
77
+ if (starters.length < 3) {
78
+ for (const id of shuffled) {
79
+ if (starters.length >= 3)
80
+ break;
81
+ if (!starters.includes(id))
82
+ starters.push(id);
83
+ }
84
+ }
63
85
  // Save for consistency until they pick
64
86
  try {
65
87
  const { writeFile, mkdir } = await import("node:fs/promises");
@@ -99,7 +121,6 @@ export function registerStarterTool(server) {
99
121
  text: "You already have a Pokemon partner! Use buddy_show to check on them.",
100
122
  },
101
123
  ],
102
- isError: true,
103
124
  };
104
125
  }
105
126
  const starterIds = await getStarters();
@@ -19,10 +19,9 @@ export function registerStatsTool(server) {
19
19
  content: [
20
20
  {
21
21
  type: "text",
22
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
22
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start your coding adventure!",
23
23
  },
24
24
  ],
25
- isError: true,
26
25
  };
27
26
  }
28
27
  const active = stateManager.getActivePokemon();
@@ -31,10 +30,9 @@ export function registerStatsTool(server) {
31
30
  content: [
32
31
  {
33
32
  type: "text",
34
- text: "No active Pokemon found in your party.",
33
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start your coding adventure!",
35
34
  },
36
35
  ],
37
- isError: true,
38
36
  };
39
37
  }
40
38
  const species = POKEMON_BY_ID.get(active.pokemonId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umang-boss/claudemon",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Pokemon coding companion for Claude Code — Gotta code 'em all!",
5
5
  "type": "module",
6
6
  "main": "dist/src/server/index.js",
@@ -33,8 +33,7 @@
33
33
  "test": "bun test",
34
34
  "typecheck": "tsc --noEmit",
35
35
  "format": "prettier --write \"src/**/*.ts\" \"cli/**/*.ts\" \"scripts/**/*.ts\" \"tests/**/*.ts\" --ignore-unknown",
36
- "format:check": "prettier --check \"src/**/*.ts\" \"cli/**/*.ts\" \"scripts/**/*.ts\" \"tests/**/*.ts\" --ignore-unknown",
37
- "prepare": "husky"
36
+ "format:check": "prettier --check \"src/**/*.ts\" \"cli/**/*.ts\" \"scripts/**/*.ts\" \"tests/**/*.ts\" --ignore-unknown"
38
37
  },
39
38
  "dependencies": {
40
39
  "@modelcontextprotocol/sdk": "^1.12.1",
@@ -58,10 +58,9 @@ export function registerAchievementsTool(server: McpServer): void {
58
58
  content: [
59
59
  {
60
60
  type: "text" as const,
61
- text: "You don't have a Pokemon yet! Use buddy_starter to begin your journey.",
61
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start earning achievements!",
62
62
  },
63
63
  ],
64
- isError: true,
65
64
  };
66
65
  }
67
66
 
@@ -59,10 +59,9 @@ export function registerCatchTool(server: McpServer): void {
59
59
  content: [
60
60
  {
61
61
  type: "text" as const,
62
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
62
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before catching wild Pokemon!",
63
63
  },
64
64
  ],
65
- isError: true,
66
65
  };
67
66
  }
68
67
 
@@ -98,10 +97,9 @@ export function registerCatchTool(server: McpServer): void {
98
97
  content: [
99
98
  {
100
99
  type: "text" as const,
101
- text: "No active Pokemon found in your party.",
100
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before catching wild Pokemon!",
102
101
  },
103
102
  ],
104
- isError: true,
105
103
  };
106
104
  }
107
105
 
@@ -51,10 +51,9 @@ export function registerEvolveTool(server: McpServer): void {
51
51
  content: [
52
52
  {
53
53
  type: "text" as const,
54
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
54
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before evolving!",
55
55
  },
56
56
  ],
57
- isError: true,
58
57
  };
59
58
  }
60
59
 
@@ -64,10 +63,9 @@ export function registerEvolveTool(server: McpServer): void {
64
63
  content: [
65
64
  {
66
65
  type: "text" as const,
67
- text: "No active Pokemon found in your party.",
66
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion before evolving!",
68
67
  },
69
68
  ],
70
- isError: true,
71
69
  };
72
70
  }
73
71
 
@@ -24,10 +24,9 @@ export function registerLegendaryTool(server: McpServer): void {
24
24
  content: [
25
25
  {
26
26
  type: "text" as const,
27
- text: "You don't have a Pokemon yet! Use buddy_starter to begin your journey.",
27
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and begin your legendary quests!",
28
28
  },
29
29
  ],
30
- isError: true,
31
30
  };
32
31
  }
33
32
 
@@ -28,10 +28,9 @@ export function registerPartyTool(server: McpServer): void {
28
28
  content: [
29
29
  {
30
30
  type: "text" as const,
31
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
31
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and build your party!",
32
32
  },
33
33
  ],
34
- isError: true,
35
34
  };
36
35
  }
37
36
 
@@ -52,10 +52,9 @@ export function registerPetTool(server: McpServer): void {
52
52
  content: [
53
53
  {
54
54
  type: "text" as const,
55
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
55
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can pet them!",
56
56
  },
57
57
  ],
58
- isError: true,
59
58
  };
60
59
  }
61
60
 
@@ -65,10 +64,9 @@ export function registerPetTool(server: McpServer): void {
65
64
  content: [
66
65
  {
67
66
  type: "text" as const,
68
- text: "No active Pokemon found in your party.",
67
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can pet them!",
69
68
  },
70
69
  ],
71
- isError: true,
72
70
  };
73
71
  }
74
72
 
@@ -32,10 +32,9 @@ export function registerPokedexTool(server: McpServer): void {
32
32
  content: [
33
33
  {
34
34
  type: "text" as const,
35
- text: "You don't have a Pokemon yet! Use buddy_starter to begin your journey.",
35
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start filling your Pokedex!",
36
36
  },
37
37
  ],
38
- isError: true,
39
38
  };
40
39
  }
41
40
 
@@ -19,16 +19,24 @@ export function registerRenameTool(server: McpServer): void {
19
19
 
20
20
  if (!state || state.party.length === 0) {
21
21
  return {
22
- content: [{ type: "text" as const, text: "No Pokemon to rename! Pick a starter first." }],
23
- isError: true,
22
+ content: [
23
+ {
24
+ type: "text" as const,
25
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can give them a nickname!",
26
+ },
27
+ ],
24
28
  };
25
29
  }
26
30
 
27
31
  const active = stateManager.getActivePokemon();
28
32
  if (!active) {
29
33
  return {
30
- content: [{ type: "text" as const, text: "No active Pokemon found." }],
31
- isError: true,
34
+ content: [
35
+ {
36
+ type: "text" as const,
37
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion -- then you can give them a nickname!",
38
+ },
39
+ ],
32
40
  };
33
41
  }
34
42
 
@@ -30,10 +30,9 @@ export function registerShowTool(server: McpServer): void {
30
30
  content: [
31
31
  {
32
32
  type: "text" as const,
33
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
33
+ text: "Welcome to Claudemon! You don't have a Pokemon yet. Use /buddy starter to pick your first companion!",
34
34
  },
35
35
  ],
36
- isError: true,
37
36
  };
38
37
  }
39
38
 
@@ -65,10 +65,29 @@ async function getStarters(): Promise<number[]> {
65
65
  // No saved options or expired — generate new ones
66
66
  }
67
67
 
68
- // Generate fresh random 3
68
+ // Generate fresh random 3 with different primary types
69
69
  const seed = hashString(`claudemon-${Date.now()}-${Math.random()}`);
70
70
  const shuffled = seededShuffle(STARTER_POOL, seed);
71
- const starters = [shuffled[0]!, shuffled[1]!, shuffled[2]!];
71
+ const starters: number[] = [];
72
+ const usedTypes = new Set<string>();
73
+
74
+ for (const id of shuffled) {
75
+ if (starters.length >= 3) break;
76
+ const pokemon = POKEMON_BY_ID.get(id);
77
+ if (!pokemon) continue;
78
+ const primaryType = pokemon.types[0];
79
+ if (usedTypes.has(primaryType)) continue;
80
+ usedTypes.add(primaryType);
81
+ starters.push(id);
82
+ }
83
+
84
+ // Fallback if not enough unique types (shouldn't happen with 39 starters)
85
+ if (starters.length < 3) {
86
+ for (const id of shuffled) {
87
+ if (starters.length >= 3) break;
88
+ if (!starters.includes(id)) starters.push(id);
89
+ }
90
+ }
72
91
 
73
92
  // Save for consistency until they pick
74
93
  try {
@@ -116,7 +135,6 @@ export function registerStarterTool(server: McpServer): void {
116
135
  text: "You already have a Pokemon partner! Use buddy_show to check on them.",
117
136
  },
118
137
  ],
119
- isError: true,
120
138
  };
121
139
  }
122
140
 
@@ -28,10 +28,9 @@ export function registerStatsTool(server: McpServer): void {
28
28
  content: [
29
29
  {
30
30
  type: "text" as const,
31
- text: "You don't have a Pokemon yet! Use buddy_starter to pick your first partner.",
31
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start your coding adventure!",
32
32
  },
33
33
  ],
34
- isError: true,
35
34
  };
36
35
  }
37
36
 
@@ -41,10 +40,9 @@ export function registerStatsTool(server: McpServer): void {
41
40
  content: [
42
41
  {
43
42
  type: "text" as const,
44
- text: "No active Pokemon found in your party.",
43
+ text: "Welcome to Claudemon! Use buddy_starter to pick your first companion and start your coding adventure!",
45
44
  },
46
45
  ],
47
- isError: true,
48
46
  };
49
47
  }
50
48