claude-mpm 4.15.2__py3-none-any.whl → 4.15.6__py3-none-any.whl
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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/templates/agentic-coder-optimizer.json +9 -2
- claude_mpm/agents/templates/api_qa.json +7 -1
- claude_mpm/agents/templates/clerk-ops.json +8 -1
- claude_mpm/agents/templates/code_analyzer.json +4 -1
- claude_mpm/agents/templates/dart_engineer.json +11 -1
- claude_mpm/agents/templates/data_engineer.json +11 -1
- claude_mpm/agents/templates/documentation.json +6 -1
- claude_mpm/agents/templates/engineer.json +13 -0
- claude_mpm/agents/templates/gcp_ops_agent.json +8 -1
- claude_mpm/agents/templates/golang_engineer.json +11 -1
- claude_mpm/agents/templates/java_engineer.json +12 -2
- claude_mpm/agents/templates/local_ops_agent.json +216 -37
- claude_mpm/agents/templates/nextjs_engineer.json +11 -1
- claude_mpm/agents/templates/ops.json +8 -1
- claude_mpm/agents/templates/php-engineer.json +11 -1
- claude_mpm/agents/templates/project_organizer.json +9 -2
- claude_mpm/agents/templates/prompt-engineer.json +5 -1
- claude_mpm/agents/templates/python_engineer.json +11 -1
- claude_mpm/agents/templates/qa.json +7 -1
- claude_mpm/agents/templates/react_engineer.json +11 -1
- claude_mpm/agents/templates/refactoring_engineer.json +8 -1
- claude_mpm/agents/templates/research.json +4 -1
- claude_mpm/agents/templates/ruby-engineer.json +11 -1
- claude_mpm/agents/templates/rust_engineer.json +11 -1
- claude_mpm/agents/templates/security.json +6 -1
- claude_mpm/agents/templates/ticketing.json +6 -1
- claude_mpm/agents/templates/typescript_engineer.json +11 -1
- claude_mpm/agents/templates/vercel_ops_agent.json +8 -1
- claude_mpm/agents/templates/version_control.json +8 -1
- claude_mpm/agents/templates/web_qa.json +7 -1
- claude_mpm/agents/templates/web_ui.json +11 -1
- claude_mpm/cli/commands/configure.py +164 -16
- claude_mpm/cli/commands/configure_agent_display.py +6 -6
- claude_mpm/cli/commands/configure_behavior_manager.py +8 -8
- claude_mpm/cli/commands/configure_navigation.py +20 -18
- claude_mpm/cli/commands/configure_startup_manager.py +14 -14
- claude_mpm/cli/commands/configure_template_editor.py +8 -8
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/startup.py +26 -0
- claude_mpm/core/enums.py +18 -0
- claude_mpm/core/types.py +2 -9
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/core/models/health.py +1 -28
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/local_ops/__init__.py +1 -1
- claude_mpm/services/local_ops/crash_detector.py +1 -1
- claude_mpm/services/local_ops/health_checks/http_check.py +2 -1
- claude_mpm/services/local_ops/health_checks/process_check.py +2 -1
- claude_mpm/services/local_ops/health_checks/resource_check.py +2 -1
- claude_mpm/services/local_ops/health_manager.py +1 -1
- claude_mpm/services/local_ops/restart_manager.py +1 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +10 -0
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +7 -7
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/registry.py +198 -0
- claude_mpm/skills/skill_manager.py +310 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.15.6.dist-info}/METADATA +1 -1
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.15.6.dist-info}/RECORD +78 -80
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.15.6.dist-info}/WHEEL +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.15.6.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.15.6.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.15.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Skills manager - integrates skills with agents."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from claude_mpm.core.logging_utils import get_logger
|
|
8
|
+
|
|
9
|
+
from .registry import Skill, get_registry
|
|
10
|
+
|
|
11
|
+
logger = get_logger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SkillManager:
|
|
15
|
+
"""Manages skills and their integration with agents."""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
"""Initialize the skill manager."""
|
|
19
|
+
self.registry = get_registry()
|
|
20
|
+
self.agent_skill_mapping: Dict[str, List[str]] = {}
|
|
21
|
+
self._load_agent_mappings()
|
|
22
|
+
|
|
23
|
+
def _load_agent_mappings(self):
|
|
24
|
+
"""Load skill mappings from agent templates."""
|
|
25
|
+
# Load mappings from agent JSON templates that have 'skills' field
|
|
26
|
+
agent_templates_dir = Path(__file__).parent.parent / "agents" / "templates"
|
|
27
|
+
|
|
28
|
+
if not agent_templates_dir.exists():
|
|
29
|
+
logger.warning(
|
|
30
|
+
f"Agent templates directory not found: {agent_templates_dir}"
|
|
31
|
+
)
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
mapping_count = 0
|
|
35
|
+
for template_file in agent_templates_dir.glob("*.json"):
|
|
36
|
+
try:
|
|
37
|
+
with open(template_file, encoding="utf-8") as f:
|
|
38
|
+
agent_data = json.load(f)
|
|
39
|
+
|
|
40
|
+
agent_id = agent_data.get("agent_id") or agent_data.get("agent_type")
|
|
41
|
+
if not agent_id:
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
# Extract skills list if present
|
|
45
|
+
skills = agent_data.get("skills", [])
|
|
46
|
+
if skills:
|
|
47
|
+
self.agent_skill_mapping[agent_id] = skills
|
|
48
|
+
mapping_count += 1
|
|
49
|
+
logger.debug(
|
|
50
|
+
f"Agent '{agent_id}' mapped to {len(skills)} skills: {', '.join(skills)}"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
logger.error(f"Error loading agent mapping from {template_file}: {e}")
|
|
55
|
+
|
|
56
|
+
if mapping_count > 0:
|
|
57
|
+
logger.info(f"Loaded skill mappings for {mapping_count} agents")
|
|
58
|
+
|
|
59
|
+
def get_agent_skills(self, agent_type: str) -> List[Skill]:
|
|
60
|
+
"""
|
|
61
|
+
Get all skills for an agent (bundled + discovered).
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
agent_type: Agent type/ID (e.g., 'engineer', 'python_engineer')
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
List of Skill objects for this agent
|
|
68
|
+
"""
|
|
69
|
+
skill_names = self.agent_skill_mapping.get(agent_type, [])
|
|
70
|
+
|
|
71
|
+
# Get skills from registry
|
|
72
|
+
skills = []
|
|
73
|
+
for name in skill_names:
|
|
74
|
+
skill = self.registry.get_skill(name)
|
|
75
|
+
if skill:
|
|
76
|
+
skills.append(skill)
|
|
77
|
+
else:
|
|
78
|
+
logger.warning(
|
|
79
|
+
f"Skill '{name}' referenced by agent '{agent_type}' not found"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Also include skills that have no agent restriction
|
|
83
|
+
# or explicitly list this agent type
|
|
84
|
+
additional_skills = self.registry.get_skills_for_agent(agent_type)
|
|
85
|
+
for skill in additional_skills:
|
|
86
|
+
if skill not in skills:
|
|
87
|
+
skills.append(skill)
|
|
88
|
+
|
|
89
|
+
return skills
|
|
90
|
+
|
|
91
|
+
def enhance_agent_prompt(
|
|
92
|
+
self, agent_type: str, base_prompt: str, include_all: bool = False
|
|
93
|
+
) -> str:
|
|
94
|
+
"""
|
|
95
|
+
Enhance agent prompt with available skills.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
agent_type: Agent type/ID
|
|
99
|
+
base_prompt: Original agent prompt
|
|
100
|
+
include_all: If True, include all available skills regardless of mapping
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Enhanced prompt with skills section appended
|
|
104
|
+
"""
|
|
105
|
+
if include_all:
|
|
106
|
+
skills = self.registry.list_skills()
|
|
107
|
+
else:
|
|
108
|
+
skills = self.get_agent_skills(agent_type)
|
|
109
|
+
|
|
110
|
+
if not skills:
|
|
111
|
+
return base_prompt
|
|
112
|
+
|
|
113
|
+
# Build skills section
|
|
114
|
+
skills_section = "\n\n" + "=" * 80 + "\n"
|
|
115
|
+
skills_section += "## 🎯 Available Skills\n\n"
|
|
116
|
+
skills_section += f"You have access to {len(skills)} specialized skills:\n\n"
|
|
117
|
+
|
|
118
|
+
for skill in skills:
|
|
119
|
+
skills_section += f"### 📚 {skill.name.replace('-', ' ').title()}\n\n"
|
|
120
|
+
skills_section += f"**Source:** {skill.source}\n"
|
|
121
|
+
if skill.description:
|
|
122
|
+
skills_section += f"**Description:** {skill.description}\n"
|
|
123
|
+
skills_section += "\n```\n"
|
|
124
|
+
skills_section += skill.content
|
|
125
|
+
skills_section += "\n```\n\n"
|
|
126
|
+
|
|
127
|
+
skills_section += "=" * 80 + "\n"
|
|
128
|
+
|
|
129
|
+
return base_prompt + skills_section
|
|
130
|
+
|
|
131
|
+
def list_agent_skill_mappings(self) -> Dict[str, List[str]]:
|
|
132
|
+
"""
|
|
133
|
+
Get all agent-to-skill mappings.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Dictionary mapping agent IDs to lists of skill names
|
|
137
|
+
"""
|
|
138
|
+
return self.agent_skill_mapping.copy()
|
|
139
|
+
|
|
140
|
+
def add_skill_to_agent(self, agent_type: str, skill_name: str) -> bool:
|
|
141
|
+
"""
|
|
142
|
+
Add a skill to an agent's mapping.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
agent_type: Agent type/ID
|
|
146
|
+
skill_name: Name of the skill to add
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
True if successful, False if skill not found
|
|
150
|
+
"""
|
|
151
|
+
skill = self.registry.get_skill(skill_name)
|
|
152
|
+
if not skill:
|
|
153
|
+
logger.error(f"Cannot add skill '{skill_name}': skill not found")
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
if agent_type not in self.agent_skill_mapping:
|
|
157
|
+
self.agent_skill_mapping[agent_type] = []
|
|
158
|
+
|
|
159
|
+
if skill_name not in self.agent_skill_mapping[agent_type]:
|
|
160
|
+
self.agent_skill_mapping[agent_type].append(skill_name)
|
|
161
|
+
logger.info(f"Added skill '{skill_name}' to agent '{agent_type}'")
|
|
162
|
+
|
|
163
|
+
return True
|
|
164
|
+
|
|
165
|
+
def remove_skill_from_agent(self, agent_type: str, skill_name: str) -> bool:
|
|
166
|
+
"""
|
|
167
|
+
Remove a skill from an agent's mapping.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
agent_type: Agent type/ID
|
|
171
|
+
skill_name: Name of the skill to remove
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
True if successful, False if not found
|
|
175
|
+
"""
|
|
176
|
+
if agent_type not in self.agent_skill_mapping:
|
|
177
|
+
return False
|
|
178
|
+
|
|
179
|
+
if skill_name in self.agent_skill_mapping[agent_type]:
|
|
180
|
+
self.agent_skill_mapping[agent_type].remove(skill_name)
|
|
181
|
+
logger.info(f"Removed skill '{skill_name}' from agent '{agent_type}'")
|
|
182
|
+
return True
|
|
183
|
+
|
|
184
|
+
return False
|
|
185
|
+
|
|
186
|
+
def reload(self):
|
|
187
|
+
"""Reload skills and agent mappings."""
|
|
188
|
+
logger.info("Reloading skill manager...")
|
|
189
|
+
self.registry.reload()
|
|
190
|
+
self.agent_skill_mapping.clear()
|
|
191
|
+
self._load_agent_mappings()
|
|
192
|
+
logger.info("Skill manager reloaded")
|
|
193
|
+
|
|
194
|
+
def infer_agents_for_skill(self, skill) -> List[str]:
|
|
195
|
+
"""Infer which agents should have this skill based on tags/name.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
skill: Skill object to analyze
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of agent IDs that should have this skill
|
|
202
|
+
"""
|
|
203
|
+
agents = []
|
|
204
|
+
content_lower = skill.content.lower()
|
|
205
|
+
name_lower = skill.name.lower()
|
|
206
|
+
|
|
207
|
+
# Python-related
|
|
208
|
+
if any(
|
|
209
|
+
tag in content_lower or tag in name_lower
|
|
210
|
+
for tag in ["python", "django", "flask", "fastapi"]
|
|
211
|
+
):
|
|
212
|
+
agents.append("python-engineer")
|
|
213
|
+
|
|
214
|
+
# TypeScript/JavaScript-related
|
|
215
|
+
if any(
|
|
216
|
+
tag in content_lower or tag in name_lower
|
|
217
|
+
for tag in ["typescript", "javascript", "react", "next", "vue", "node"]
|
|
218
|
+
):
|
|
219
|
+
agents.extend(["typescript-engineer", "react-engineer", "nextjs-engineer"])
|
|
220
|
+
|
|
221
|
+
# Go-related
|
|
222
|
+
if any(tag in content_lower or tag in name_lower for tag in ["golang", "go "]):
|
|
223
|
+
agents.append("golang-engineer")
|
|
224
|
+
|
|
225
|
+
# Ops-related
|
|
226
|
+
if any(
|
|
227
|
+
tag in content_lower or tag in name_lower
|
|
228
|
+
for tag in ["docker", "kubernetes", "deploy", "devops", "ops"]
|
|
229
|
+
):
|
|
230
|
+
agents.extend(["ops", "devops", "local-ops"])
|
|
231
|
+
|
|
232
|
+
# Testing/QA-related
|
|
233
|
+
if any(
|
|
234
|
+
tag in content_lower or tag in name_lower
|
|
235
|
+
for tag in ["test", "qa", "quality", "assert"]
|
|
236
|
+
):
|
|
237
|
+
agents.extend(["qa", "web-qa", "api-qa"])
|
|
238
|
+
|
|
239
|
+
# Documentation-related
|
|
240
|
+
if any(
|
|
241
|
+
tag in content_lower or tag in name_lower
|
|
242
|
+
for tag in ["documentation", "docs", "api doc", "openapi"]
|
|
243
|
+
):
|
|
244
|
+
agents.extend(["docs", "documentation", "technical-writer"])
|
|
245
|
+
|
|
246
|
+
# Remove duplicates
|
|
247
|
+
return list(set(agents))
|
|
248
|
+
|
|
249
|
+
def save_mappings_to_config(self, config_path: Optional[Path] = None):
|
|
250
|
+
"""Save current agent-skill mappings to configuration file.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
config_path: Path to configuration file. If None, uses default.
|
|
254
|
+
"""
|
|
255
|
+
import json
|
|
256
|
+
|
|
257
|
+
if config_path is None:
|
|
258
|
+
config_path = Path.cwd() / ".claude-mpm" / "skills_config.json"
|
|
259
|
+
|
|
260
|
+
# Ensure directory exists
|
|
261
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
262
|
+
|
|
263
|
+
# Save mappings
|
|
264
|
+
with open(config_path, "w", encoding="utf-8") as f:
|
|
265
|
+
json.dump(self.agent_skill_mapping, f, indent=2)
|
|
266
|
+
|
|
267
|
+
logger.info(f"Saved skill mappings to {config_path}")
|
|
268
|
+
|
|
269
|
+
def load_mappings_from_config(self, config_path: Optional[Path] = None):
|
|
270
|
+
"""Load agent-skill mappings from configuration file.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
config_path: Path to configuration file. If None, uses default.
|
|
274
|
+
"""
|
|
275
|
+
import json
|
|
276
|
+
|
|
277
|
+
if config_path is None:
|
|
278
|
+
config_path = Path.cwd() / ".claude-mpm" / "skills_config.json"
|
|
279
|
+
|
|
280
|
+
if not config_path.exists():
|
|
281
|
+
logger.debug(f"No skill mappings config found at {config_path}")
|
|
282
|
+
return
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
with open(config_path, encoding="utf-8") as f:
|
|
286
|
+
loaded_mappings = json.load(f)
|
|
287
|
+
|
|
288
|
+
# Merge with existing mappings
|
|
289
|
+
for agent_id, skills in loaded_mappings.items():
|
|
290
|
+
if agent_id not in self.agent_skill_mapping:
|
|
291
|
+
self.agent_skill_mapping[agent_id] = []
|
|
292
|
+
for skill in skills:
|
|
293
|
+
if skill not in self.agent_skill_mapping[agent_id]:
|
|
294
|
+
self.agent_skill_mapping[agent_id].append(skill)
|
|
295
|
+
|
|
296
|
+
logger.info(f"Loaded skill mappings from {config_path}")
|
|
297
|
+
except Exception as e:
|
|
298
|
+
logger.error(f"Error loading skill mappings from {config_path}: {e}")
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
# Global manager instance (singleton pattern)
|
|
302
|
+
_manager: Optional[SkillManager] = None
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def get_manager() -> SkillManager:
|
|
306
|
+
"""Get the global skill manager (singleton)."""
|
|
307
|
+
global _manager
|
|
308
|
+
if _manager is None:
|
|
309
|
+
_manager = SkillManager()
|
|
310
|
+
return _manager
|