claude-mpm 5.1.9__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 (176) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +1 -1
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +290 -34
  5. claude_mpm/agents/agent_loader.py +13 -44
  6. claude_mpm/agents/templates/circuit-breakers.md +138 -1
  7. claude_mpm/cli/__main__.py +4 -0
  8. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  9. claude_mpm/cli/commands/agent_state_manager.py +8 -17
  10. claude_mpm/cli/commands/agents.py +0 -31
  11. claude_mpm/cli/commands/auto_configure.py +210 -25
  12. claude_mpm/cli/commands/config.py +88 -2
  13. claude_mpm/cli/commands/configure.py +1097 -158
  14. claude_mpm/cli/commands/configure_agent_display.py +15 -6
  15. claude_mpm/cli/commands/mpm_init/core.py +160 -46
  16. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  17. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  18. claude_mpm/cli/commands/skills.py +214 -189
  19. claude_mpm/cli/commands/summarize.py +413 -0
  20. claude_mpm/cli/executor.py +11 -3
  21. claude_mpm/cli/parsers/agents_parser.py +0 -9
  22. claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
  23. claude_mpm/cli/parsers/base_parser.py +5 -0
  24. claude_mpm/cli/parsers/config_parser.py +153 -83
  25. claude_mpm/cli/parsers/skills_parser.py +3 -2
  26. claude_mpm/cli/startup.py +550 -94
  27. claude_mpm/commands/mpm-config.md +265 -0
  28. claude_mpm/commands/mpm-help.md +14 -95
  29. claude_mpm/commands/mpm-organize.md +500 -0
  30. claude_mpm/config/agent_sources.py +27 -0
  31. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  32. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  33. claude_mpm/core/framework_loader.py +4 -2
  34. claude_mpm/core/logger.py +13 -0
  35. claude_mpm/core/socketio_pool.py +3 -3
  36. claude_mpm/core/unified_agent_registry.py +5 -15
  37. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  38. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  39. claude_mpm/hooks/claude_hooks/hook_handler.py +6 -0
  40. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  41. claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
  42. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  43. claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
  44. claude_mpm/hooks/memory_integration_hook.py +46 -1
  45. claude_mpm/init.py +0 -19
  46. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  47. claude_mpm/scripts/launch_monitor.py +93 -13
  48. claude_mpm/scripts/start_activity_logging.py +0 -0
  49. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  50. claude_mpm/services/agents/agent_review_service.py +280 -0
  51. claude_mpm/services/agents/deployment/agent_discovery_service.py +2 -3
  52. claude_mpm/services/agents/deployment/agent_template_builder.py +4 -2
  53. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +78 -9
  54. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +335 -53
  55. claude_mpm/services/agents/git_source_manager.py +34 -0
  56. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  57. claude_mpm/services/agents/sources/git_source_sync_service.py +8 -1
  58. claude_mpm/services/agents/toolchain_detector.py +10 -6
  59. claude_mpm/services/analysis/__init__.py +11 -1
  60. claude_mpm/services/analysis/clone_detector.py +1030 -0
  61. claude_mpm/services/command_deployment_service.py +81 -10
  62. claude_mpm/services/event_bus/config.py +3 -1
  63. claude_mpm/services/git/git_operations_service.py +93 -8
  64. claude_mpm/services/monitor/daemon.py +9 -2
  65. claude_mpm/services/monitor/daemon_manager.py +39 -3
  66. claude_mpm/services/monitor/server.py +225 -19
  67. claude_mpm/services/self_upgrade_service.py +120 -12
  68. claude_mpm/services/skills/__init__.py +3 -0
  69. claude_mpm/services/skills/git_skill_source_manager.py +32 -2
  70. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  71. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  72. claude_mpm/services/skills_deployer.py +126 -9
  73. claude_mpm/services/socketio/event_normalizer.py +15 -1
  74. claude_mpm/services/socketio/server/core.py +160 -21
  75. claude_mpm/services/version_control/git_operations.py +103 -0
  76. claude_mpm/utils/agent_filters.py +17 -44
  77. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.22.dist-info}/METADATA +47 -84
  78. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.22.dist-info}/RECORD +82 -161
  79. claude_mpm-5.4.22.dist-info/entry_points.txt +5 -0
  80. claude_mpm-5.4.22.dist-info/licenses/LICENSE +94 -0
  81. claude_mpm-5.4.22.dist-info/licenses/LICENSE-FAQ.md +153 -0
  82. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  83. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  84. claude_mpm/agents/BASE_ENGINEER.md +0 -658
  85. claude_mpm/agents/BASE_OPS.md +0 -219
  86. claude_mpm/agents/BASE_PM.md +0 -480
  87. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  88. claude_mpm/agents/BASE_QA.md +0 -167
  89. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  90. claude_mpm/agents/base_agent.json +0 -31
  91. claude_mpm/agents/base_agent_loader.py +0 -601
  92. claude_mpm/cli/commands/agents_detect.py +0 -380
  93. claude_mpm/cli/commands/agents_recommend.py +0 -309
  94. claude_mpm/cli/ticket_cli.py +0 -35
  95. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  96. claude_mpm/commands/mpm-agents-detect.md +0 -177
  97. claude_mpm/commands/mpm-agents-list.md +0 -131
  98. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  99. claude_mpm/commands/mpm-config-view.md +0 -150
  100. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  101. claude_mpm/dashboard/analysis_runner.py +0 -455
  102. claude_mpm/dashboard/index.html +0 -13
  103. claude_mpm/dashboard/open_dashboard.py +0 -66
  104. claude_mpm/dashboard/static/css/activity.css +0 -1958
  105. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  106. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  107. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  108. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  109. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  110. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  111. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  112. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  113. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  114. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  115. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  116. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  117. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  118. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  119. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  120. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  121. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  122. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  123. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  124. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  125. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  126. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  127. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  128. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  129. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  130. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  131. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  132. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  133. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  134. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  135. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  136. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  137. claude_mpm/dashboard/templates/code_simple.html +0 -153
  138. claude_mpm/dashboard/templates/index.html +0 -606
  139. claude_mpm/dashboard/test_dashboard.html +0 -372
  140. claude_mpm/scripts/mcp_server.py +0 -75
  141. claude_mpm/scripts/mcp_wrapper.py +0 -39
  142. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  143. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  144. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  145. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  146. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  147. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  148. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  149. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  150. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  151. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  152. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  153. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  154. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  155. claude_mpm/services/mcp_gateway/main.py +0 -589
  156. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  157. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  158. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  159. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  160. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  161. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  162. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  163. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  164. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  165. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  166. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  167. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  168. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  169. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  170. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  171. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  172. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  173. claude_mpm-5.1.9.dist-info/entry_points.txt +0 -10
  174. claude_mpm-5.1.9.dist-info/licenses/LICENSE +0 -21
  175. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.22.dist-info}/WHEEL +0 -0
  176. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.22.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,6 @@ from typing import Optional
21
21
 
22
22
  try:
23
23
  from rich.console import Console
24
- from rich.panel import Panel
25
24
  from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
26
25
  from rich.table import Table
27
26
 
@@ -267,6 +266,15 @@ class AutoConfigureCommand(BaseCommand):
267
266
  project_path, min_confidence
268
267
  )
269
268
 
269
+ # Review existing project agents
270
+ agent_review_results = None
271
+ if configure_agents:
272
+ if self.console and not json_output:
273
+ with self.console.status("[bold green]Reviewing existing agents..."):
274
+ agent_review_results = self._review_project_agents(agent_preview)
275
+ else:
276
+ agent_review_results = self._review_project_agents(agent_preview)
277
+
270
278
  # Get skills recommendations
271
279
  skills_recommendations = None
272
280
  if configure_skills:
@@ -283,9 +291,14 @@ class AutoConfigureCommand(BaseCommand):
283
291
  skills_recommendations,
284
292
  configure_agents,
285
293
  configure_skills,
294
+ agent_review_results,
286
295
  )
287
296
  return self._display_preview(
288
- agent_preview, skills_recommendations, configure_agents, configure_skills
297
+ agent_preview,
298
+ skills_recommendations,
299
+ configure_agents,
300
+ configure_skills,
301
+ agent_review_results,
289
302
  )
290
303
 
291
304
  def _run_full_configuration(
@@ -311,6 +324,15 @@ class AutoConfigureCommand(BaseCommand):
311
324
  project_path, min_confidence
312
325
  )
313
326
 
327
+ # Review existing project agents
328
+ agent_review_results = None
329
+ if configure_agents:
330
+ if self.console and not json_output:
331
+ with self.console.status("[bold green]Reviewing existing agents..."):
332
+ agent_review_results = self._review_project_agents(agent_preview)
333
+ else:
334
+ agent_review_results = self._review_project_agents(agent_preview)
335
+
314
336
  # Get skills recommendations
315
337
  skills_recommendations = None
316
338
  if configure_skills:
@@ -327,6 +349,7 @@ class AutoConfigureCommand(BaseCommand):
327
349
  skills_recommendations,
328
350
  configure_agents,
329
351
  configure_skills,
352
+ agent_review_results,
330
353
  )
331
354
 
332
355
  # Ask for confirmation (unless skipped)
@@ -336,6 +359,7 @@ class AutoConfigureCommand(BaseCommand):
336
359
  skills_recommendations,
337
360
  configure_agents,
338
361
  configure_skills,
362
+ agent_review_results,
339
363
  ):
340
364
  if self.console:
341
365
  self.console.print("\n❌ Operation cancelled by user")
@@ -343,6 +367,17 @@ class AutoConfigureCommand(BaseCommand):
343
367
  print("\nOperation cancelled by user")
344
368
  return CommandResult.error_result("Operation cancelled", exit_code=0)
345
369
 
370
+ # Archive unused agents (before deploying new ones)
371
+ archive_result = None
372
+ if configure_agents and agent_review_results:
373
+ agents_to_archive = agent_review_results.get("unused", [])
374
+ if agents_to_archive:
375
+ if self.console and not json_output:
376
+ self.console.print(
377
+ "\n[bold yellow]Archiving unused agents...[/bold yellow]\n"
378
+ )
379
+ archive_result = self._archive_agents(agents_to_archive)
380
+
346
381
  # Execute agent configuration
347
382
  agent_result = None
348
383
  if configure_agents and agent_preview:
@@ -368,8 +403,8 @@ class AutoConfigureCommand(BaseCommand):
368
403
 
369
404
  # Output results
370
405
  if json_output:
371
- return self._output_result_json(agent_result, skills_result)
372
- return self._display_result(agent_result, skills_result)
406
+ return self._output_result_json(agent_result, skills_result, archive_result)
407
+ return self._display_result(agent_result, skills_result, archive_result)
373
408
 
374
409
  def _display_preview(
375
410
  self,
@@ -377,6 +412,7 @@ class AutoConfigureCommand(BaseCommand):
377
412
  skills_recommendations=None,
378
413
  configure_agents=True,
379
414
  configure_skills=True,
415
+ agent_review_results=None,
380
416
  ) -> CommandResult:
381
417
  """Display configuration preview with Rich formatting."""
382
418
  if not self.console:
@@ -386,6 +422,7 @@ class AutoConfigureCommand(BaseCommand):
386
422
  skills_recommendations,
387
423
  configure_agents,
388
424
  configure_skills,
425
+ agent_review_results,
389
426
  )
390
427
 
391
428
  # Only show toolchain and agents if configuring agents
@@ -457,6 +494,10 @@ class AutoConfigureCommand(BaseCommand):
457
494
  f" {severity_icon} {issue.message}", style="yellow"
458
495
  )
459
496
 
497
+ # Display agent review results
498
+ if configure_agents and agent_review_results:
499
+ self._display_agent_review(agent_review_results)
500
+
460
501
  # Display recommended skills
461
502
  if configure_skills and skills_recommendations:
462
503
  self.console.print("\n🎯 Recommended Skills:", style="bold blue")
@@ -471,6 +512,7 @@ class AutoConfigureCommand(BaseCommand):
471
512
  skills_recommendations=None,
472
513
  configure_agents=True,
473
514
  configure_skills=True,
515
+ agent_review_results=None,
474
516
  ) -> CommandResult:
475
517
  """Display preview in plain text (fallback when Rich not available)."""
476
518
  if configure_agents and agent_preview:
@@ -517,6 +559,7 @@ class AutoConfigureCommand(BaseCommand):
517
559
  skills_recommendations=None,
518
560
  configure_agents=True,
519
561
  configure_skills=True,
562
+ agent_review_results=None,
520
563
  ) -> bool:
521
564
  """Ask user to confirm deployment."""
522
565
  has_agents = (
@@ -566,11 +609,16 @@ class AutoConfigureCommand(BaseCommand):
566
609
  return False
567
610
 
568
611
  def _display_result(
569
- self, agent_result: Optional = None, skills_result: Optional[dict] = None
612
+ self,
613
+ agent_result: Optional = None,
614
+ skills_result: Optional[dict] = None,
615
+ archive_result: Optional[dict] = None,
570
616
  ) -> CommandResult:
571
617
  """Display configuration result."""
572
618
  if not self.console:
573
- return self._display_result_plain(agent_result, skills_result)
619
+ return self._display_result_plain(
620
+ agent_result, skills_result, archive_result
621
+ )
574
622
 
575
623
  # Determine overall success
576
624
  agent_success = (
@@ -581,26 +629,11 @@ class AutoConfigureCommand(BaseCommand):
581
629
  skills_success = not skills_result or (
582
630
  skills_result and not skills_result.get("errors")
583
631
  )
584
- overall_success = agent_success and skills_success
632
+ archive_success = not archive_result or not archive_result.get("errors")
633
+ overall_success = agent_success and skills_success and archive_success
585
634
 
586
635
  # Display summary
587
636
  if overall_success:
588
- # Build summary message
589
- deployed_items = []
590
- if agent_result and agent_result.deployed_agents:
591
- deployed_items.append(f"{len(agent_result.deployed_agents)} agent(s)")
592
- if skills_result and skills_result.get("deployed"):
593
- deployed_items.append(f"{len(skills_result['deployed'])} skill(s)")
594
-
595
- panel_text = "✅ Auto-configuration completed successfully!\n\n"
596
- if deployed_items:
597
- panel_text += f"Deployed {' and '.join(deployed_items)}"
598
- else:
599
- panel_text += "No deployments needed"
600
-
601
- panel = Panel(panel_text, title="Success", border_style="green")
602
- self.console.print(panel)
603
-
604
637
  # Show deployed agents
605
638
  if agent_result and agent_result.deployed_agents:
606
639
  self.console.print("\n📦 Deployed Agents:", style="bold green")
@@ -613,6 +646,15 @@ class AutoConfigureCommand(BaseCommand):
613
646
  for skill in skills_result["deployed"]:
614
647
  self.console.print(f" ✓ {skill}")
615
648
 
649
+ # Show archived agents
650
+ if archive_result and archive_result.get("archived"):
651
+ self.console.print("\n📁 Archived Agents:", style="bold yellow")
652
+ for archived in archive_result["archived"]:
653
+ self.console.print(f" → {archived['name']}")
654
+
655
+ # Show restart notification
656
+ self._show_restart_notification(agent_result, skills_result, archive_result)
657
+
616
658
  return CommandResult.success_result()
617
659
 
618
660
  # Partial or complete failure
@@ -654,7 +696,10 @@ class AutoConfigureCommand(BaseCommand):
654
696
  )
655
697
 
656
698
  def _display_result_plain(
657
- self, agent_result: Optional = None, skills_result: Optional[dict] = None
699
+ self,
700
+ agent_result: Optional = None,
701
+ skills_result: Optional[dict] = None,
702
+ archive_result: Optional[dict] = None,
658
703
  ) -> CommandResult:
659
704
  """Display result in plain text (fallback)."""
660
705
  # Determine overall success
@@ -725,6 +770,7 @@ class AutoConfigureCommand(BaseCommand):
725
770
  skills_recommendations=None,
726
771
  configure_agents=True,
727
772
  configure_skills=True,
773
+ agent_review_results=None,
728
774
  ) -> CommandResult:
729
775
  """Output preview as JSON."""
730
776
  output = {}
@@ -790,7 +836,10 @@ class AutoConfigureCommand(BaseCommand):
790
836
  return CommandResult.success_result(data=output)
791
837
 
792
838
  def _output_result_json(
793
- self, agent_result: Optional = None, skills_result: Optional[dict] = None
839
+ self,
840
+ agent_result: Optional = None,
841
+ skills_result: Optional[dict] = None,
842
+ archive_result: Optional[dict] = None,
794
843
  ) -> CommandResult:
795
844
  """Output result as JSON."""
796
845
  output = {}
@@ -866,3 +915,139 @@ class AutoConfigureCommand(BaseCommand):
866
915
  except Exception as e:
867
916
  self.logger.error(f"Failed to deploy skills: {e}")
868
917
  return {"deployed": [], "errors": [str(e)]}
918
+
919
+ def _review_project_agents(self, agent_preview) -> Optional[dict]:
920
+ """Review existing project agents and categorize them.
921
+
922
+ Args:
923
+ agent_preview: Agent preview result with recommendations
924
+
925
+ Returns:
926
+ Dictionary with categorized agents or None if no preview
927
+ """
928
+ if not agent_preview:
929
+ return None
930
+
931
+ from ...services.agents.agent_review_service import AgentReviewService
932
+ from ...services.agents.deployment.remote_agent_discovery_service import (
933
+ RemoteAgentDiscoveryService,
934
+ )
935
+
936
+ # Get managed agents from cache
937
+ remote_agents_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
938
+ if not remote_agents_dir.exists():
939
+ self.logger.debug("No remote agents cache found")
940
+ return None
941
+
942
+ # Discover managed agents
943
+ discovery_service = RemoteAgentDiscoveryService(remote_agents_dir)
944
+ managed_agents = discovery_service.discover_remote_agents()
945
+
946
+ if not managed_agents:
947
+ self.logger.debug("No managed agents found in cache")
948
+ return None
949
+
950
+ # Get recommended agent IDs
951
+ recommended_ids = set()
952
+ if agent_preview.recommendations:
953
+ recommended_ids = {rec.agent_id for rec in agent_preview.recommendations}
954
+
955
+ # Review project agents
956
+ project_agents_dir = Path.cwd() / ".claude" / "agents"
957
+ review_service = AgentReviewService()
958
+ return review_service.review_project_agents(
959
+ project_agents_dir, managed_agents, recommended_ids
960
+ )
961
+
962
+ def _archive_agents(self, agents_to_archive: list[dict]) -> dict:
963
+ """Archive unused agents by moving them to .claude/agents/unused/.
964
+
965
+ Args:
966
+ agents_to_archive: List of agent dicts to archive
967
+
968
+ Returns:
969
+ Dictionary with archival results
970
+ """
971
+ from ...services.agents.agent_review_service import AgentReviewService
972
+
973
+ project_agents_dir = Path.cwd() / ".claude" / "agents"
974
+ review_service = AgentReviewService()
975
+ return review_service.archive_agents(agents_to_archive, project_agents_dir)
976
+
977
+ def _display_agent_review(self, review_results: dict) -> None:
978
+ """Display agent review results in the preview.
979
+
980
+ Args:
981
+ review_results: Dictionary with categorized agents
982
+ """
983
+ if not self.console:
984
+ return
985
+
986
+ # Count agents to archive
987
+ unused_count = len(review_results.get("unused", []))
988
+ outdated_count = len(review_results.get("outdated", []))
989
+ custom_count = len(review_results.get("custom", []))
990
+
991
+ if unused_count > 0 or outdated_count > 0 or custom_count > 0:
992
+ self.console.print("\n📋 Existing Agents Review:", style="bold blue")
993
+
994
+ # Show custom agents (will be preserved)
995
+ if custom_count > 0:
996
+ self.console.print(
997
+ "\n [green]Custom agents (will be preserved):[/green]"
998
+ )
999
+ for agent in review_results["custom"]:
1000
+ self.console.print(f" ✓ {agent['name']} (v{agent['version']})")
1001
+
1002
+ # Show agents to be archived
1003
+ if unused_count > 0:
1004
+ self.console.print(
1005
+ "\n [yellow]Agents to archive (not needed for this toolchain):[/yellow]"
1006
+ )
1007
+ for agent in review_results["unused"]:
1008
+ reason = (
1009
+ f"outdated (v{agent['current_version']} → v{agent['available_version']})"
1010
+ if "current_version" in agent
1011
+ else "not recommended"
1012
+ )
1013
+ self.console.print(f" → {agent['name']} ({reason})")
1014
+ self.console.print(
1015
+ " [dim]Will be moved to .claude/agents/unused/[/dim]"
1016
+ )
1017
+
1018
+ def _show_restart_notification(
1019
+ self, agent_result=None, skills_result=None, archive_result=None
1020
+ ) -> None:
1021
+ """Show restart notification after configuration is complete.
1022
+
1023
+ Args:
1024
+ agent_result: Agent deployment results
1025
+ skills_result: Skills deployment results
1026
+ archive_result: Agent archival results
1027
+ """
1028
+ if not self.console:
1029
+ return
1030
+
1031
+ # Build summary of changes
1032
+ changes = []
1033
+ if agent_result and agent_result.deployed_agents:
1034
+ changes.append(f"Deployed {len(agent_result.deployed_agents)} agent(s)")
1035
+ if skills_result and skills_result.get("deployed"):
1036
+ changes.append(f"Deployed {len(skills_result['deployed'])} skill(s)")
1037
+ if archive_result and archive_result.get("archived"):
1038
+ changes.append(
1039
+ f"Archived {len(archive_result['archived'])} unused agent(s) to .claude/agents/unused/"
1040
+ )
1041
+
1042
+ if changes:
1043
+ self.console.print("\n" + "=" * 70)
1044
+ self.console.print("✅ [bold green]Configuration complete![/bold green]")
1045
+ self.console.print(
1046
+ "\n🔄 [bold yellow]Please restart Claude Code to apply changes:[/bold yellow]"
1047
+ )
1048
+ self.console.print(" - Quit Claude Code completely")
1049
+ self.console.print(" - Relaunch Claude Code")
1050
+ self.console.print("\n[bold]Changes applied:[/bold]")
1051
+ for change in changes:
1052
+ self.console.print(f" • {change}")
1053
+ self.console.print("=" * 70 + "\n")
@@ -68,10 +68,12 @@ class ConfigCommand(BaseCommand):
68
68
 
69
69
  def validate_args(self, args) -> str:
70
70
  """Validate command arguments."""
71
+ # If no config_command specified, default to 'auto' (preview mode)
71
72
  if not hasattr(args, "config_command") or not args.config_command:
72
- return "No config command specified"
73
+ args.config_command = "auto"
74
+ args.preview = True # Default to preview when no args
73
75
 
74
- valid_commands = ["validate", "view", "status"]
76
+ valid_commands = ["validate", "view", "status", "auto", "gitignore"]
75
77
  if args.config_command not in valid_commands:
76
78
  return f"Unknown config command: {args.config_command}. Valid commands: {', '.join(valid_commands)}"
77
79
 
@@ -85,6 +87,11 @@ class ConfigCommand(BaseCommand):
85
87
  return self._view_config(args)
86
88
  if args.config_command == "status":
87
89
  return self._show_config_status(args)
90
+ if args.config_command == "gitignore":
91
+ self._show_gitignore_recommendations()
92
+ return CommandResult.success_result("Gitignore recommendations displayed")
93
+ if args.config_command == "auto":
94
+ return self._auto_configure(args)
88
95
  return CommandResult.error_result(
89
96
  f"Unknown config command: {args.config_command}"
90
97
  )
@@ -450,6 +457,85 @@ class ConfigCommand(BaseCommand):
450
457
 
451
458
  return flattened
452
459
 
460
+ def _show_gitignore_recommendations(self) -> None:
461
+ """Show recommended .gitignore patterns for Claude MPM projects.
462
+
463
+ This displays recommended gitignore patterns without making any changes
464
+ to the user's .gitignore file. Users can choose to apply these manually.
465
+ """
466
+ console.print(
467
+ "\n[bold cyan]Recommended .gitignore Patterns for Claude MPM[/bold cyan]\n"
468
+ )
469
+
470
+ console.print("[bold]Track agent memories, ignore runtime data:[/bold]")
471
+ console.print("[dim]# Add this to your .gitignore:[/dim]\n")
472
+
473
+ # The recommended gitignore block
474
+ recommended_patterns = """# Claude MPM - Track memories, ignore runtime data
475
+ .claude-mpm/*
476
+ !.claude-mpm/memories/
477
+ .claude-mpm/memories/*
478
+ !.claude-mpm/memories/*.md"""
479
+
480
+ # Display in a panel for clarity
481
+ from rich.panel import Panel
482
+
483
+ panel = Panel(
484
+ recommended_patterns,
485
+ title="Recommended .gitignore Patterns",
486
+ border_style="green",
487
+ padding=(1, 2),
488
+ )
489
+ console.print(panel)
490
+
491
+ # Explanation
492
+ console.print("\n[bold]What this does:[/bold]")
493
+ console.print(
494
+ " • Track [cyan].claude-mpm/memories/*.md[/cyan] (agent memories are valuable)"
495
+ )
496
+ console.print(
497
+ " • Ignore everything else in [dim].claude-mpm/[/dim] (cache, logs, sessions, tmp)"
498
+ )
499
+ console.print(
500
+ " • Services (mcp-vector-search, kuzu-memory, etc.) handle their own .gitignore"
501
+ )
502
+
503
+ console.print(
504
+ "\n[yellow]Note:[/yellow] These patterns are recommendations only."
505
+ )
506
+ console.print(" Add them manually to your .gitignore if desired.\n")
507
+
508
+ def _auto_configure(self, args) -> CommandResult:
509
+ """
510
+ Run auto-configuration to detect toolchain and recommend agents/skills.
511
+
512
+ This delegates to the AutoConfigureCommand for the actual implementation.
513
+ """
514
+ # Check if user wants gitignore recommendations
515
+ if hasattr(args, "gitignore") and args.gitignore:
516
+ self._show_gitignore_recommendations()
517
+ return CommandResult.success_result("Gitignore recommendations displayed")
518
+
519
+ try:
520
+ # Import AutoConfigureCommand
521
+ from .auto_configure import AutoConfigureCommand
522
+
523
+ # Create auto-configure command instance
524
+ auto_cmd = AutoConfigureCommand()
525
+
526
+ # Run auto-configuration
527
+ return auto_cmd.run(args)
528
+
529
+ except ImportError as e:
530
+ self.logger.error(f"AutoConfigureCommand not available: {e}")
531
+ return CommandResult.error_result(
532
+ "Auto-configuration feature not available. "
533
+ "Please ensure all dependencies are installed."
534
+ )
535
+ except Exception as e:
536
+ self.logger.error(f"Auto-configuration failed: {e}", exc_info=True)
537
+ return CommandResult.error_result(f"Auto-configuration failed: {e}")
538
+
453
539
 
454
540
  def manage_config(args) -> int:
455
541
  """Main entry point for configuration management commands.