claude-mpm 5.1.8__py3-none-any.whl → 5.4.22__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.

Files changed (191) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/{PM_INSTRUCTIONS_TEACH.md → CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md} +721 -41
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +290 -34
  5. claude_mpm/agents/agent_loader.py +13 -44
  6. claude_mpm/agents/frontmatter_validator.py +68 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +138 -1
  8. claude_mpm/cli/__main__.py +4 -0
  9. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  10. claude_mpm/cli/commands/agent_state_manager.py +8 -17
  11. claude_mpm/cli/commands/agents.py +169 -31
  12. claude_mpm/cli/commands/auto_configure.py +210 -25
  13. claude_mpm/cli/commands/config.py +88 -2
  14. claude_mpm/cli/commands/configure.py +1111 -161
  15. claude_mpm/cli/commands/configure_agent_display.py +15 -6
  16. claude_mpm/cli/commands/mpm_init/core.py +160 -46
  17. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  18. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  19. claude_mpm/cli/commands/skills.py +214 -189
  20. claude_mpm/cli/commands/summarize.py +413 -0
  21. claude_mpm/cli/executor.py +11 -3
  22. claude_mpm/cli/parsers/agents_parser.py +54 -9
  23. claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
  24. claude_mpm/cli/parsers/base_parser.py +5 -0
  25. claude_mpm/cli/parsers/config_parser.py +153 -83
  26. claude_mpm/cli/parsers/skills_parser.py +3 -2
  27. claude_mpm/cli/startup.py +550 -94
  28. claude_mpm/commands/mpm-config.md +265 -0
  29. claude_mpm/commands/mpm-help.md +14 -95
  30. claude_mpm/commands/mpm-organize.md +500 -0
  31. claude_mpm/config/agent_sources.py +27 -0
  32. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  33. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  34. claude_mpm/core/framework_loader.py +4 -2
  35. claude_mpm/core/logger.py +13 -0
  36. claude_mpm/core/output_style_manager.py +173 -43
  37. claude_mpm/core/socketio_pool.py +3 -3
  38. claude_mpm/core/unified_agent_registry.py +134 -16
  39. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  40. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  41. claude_mpm/hooks/claude_hooks/hook_handler.py +6 -0
  42. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  43. claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
  44. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  45. claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
  46. claude_mpm/hooks/memory_integration_hook.py +46 -1
  47. claude_mpm/init.py +0 -19
  48. claude_mpm/models/agent_definition.py +7 -0
  49. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  50. claude_mpm/scripts/launch_monitor.py +93 -13
  51. claude_mpm/scripts/start_activity_logging.py +0 -0
  52. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  53. claude_mpm/services/agents/agent_review_service.py +280 -0
  54. claude_mpm/services/agents/deployment/agent_discovery_service.py +2 -3
  55. claude_mpm/services/agents/deployment/agent_template_builder.py +4 -2
  56. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +188 -12
  57. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +531 -55
  58. claude_mpm/services/agents/git_source_manager.py +34 -0
  59. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  60. claude_mpm/services/agents/sources/git_source_sync_service.py +8 -1
  61. claude_mpm/services/agents/toolchain_detector.py +10 -6
  62. claude_mpm/services/analysis/__init__.py +11 -1
  63. claude_mpm/services/analysis/clone_detector.py +1030 -0
  64. claude_mpm/services/command_deployment_service.py +81 -10
  65. claude_mpm/services/event_bus/config.py +3 -1
  66. claude_mpm/services/git/git_operations_service.py +93 -8
  67. claude_mpm/services/monitor/daemon.py +9 -2
  68. claude_mpm/services/monitor/daemon_manager.py +39 -3
  69. claude_mpm/services/monitor/server.py +225 -19
  70. claude_mpm/services/self_upgrade_service.py +120 -12
  71. claude_mpm/services/skills/__init__.py +3 -0
  72. claude_mpm/services/skills/git_skill_source_manager.py +32 -2
  73. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  74. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  75. claude_mpm/services/skills_deployer.py +126 -9
  76. claude_mpm/services/socketio/event_normalizer.py +15 -1
  77. claude_mpm/services/socketio/server/core.py +160 -21
  78. claude_mpm/services/version_control/git_operations.py +103 -0
  79. claude_mpm/utils/agent_filters.py +17 -44
  80. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/METADATA +47 -84
  81. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/RECORD +86 -176
  82. claude_mpm-5.4.22.dist-info/entry_points.txt +5 -0
  83. claude_mpm-5.4.22.dist-info/licenses/LICENSE +94 -0
  84. claude_mpm-5.4.22.dist-info/licenses/LICENSE-FAQ.md +153 -0
  85. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  86. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  87. claude_mpm/agents/BASE_ENGINEER.md +0 -658
  88. claude_mpm/agents/BASE_OPS.md +0 -219
  89. claude_mpm/agents/BASE_PM.md +0 -480
  90. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  91. claude_mpm/agents/BASE_QA.md +0 -167
  92. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  93. claude_mpm/agents/base_agent.json +0 -31
  94. claude_mpm/agents/base_agent_loader.py +0 -601
  95. claude_mpm/cli/commands/agents_detect.py +0 -380
  96. claude_mpm/cli/commands/agents_recommend.py +0 -309
  97. claude_mpm/cli/ticket_cli.py +0 -35
  98. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  99. claude_mpm/commands/mpm-agents-detect.md +0 -177
  100. claude_mpm/commands/mpm-agents-list.md +0 -131
  101. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  102. claude_mpm/commands/mpm-config-view.md +0 -150
  103. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  104. claude_mpm/dashboard/analysis_runner.py +0 -455
  105. claude_mpm/dashboard/index.html +0 -13
  106. claude_mpm/dashboard/open_dashboard.py +0 -66
  107. claude_mpm/dashboard/static/css/activity.css +0 -1958
  108. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  109. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  110. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  111. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  112. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  113. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  114. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  115. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  116. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  117. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  118. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  119. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  120. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  121. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  122. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  123. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  124. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  125. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  126. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  127. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  128. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  129. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  130. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  131. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  132. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  133. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  134. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  135. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  136. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  137. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  138. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  139. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  140. claude_mpm/dashboard/templates/code_simple.html +0 -153
  141. claude_mpm/dashboard/templates/index.html +0 -606
  142. claude_mpm/dashboard/test_dashboard.html +0 -372
  143. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  144. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  145. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  146. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  147. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  148. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  149. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  150. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  151. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  152. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  153. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  154. claude_mpm/scripts/mcp_server.py +0 -75
  155. claude_mpm/scripts/mcp_wrapper.py +0 -39
  156. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  157. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  158. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  159. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  160. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  161. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  162. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  163. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  164. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  165. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  166. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  167. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  168. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  169. claude_mpm/services/mcp_gateway/main.py +0 -589
  170. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  171. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  172. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  173. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  174. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  175. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  176. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  177. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  178. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  179. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  180. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  181. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  182. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  183. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  184. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  185. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  186. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  187. claude_mpm-5.1.8.dist-info/entry_points.txt +0 -10
  188. claude_mpm-5.1.8.dist-info/licenses/LICENSE +0 -21
  189. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  190. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/WHEEL +0 -0
  191. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/top_level.txt +0 -0
@@ -537,7 +537,7 @@ class SkillsManagementCommand(BaseCommand):
537
537
  toolchain = getattr(args, "toolchain", None)
538
538
  categories = getattr(args, "categories", None)
539
539
  force = getattr(args, "force", False)
540
- all_skills = getattr(args, "all", False)
540
+ all_skills = getattr(args, "all_skills", False)
541
541
 
542
542
  if collection:
543
543
  console.print(
@@ -554,17 +554,36 @@ class SkillsManagementCommand(BaseCommand):
554
554
  "[yellow]No toolchain specified. Use --toolchain to filter by language,[/yellow]"
555
555
  )
556
556
  console.print(
557
- "[yellow]or --all to deploy all available skills.[/yellow]\n"
557
+ "[yellow]or --all-skills to deploy all available skills (not just agent-referenced).[/yellow]\n"
558
558
  )
559
559
 
560
+ # Selective deployment is enabled by default (deploy only agent-referenced skills)
561
+ # Use --all-skills to disable selective mode
560
562
  result = self.skills_deployer.deploy_skills(
561
563
  collection=collection,
562
564
  toolchain=toolchain,
563
565
  categories=categories,
564
566
  force=force,
567
+ selective=not all_skills, # Disable selective mode if --all-skills is set
565
568
  )
566
569
 
567
570
  # Display results
571
+ # Show selective mode summary
572
+ if result.get("selective_mode"):
573
+ total_available = result.get("total_available", 0)
574
+ deployed_count = result["deployed_count"]
575
+ console.print(
576
+ f"[cyan]📌 Selective deployment: {deployed_count} agent-referenced skills "
577
+ f"(out of {total_available} available)[/cyan]"
578
+ )
579
+ console.print(
580
+ "[dim]Use --all-skills to deploy all available skills[/dim]\n"
581
+ )
582
+ else:
583
+ console.print(
584
+ "[cyan]📦 Deploying all available skills (selective mode disabled)[/cyan]\n"
585
+ )
586
+
568
587
  if result["deployed_count"] > 0:
569
588
  console.print(
570
589
  f"[green]✓ Deployed {result['deployed_count']} skill(s):[/green]"
@@ -953,23 +972,37 @@ class SkillsManagementCommand(BaseCommand):
953
972
  console.print(f"[red]Unexpected error: {e}[/red]")
954
973
 
955
974
  def _configure_skills(self, args) -> CommandResult:
956
- """Interactive skills configuration with checkbox selection.
975
+ """Interactive skills configuration using configuration.yaml.
957
976
 
958
977
  Provides checkbox-based selection interface matching agents configure UX:
959
- - Status column showing Installed/Available
960
- - Pre-selection for installed skills
961
- - Apply/Adjust/Cancel menu
962
- - While loop for adjustment
963
- - Simplified labels (checkbox state only)
964
-
965
- This is Option 3 (Hybrid approach): Separate command for interactive mode
966
- while keeping deploy-github for CLI automation.
978
+ - Shows current mode (user_defined vs agent_referenced)
979
+ - If agent mode: shows agent-scanned skills
980
+ - Allows switching to user_defined mode and selecting skills
981
+ - Can reset to agent mode (clears user_defined)
982
+ - Saves selections to configuration.yaml
983
+
984
+ Configuration structure:
985
+ ```yaml
986
+ skills:
987
+ agent_referenced: # Auto-populated from agent scan (read-only)
988
+ - systematic-debugging
989
+ - typescript-core
990
+ user_defined: # User override - if set, ONLY these are deployed
991
+ [] # Empty = use agent_referenced
992
+ ```
967
993
  """
968
994
  try:
995
+ from pathlib import Path
996
+
969
997
  import questionary
998
+ import yaml
970
999
  from questionary import Choice, Style
971
1000
  from rich.prompt import Prompt
972
1001
 
1002
+ from ...services.skills.selective_skill_deployer import (
1003
+ get_skills_to_deploy,
1004
+ )
1005
+
973
1006
  # Questionary style (matching agents configure)
974
1007
  QUESTIONARY_STYLE = Style(
975
1008
  [
@@ -994,203 +1027,197 @@ class SkillsManagementCommand(BaseCommand):
994
1027
  ]
995
1028
  )
996
1029
 
997
- console.print("\n[bold cyan]Interactive Skills Configuration[/bold cyan]\n")
998
- console.print(
999
- "[dim]Select skills to install/uninstall using checkboxes[/dim]"
1000
- )
1001
- console.print("[dim]● = Installed, ○ = Available[/dim]\n")
1030
+ console.print("\n[bold cyan]Skills Configuration Manager[/bold cyan]\n")
1002
1031
 
1003
- # Get deployed skills for status detection
1004
- deployed_result = self.skills_deployer.check_deployed_skills()
1005
- deployed_skills = {
1006
- skill["name"] for skill in deployed_result.get("skills", [])
1007
- }
1032
+ # Load current configuration
1033
+ project_config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
1034
+ skills_to_deploy, current_mode = get_skills_to_deploy(project_config_path)
1008
1035
 
1009
- # Get available skills from GitHub
1010
- console.print("[dim]Fetching available skills from GitHub...[/dim]\n")
1011
- available_result = self.skills_deployer.list_available_skills()
1036
+ # Display current mode and skill count
1037
+ console.print(f"[bold]Current Mode:[/bold] [cyan]{current_mode}[/cyan]")
1038
+ console.print(
1039
+ f"[bold]Active Skills:[/bold] {len(skills_to_deploy)} skills\n"
1040
+ )
1012
1041
 
1013
- if available_result.get("error"):
1014
- console.print(f"[red]Error: {available_result['error']}[/red]")
1015
- return CommandResult(
1016
- success=False, message=available_result["error"], exit_code=1
1042
+ if current_mode == "agent_referenced":
1043
+ console.print(
1044
+ "[dim]Agent mode: Skills are auto-detected from deployed agents[/dim]"
1045
+ )
1046
+ console.print(
1047
+ "[dim]Switch to user mode to manually select skills[/dim]\n"
1017
1048
  )
1049
+ else:
1050
+ console.print(
1051
+ "[dim]User mode: You've manually selected which skills to deploy[/dim]"
1052
+ )
1053
+ console.print("[dim]Reset to agent mode to use auto-detection[/dim]\n")
1054
+
1055
+ # Offer mode switching
1056
+ action_choices = [
1057
+ Choice("View current skills", value="view"),
1058
+ Choice("Switch to user mode (manual selection)", value="switch_user"),
1059
+ Choice("Reset to agent mode (auto-detection)", value="reset_agent"),
1060
+ Choice("Cancel", value="cancel"),
1061
+ ]
1062
+
1063
+ action = questionary.select(
1064
+ "What would you like to do?",
1065
+ choices=action_choices,
1066
+ style=QUESTIONARY_STYLE,
1067
+ ).ask()
1068
+
1069
+ if action == "cancel" or action is None:
1070
+ console.print("[yellow]Configuration cancelled[/yellow]")
1071
+ return CommandResult(success=True, exit_code=0)
1018
1072
 
1019
- # Flatten skills by category
1020
- all_skills = []
1021
- for category, skills in available_result.get("by_category", {}).items():
1022
- for skill in skills:
1023
- skill_info = {
1024
- "name": skill.get("name", "unknown"),
1025
- "category": category,
1026
- "is_deployed": skill.get("name", "unknown") in deployed_skills,
1027
- }
1028
- all_skills.append(skill_info)
1029
-
1030
- # Sort by deployed status (deployed first), then by name
1031
- all_skills.sort(key=lambda s: (not s["is_deployed"], s["name"]))
1032
-
1033
- # Build checkbox choices with pre-selection
1034
- # Loop to allow adjusting selection
1035
- while True:
1036
- skill_choices = []
1037
- skill_map = {} # For lookup after selection
1038
-
1039
- for skill in all_skills:
1040
- skill_name = skill["name"]
1041
- category = skill["category"]
1042
- is_deployed = skill["is_deployed"]
1043
-
1044
- # Simple format: "skill-name (category)"
1045
- # Checkbox state (checked/unchecked) indicates installed status
1046
- choice_text = f"{skill_name} ({category})"
1047
-
1048
- # Pre-select if deployed
1049
- choice = Choice(
1050
- title=choice_text, value=skill_name, checked=is_deployed
1051
- )
1073
+ if action == "view":
1074
+ # Display current skills
1075
+ console.print("\n[bold]Current Skills:[/bold]\n")
1076
+ for skill in sorted(skills_to_deploy):
1077
+ console.print(f" • {skill}")
1078
+ console.print()
1079
+ Prompt.ask("\nPress Enter to continue")
1080
+ return CommandResult(success=True, exit_code=0)
1052
1081
 
1053
- skill_choices.append(choice)
1054
- skill_map[skill_name] = skill
1082
+ if action == "reset_agent":
1083
+ # Reset to agent mode by clearing user_defined
1084
+ with open(project_config_path, encoding="utf-8") as f:
1085
+ config = yaml.safe_load(f) or {}
1055
1086
 
1056
- # Display checkbox selection
1057
- selected_skills = questionary.checkbox(
1058
- "Select skills (Space to toggle, Enter to confirm):",
1059
- choices=skill_choices,
1060
- style=QUESTIONARY_STYLE,
1061
- ).ask()
1087
+ if "skills" not in config:
1088
+ config["skills"] = {}
1062
1089
 
1063
- if selected_skills is None:
1064
- # User cancelled (Ctrl+C)
1065
- console.print("[yellow]Skills configuration cancelled[/yellow]")
1066
- return CommandResult(success=True, exit_code=0)
1090
+ config["skills"]["user_defined"] = []
1067
1091
 
1068
- # Determine changes
1069
- to_install = []
1070
- to_remove = []
1092
+ with open(project_config_path, "w", encoding="utf-8") as f:
1093
+ yaml.dump(config, f, default_flow_style=False, sort_keys=False)
1071
1094
 
1072
- for skill in all_skills:
1073
- skill_name = skill["name"]
1074
- is_deployed = skill["is_deployed"]
1075
- is_selected = skill_name in selected_skills
1095
+ console.print(
1096
+ "\n[green]✓ Reset to agent mode - skills will be auto-detected from agents[/green]\n"
1097
+ )
1098
+ Prompt.ask("\nPress Enter to continue")
1099
+ return CommandResult(success=True, exit_code=0)
1076
1100
 
1077
- if is_selected and not is_deployed:
1078
- to_install.append(skill_name)
1079
- elif not is_selected and is_deployed:
1080
- to_remove.append(skill_name)
1101
+ # Switch to user mode - manual skill selection
1102
+ if action == "switch_user":
1103
+ console.print(
1104
+ "\n[bold cyan]Switching to User Mode - Manual Skill Selection[/bold cyan]\n"
1105
+ )
1106
+ console.print("[dim]Fetching available skills from GitHub...[/dim]\n")
1081
1107
 
1082
- # Show summary of changes
1083
- console.print("\n[bold]Changes to apply:[/bold]")
1084
- if to_install:
1085
- console.print(
1086
- f"\n[green]✓ Install ({len(to_install)} skills):[/green]"
1087
- )
1088
- for skill in to_install:
1089
- console.print(f" • {skill}")
1108
+ # Get available skills
1109
+ available_result = self.skills_deployer.list_available_skills()
1090
1110
 
1091
- if to_remove:
1092
- console.print(
1093
- f"\n[yellow]✗ Remove ({len(to_remove)} skills):[/yellow]"
1111
+ if available_result.get("error"):
1112
+ console.print(f"[red]Error: {available_result['error']}[/red]")
1113
+ return CommandResult(
1114
+ success=False, message=available_result["error"], exit_code=1
1094
1115
  )
1095
- for skill in to_remove:
1096
- console.print(f" • {skill}")
1097
1116
 
1098
- if not to_install and not to_remove:
1099
- console.print(
1100
- "\n[dim]No changes (selection matches current deployment)[/dim]"
1101
- )
1117
+ # Flatten skills by category
1118
+ all_skills = []
1119
+ for category, skills in available_result.get("by_category", {}).items():
1120
+ for skill in skills:
1121
+ skill_name = skill.get("name", "unknown")
1122
+ is_currently_selected = skill_name in skills_to_deploy
1123
+ skill_info = {
1124
+ "name": skill_name,
1125
+ "category": category,
1126
+ "is_selected": is_currently_selected,
1127
+ }
1128
+ all_skills.append(skill_info)
1129
+
1130
+ # Sort by selection status (selected first), then by name
1131
+ all_skills.sort(key=lambda s: (not s["is_selected"], s["name"]))
1132
+
1133
+ # Build checkbox choices
1134
+ while True:
1135
+ skill_choices = []
1136
+
1137
+ for skill in all_skills:
1138
+ skill_name = skill["name"]
1139
+ category = skill["category"]
1140
+ is_selected = skill["is_selected"]
1141
+
1142
+ # Format: "skill-name (category)"
1143
+ choice_text = f"{skill_name} ({category})"
1144
+
1145
+ # Pre-select if currently in skills_to_deploy
1146
+ choice = Choice(
1147
+ title=choice_text, value=skill_name, checked=is_selected
1148
+ )
1102
1149
 
1103
- console.print()
1150
+ skill_choices.append(choice)
1151
+
1152
+ # Display checkbox selection
1153
+ selected_skills = questionary.checkbox(
1154
+ "Select skills (Space to toggle, Enter to confirm):",
1155
+ choices=skill_choices,
1156
+ style=QUESTIONARY_STYLE,
1157
+ ).ask()
1158
+
1159
+ if selected_skills is None:
1160
+ # User cancelled (Ctrl+C)
1161
+ console.print("[yellow]Skills configuration cancelled[/yellow]")
1162
+ return CommandResult(success=True, exit_code=0)
1163
+
1164
+ # Show summary
1165
+ console.print("\n[bold]Selected Skills:[/bold]")
1166
+ console.print(f" {len(selected_skills)} skills selected\n")
1167
+
1168
+ if selected_skills:
1169
+ for skill in sorted(selected_skills):
1170
+ console.print(f" • {skill}")
1171
+ console.print()
1172
+
1173
+ # Ask user to confirm, adjust, or cancel
1174
+ confirm_action = questionary.select(
1175
+ "\nWhat would you like to do?",
1176
+ choices=[
1177
+ Choice("Save to configuration", value="apply"),
1178
+ Choice("Adjust selection", value="adjust"),
1179
+ Choice("Cancel", value="cancel"),
1180
+ ],
1181
+ default="apply",
1182
+ style=QUESTIONARY_STYLE,
1183
+ ).ask()
1184
+
1185
+ if confirm_action == "cancel":
1186
+ console.print("[yellow]Configuration cancelled[/yellow]")
1187
+ Prompt.ask("\nPress Enter to continue")
1188
+ return CommandResult(success=True, exit_code=0)
1189
+
1190
+ if confirm_action == "adjust":
1191
+ # Update selection state and loop back
1192
+ for skill in all_skills:
1193
+ skill["is_selected"] = skill["name"] in selected_skills
1194
+ console.print("\n[dim]Adjusting selection...[/dim]\n")
1195
+ continue
1196
+
1197
+ # Save to configuration.yaml
1198
+ with open(project_config_path, encoding="utf-8") as f:
1199
+ config = yaml.safe_load(f) or {}
1200
+
1201
+ if "skills" not in config:
1202
+ config["skills"] = {}
1203
+
1204
+ config["skills"]["user_defined"] = sorted(selected_skills)
1205
+
1206
+ with open(project_config_path, "w", encoding="utf-8") as f:
1207
+ yaml.dump(config, f, default_flow_style=False, sort_keys=False)
1104
1208
 
1105
- # Ask user to confirm, adjust, or cancel
1106
- action = questionary.select(
1107
- "\nWhat would you like to do?",
1108
- choices=[
1109
- Choice("Apply these changes", value="apply"),
1110
- Choice("Adjust selection", value="adjust"),
1111
- Choice("Cancel", value="cancel"),
1112
- ],
1113
- default="apply",
1114
- style=QUESTIONARY_STYLE,
1115
- ).ask()
1116
-
1117
- if action == "cancel":
1118
- console.print("[yellow]Changes cancelled[/yellow]")
1119
- Prompt.ask("\nPress Enter to continue")
1120
- return CommandResult(success=True, exit_code=0)
1121
- if action == "adjust":
1122
- # Loop back to skill selection
1123
- console.print("\n[dim]Adjusting selection...[/dim]\n")
1124
- continue
1125
-
1126
- # Apply changes
1127
- success = True
1128
- errors = []
1129
-
1130
- # Install skills
1131
- if to_install:
1132
- console.print("\n[bold cyan]Installing skills...[/bold cyan]\n")
1133
- for skill_name in to_install:
1134
- try:
1135
- # Deploy single skill
1136
- result = self.skills_deployer.deploy_skills(
1137
- skill_names=[skill_name], force=False
1138
- )
1139
-
1140
- if result.get("errors"):
1141
- errors.extend(result["errors"])
1142
- success = False
1143
- else:
1144
- console.print(
1145
- f"[green]✓ Installed: {skill_name}[/green]"
1146
- )
1147
- except Exception as e:
1148
- errors.append(f"Failed to install {skill_name}: {e}")
1149
- success = False
1150
-
1151
- # Remove skills
1152
- if to_remove:
1153
- console.print("\n[bold yellow]Removing skills...[/bold yellow]\n")
1154
- for skill_name in to_remove:
1155
- try:
1156
- # Remove single skill
1157
- result = self.skills_deployer.remove_skills(
1158
- skill_names=[skill_name]
1159
- )
1160
-
1161
- if result.get("errors"):
1162
- errors.extend(result["errors"])
1163
- success = False
1164
- else:
1165
- console.print(
1166
- f"[yellow]✗ Removed: {skill_name}[/yellow]"
1167
- )
1168
- except Exception as e:
1169
- errors.append(f"Failed to remove {skill_name}: {e}")
1170
- success = False
1171
-
1172
- # Show errors if any
1173
- if errors:
1174
- console.print(f"\n[red]✗ {len(errors)} error(s):[/red]")
1175
- for error in errors:
1176
- console.print(f" • {error}")
1177
-
1178
- # Show restart instructions
1179
- if success and (to_install or to_remove):
1180
1209
  console.print(
1181
- "\n[bold green]✓ Changes applied successfully![/bold green]"
1210
+ f"\n[green]✓ Saved {len(selected_skills)} skills to user_defined mode[/green]"
1182
1211
  )
1183
- console.print("\n[yellow]⚠️ Important:[/yellow]")
1184
- console.print(" Restart Claude Code for changes to take effect")
1185
-
1186
- console.print()
1187
- Prompt.ask("\nPress Enter to continue")
1212
+ console.print(
1213
+ "[yellow]⚠️ Important:[/yellow] Run [cyan]claude-mpm init[/cyan] to deploy these skills\n"
1214
+ )
1215
+ Prompt.ask("\nPress Enter to continue")
1188
1216
 
1189
- # Exit the loop after successful execution
1190
- break
1217
+ # Exit the loop after successful save
1218
+ break
1191
1219
 
1192
- exit_code = 0 if success else 1
1193
- return CommandResult(success=success, exit_code=exit_code)
1220
+ return CommandResult(success=True, exit_code=0)
1194
1221
 
1195
1222
  except Exception as e:
1196
1223
  console.print(f"[red]Error in skills configuration: {e}[/red]")
@@ -1199,8 +1226,6 @@ class SkillsManagementCommand(BaseCommand):
1199
1226
  console.print(f"[dim]{traceback.format_exc()}[/dim]")
1200
1227
  return CommandResult(success=False, message=str(e), exit_code=1)
1201
1228
 
1202
- return CommandResult(success=False, message=str(e), exit_code=1)
1203
-
1204
1229
 
1205
1230
  def manage_skills(args) -> int:
1206
1231
  """