claude-mpm 4.15.2__py3-none-any.whl → 4.20.3__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +255 -23
- claude_mpm/agents/PM_INSTRUCTIONS.md +40 -0
- claude_mpm/agents/agent_loader.py +4 -4
- 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 +18 -1
- 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 +19 -4
- 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 +23 -8
- claude_mpm/agents/templates/security.json +6 -1
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- 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/__init__.py +2 -0
- 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/commands/mpm_init.py +109 -24
- claude_mpm/cli/commands/skills.py +434 -0
- claude_mpm/cli/executor.py +2 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/skills_parser.py +137 -0
- claude_mpm/cli/startup.py +83 -0
- claude_mpm/commands/mpm-auto-configure.md +52 -0
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/mpm-init.md +112 -6
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/constants.py +12 -0
- claude_mpm/core/config.py +42 -0
- claude_mpm/core/enums.py +18 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/optimized_agent_loader.py +3 -3
- 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/hooks/__init__.py +8 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/auto_config_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/recommender.py +47 -0
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_manager.py +87 -0
- claude_mpm/services/cli/session_resume_helper.py +352 -0
- claude_mpm/services/core/models/health.py +1 -28
- claude_mpm/services/core/path_resolver.py +1 -1
- 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/infrastructure/resume_log_generator.py +439 -0
- 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/mcp_config_manager.py +7 -131
- claude_mpm/services/session_manager.py +205 -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/services/unified/deployment_strategies/local.py +1 -1
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +42 -0
- claude_mpm/skills/agent_skills_injector.py +331 -0
- claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +75 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +184 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +107 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/code-reviewer.md +146 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +118 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +177 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +175 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +213 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +314 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +227 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +74 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +32 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +328 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +150 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +372 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +209 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +302 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +111 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +65 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +123 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +304 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +96 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +40 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +107 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/skills/skills_registry.py +351 -0
- claude_mpm/skills/skills_service.py +730 -0
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/METADATA +211 -33
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/RECORD +195 -115
- claude_mpm/agents/INSTRUCTIONS_OLD_DEPRECATED.md +0 -602
- 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.20.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
"""Interactive Skills Selection Wizard for Claude MPM.
|
|
2
|
+
|
|
3
|
+
This module provides a step-by-step interactive wizard for selecting and configuring
|
|
4
|
+
skills for agents with user-friendly prompts and intelligent auto-linking.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, List, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
from claude_mpm.core.logging_config import get_logger
|
|
10
|
+
from claude_mpm.skills.registry import get_registry
|
|
11
|
+
from claude_mpm.skills.skill_manager import get_manager
|
|
12
|
+
|
|
13
|
+
logger = get_logger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Agent-to-skills auto-linking mappings
|
|
17
|
+
ENGINEER_CORE_SKILLS = [
|
|
18
|
+
"test-driven-development",
|
|
19
|
+
"systematic-debugging",
|
|
20
|
+
"code-review",
|
|
21
|
+
"refactoring-patterns",
|
|
22
|
+
"git-workflow",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
PYTHON_SKILLS = ENGINEER_CORE_SKILLS + ["async-testing"]
|
|
26
|
+
TYPESCRIPT_SKILLS = ENGINEER_CORE_SKILLS + ["async-testing"]
|
|
27
|
+
GOLANG_SKILLS = ENGINEER_CORE_SKILLS + ["async-testing"]
|
|
28
|
+
REACT_SKILLS = TYPESCRIPT_SKILLS + ["performance-profiling"]
|
|
29
|
+
NEXTJS_SKILLS = REACT_SKILLS
|
|
30
|
+
VUE_SKILLS = TYPESCRIPT_SKILLS + ["performance-profiling"]
|
|
31
|
+
|
|
32
|
+
OPS_SKILLS = [
|
|
33
|
+
"docker-containerization",
|
|
34
|
+
"database-migration",
|
|
35
|
+
"security-scanning",
|
|
36
|
+
"systematic-debugging",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
DOCUMENTATION_SKILLS = [
|
|
40
|
+
"api-documentation",
|
|
41
|
+
"code-review",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
QA_SKILLS = [
|
|
45
|
+
"test-driven-development",
|
|
46
|
+
"systematic-debugging",
|
|
47
|
+
"async-testing",
|
|
48
|
+
"performance-profiling",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
# Mapping of agent types to their recommended skills
|
|
52
|
+
AGENT_SKILL_MAPPING = {
|
|
53
|
+
# Engineer agents
|
|
54
|
+
"engineer": ENGINEER_CORE_SKILLS,
|
|
55
|
+
"python-engineer": PYTHON_SKILLS,
|
|
56
|
+
"typescript-engineer": TYPESCRIPT_SKILLS,
|
|
57
|
+
"golang-engineer": GOLANG_SKILLS,
|
|
58
|
+
"react-engineer": REACT_SKILLS,
|
|
59
|
+
"nextjs-engineer": NEXTJS_SKILLS,
|
|
60
|
+
"vue-engineer": VUE_SKILLS,
|
|
61
|
+
# Ops agents
|
|
62
|
+
"ops": OPS_SKILLS,
|
|
63
|
+
"devops": OPS_SKILLS,
|
|
64
|
+
"local-ops": OPS_SKILLS,
|
|
65
|
+
# Documentation agents
|
|
66
|
+
"docs": DOCUMENTATION_SKILLS,
|
|
67
|
+
"documentation": DOCUMENTATION_SKILLS,
|
|
68
|
+
"technical-writer": DOCUMENTATION_SKILLS,
|
|
69
|
+
# QA agents
|
|
70
|
+
"qa": QA_SKILLS,
|
|
71
|
+
"web-qa": QA_SKILLS,
|
|
72
|
+
"api-qa": QA_SKILLS,
|
|
73
|
+
"tester": QA_SKILLS,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class SkillsWizard:
|
|
78
|
+
"""Interactive wizard for skills selection and configuration."""
|
|
79
|
+
|
|
80
|
+
def __init__(self):
|
|
81
|
+
"""Initialize the skills wizard."""
|
|
82
|
+
self.registry = get_registry()
|
|
83
|
+
self.manager = get_manager()
|
|
84
|
+
self.logger = logger
|
|
85
|
+
|
|
86
|
+
def run_interactive_selection(
|
|
87
|
+
self, selected_agents: Optional[List[str]] = None
|
|
88
|
+
) -> Tuple[bool, Dict[str, List[str]]]:
|
|
89
|
+
"""Run interactive skills selection wizard.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
selected_agents: List of agent IDs that were selected in agent wizard
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Tuple of (success, agent_skills_mapping)
|
|
96
|
+
- success: Boolean indicating if selection was successful
|
|
97
|
+
- agent_skills_mapping: Dict mapping agent IDs to lists of skill names
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
print("\n" + "=" * 60)
|
|
101
|
+
print("🎯 Skills Selection Wizard")
|
|
102
|
+
print("=" * 60)
|
|
103
|
+
print("\nI'll help you select skills for your agents.")
|
|
104
|
+
print("Press Ctrl+C anytime to cancel.\n")
|
|
105
|
+
|
|
106
|
+
# Auto-link skills based on selected agents
|
|
107
|
+
agent_skills_mapping = {}
|
|
108
|
+
if selected_agents:
|
|
109
|
+
print("📋 Auto-linking skills based on selected agents...\n")
|
|
110
|
+
agent_skills_mapping = self._auto_link_skills(selected_agents)
|
|
111
|
+
self._display_auto_linked_skills(agent_skills_mapping)
|
|
112
|
+
|
|
113
|
+
# Ask if user wants to customize
|
|
114
|
+
customize = (
|
|
115
|
+
input("\nWould you like to customize skill selections? [y/N]: ")
|
|
116
|
+
.strip()
|
|
117
|
+
.lower()
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if customize in ["y", "yes"]:
|
|
121
|
+
agent_skills_mapping = self._run_custom_selection(
|
|
122
|
+
selected_agents, agent_skills_mapping
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Preview final configuration
|
|
126
|
+
self._preview_final_configuration(agent_skills_mapping)
|
|
127
|
+
|
|
128
|
+
# Confirm
|
|
129
|
+
confirm = (
|
|
130
|
+
input("\nApply this skills configuration? [Y/n]: ").strip().lower()
|
|
131
|
+
)
|
|
132
|
+
if confirm in ["n", "no"]:
|
|
133
|
+
return False, {}
|
|
134
|
+
|
|
135
|
+
# Apply configuration
|
|
136
|
+
self._apply_skills_configuration(agent_skills_mapping)
|
|
137
|
+
|
|
138
|
+
print("\n✅ Skills configuration complete!")
|
|
139
|
+
return True, agent_skills_mapping
|
|
140
|
+
|
|
141
|
+
except KeyboardInterrupt:
|
|
142
|
+
print("\n\n❌ Skills selection cancelled")
|
|
143
|
+
return False, {}
|
|
144
|
+
except Exception as e:
|
|
145
|
+
error_msg = f"Skills selection error: {e}"
|
|
146
|
+
self.logger.error(error_msg, exc_info=True)
|
|
147
|
+
print(f"\n❌ {error_msg}")
|
|
148
|
+
return False, {}
|
|
149
|
+
|
|
150
|
+
def _auto_link_skills(self, agent_ids: List[str]) -> Dict[str, List[str]]:
|
|
151
|
+
"""Auto-link skills to agents based on agent types.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
agent_ids: List of agent IDs
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Dictionary mapping agent IDs to skill names
|
|
158
|
+
"""
|
|
159
|
+
mapping = {}
|
|
160
|
+
for agent_id in agent_ids:
|
|
161
|
+
# Try to match against known patterns
|
|
162
|
+
skills = self._get_recommended_skills_for_agent(agent_id)
|
|
163
|
+
if skills:
|
|
164
|
+
mapping[agent_id] = skills
|
|
165
|
+
else:
|
|
166
|
+
# Default to core engineer skills if no match
|
|
167
|
+
mapping[agent_id] = ENGINEER_CORE_SKILLS.copy()
|
|
168
|
+
|
|
169
|
+
return mapping
|
|
170
|
+
|
|
171
|
+
def _get_recommended_skills_for_agent(self, agent_id: str) -> List[str]:
|
|
172
|
+
"""Get recommended skills for an agent based on its ID.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
agent_id: Agent identifier
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
List of recommended skill names
|
|
179
|
+
"""
|
|
180
|
+
agent_id_lower = agent_id.lower()
|
|
181
|
+
|
|
182
|
+
# Direct match
|
|
183
|
+
if agent_id_lower in AGENT_SKILL_MAPPING:
|
|
184
|
+
return AGENT_SKILL_MAPPING[agent_id_lower].copy()
|
|
185
|
+
|
|
186
|
+
# Fuzzy matching for common patterns
|
|
187
|
+
if "python" in agent_id_lower:
|
|
188
|
+
return PYTHON_SKILLS.copy()
|
|
189
|
+
if any(js in agent_id_lower for js in ["typescript", "ts", "javascript", "js"]):
|
|
190
|
+
return TYPESCRIPT_SKILLS.copy()
|
|
191
|
+
if "react" in agent_id_lower:
|
|
192
|
+
return REACT_SKILLS.copy()
|
|
193
|
+
if "next" in agent_id_lower:
|
|
194
|
+
return NEXTJS_SKILLS.copy()
|
|
195
|
+
if "vue" in agent_id_lower:
|
|
196
|
+
return VUE_SKILLS.copy()
|
|
197
|
+
if "go" in agent_id_lower or "golang" in agent_id_lower:
|
|
198
|
+
return GOLANG_SKILLS.copy()
|
|
199
|
+
if any(ops in agent_id_lower for ops in ["ops", "devops", "deploy"]):
|
|
200
|
+
return OPS_SKILLS.copy()
|
|
201
|
+
if any(qa in agent_id_lower for qa in ["qa", "test", "quality"]):
|
|
202
|
+
return QA_SKILLS.copy()
|
|
203
|
+
if any(doc in agent_id_lower for doc in ["doc", "writer", "technical"]):
|
|
204
|
+
return DOCUMENTATION_SKILLS.copy()
|
|
205
|
+
if "engineer" in agent_id_lower:
|
|
206
|
+
return ENGINEER_CORE_SKILLS.copy()
|
|
207
|
+
|
|
208
|
+
# Default
|
|
209
|
+
return []
|
|
210
|
+
|
|
211
|
+
def _display_auto_linked_skills(self, mapping: Dict[str, List[str]]):
|
|
212
|
+
"""Display auto-linked skills configuration.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
mapping: Agent-to-skills mapping
|
|
216
|
+
"""
|
|
217
|
+
for agent_id, skills in mapping.items():
|
|
218
|
+
print(f" • {agent_id}:")
|
|
219
|
+
for skill in skills:
|
|
220
|
+
print(f" - {skill}")
|
|
221
|
+
print()
|
|
222
|
+
|
|
223
|
+
def _run_custom_selection(
|
|
224
|
+
self, agent_ids: Optional[List[str]], initial_mapping: Dict[str, List[str]]
|
|
225
|
+
) -> Dict[str, List[str]]:
|
|
226
|
+
"""Run custom skills selection for each agent.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
agent_ids: List of agent IDs
|
|
230
|
+
initial_mapping: Initial auto-linked mapping
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Updated agent-to-skills mapping
|
|
234
|
+
"""
|
|
235
|
+
mapping = initial_mapping.copy()
|
|
236
|
+
|
|
237
|
+
# Get all available bundled skills
|
|
238
|
+
bundled_skills = self.registry.list_skills(source="bundled")
|
|
239
|
+
skill_list = sorted([skill.name for skill in bundled_skills])
|
|
240
|
+
|
|
241
|
+
print("\n" + "=" * 60)
|
|
242
|
+
print("Available Bundled Skills:")
|
|
243
|
+
print("=" * 60)
|
|
244
|
+
for i, skill in enumerate(bundled_skills, 1):
|
|
245
|
+
description = (
|
|
246
|
+
skill.description[:60] + "..."
|
|
247
|
+
if len(skill.description) > 60
|
|
248
|
+
else skill.description
|
|
249
|
+
)
|
|
250
|
+
print(f" [{i:2d}] {skill.name}")
|
|
251
|
+
print(f" {description}")
|
|
252
|
+
print()
|
|
253
|
+
|
|
254
|
+
# If no agents provided, ask which agents to configure
|
|
255
|
+
if not agent_ids:
|
|
256
|
+
agent_ids = self._get_agents_to_configure()
|
|
257
|
+
|
|
258
|
+
# Configure each agent
|
|
259
|
+
for agent_id in agent_ids:
|
|
260
|
+
print(f"\n🔧 Configuring skills for: {agent_id}")
|
|
261
|
+
current_skills = mapping.get(agent_id, [])
|
|
262
|
+
|
|
263
|
+
print(f" Current skills ({len(current_skills)}):")
|
|
264
|
+
for skill in current_skills:
|
|
265
|
+
print(f" - {skill}")
|
|
266
|
+
|
|
267
|
+
modify = (
|
|
268
|
+
input(f"\n Modify skills for {agent_id}? [y/N]: ").strip().lower()
|
|
269
|
+
)
|
|
270
|
+
if modify not in ["y", "yes"]:
|
|
271
|
+
continue
|
|
272
|
+
|
|
273
|
+
# Let user select skills
|
|
274
|
+
print("\n Enter skill numbers (comma-separated), or:")
|
|
275
|
+
print(" 'all' - Select all skills")
|
|
276
|
+
print(" 'none' - Clear all skills")
|
|
277
|
+
print(" 'keep' - Keep current selection")
|
|
278
|
+
selection = input(" Selection: ").strip().lower()
|
|
279
|
+
|
|
280
|
+
if selection == "keep":
|
|
281
|
+
continue
|
|
282
|
+
if selection == "none":
|
|
283
|
+
mapping[agent_id] = []
|
|
284
|
+
elif selection == "all":
|
|
285
|
+
mapping[agent_id] = skill_list.copy()
|
|
286
|
+
else:
|
|
287
|
+
# Parse comma-separated numbers
|
|
288
|
+
try:
|
|
289
|
+
selected_indices = [
|
|
290
|
+
int(idx.strip()) for idx in selection.split(",")
|
|
291
|
+
]
|
|
292
|
+
selected_skills = [
|
|
293
|
+
skill_list[idx - 1]
|
|
294
|
+
for idx in selected_indices
|
|
295
|
+
if 1 <= idx <= len(skill_list)
|
|
296
|
+
]
|
|
297
|
+
mapping[agent_id] = selected_skills
|
|
298
|
+
except (ValueError, IndexError) as e:
|
|
299
|
+
print(f" ⚠️ Invalid selection, keeping current: {e}")
|
|
300
|
+
|
|
301
|
+
return mapping
|
|
302
|
+
|
|
303
|
+
def _get_agents_to_configure(self) -> List[str]:
|
|
304
|
+
"""Ask user which agents to configure.
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
List of agent IDs
|
|
308
|
+
"""
|
|
309
|
+
agent_ids_input = input("\nEnter agent IDs (comma-separated): ").strip()
|
|
310
|
+
return [aid.strip() for aid in agent_ids_input.split(",") if aid.strip()]
|
|
311
|
+
|
|
312
|
+
def _preview_final_configuration(self, mapping: Dict[str, List[str]]):
|
|
313
|
+
"""Display final skills configuration preview.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
mapping: Agent-to-skills mapping
|
|
317
|
+
"""
|
|
318
|
+
print("\n" + "=" * 60)
|
|
319
|
+
print("📋 Final Skills Configuration:")
|
|
320
|
+
print("=" * 60)
|
|
321
|
+
|
|
322
|
+
if not mapping:
|
|
323
|
+
print(" (No skills configured)")
|
|
324
|
+
return
|
|
325
|
+
|
|
326
|
+
for agent_id, skills in mapping.items():
|
|
327
|
+
print(f"\n {agent_id} ({len(skills)} skills):")
|
|
328
|
+
if skills:
|
|
329
|
+
for skill in skills:
|
|
330
|
+
print(f" ✓ {skill}")
|
|
331
|
+
else:
|
|
332
|
+
print(" (no skills)")
|
|
333
|
+
|
|
334
|
+
def _apply_skills_configuration(self, mapping: Dict[str, List[str]]):
|
|
335
|
+
"""Apply skills configuration to skill manager.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
mapping: Agent-to-skills mapping
|
|
339
|
+
"""
|
|
340
|
+
for agent_id, skills in mapping.items():
|
|
341
|
+
# Clear existing mappings for this agent
|
|
342
|
+
if agent_id in self.manager.agent_skill_mapping:
|
|
343
|
+
self.manager.agent_skill_mapping[agent_id] = []
|
|
344
|
+
|
|
345
|
+
# Add each skill
|
|
346
|
+
for skill_name in skills:
|
|
347
|
+
self.manager.add_skill_to_agent(agent_id, skill_name)
|
|
348
|
+
|
|
349
|
+
self.logger.info(f"Applied skills configuration for {len(mapping)} agents")
|
|
350
|
+
|
|
351
|
+
def list_available_skills(self):
|
|
352
|
+
"""Display all available skills."""
|
|
353
|
+
print("\n" + "=" * 60)
|
|
354
|
+
print("📚 Available Skills")
|
|
355
|
+
print("=" * 60)
|
|
356
|
+
|
|
357
|
+
# Bundled skills
|
|
358
|
+
bundled_skills = self.registry.list_skills(source="bundled")
|
|
359
|
+
if bundled_skills:
|
|
360
|
+
print(f"\n🔹 Bundled Skills ({len(bundled_skills)}):")
|
|
361
|
+
for skill in sorted(bundled_skills, key=lambda s: s.name):
|
|
362
|
+
print(f" • {skill.name}")
|
|
363
|
+
if skill.description:
|
|
364
|
+
desc = (
|
|
365
|
+
skill.description[:80] + "..."
|
|
366
|
+
if len(skill.description) > 80
|
|
367
|
+
else skill.description
|
|
368
|
+
)
|
|
369
|
+
print(f" {desc}")
|
|
370
|
+
|
|
371
|
+
# User skills
|
|
372
|
+
user_skills = self.registry.list_skills(source="user")
|
|
373
|
+
if user_skills:
|
|
374
|
+
print(f"\n👤 User Skills ({len(user_skills)}):")
|
|
375
|
+
for skill in sorted(user_skills, key=lambda s: s.name):
|
|
376
|
+
print(f" • {skill.name}")
|
|
377
|
+
if skill.description:
|
|
378
|
+
desc = (
|
|
379
|
+
skill.description[:80] + "..."
|
|
380
|
+
if len(skill.description) > 80
|
|
381
|
+
else skill.description
|
|
382
|
+
)
|
|
383
|
+
print(f" {desc}")
|
|
384
|
+
|
|
385
|
+
# Project skills
|
|
386
|
+
project_skills = self.registry.list_skills(source="project")
|
|
387
|
+
if project_skills:
|
|
388
|
+
print(f"\n📂 Project Skills ({len(project_skills)}):")
|
|
389
|
+
for skill in sorted(project_skills, key=lambda s: s.name):
|
|
390
|
+
print(f" • {skill.name}")
|
|
391
|
+
if skill.description:
|
|
392
|
+
desc = (
|
|
393
|
+
skill.description[:80] + "..."
|
|
394
|
+
if len(skill.description) > 80
|
|
395
|
+
else skill.description
|
|
396
|
+
)
|
|
397
|
+
print(f" {desc}")
|
|
398
|
+
|
|
399
|
+
print()
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def discover_and_link_runtime_skills():
|
|
403
|
+
"""Discover user/project skills and auto-link to agents at runtime.
|
|
404
|
+
|
|
405
|
+
This function is called during startup to:
|
|
406
|
+
1. Reload the skills registry (picks up new skills from .claude/skills/)
|
|
407
|
+
2. Auto-link discovered skills to agents based on tags/naming conventions
|
|
408
|
+
"""
|
|
409
|
+
try:
|
|
410
|
+
registry = get_registry()
|
|
411
|
+
manager = get_manager()
|
|
412
|
+
|
|
413
|
+
# Reload registry to pick up new skills
|
|
414
|
+
registry.reload()
|
|
415
|
+
|
|
416
|
+
# Get discovered skills (user and project)
|
|
417
|
+
discovered_skills = registry.list_skills(source="user") + registry.list_skills(
|
|
418
|
+
source="project"
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
if not discovered_skills:
|
|
422
|
+
logger.debug("No runtime skills discovered")
|
|
423
|
+
return
|
|
424
|
+
|
|
425
|
+
logger.info(f"Discovered {len(discovered_skills)} runtime skills")
|
|
426
|
+
|
|
427
|
+
# Auto-link based on skill content and naming
|
|
428
|
+
for skill in discovered_skills:
|
|
429
|
+
agents = _infer_agents_for_skill(skill)
|
|
430
|
+
for agent_id in agents:
|
|
431
|
+
manager.add_skill_to_agent(agent_id, skill.name)
|
|
432
|
+
logger.debug(f"Auto-linked skill '{skill.name}' to agent '{agent_id}'")
|
|
433
|
+
|
|
434
|
+
except Exception as e:
|
|
435
|
+
logger.error(f"Error during runtime skills discovery: {e}", exc_info=True)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def _infer_agents_for_skill(skill) -> List[str]:
|
|
439
|
+
"""Infer which agents should have this skill based on tags/name.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
skill: Skill object to analyze
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
List of agent IDs that should have this skill
|
|
446
|
+
"""
|
|
447
|
+
agents = []
|
|
448
|
+
content_lower = skill.content.lower()
|
|
449
|
+
name_lower = skill.name.lower()
|
|
450
|
+
|
|
451
|
+
# Python-related
|
|
452
|
+
if any(
|
|
453
|
+
tag in content_lower or tag in name_lower
|
|
454
|
+
for tag in ["python", "django", "flask", "fastapi"]
|
|
455
|
+
):
|
|
456
|
+
agents.append("python-engineer")
|
|
457
|
+
|
|
458
|
+
# TypeScript/JavaScript-related
|
|
459
|
+
if any(
|
|
460
|
+
tag in content_lower or tag in name_lower
|
|
461
|
+
for tag in ["typescript", "javascript", "react", "next", "vue", "node"]
|
|
462
|
+
):
|
|
463
|
+
agents.extend(["typescript-engineer", "react-engineer", "nextjs-engineer"])
|
|
464
|
+
|
|
465
|
+
# Go-related
|
|
466
|
+
if any(tag in content_lower or tag in name_lower for tag in ["golang", "go "]):
|
|
467
|
+
agents.append("golang-engineer")
|
|
468
|
+
|
|
469
|
+
# Ops-related
|
|
470
|
+
if any(
|
|
471
|
+
tag in content_lower or tag in name_lower
|
|
472
|
+
for tag in ["docker", "kubernetes", "deploy", "devops", "ops"]
|
|
473
|
+
):
|
|
474
|
+
agents.extend(["ops", "devops", "local-ops"])
|
|
475
|
+
|
|
476
|
+
# Testing/QA-related
|
|
477
|
+
if any(
|
|
478
|
+
tag in content_lower or tag in name_lower
|
|
479
|
+
for tag in ["test", "qa", "quality", "assert"]
|
|
480
|
+
):
|
|
481
|
+
agents.extend(["qa", "web-qa", "api-qa"])
|
|
482
|
+
|
|
483
|
+
# Documentation-related
|
|
484
|
+
if any(
|
|
485
|
+
tag in content_lower or tag in name_lower
|
|
486
|
+
for tag in ["documentation", "docs", "api doc", "openapi"]
|
|
487
|
+
):
|
|
488
|
+
agents.extend(["docs", "documentation", "technical-writer"])
|
|
489
|
+
|
|
490
|
+
# Remove duplicates
|
|
491
|
+
return list(set(agents))
|
|
@@ -403,6 +403,13 @@ def create_parser(
|
|
|
403
403
|
except ImportError:
|
|
404
404
|
pass
|
|
405
405
|
|
|
406
|
+
try:
|
|
407
|
+
from .skills_parser import add_skills_subparser
|
|
408
|
+
|
|
409
|
+
add_skills_subparser(subparsers)
|
|
410
|
+
except ImportError:
|
|
411
|
+
pass
|
|
412
|
+
|
|
406
413
|
try:
|
|
407
414
|
from .config_parser import add_config_subparser
|
|
408
415
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Skills command parser for claude-mpm CLI.
|
|
3
|
+
|
|
4
|
+
WHY: This module contains all arguments specific to skills management commands,
|
|
5
|
+
providing CLI access to the Skills Integration system.
|
|
6
|
+
|
|
7
|
+
DESIGN DECISION: Skills commands expose the SkillsService functionality via CLI
|
|
8
|
+
for listing, deploying, validating, updating, and configuring Claude Code skills.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
|
|
13
|
+
from ...constants import CLICommands, SkillsCommands
|
|
14
|
+
from .base_parser import add_common_arguments
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def add_skills_subparser(subparsers) -> argparse.ArgumentParser:
|
|
18
|
+
"""
|
|
19
|
+
Add the skills subparser with all skills management commands.
|
|
20
|
+
|
|
21
|
+
WHY: Skills management has multiple subcommands for discovery, deployment,
|
|
22
|
+
validation, updates, and configuration that need their own argument structures.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
subparsers: The subparsers object from the main parser
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
The configured skills subparser
|
|
29
|
+
"""
|
|
30
|
+
# Skills command with subcommands
|
|
31
|
+
skills_parser = subparsers.add_parser(
|
|
32
|
+
CLICommands.SKILLS.value, help="Manage Claude Code skills"
|
|
33
|
+
)
|
|
34
|
+
add_common_arguments(skills_parser)
|
|
35
|
+
|
|
36
|
+
skills_subparsers = skills_parser.add_subparsers(
|
|
37
|
+
dest="skills_command", help="Skills commands", metavar="SUBCOMMAND"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# List command
|
|
41
|
+
list_parser = skills_subparsers.add_parser(
|
|
42
|
+
SkillsCommands.LIST.value, help="List available skills"
|
|
43
|
+
)
|
|
44
|
+
list_parser.add_argument(
|
|
45
|
+
"--category",
|
|
46
|
+
help="Filter by category (e.g., development, infrastructure, web-development)",
|
|
47
|
+
)
|
|
48
|
+
list_parser.add_argument(
|
|
49
|
+
"--agent", help="Show skills for specific agent (e.g., engineer, pm)"
|
|
50
|
+
)
|
|
51
|
+
list_parser.add_argument(
|
|
52
|
+
"--verbose",
|
|
53
|
+
"-v",
|
|
54
|
+
action="store_true",
|
|
55
|
+
help="Show detailed skill information",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Deploy command
|
|
59
|
+
deploy_parser = skills_subparsers.add_parser(
|
|
60
|
+
SkillsCommands.DEPLOY.value, help="Deploy bundled skills to project"
|
|
61
|
+
)
|
|
62
|
+
deploy_parser.add_argument(
|
|
63
|
+
"--force",
|
|
64
|
+
action="store_true",
|
|
65
|
+
help="Force redeployment of already deployed skills",
|
|
66
|
+
)
|
|
67
|
+
deploy_parser.add_argument(
|
|
68
|
+
"--skill",
|
|
69
|
+
action="append",
|
|
70
|
+
dest="skills",
|
|
71
|
+
help="Deploy specific skill(s) only (can be used multiple times)",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Validate command
|
|
75
|
+
validate_parser = skills_subparsers.add_parser(
|
|
76
|
+
SkillsCommands.VALIDATE.value, help="Validate skill structure and metadata"
|
|
77
|
+
)
|
|
78
|
+
validate_parser.add_argument("skill_name", help="Name of the skill to validate")
|
|
79
|
+
validate_parser.add_argument(
|
|
80
|
+
"--strict",
|
|
81
|
+
action="store_true",
|
|
82
|
+
help="Use strict validation (treat warnings as errors)",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Update command
|
|
86
|
+
update_parser = skills_subparsers.add_parser(
|
|
87
|
+
SkillsCommands.UPDATE.value, help="Check for and install skill updates"
|
|
88
|
+
)
|
|
89
|
+
update_parser.add_argument(
|
|
90
|
+
"skill_names",
|
|
91
|
+
nargs="*",
|
|
92
|
+
help="Specific skills to update (default: all)",
|
|
93
|
+
)
|
|
94
|
+
update_parser.add_argument(
|
|
95
|
+
"--check-only",
|
|
96
|
+
action="store_true",
|
|
97
|
+
help="Check for updates without installing them",
|
|
98
|
+
)
|
|
99
|
+
update_parser.add_argument(
|
|
100
|
+
"--force",
|
|
101
|
+
action="store_true",
|
|
102
|
+
help="Force update even if versions match",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Info command
|
|
106
|
+
info_parser = skills_subparsers.add_parser(
|
|
107
|
+
SkillsCommands.INFO.value, help="Show detailed skill information"
|
|
108
|
+
)
|
|
109
|
+
info_parser.add_argument("skill_name", help="Name of the skill")
|
|
110
|
+
info_parser.add_argument(
|
|
111
|
+
"--show-content",
|
|
112
|
+
action="store_true",
|
|
113
|
+
help="Show full skill content (SKILL.md)",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Config command
|
|
117
|
+
config_parser = skills_subparsers.add_parser(
|
|
118
|
+
SkillsCommands.CONFIG.value, help="View or edit skills configuration"
|
|
119
|
+
)
|
|
120
|
+
config_parser.add_argument(
|
|
121
|
+
"--scope",
|
|
122
|
+
choices=["system", "user", "project"],
|
|
123
|
+
default="project",
|
|
124
|
+
help="Configuration scope (default: project)",
|
|
125
|
+
)
|
|
126
|
+
config_parser.add_argument(
|
|
127
|
+
"--edit",
|
|
128
|
+
action="store_true",
|
|
129
|
+
help="Open configuration in $EDITOR",
|
|
130
|
+
)
|
|
131
|
+
config_parser.add_argument(
|
|
132
|
+
"--path",
|
|
133
|
+
action="store_true",
|
|
134
|
+
help="Show configuration file path",
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return skills_parser
|