claude-mpm 5.1.9__py3-none-any.whl → 5.4.48__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 (248) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/BASE_AGENT.md +164 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +1 -1
  5. claude_mpm/agents/MEMORY.md +1 -1
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +843 -900
  7. claude_mpm/agents/WORKFLOW.md +5 -254
  8. claude_mpm/agents/agent_loader.py +13 -44
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/frontmatter_validator.py +2 -2
  11. claude_mpm/agents/templates/circuit-breakers.md +138 -1
  12. claude_mpm/cli/__main__.py +4 -0
  13. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  14. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  15. claude_mpm/cli/commands/agents.py +9 -40
  16. claude_mpm/cli/commands/auto_configure.py +210 -25
  17. claude_mpm/cli/commands/config.py +88 -2
  18. claude_mpm/cli/commands/configure.py +1098 -159
  19. claude_mpm/cli/commands/configure_agent_display.py +25 -6
  20. claude_mpm/cli/commands/mpm_init/core.py +225 -46
  21. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  22. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  23. claude_mpm/cli/commands/postmortem.py +1 -1
  24. claude_mpm/cli/commands/profile.py +277 -0
  25. claude_mpm/cli/commands/skills.py +218 -197
  26. claude_mpm/cli/commands/summarize.py +413 -0
  27. claude_mpm/cli/executor.py +21 -3
  28. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  29. claude_mpm/cli/parsers/agents_parser.py +0 -9
  30. claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
  31. claude_mpm/cli/parsers/base_parser.py +12 -0
  32. claude_mpm/cli/parsers/config_parser.py +153 -83
  33. claude_mpm/cli/parsers/profile_parser.py +148 -0
  34. claude_mpm/cli/parsers/skills_parser.py +0 -5
  35. claude_mpm/cli/startup.py +876 -149
  36. claude_mpm/commands/mpm-config.md +28 -0
  37. claude_mpm/commands/mpm-doctor.md +9 -22
  38. claude_mpm/commands/mpm-help.md +5 -287
  39. claude_mpm/commands/mpm-init.md +81 -507
  40. claude_mpm/commands/mpm-monitor.md +15 -402
  41. claude_mpm/commands/mpm-organize.md +120 -0
  42. claude_mpm/commands/mpm-postmortem.md +6 -108
  43. claude_mpm/commands/mpm-session-resume.md +12 -363
  44. claude_mpm/commands/mpm-status.md +5 -69
  45. claude_mpm/commands/mpm-ticket-view.md +52 -495
  46. claude_mpm/commands/mpm-version.md +5 -107
  47. claude_mpm/config/agent_sources.py +27 -0
  48. claude_mpm/core/config.py +2 -4
  49. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  50. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  51. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  52. claude_mpm/core/framework_loader.py +4 -2
  53. claude_mpm/core/logger.py +13 -0
  54. claude_mpm/core/optimized_startup.py +59 -0
  55. claude_mpm/core/shared/config_loader.py +1 -1
  56. claude_mpm/core/socketio_pool.py +3 -3
  57. claude_mpm/core/unified_agent_registry.py +5 -15
  58. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  59. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  60. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  61. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  62. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  63. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  64. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  65. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  66. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  67. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  68. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  69. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  70. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  71. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  72. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  73. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  74. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  75. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  76. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  77. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  78. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  79. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  80. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  81. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  82. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  83. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  84. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  85. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  86. claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
  87. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  88. claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
  89. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  90. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  91. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  92. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  93. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
  97. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  98. claude_mpm/hooks/memory_integration_hook.py +46 -1
  99. claude_mpm/init.py +63 -19
  100. claude_mpm/models/git_repository.py +3 -3
  101. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  102. claude_mpm/scripts/launch_monitor.py +93 -13
  103. claude_mpm/services/agents/agent_builder.py +3 -3
  104. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  105. claude_mpm/services/agents/agent_review_service.py +280 -0
  106. claude_mpm/services/agents/cache_git_manager.py +6 -6
  107. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  108. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
  109. claude_mpm/services/agents/deployment/agent_format_converter.py +23 -13
  110. claude_mpm/services/agents/deployment/agent_template_builder.py +32 -20
  111. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  112. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  113. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  114. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +247 -35
  115. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +392 -87
  116. claude_mpm/services/agents/git_source_manager.py +53 -4
  117. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  118. claude_mpm/services/agents/recommender.py +5 -3
  119. claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
  120. claude_mpm/services/agents/sources/git_source_sync_service.py +120 -7
  121. claude_mpm/services/agents/startup_sync.py +22 -2
  122. claude_mpm/services/agents/toolchain_detector.py +10 -6
  123. claude_mpm/services/analysis/__init__.py +11 -1
  124. claude_mpm/services/analysis/clone_detector.py +1030 -0
  125. claude_mpm/services/command_deployment_service.py +81 -10
  126. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  127. claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
  128. claude_mpm/services/event_bus/config.py +3 -1
  129. claude_mpm/services/git/git_operations_service.py +101 -16
  130. claude_mpm/services/monitor/daemon.py +9 -2
  131. claude_mpm/services/monitor/daemon_manager.py +39 -3
  132. claude_mpm/services/monitor/management/lifecycle.py +8 -1
  133. claude_mpm/services/monitor/server.py +698 -22
  134. claude_mpm/services/pm_skills_deployer.py +711 -0
  135. claude_mpm/services/profile_manager.py +331 -0
  136. claude_mpm/services/self_upgrade_service.py +120 -12
  137. claude_mpm/services/skills/__init__.py +3 -0
  138. claude_mpm/services/skills/git_skill_source_manager.py +130 -2
  139. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  140. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  141. claude_mpm/services/skills_deployer.py +127 -9
  142. claude_mpm/services/socketio/dashboard_server.py +1 -0
  143. claude_mpm/services/socketio/event_normalizer.py +51 -6
  144. claude_mpm/services/socketio/server/core.py +386 -108
  145. claude_mpm/services/version_control/git_operations.py +103 -0
  146. claude_mpm/skills/skill_manager.py +92 -3
  147. claude_mpm/utils/agent_dependency_loader.py +14 -2
  148. claude_mpm/utils/agent_filters.py +17 -44
  149. claude_mpm/utils/migration.py +4 -4
  150. claude_mpm/utils/robust_installer.py +47 -3
  151. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/METADATA +53 -87
  152. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/RECORD +157 -197
  153. claude_mpm-5.4.48.dist-info/entry_points.txt +5 -0
  154. claude_mpm-5.4.48.dist-info/licenses/LICENSE +94 -0
  155. claude_mpm-5.4.48.dist-info/licenses/LICENSE-FAQ.md +153 -0
  156. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  157. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  158. claude_mpm/agents/BASE_OPS.md +0 -219
  159. claude_mpm/agents/BASE_PM.md +0 -480
  160. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  161. claude_mpm/agents/BASE_QA.md +0 -167
  162. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  163. claude_mpm/agents/base_agent_loader.py +0 -601
  164. claude_mpm/cli/commands/agents_detect.py +0 -380
  165. claude_mpm/cli/commands/agents_recommend.py +0 -309
  166. claude_mpm/cli/ticket_cli.py +0 -35
  167. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  168. claude_mpm/commands/mpm-agents-detect.md +0 -177
  169. claude_mpm/commands/mpm-agents-list.md +0 -131
  170. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  171. claude_mpm/commands/mpm-config-view.md +0 -150
  172. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  173. claude_mpm/dashboard/analysis_runner.py +0 -455
  174. claude_mpm/dashboard/index.html +0 -13
  175. claude_mpm/dashboard/open_dashboard.py +0 -66
  176. claude_mpm/dashboard/static/css/activity.css +0 -1958
  177. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  178. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  179. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  180. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  181. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  182. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  183. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  184. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  185. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  186. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  187. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  188. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  189. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  190. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  191. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  192. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  193. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  194. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  195. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  196. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  197. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  198. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  199. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  200. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  201. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  202. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  203. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  204. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  205. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  206. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  207. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  208. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  209. claude_mpm/dashboard/templates/code_simple.html +0 -153
  210. claude_mpm/dashboard/templates/index.html +0 -606
  211. claude_mpm/dashboard/test_dashboard.html +0 -372
  212. claude_mpm/scripts/mcp_server.py +0 -75
  213. claude_mpm/scripts/mcp_wrapper.py +0 -39
  214. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  215. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  216. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  217. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  218. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  219. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  220. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  221. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  222. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  223. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  224. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  225. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  226. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  227. claude_mpm/services/mcp_gateway/main.py +0 -589
  228. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  229. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  230. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  231. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  232. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  233. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  234. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  235. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  236. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  237. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  238. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  239. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  240. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  241. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  242. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  243. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  244. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  245. claude_mpm-5.1.9.dist-info/entry_points.txt +0 -10
  246. claude_mpm-5.1.9.dist-info/licenses/LICENSE +0 -21
  247. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/WHEEL +0 -0
  248. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/top_level.txt +0 -0
@@ -1,380 +0,0 @@
1
- """
2
- Agents Detect CLI Command for Claude MPM Framework
3
- ===================================================
4
-
5
- WHY: This module provides a CLI interface for detecting project toolchain
6
- without making any changes. Useful for debugging and verification of the
7
- toolchain detection system.
8
-
9
- DESIGN DECISION: Focused solely on detection and display, with no side effects.
10
- Supports multiple output formats for different use cases (human-readable,
11
- JSON for scripting).
12
-
13
- Part of TSK-0054: Auto-Configuration Feature - Phase 5
14
- """
15
-
16
- import json
17
- from pathlib import Path
18
- from typing import Optional
19
-
20
- try:
21
- from rich.console import Console
22
- from rich.table import Table
23
-
24
- RICH_AVAILABLE = True
25
- except ImportError:
26
- RICH_AVAILABLE = False
27
-
28
- from ...services.project.toolchain_analyzer import ToolchainAnalyzerService
29
- from ..shared import BaseCommand, CommandResult
30
-
31
-
32
- class AgentsDetectCommand(BaseCommand):
33
- """
34
- Handle agents detect CLI command.
35
-
36
- This command analyzes the project to detect languages, frameworks,
37
- and deployment targets without making any configuration changes.
38
- """
39
-
40
- def __init__(self):
41
- """Initialize the agents detect command."""
42
- super().__init__("agents-detect")
43
- self.console = Console() if RICH_AVAILABLE else None
44
- self._toolchain_analyzer = None
45
-
46
- @property
47
- def toolchain_analyzer(self) -> ToolchainAnalyzerService:
48
- """Get toolchain analyzer (lazy loaded)."""
49
- if self._toolchain_analyzer is None:
50
- self._toolchain_analyzer = ToolchainAnalyzerService()
51
- return self._toolchain_analyzer
52
-
53
- def validate_args(self, args) -> Optional[str]:
54
- """Validate command arguments."""
55
- # Validate project path
56
- project_path = (
57
- Path(args.project_path)
58
- if hasattr(args, "project_path") and args.project_path
59
- else Path.cwd()
60
- )
61
- if not project_path.exists():
62
- return f"Project path does not exist: {project_path}"
63
-
64
- return None
65
-
66
- def run(self, args) -> CommandResult:
67
- """
68
- Execute agents detect command.
69
-
70
- Returns:
71
- CommandResult with success status and exit code
72
- """
73
- try:
74
- # Setup logging
75
- self.setup_logging(args)
76
-
77
- # Validate arguments
78
- error = self.validate_args(args)
79
- if error:
80
- return CommandResult.error_result(error)
81
-
82
- # Get configuration options
83
- project_path = (
84
- Path(args.project_path)
85
- if hasattr(args, "project_path") and args.project_path
86
- else Path.cwd()
87
- )
88
- json_output = args.json if hasattr(args, "json") and args.json else False
89
- verbose = (
90
- args.verbose if hasattr(args, "verbose") and args.verbose else False
91
- )
92
-
93
- # Analyze toolchain
94
- if self.console and not json_output:
95
- with self.console.status("[bold green]Analyzing project toolchain..."):
96
- analysis = self.toolchain_analyzer.analyze_project(
97
- str(project_path)
98
- )
99
- else:
100
- analysis = self.toolchain_analyzer.analyze_project(str(project_path))
101
-
102
- # Output results
103
- if json_output:
104
- return self._output_json(analysis, verbose)
105
- return self._display_results(analysis, verbose)
106
-
107
- except KeyboardInterrupt:
108
- if self.console:
109
- self.console.print("\n\nāŒ Operation cancelled by user")
110
- else:
111
- print("\n\nOperation cancelled by user")
112
- return CommandResult.error_result("Operation cancelled", exit_code=130)
113
-
114
- except Exception as e:
115
- self.logger.exception("Toolchain detection failed")
116
- error_msg = f"Toolchain detection failed: {e!s}"
117
- if self.console:
118
- self.console.print(f"\nāŒ {error_msg}")
119
- else:
120
- print(f"\n{error_msg}")
121
- return CommandResult.error_result(error_msg)
122
-
123
- def _display_results(self, analysis, verbose: bool) -> CommandResult:
124
- """Display toolchain analysis results with Rich formatting."""
125
- if not self.console:
126
- return self._display_results_plain(analysis, verbose)
127
-
128
- # Display header
129
- self.console.print("\nšŸ“Š Project Toolchain Analysis", style="bold blue")
130
- self.console.print(f"Project: {analysis.project_path}\n")
131
-
132
- # Display detected languages
133
- if analysis.languages:
134
- self.console.print("šŸ”¤ Detected Languages:", style="bold green")
135
- lang_table = Table(show_header=True, header_style="bold")
136
- lang_table.add_column("Language", style="cyan")
137
- lang_table.add_column("Version", style="yellow")
138
- lang_table.add_column("Confidence", style="green")
139
- if verbose:
140
- lang_table.add_column("Evidence", style="dim")
141
-
142
- for lang in analysis.languages:
143
- confidence_pct = int(lang.confidence * 100)
144
- bar = "ā–ˆ" * (confidence_pct // 10) + "ā–‘" * (10 - confidence_pct // 10)
145
- confidence_str = f"{bar} {confidence_pct}%"
146
-
147
- if verbose:
148
- evidence = ", ".join(lang.evidence[:3]) # First 3 items
149
- if len(lang.evidence) > 3:
150
- evidence += f" (+{len(lang.evidence) - 3} more)"
151
- lang_table.add_row(
152
- lang.language,
153
- lang.version or "Unknown",
154
- confidence_str,
155
- evidence,
156
- )
157
- else:
158
- lang_table.add_row(
159
- lang.language, lang.version or "Unknown", confidence_str
160
- )
161
-
162
- self.console.print(lang_table)
163
- else:
164
- self.console.print(" No languages detected", style="yellow")
165
-
166
- # Display detected frameworks
167
- if analysis.frameworks:
168
- self.console.print("\nšŸ—ļø Detected Frameworks:", style="bold green")
169
- fw_table = Table(show_header=True, header_style="bold")
170
- fw_table.add_column("Framework", style="cyan")
171
- fw_table.add_column("Version", style="yellow")
172
- fw_table.add_column("Category", style="magenta")
173
- fw_table.add_column("Confidence", style="green")
174
-
175
- for fw in analysis.frameworks:
176
- confidence_pct = int(fw.confidence * 100)
177
- bar = "ā–ˆ" * (confidence_pct // 10) + "ā–‘" * (10 - confidence_pct // 10)
178
- confidence_str = f"{bar} {confidence_pct}%"
179
-
180
- fw_table.add_row(
181
- fw.name,
182
- fw.version or "Unknown",
183
- (
184
- fw.category.value
185
- if hasattr(fw.category, "value")
186
- else str(fw.category)
187
- ),
188
- confidence_str,
189
- )
190
-
191
- self.console.print(fw_table)
192
- else:
193
- self.console.print("\n No frameworks detected", style="yellow")
194
-
195
- # Display deployment targets
196
- if analysis.deployment_targets:
197
- self.console.print("\nšŸš€ Deployment Targets:", style="bold green")
198
- dt_table = Table(show_header=True, header_style="bold")
199
- dt_table.add_column("Target", style="cyan")
200
- dt_table.add_column("Confidence", style="green")
201
- if verbose:
202
- dt_table.add_column("Evidence", style="dim")
203
-
204
- for target in analysis.deployment_targets:
205
- confidence_pct = int(target.confidence * 100)
206
- bar = "ā–ˆ" * (confidence_pct // 10) + "ā–‘" * (10 - confidence_pct // 10)
207
- confidence_str = f"{bar} {confidence_pct}%"
208
-
209
- if verbose:
210
- evidence = ", ".join(target.evidence[:3])
211
- if len(target.evidence) > 3:
212
- evidence += f" (+{len(target.evidence) - 3} more)"
213
- dt_table.add_row(
214
- (
215
- target.target_type.value
216
- if hasattr(target.target_type, "value")
217
- else str(target.target_type)
218
- ),
219
- confidence_str,
220
- evidence,
221
- )
222
- else:
223
- dt_table.add_row(
224
- (
225
- target.target_type.value
226
- if hasattr(target.target_type, "value")
227
- else str(target.target_type)
228
- ),
229
- confidence_str,
230
- )
231
-
232
- self.console.print(dt_table)
233
- else:
234
- self.console.print("\n No deployment targets detected", style="yellow")
235
-
236
- # Display all components summary
237
- if analysis.components:
238
- self.console.print("\nšŸ“¦ All Components:", style="bold blue")
239
- comp_table = Table(show_header=True, header_style="bold")
240
- comp_table.add_column("Type", style="cyan")
241
- comp_table.add_column("Name", style="yellow")
242
- comp_table.add_column("Version", style="magenta")
243
- comp_table.add_column("Confidence", style="green")
244
-
245
- for comp in analysis.components:
246
- confidence_pct = int(comp.confidence * 100)
247
- bar = "ā–ˆ" * (confidence_pct // 10) + "ā–‘" * (10 - confidence_pct // 10)
248
- confidence_str = f"{bar} {confidence_pct}%"
249
-
250
- comp_table.add_row(
251
- comp.type.value if hasattr(comp.type, "value") else str(comp.type),
252
- comp.name or "-",
253
- comp.version or "Unknown",
254
- confidence_str,
255
- )
256
-
257
- self.console.print(comp_table)
258
-
259
- # Summary
260
- self.console.print(
261
- f"\nāœ… Analysis complete: {len(analysis.languages)} language(s), "
262
- f"{len(analysis.frameworks)} framework(s), "
263
- f"{len(analysis.deployment_targets)} deployment target(s)",
264
- style="bold green",
265
- )
266
-
267
- return CommandResult.success_result()
268
-
269
- def _display_results_plain(self, analysis, verbose: bool) -> CommandResult:
270
- """Display results in plain text (fallback)."""
271
- print("\nšŸ“Š Project Toolchain Analysis")
272
- print(f"Project: {analysis.project_path}\n")
273
-
274
- # Languages
275
- if analysis.languages:
276
- print("Detected Languages:")
277
- for lang in analysis.languages:
278
- confidence_pct = int(lang.confidence * 100)
279
- print(
280
- f" - {lang.language} {lang.version or 'Unknown'} ({confidence_pct}%)"
281
- )
282
- if verbose:
283
- print(f" Evidence: {', '.join(lang.evidence[:5])}")
284
- else:
285
- print("No languages detected")
286
-
287
- # Frameworks
288
- if analysis.frameworks:
289
- print("\nDetected Frameworks:")
290
- for fw in analysis.frameworks:
291
- confidence_pct = int(fw.confidence * 100)
292
- print(
293
- f" - {fw.name} {fw.version or 'Unknown'} ({fw.category}) ({confidence_pct}%)"
294
- )
295
- else:
296
- print("\nNo frameworks detected")
297
-
298
- # Deployment targets
299
- if analysis.deployment_targets:
300
- print("\nDeployment Targets:")
301
- for target in analysis.deployment_targets:
302
- confidence_pct = int(target.confidence * 100)
303
- print(f" - {target.target_type} ({confidence_pct}%)")
304
- if verbose:
305
- print(f" Evidence: {', '.join(target.evidence[:5])}")
306
- else:
307
- print("\nNo deployment targets detected")
308
-
309
- print(
310
- f"\nAnalysis complete: {len(analysis.languages)} language(s), "
311
- f"{len(analysis.frameworks)} framework(s), "
312
- f"{len(analysis.deployment_targets)} deployment target(s)"
313
- )
314
-
315
- return CommandResult.success_result()
316
-
317
- def _output_json(self, analysis, verbose: bool) -> CommandResult:
318
- """Output toolchain analysis as JSON."""
319
- output = {
320
- "project_path": analysis.project_path,
321
- "analysis_time": analysis.analysis_time,
322
- "languages": [
323
- {
324
- "language": lang.language,
325
- "version": lang.version,
326
- "confidence": lang.confidence,
327
- "evidence": lang.evidence if verbose else None,
328
- }
329
- for lang in analysis.languages
330
- ],
331
- "frameworks": [
332
- {
333
- "name": fw.name,
334
- "version": fw.version,
335
- "category": (
336
- fw.category.value
337
- if hasattr(fw.category, "value")
338
- else str(fw.category)
339
- ),
340
- "confidence": fw.confidence,
341
- "config_file": fw.config_file,
342
- }
343
- for fw in analysis.frameworks
344
- ],
345
- "deployment_targets": [
346
- {
347
- "target_type": (
348
- target.target_type.value
349
- if hasattr(target.target_type, "value")
350
- else str(target.target_type)
351
- ),
352
- "confidence": target.confidence,
353
- "evidence": target.evidence if verbose else None,
354
- }
355
- for target in analysis.deployment_targets
356
- ],
357
- "components": [
358
- {
359
- "type": (
360
- comp.type.value
361
- if hasattr(comp.type, "value")
362
- else str(comp.type)
363
- ),
364
- "name": comp.name,
365
- "version": comp.version,
366
- "confidence": comp.confidence,
367
- }
368
- for comp in analysis.components
369
- ],
370
- }
371
-
372
- # Remove None values if not verbose
373
- if not verbose:
374
- for lang in output["languages"]:
375
- lang.pop("evidence", None)
376
- for target in output["deployment_targets"]:
377
- target.pop("evidence", None)
378
-
379
- print(json.dumps(output, indent=2))
380
- return CommandResult.success_result(data=output)
@@ -1,309 +0,0 @@
1
- """
2
- Agents Recommend CLI Command for Claude MPM Framework
3
- ======================================================
4
-
5
- WHY: This module provides a CLI interface for getting agent recommendations
6
- based on project toolchain without deploying anything. Useful for reviewing
7
- recommendations before committing to deployment.
8
-
9
- DESIGN DECISION: Focused on recommendation display with detailed reasoning,
10
- showing users why each agent was recommended. Supports JSON output for
11
- integration with other tools.
12
-
13
- Part of TSK-0054: Auto-Configuration Feature - Phase 5
14
- """
15
-
16
- import json
17
- from pathlib import Path
18
- from typing import Optional
19
-
20
- try:
21
- from rich.console import Console
22
- from rich.panel import Panel
23
- from rich.table import Table
24
-
25
- RICH_AVAILABLE = True
26
- except ImportError:
27
- RICH_AVAILABLE = False
28
-
29
- from ...services.agents.recommender import AgentRecommenderService
30
- from ...services.agents.registry import AgentRegistry
31
- from ...services.project.toolchain_analyzer import ToolchainAnalyzerService
32
- from ..shared import BaseCommand, CommandResult
33
-
34
-
35
- class AgentsRecommendCommand(BaseCommand):
36
- """
37
- Handle agents recommend CLI command.
38
-
39
- This command analyzes the project toolchain and recommends appropriate
40
- agents without deploying them. Shows detailed reasoning for each
41
- recommendation.
42
- """
43
-
44
- def __init__(self):
45
- """Initialize the agents recommend command."""
46
- super().__init__("agents-recommend")
47
- self.console = Console() if RICH_AVAILABLE else None
48
- self._toolchain_analyzer = None
49
- self._agent_recommender = None
50
-
51
- @property
52
- def toolchain_analyzer(self) -> ToolchainAnalyzerService:
53
- """Get toolchain analyzer (lazy loaded)."""
54
- if self._toolchain_analyzer is None:
55
- self._toolchain_analyzer = ToolchainAnalyzerService()
56
- return self._toolchain_analyzer
57
-
58
- @property
59
- def agent_recommender(self) -> AgentRecommenderService:
60
- """Get agent recommender (lazy loaded)."""
61
- if self._agent_recommender is None:
62
- agent_registry = AgentRegistry()
63
- self._agent_recommender = AgentRecommenderService(
64
- agent_registry=agent_registry
65
- )
66
- return self._agent_recommender
67
-
68
- def validate_args(self, args) -> Optional[str]:
69
- """Validate command arguments."""
70
- # Validate project path
71
- project_path = (
72
- Path(args.project_path)
73
- if hasattr(args, "project_path") and args.project_path
74
- else Path.cwd()
75
- )
76
- if not project_path.exists():
77
- return f"Project path does not exist: {project_path}"
78
-
79
- # Validate min_confidence range
80
- if hasattr(args, "min_confidence") and args.min_confidence:
81
- if not 0.0 <= args.min_confidence <= 1.0:
82
- return "min_confidence must be between 0.0 and 1.0"
83
-
84
- return None
85
-
86
- def run(self, args) -> CommandResult:
87
- """
88
- Execute agents recommend command.
89
-
90
- Returns:
91
- CommandResult with success status and exit code
92
- """
93
- try:
94
- # Setup logging
95
- self.setup_logging(args)
96
-
97
- # Validate arguments
98
- error = self.validate_args(args)
99
- if error:
100
- return CommandResult.error_result(error)
101
-
102
- # Get configuration options
103
- project_path = (
104
- Path(args.project_path)
105
- if hasattr(args, "project_path") and args.project_path
106
- else Path.cwd()
107
- )
108
- min_confidence = (
109
- args.min_confidence
110
- if hasattr(args, "min_confidence") and args.min_confidence
111
- else 0.8
112
- )
113
- json_output = args.json if hasattr(args, "json") and args.json else False
114
- show_reasoning = (
115
- args.show_reasoning
116
- if hasattr(args, "show_reasoning") and args.show_reasoning
117
- else True
118
- )
119
-
120
- # Analyze toolchain
121
- if self.console and not json_output:
122
- with self.console.status("[bold green]Analyzing project toolchain..."):
123
- analysis = self.toolchain_analyzer.analyze_project(
124
- str(project_path)
125
- )
126
- else:
127
- analysis = self.toolchain_analyzer.analyze_project(str(project_path))
128
-
129
- # Get recommendations
130
- if self.console and not json_output:
131
- with self.console.status(
132
- "[bold green]Generating agent recommendations..."
133
- ):
134
- recommendations = self.agent_recommender.recommend_agents(
135
- analysis, min_confidence
136
- )
137
- else:
138
- recommendations = self.agent_recommender.recommend_agents(
139
- analysis, min_confidence
140
- )
141
-
142
- # Output results
143
- if json_output:
144
- return self._output_json(recommendations, analysis)
145
- return self._display_results(recommendations, analysis, show_reasoning)
146
-
147
- except KeyboardInterrupt:
148
- if self.console:
149
- self.console.print("\n\nāŒ Operation cancelled by user")
150
- else:
151
- print("\n\nOperation cancelled by user")
152
- return CommandResult.error_result("Operation cancelled", exit_code=130)
153
-
154
- except Exception as e:
155
- self.logger.exception("Agent recommendation failed")
156
- error_msg = f"Agent recommendation failed: {e!s}"
157
- if self.console:
158
- self.console.print(f"\nāŒ {error_msg}")
159
- else:
160
- print(f"\n{error_msg}")
161
- return CommandResult.error_result(error_msg)
162
-
163
- def _display_results(
164
- self, recommendations, analysis, show_reasoning: bool
165
- ) -> CommandResult:
166
- """Display agent recommendations with Rich formatting."""
167
- if not self.console:
168
- return self._display_results_plain(
169
- recommendations, analysis, show_reasoning
170
- )
171
-
172
- # Display header
173
- self.console.print("\nšŸ¤– Agent Recommendations", style="bold blue")
174
- self.console.print(f"Project: {analysis.project_path}\n")
175
-
176
- # Display quick summary
177
- if recommendations:
178
- summary_text = (
179
- f"Found {len(recommendations)} recommended agent(s) "
180
- f"for your project based on detected toolchain."
181
- )
182
- panel = Panel(summary_text, border_style="green")
183
- self.console.print(panel)
184
- else:
185
- panel = Panel(
186
- "No agents recommended for this project.\n"
187
- "Try lowering the confidence threshold with --min-confidence",
188
- border_style="yellow",
189
- )
190
- self.console.print(panel)
191
- return CommandResult.success_result()
192
-
193
- # Display recommendations table
194
- self.console.print("\nšŸ“‹ Recommended Agents:", style="bold green")
195
- table = Table(show_header=True, header_style="bold")
196
- table.add_column("Agent ID", style="cyan")
197
- table.add_column("Confidence", style="green")
198
- table.add_column("Priority", style="yellow")
199
- if show_reasoning:
200
- table.add_column("Reasoning", style="dim", no_wrap=False)
201
-
202
- for rec in recommendations:
203
- confidence_pct = int(rec.confidence * 100)
204
- bar = "ā–ˆ" * (confidence_pct // 10) + "ā–‘" * (10 - confidence_pct // 10)
205
- confidence_str = f"{bar} {confidence_pct}%"
206
-
207
- if show_reasoning:
208
- table.add_row(
209
- rec.agent_id,
210
- confidence_str,
211
- str(rec.priority),
212
- rec.reasoning,
213
- )
214
- else:
215
- table.add_row(rec.agent_id, confidence_str, str(rec.priority))
216
-
217
- self.console.print(table)
218
-
219
- # Display match details if reasoning enabled
220
- if show_reasoning:
221
- self.console.print("\nšŸ” Match Details:", style="bold blue")
222
- for rec in recommendations:
223
- self.console.print(f"\n[bold cyan]{rec.agent_id}[/bold cyan]")
224
- self.console.print(f" Confidence: {int(rec.confidence * 100)}%")
225
- self.console.print(f" Priority: {rec.priority}")
226
- self.console.print(f" Reasoning: {rec.reasoning}")
227
-
228
- if rec.matched_capabilities:
229
- self.console.print(" Matched capabilities:", style="green")
230
- for cap in rec.matched_capabilities[:5]:
231
- self.console.print(f" • {cap}", style="dim")
232
- if len(rec.matched_capabilities) > 5:
233
- remaining = len(rec.matched_capabilities) - 5
234
- self.console.print(f" ... and {remaining} more", style="dim")
235
-
236
- # Display next steps
237
- self.console.print("\nšŸ’” Next Steps:", style="bold yellow")
238
- self.console.print(" 1. Review the recommendations and their reasoning")
239
- self.console.print(
240
- " 2. Deploy agents with: [bold]claude-mpm auto-configure[/bold]"
241
- )
242
- self.console.print(
243
- " 3. Or preview deployment with: [bold]claude-mpm auto-configure --preview[/bold]"
244
- )
245
-
246
- return CommandResult.success_result()
247
-
248
- def _display_results_plain(
249
- self, recommendations, analysis, show_reasoning: bool
250
- ) -> CommandResult:
251
- """Display results in plain text (fallback)."""
252
- print("\nšŸ¤– Agent Recommendations")
253
- print(f"Project: {analysis.project_path}\n")
254
-
255
- if not recommendations:
256
- print("No agents recommended for this project.")
257
- print("Try lowering the confidence threshold with --min-confidence")
258
- return CommandResult.success_result()
259
-
260
- print(f"Found {len(recommendations)} recommended agent(s) for your project:\n")
261
-
262
- for rec in recommendations:
263
- confidence_pct = int(rec.confidence * 100)
264
- print(f"• {rec.agent_id} ({confidence_pct}% confidence)")
265
-
266
- if show_reasoning:
267
- print(f" Priority: {rec.priority}")
268
- print(f" Reasoning: {rec.reasoning}")
269
-
270
- if rec.matched_capabilities:
271
- print(" Matched capabilities:")
272
- for cap in rec.matched_capabilities[:5]:
273
- print(f" - {cap}")
274
- if len(rec.matched_capabilities) > 5:
275
- remaining = len(rec.matched_capabilities) - 5
276
- print(f" ... and {remaining} more")
277
- print()
278
-
279
- print("\nNext Steps:")
280
- print(" 1. Review the recommendations and their reasoning")
281
- print(" 2. Deploy agents with: claude-mpm auto-configure")
282
- print(" 3. Or preview deployment with: claude-mpm auto-configure --preview")
283
-
284
- return CommandResult.success_result()
285
-
286
- def _output_json(self, recommendations, analysis) -> CommandResult:
287
- """Output recommendations as JSON."""
288
- output = {
289
- "project_path": analysis.project_path,
290
- "recommendations": [
291
- {
292
- "agent_id": rec.agent_id,
293
- "confidence": rec.confidence,
294
- "priority": rec.priority,
295
- "reasoning": rec.reasoning,
296
- "matched_capabilities": rec.matched_capabilities,
297
- "requirements": rec.requirements,
298
- }
299
- for rec in recommendations
300
- ],
301
- "toolchain_summary": {
302
- "languages": len(analysis.languages),
303
- "frameworks": len(analysis.frameworks),
304
- "deployment_targets": len(analysis.deployment_targets),
305
- },
306
- }
307
-
308
- print(json.dumps(output, indent=2))
309
- return CommandResult.success_result(data=output)