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.
Files changed (203) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  3. claude_mpm/agents/BASE_PM.md +255 -23
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +40 -0
  5. claude_mpm/agents/agent_loader.py +4 -4
  6. claude_mpm/agents/templates/agentic-coder-optimizer.json +9 -2
  7. claude_mpm/agents/templates/api_qa.json +7 -1
  8. claude_mpm/agents/templates/clerk-ops.json +8 -1
  9. claude_mpm/agents/templates/code_analyzer.json +4 -1
  10. claude_mpm/agents/templates/dart_engineer.json +11 -1
  11. claude_mpm/agents/templates/data_engineer.json +11 -1
  12. claude_mpm/agents/templates/documentation.json +6 -1
  13. claude_mpm/agents/templates/engineer.json +18 -1
  14. claude_mpm/agents/templates/gcp_ops_agent.json +8 -1
  15. claude_mpm/agents/templates/golang_engineer.json +11 -1
  16. claude_mpm/agents/templates/java_engineer.json +12 -2
  17. claude_mpm/agents/templates/local_ops_agent.json +216 -37
  18. claude_mpm/agents/templates/nextjs_engineer.json +11 -1
  19. claude_mpm/agents/templates/ops.json +8 -1
  20. claude_mpm/agents/templates/php-engineer.json +11 -1
  21. claude_mpm/agents/templates/project_organizer.json +9 -2
  22. claude_mpm/agents/templates/prompt-engineer.json +5 -1
  23. claude_mpm/agents/templates/python_engineer.json +19 -4
  24. claude_mpm/agents/templates/qa.json +7 -1
  25. claude_mpm/agents/templates/react_engineer.json +11 -1
  26. claude_mpm/agents/templates/refactoring_engineer.json +8 -1
  27. claude_mpm/agents/templates/research.json +4 -1
  28. claude_mpm/agents/templates/ruby-engineer.json +11 -1
  29. claude_mpm/agents/templates/rust_engineer.json +23 -8
  30. claude_mpm/agents/templates/security.json +6 -1
  31. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  32. claude_mpm/agents/templates/ticketing.json +6 -1
  33. claude_mpm/agents/templates/typescript_engineer.json +11 -1
  34. claude_mpm/agents/templates/vercel_ops_agent.json +8 -1
  35. claude_mpm/agents/templates/version_control.json +8 -1
  36. claude_mpm/agents/templates/web_qa.json +7 -1
  37. claude_mpm/agents/templates/web_ui.json +11 -1
  38. claude_mpm/cli/commands/__init__.py +2 -0
  39. claude_mpm/cli/commands/configure.py +164 -16
  40. claude_mpm/cli/commands/configure_agent_display.py +6 -6
  41. claude_mpm/cli/commands/configure_behavior_manager.py +8 -8
  42. claude_mpm/cli/commands/configure_navigation.py +20 -18
  43. claude_mpm/cli/commands/configure_startup_manager.py +14 -14
  44. claude_mpm/cli/commands/configure_template_editor.py +8 -8
  45. claude_mpm/cli/commands/mpm_init.py +109 -24
  46. claude_mpm/cli/commands/skills.py +434 -0
  47. claude_mpm/cli/executor.py +2 -0
  48. claude_mpm/cli/interactive/__init__.py +3 -0
  49. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  50. claude_mpm/cli/parsers/base_parser.py +7 -0
  51. claude_mpm/cli/parsers/skills_parser.py +137 -0
  52. claude_mpm/cli/startup.py +83 -0
  53. claude_mpm/commands/mpm-auto-configure.md +52 -0
  54. claude_mpm/commands/mpm-help.md +3 -0
  55. claude_mpm/commands/mpm-init.md +112 -6
  56. claude_mpm/commands/mpm-version.md +113 -0
  57. claude_mpm/commands/mpm.md +1 -0
  58. claude_mpm/config/agent_config.py +2 -2
  59. claude_mpm/constants.py +12 -0
  60. claude_mpm/core/config.py +42 -0
  61. claude_mpm/core/enums.py +18 -0
  62. claude_mpm/core/factories.py +1 -1
  63. claude_mpm/core/optimized_agent_loader.py +3 -3
  64. claude_mpm/core/types.py +2 -9
  65. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  66. claude_mpm/dashboard/templates/index.html +3 -41
  67. claude_mpm/hooks/__init__.py +8 -0
  68. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  69. claude_mpm/hooks/session_resume_hook.py +121 -0
  70. claude_mpm/models/resume_log.py +340 -0
  71. claude_mpm/services/agents/auto_config_manager.py +1 -1
  72. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  73. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  74. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  75. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  76. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  77. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  78. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  79. claude_mpm/services/agents/local_template_manager.py +1 -1
  80. claude_mpm/services/agents/recommender.py +47 -0
  81. claude_mpm/services/cli/resume_service.py +617 -0
  82. claude_mpm/services/cli/session_manager.py +87 -0
  83. claude_mpm/services/cli/session_resume_helper.py +352 -0
  84. claude_mpm/services/core/models/health.py +1 -28
  85. claude_mpm/services/core/path_resolver.py +1 -1
  86. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  87. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  88. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  89. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  90. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  91. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  92. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  93. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  94. claude_mpm/services/local_ops/__init__.py +1 -1
  95. claude_mpm/services/local_ops/crash_detector.py +1 -1
  96. claude_mpm/services/local_ops/health_checks/http_check.py +2 -1
  97. claude_mpm/services/local_ops/health_checks/process_check.py +2 -1
  98. claude_mpm/services/local_ops/health_checks/resource_check.py +2 -1
  99. claude_mpm/services/local_ops/health_manager.py +1 -1
  100. claude_mpm/services/local_ops/restart_manager.py +1 -1
  101. claude_mpm/services/mcp_config_manager.py +7 -131
  102. claude_mpm/services/session_manager.py +205 -1
  103. claude_mpm/services/shared/async_service_base.py +16 -27
  104. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  105. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  106. claude_mpm/services/socketio/handlers/hook.py +10 -0
  107. claude_mpm/services/socketio/handlers/registry.py +4 -2
  108. claude_mpm/services/socketio/server/main.py +7 -7
  109. claude_mpm/services/unified/deployment_strategies/local.py +1 -1
  110. claude_mpm/services/version_service.py +104 -1
  111. claude_mpm/skills/__init__.py +42 -0
  112. claude_mpm/skills/agent_skills_injector.py +331 -0
  113. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  114. claude_mpm/skills/bundled/__init__.py +6 -0
  115. claude_mpm/skills/bundled/api-documentation.md +393 -0
  116. claude_mpm/skills/bundled/async-testing.md +571 -0
  117. claude_mpm/skills/bundled/code-review.md +143 -0
  118. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +75 -0
  119. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +184 -0
  120. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +107 -0
  121. claude_mpm/skills/bundled/collaboration/requesting-code-review/code-reviewer.md +146 -0
  122. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +118 -0
  123. claude_mpm/skills/bundled/database-migration.md +199 -0
  124. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +177 -0
  125. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  126. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  127. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  128. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  129. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  130. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  131. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  132. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  133. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  134. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  135. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +175 -0
  136. claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +213 -0
  137. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +314 -0
  138. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +227 -0
  139. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  140. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  141. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  142. claude_mpm/skills/bundled/git-workflow.md +414 -0
  143. claude_mpm/skills/bundled/imagemagick.md +204 -0
  144. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  145. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +74 -0
  146. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +32 -0
  147. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  148. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  149. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  150. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  151. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +328 -0
  152. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  153. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  154. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  155. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  156. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +150 -0
  157. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +372 -0
  158. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +209 -0
  159. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +302 -0
  160. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +111 -0
  161. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +65 -0
  162. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  163. claude_mpm/skills/bundled/pdf.md +141 -0
  164. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  165. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  166. claude_mpm/skills/bundled/security-scanning.md +327 -0
  167. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  168. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  169. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +123 -0
  170. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  171. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  172. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  173. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  174. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  175. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  176. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +304 -0
  177. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +96 -0
  178. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  179. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +40 -0
  180. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  181. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +107 -0
  182. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  183. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  184. claude_mpm/skills/bundled/xlsx.md +157 -0
  185. claude_mpm/skills/registry.py +286 -0
  186. claude_mpm/skills/skill_manager.py +310 -0
  187. claude_mpm/skills/skills_registry.py +351 -0
  188. claude_mpm/skills/skills_service.py +730 -0
  189. claude_mpm/utils/agent_dependency_loader.py +2 -2
  190. {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/METADATA +211 -33
  191. {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/RECORD +195 -115
  192. claude_mpm/agents/INSTRUCTIONS_OLD_DEPRECATED.md +0 -602
  193. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  194. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  195. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  196. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  197. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  198. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  199. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  200. {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/WHEEL +0 -0
  201. {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/entry_points.txt +0 -0
  202. {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/licenses/LICENSE +0 -0
  203. {claude_mpm-4.15.2.dist-info → claude_mpm-4.20.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,434 @@
1
+ """
2
+ Skills command implementation for claude-mpm.
3
+
4
+ WHY: This module provides CLI commands for managing Claude Code skills,
5
+ exposing SkillsService functionality for skill discovery, deployment, validation,
6
+ updates, and configuration.
7
+
8
+ DESIGN DECISIONS:
9
+ - Use BaseCommand pattern for consistency with other CLI commands
10
+ - Rich output formatting for user-friendly display
11
+ - Graceful error handling with informative messages
12
+ - Support for verbose output and structured formats
13
+ """
14
+
15
+ import os
16
+ import subprocess
17
+ from typing import Optional
18
+
19
+ from rich.console import Console
20
+ from rich.markdown import Markdown
21
+ from rich.panel import Panel
22
+
23
+ from ...constants import SkillsCommands
24
+ from ...skills.skills_service import SkillsService
25
+ from ..shared import BaseCommand, CommandResult
26
+
27
+ console = Console()
28
+
29
+
30
+ class SkillsManagementCommand(BaseCommand):
31
+ """Skills management command for Claude Code skills."""
32
+
33
+ def __init__(self):
34
+ super().__init__("skills")
35
+ self._skills_service = None
36
+
37
+ @property
38
+ def skills_service(self) -> SkillsService:
39
+ """Get skills service instance (lazy loaded)."""
40
+ if self._skills_service is None:
41
+ self._skills_service = SkillsService()
42
+ return self._skills_service
43
+
44
+ def validate_args(self, args) -> Optional[str]:
45
+ """Validate command arguments."""
46
+ # Most skills commands are optional, basic validation
47
+ if hasattr(args, "skills_command") and args.skills_command:
48
+ if args.skills_command == SkillsCommands.VALIDATE.value:
49
+ if not hasattr(args, "skill_name") or not args.skill_name:
50
+ return "Validate command requires a skill name"
51
+ elif args.skills_command == SkillsCommands.INFO.value:
52
+ if not hasattr(args, "skill_name") or not args.skill_name:
53
+ return "Info command requires a skill name"
54
+ return None
55
+
56
+ def run(self, args) -> CommandResult:
57
+ """Execute the skills command."""
58
+ try:
59
+ # Handle default case (no subcommand) - show list
60
+ if not hasattr(args, "skills_command") or not args.skills_command:
61
+ return self._list_skills(args)
62
+
63
+ # Route to appropriate subcommand
64
+ command_map = {
65
+ SkillsCommands.LIST.value: self._list_skills,
66
+ SkillsCommands.DEPLOY.value: self._deploy_skills,
67
+ SkillsCommands.VALIDATE.value: self._validate_skill,
68
+ SkillsCommands.UPDATE.value: self._update_skills,
69
+ SkillsCommands.INFO.value: self._show_skill_info,
70
+ SkillsCommands.CONFIG.value: self._manage_config,
71
+ }
72
+
73
+ handler = command_map.get(args.skills_command)
74
+ if handler:
75
+ return handler(args)
76
+ return CommandResult(
77
+ success=False,
78
+ message=f"Unknown skills command: {args.skills_command}",
79
+ exit_code=1,
80
+ )
81
+
82
+ except Exception as e:
83
+ self.logger.error(f"Skills command failed: {e}")
84
+ if hasattr(args, "debug") and args.debug:
85
+ import traceback
86
+ traceback.print_exc()
87
+ return CommandResult(
88
+ success=False, message=f"Skills command failed: {e}", exit_code=1
89
+ )
90
+
91
+ def _list_skills(self, args) -> CommandResult:
92
+ """List available skills."""
93
+ try:
94
+ # Get skills based on filter
95
+ if hasattr(args, "agent") and args.agent:
96
+ skills = self.skills_service.get_skills_for_agent(args.agent)
97
+ console.print(f"\n[bold cyan]Skills for agent '{args.agent}':[/bold cyan]\n")
98
+
99
+ if not skills:
100
+ console.print(f"[yellow]No skills found for agent '{args.agent}'[/yellow]")
101
+ return CommandResult(success=True, exit_code=0)
102
+
103
+ for skill_name in skills:
104
+ # Get skill metadata
105
+ skill_info = self._get_skill_metadata(skill_name)
106
+ if skill_info:
107
+ console.print(f" [green]•[/green] {skill_name}")
108
+ if hasattr(args, "verbose") and args.verbose and skill_info.get("description"):
109
+ console.print(f" {skill_info['description']}")
110
+ else:
111
+ console.print(f" [green]•[/green] {skill_name}")
112
+
113
+ else:
114
+ # Discover all bundled skills
115
+ skills = self.skills_service.discover_bundled_skills()
116
+
117
+ # Filter by category if specified
118
+ if hasattr(args, "category") and args.category:
119
+ skills = [s for s in skills if s.get("category") == args.category]
120
+ console.print(f"\n[bold cyan]Skills in category '{args.category}':[/bold cyan]\n")
121
+ else:
122
+ console.print("\n[bold cyan]Available Skills:[/bold cyan]\n")
123
+
124
+ if not skills:
125
+ console.print("[yellow]No skills found[/yellow]")
126
+ return CommandResult(success=True, exit_code=0)
127
+
128
+ # Group by category
129
+ by_category = {}
130
+ for skill in skills:
131
+ category = skill.get("category", "uncategorized")
132
+ if category not in by_category:
133
+ by_category[category] = []
134
+ by_category[category].append(skill)
135
+
136
+ # Display by category
137
+ for category, category_skills in sorted(by_category.items()):
138
+ console.print(f"[bold yellow]{category}[/bold yellow]")
139
+ for skill in sorted(category_skills, key=lambda s: s.get("name", "")):
140
+ name = skill.get("name", "unknown")
141
+ console.print(f" [green]•[/green] {name}")
142
+
143
+ if hasattr(args, "verbose") and args.verbose:
144
+ metadata = skill.get("metadata", {})
145
+ if desc := metadata.get("description"):
146
+ console.print(f" {desc}")
147
+ if version := metadata.get("version"):
148
+ console.print(f" [dim]Version: {version}[/dim]")
149
+ console.print()
150
+
151
+ return CommandResult(success=True, exit_code=0)
152
+
153
+ except Exception as e:
154
+ console.print(f"[red]Error listing skills: {e}[/red]")
155
+ return CommandResult(success=False, message=str(e), exit_code=1)
156
+
157
+ def _deploy_skills(self, args) -> CommandResult:
158
+ """Deploy bundled skills to project."""
159
+ try:
160
+ force = getattr(args, "force", False)
161
+ specific_skills = getattr(args, "skills", None)
162
+
163
+ console.print("\n[bold cyan]Deploying skills...[/bold cyan]\n")
164
+
165
+ result = self.skills_service.deploy_bundled_skills(
166
+ force=force,
167
+ skill_names=specific_skills
168
+ )
169
+
170
+ # Display results
171
+ if result["deployed"]:
172
+ console.print(f"[green]✓ Deployed {len(result['deployed'])} skill(s):[/green]")
173
+ for skill in result["deployed"]:
174
+ console.print(f" • {skill}")
175
+ console.print()
176
+
177
+ if result["skipped"]:
178
+ console.print(f"[yellow]⊘ Skipped {len(result['skipped'])} skill(s) (already deployed):[/yellow]")
179
+ for skill in result["skipped"]:
180
+ console.print(f" • {skill}")
181
+ console.print("[dim]Use --force to redeploy[/dim]\n")
182
+
183
+ if result["errors"]:
184
+ console.print(f"[red]✗ Failed to deploy {len(result['errors'])} skill(s):[/red]")
185
+ for skill, error in result["errors"].items():
186
+ console.print(f" • {skill}: {error}")
187
+ console.print()
188
+
189
+ # Summary
190
+ total = len(result["deployed"]) + len(result["skipped"]) + len(result["errors"])
191
+ console.print(f"[bold]Summary:[/bold] {len(result['deployed'])} deployed, "
192
+ f"{len(result['skipped'])} skipped, {len(result['errors'])} errors "
193
+ f"(Total: {total})\n")
194
+
195
+ # Exit with error if any deployments failed
196
+ exit_code = 1 if result["errors"] else 0
197
+ return CommandResult(success=not result["errors"], exit_code=exit_code)
198
+
199
+ except Exception as e:
200
+ console.print(f"[red]Error deploying skills: {e}[/red]")
201
+ return CommandResult(success=False, message=str(e), exit_code=1)
202
+
203
+ def _validate_skill(self, args) -> CommandResult:
204
+ """Validate skill structure and metadata."""
205
+ try:
206
+ skill_name = args.skill_name
207
+ strict = getattr(args, "strict", False)
208
+
209
+ console.print(f"\n[bold cyan]Validating skill '{skill_name}'...[/bold cyan]\n")
210
+
211
+ result = self.skills_service.validate_skill(skill_name)
212
+
213
+ if result["valid"]:
214
+ console.print(f"[green]✓ {skill_name} is valid[/green]\n")
215
+
216
+ if result.get("warnings"):
217
+ console.print(f"[yellow]Warnings ({len(result['warnings'])}):[/yellow]")
218
+ for warning in result["warnings"]:
219
+ console.print(f" • {warning}")
220
+ console.print()
221
+
222
+ # Treat warnings as errors in strict mode
223
+ if strict:
224
+ console.print("[red]Strict mode: treating warnings as errors[/red]")
225
+ return CommandResult(success=False, exit_code=1)
226
+
227
+ return CommandResult(success=True, exit_code=0)
228
+ console.print(f"[red]✗ {skill_name} has validation errors:[/red]")
229
+ for error in result.get("errors", []):
230
+ console.print(f" • {error}")
231
+ console.print()
232
+
233
+ if result.get("warnings"):
234
+ console.print("[yellow]Warnings:[/yellow]")
235
+ for warning in result["warnings"]:
236
+ console.print(f" • {warning}")
237
+ console.print()
238
+
239
+ return CommandResult(success=False, exit_code=1)
240
+
241
+ except Exception as e:
242
+ console.print(f"[red]Error validating skill: {e}[/red]")
243
+ return CommandResult(success=False, message=str(e), exit_code=1)
244
+
245
+ def _update_skills(self, args) -> CommandResult:
246
+ """Check for and install skill updates."""
247
+ try:
248
+ skill_names = getattr(args, "skill_names", [])
249
+ check_only = getattr(args, "check_only", False)
250
+ force = getattr(args, "force", False)
251
+
252
+ action = "Checking" if check_only else "Updating"
253
+ console.print(f"\n[bold cyan]{action} skills...[/bold cyan]\n")
254
+
255
+ result = self.skills_service.check_for_updates(skill_names)
256
+
257
+ if not result.get("updates_available"):
258
+ console.print("[green]All skills are up to date[/green]\n")
259
+ return CommandResult(success=True, exit_code=0)
260
+
261
+ # Display available updates
262
+ console.print(f"[yellow]Updates available for {len(result['updates_available'])} skill(s):[/yellow]")
263
+ for update_info in result["updates_available"]:
264
+ skill_name = update_info["skill"]
265
+ current = update_info["current_version"]
266
+ latest = update_info["latest_version"]
267
+ console.print(f" • {skill_name}: {current} → {latest}")
268
+ console.print()
269
+
270
+ if check_only:
271
+ console.print("[dim]Run without --check-only to install updates[/dim]\n")
272
+ return CommandResult(success=True, exit_code=0)
273
+
274
+ # Install updates
275
+ console.print("[bold cyan]Installing updates...[/bold cyan]\n")
276
+ install_result = self.skills_service.install_updates(
277
+ result["updates_available"], force=force
278
+ )
279
+
280
+ if install_result["updated"]:
281
+ console.print(f"[green]✓ Updated {len(install_result['updated'])} skill(s)[/green]\n")
282
+
283
+ if install_result.get("errors"):
284
+ console.print(f"[red]✗ Failed to update {len(install_result['errors'])} skill(s)[/red]")
285
+ for skill, error in install_result["errors"].items():
286
+ console.print(f" • {skill}: {error}")
287
+ console.print()
288
+
289
+ exit_code = 1 if install_result.get("errors") else 0
290
+ return CommandResult(success=not install_result.get("errors"), exit_code=exit_code)
291
+
292
+ except Exception as e:
293
+ console.print(f"[red]Error updating skills: {e}[/red]")
294
+ return CommandResult(success=False, message=str(e), exit_code=1)
295
+
296
+ def _show_skill_info(self, args) -> CommandResult:
297
+ """Show detailed skill information."""
298
+ try:
299
+ skill_name = args.skill_name
300
+ show_content = getattr(args, "show_content", False)
301
+
302
+ skill_info = self._get_skill_metadata(skill_name)
303
+
304
+ if not skill_info:
305
+ console.print(f"[red]Skill '{skill_name}' not found[/red]")
306
+ return CommandResult(success=False, exit_code=1)
307
+
308
+ # Display skill info in a panel
309
+ info_text = f"[bold cyan]{skill_name}[/bold cyan]\n\n"
310
+
311
+ if desc := skill_info.get("description"):
312
+ info_text += f"{desc}\n\n"
313
+
314
+ if category := skill_info.get("category"):
315
+ info_text += f"[bold]Category:[/bold] {category}\n"
316
+
317
+ if version := skill_info.get("version"):
318
+ info_text += f"[bold]Version:[/bold] {version}\n"
319
+
320
+ if source := skill_info.get("source"):
321
+ info_text += f"[bold]Source:[/bold] {source}\n"
322
+
323
+ # Show agents using this skill
324
+ agents_using = self.skills_service.get_agents_for_skill(skill_name)
325
+ if agents_using:
326
+ info_text += f"\n[bold]Used by agents:[/bold] {', '.join(agents_using)}\n"
327
+
328
+ console.print(Panel(info_text, title="Skill Information", border_style="cyan"))
329
+
330
+ # Show content if requested
331
+ if show_content:
332
+ skill_path = self.skills_service.get_skill_path(skill_name)
333
+ skill_md = skill_path / "SKILL.md"
334
+
335
+ if skill_md.exists():
336
+ console.print("\n[bold cyan]Skill Content:[/bold cyan]\n")
337
+ content = skill_md.read_text()
338
+ console.print(Markdown(content))
339
+ else:
340
+ console.print(f"\n[yellow]SKILL.md not found at {skill_md}[/yellow]")
341
+
342
+ return CommandResult(success=True, exit_code=0)
343
+
344
+ except Exception as e:
345
+ console.print(f"[red]Error showing skill info: {e}[/red]")
346
+ return CommandResult(success=False, message=str(e), exit_code=1)
347
+
348
+ def _manage_config(self, args) -> CommandResult:
349
+ """View or edit skills configuration."""
350
+ try:
351
+ scope = getattr(args, "scope", "project")
352
+ edit = getattr(args, "edit", False)
353
+ show_path = getattr(args, "path", False)
354
+
355
+ config_path = self.skills_service.get_config_path(scope)
356
+
357
+ if show_path:
358
+ console.print(f"\n[cyan]Configuration path ({scope}):[/cyan] {config_path}\n")
359
+ return CommandResult(success=True, exit_code=0)
360
+
361
+ if not config_path.exists():
362
+ console.print(f"\n[yellow]Configuration file does not exist: {config_path}[/yellow]")
363
+ console.print("[dim]Would you like to create it? (y/n):[/dim] ", end="")
364
+
365
+ if input().lower() == 'y':
366
+ self.skills_service.create_default_config(scope)
367
+ console.print(f"[green]Created default configuration at {config_path}[/green]\n")
368
+ else:
369
+ return CommandResult(success=False, exit_code=1)
370
+
371
+ if edit:
372
+ # Open in editor
373
+ editor = os.environ.get("EDITOR", "nano")
374
+ try:
375
+ subprocess.run([editor, str(config_path)], check=True)
376
+ console.print(f"\n[green]Configuration saved to {config_path}[/green]\n")
377
+ return CommandResult(success=True, exit_code=0)
378
+ except subprocess.CalledProcessError as e:
379
+ console.print(f"[red]Error opening editor: {e}[/red]")
380
+ return CommandResult(success=False, exit_code=1)
381
+ else:
382
+ # Display config
383
+ console.print(f"\n[bold cyan]Skills Configuration ({scope}):[/bold cyan]\n")
384
+ console.print(f"[dim]Path: {config_path}[/dim]\n")
385
+
386
+ import yaml
387
+ config = yaml.safe_load(config_path.read_text())
388
+ console.print(yaml.dump(config, default_flow_style=False))
389
+
390
+ return CommandResult(success=True, exit_code=0)
391
+
392
+ except Exception as e:
393
+ console.print(f"[red]Error managing configuration: {e}[/red]")
394
+ return CommandResult(success=False, message=str(e), exit_code=1)
395
+
396
+ def _get_skill_metadata(self, skill_name: str) -> Optional[dict]:
397
+ """Get skill metadata from SKILL.md file."""
398
+ try:
399
+ skill_path = self.skills_service.get_skill_path(skill_name)
400
+ skill_md = skill_path / "SKILL.md"
401
+
402
+ if not skill_md.exists():
403
+ return None
404
+
405
+ # Parse SKILL.md metadata
406
+ content = skill_md.read_text()
407
+ metadata = self.skills_service.parse_skill_metadata(content)
408
+ return metadata
409
+
410
+ except Exception:
411
+ return None
412
+
413
+
414
+ def manage_skills(args) -> int:
415
+ """
416
+ Main entry point for skills command.
417
+
418
+ Args:
419
+ args: Parsed command-line arguments
420
+
421
+ Returns:
422
+ Exit code (0 for success, non-zero for failure)
423
+ """
424
+ command = SkillsManagementCommand()
425
+
426
+ # Validate arguments
427
+ error = command.validate_args(args)
428
+ if error:
429
+ console.print(f"[red]Error: {error}[/red]")
430
+ return 1
431
+
432
+ # Run command
433
+ result = command.run(args)
434
+ return result.exit_code
@@ -26,6 +26,7 @@ from .commands import (
26
26
  )
27
27
  from .commands.analyze_code import manage_analyze_code
28
28
  from .commands.dashboard import manage_dashboard
29
+ from .commands.skills import manage_skills
29
30
  from .commands.upgrade import upgrade
30
31
 
31
32
 
@@ -164,6 +165,7 @@ def execute_command(command: str, args) -> int:
164
165
  CLICommands.MCP.value: manage_mcp,
165
166
  CLICommands.DOCTOR.value: run_doctor,
166
167
  CLICommands.UPGRADE.value: upgrade,
168
+ CLICommands.SKILLS.value: manage_skills,
167
169
  "debug": manage_debug, # Add debug command
168
170
  "mpm-init": None, # Will be handled separately with lazy import
169
171
  }
@@ -10,9 +10,12 @@ from .agent_wizard import (
10
10
  run_interactive_agent_manager,
11
11
  run_interactive_agent_wizard,
12
12
  )
13
+ from .skills_wizard import SkillsWizard, discover_and_link_runtime_skills
13
14
 
14
15
  __all__ = [
15
16
  "AgentWizard",
17
+ "SkillsWizard",
18
+ "discover_and_link_runtime_skills",
16
19
  "run_interactive_agent_manager",
17
20
  "run_interactive_agent_wizard",
18
21
  ]