claude-mpm 4.7.4__py3-none-any.whl → 4.18.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  4. claude_mpm/agents/BASE_PM.md +106 -1
  5. claude_mpm/agents/OUTPUT_STYLE.md +329 -11
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
  7. claude_mpm/agents/agent_loader.py +17 -5
  8. claude_mpm/agents/frontmatter_validator.py +284 -253
  9. claude_mpm/agents/templates/README.md +465 -0
  10. claude_mpm/agents/templates/agent-manager.json +4 -1
  11. claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
  12. claude_mpm/agents/templates/api_qa.json +11 -2
  13. claude_mpm/agents/templates/circuit_breakers.md +638 -0
  14. claude_mpm/agents/templates/clerk-ops.json +12 -2
  15. claude_mpm/agents/templates/code_analyzer.json +8 -2
  16. claude_mpm/agents/templates/content-agent.json +358 -0
  17. claude_mpm/agents/templates/dart_engineer.json +15 -2
  18. claude_mpm/agents/templates/data_engineer.json +15 -2
  19. claude_mpm/agents/templates/documentation.json +10 -2
  20. claude_mpm/agents/templates/engineer.json +21 -1
  21. claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
  22. claude_mpm/agents/templates/git_file_tracking.md +584 -0
  23. claude_mpm/agents/templates/golang_engineer.json +270 -0
  24. claude_mpm/agents/templates/imagemagick.json +4 -1
  25. claude_mpm/agents/templates/java_engineer.json +346 -0
  26. claude_mpm/agents/templates/local_ops_agent.json +1227 -6
  27. claude_mpm/agents/templates/memory_manager.json +4 -1
  28. claude_mpm/agents/templates/nextjs_engineer.json +141 -133
  29. claude_mpm/agents/templates/ops.json +12 -2
  30. claude_mpm/agents/templates/php-engineer.json +270 -174
  31. claude_mpm/agents/templates/pm_examples.md +474 -0
  32. claude_mpm/agents/templates/pm_red_flags.md +240 -0
  33. claude_mpm/agents/templates/product_owner.json +338 -0
  34. claude_mpm/agents/templates/project_organizer.json +14 -4
  35. claude_mpm/agents/templates/prompt-engineer.json +13 -2
  36. claude_mpm/agents/templates/python_engineer.json +174 -81
  37. claude_mpm/agents/templates/qa.json +11 -2
  38. claude_mpm/agents/templates/react_engineer.json +16 -3
  39. claude_mpm/agents/templates/refactoring_engineer.json +12 -2
  40. claude_mpm/agents/templates/research.json +34 -21
  41. claude_mpm/agents/templates/response_format.md +583 -0
  42. claude_mpm/agents/templates/ruby-engineer.json +129 -192
  43. claude_mpm/agents/templates/rust_engineer.json +270 -0
  44. claude_mpm/agents/templates/security.json +10 -2
  45. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  46. claude_mpm/agents/templates/ticketing.json +10 -2
  47. claude_mpm/agents/templates/typescript_engineer.json +116 -125
  48. claude_mpm/agents/templates/validation_templates.md +312 -0
  49. claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
  50. claude_mpm/agents/templates/version_control.json +12 -2
  51. claude_mpm/agents/templates/web_qa.json +11 -2
  52. claude_mpm/agents/templates/web_ui.json +15 -2
  53. claude_mpm/cli/__init__.py +34 -614
  54. claude_mpm/cli/commands/agent_manager.py +25 -12
  55. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  56. claude_mpm/cli/commands/agents.py +235 -148
  57. claude_mpm/cli/commands/agents_detect.py +380 -0
  58. claude_mpm/cli/commands/agents_recommend.py +309 -0
  59. claude_mpm/cli/commands/aggregate.py +7 -3
  60. claude_mpm/cli/commands/analyze.py +9 -4
  61. claude_mpm/cli/commands/analyze_code.py +7 -2
  62. claude_mpm/cli/commands/auto_configure.py +570 -0
  63. claude_mpm/cli/commands/config.py +47 -13
  64. claude_mpm/cli/commands/configure.py +419 -1571
  65. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  66. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  67. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  68. claude_mpm/cli/commands/configure_models.py +18 -0
  69. claude_mpm/cli/commands/configure_navigation.py +167 -0
  70. claude_mpm/cli/commands/configure_paths.py +104 -0
  71. claude_mpm/cli/commands/configure_persistence.py +254 -0
  72. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  73. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  74. claude_mpm/cli/commands/configure_validators.py +73 -0
  75. claude_mpm/cli/commands/local_deploy.py +537 -0
  76. claude_mpm/cli/commands/memory.py +54 -20
  77. claude_mpm/cli/commands/mpm_init.py +585 -196
  78. claude_mpm/cli/commands/mpm_init_handler.py +37 -3
  79. claude_mpm/cli/commands/search.py +170 -4
  80. claude_mpm/cli/commands/upgrade.py +152 -0
  81. claude_mpm/cli/executor.py +202 -0
  82. claude_mpm/cli/helpers.py +105 -0
  83. claude_mpm/cli/interactive/__init__.py +3 -0
  84. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  85. claude_mpm/cli/parsers/__init__.py +7 -1
  86. claude_mpm/cli/parsers/agents_parser.py +9 -0
  87. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  88. claude_mpm/cli/parsers/base_parser.py +110 -3
  89. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  90. claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
  91. claude_mpm/cli/shared/output_formatters.py +28 -19
  92. claude_mpm/cli/startup.py +481 -0
  93. claude_mpm/cli/utils.py +52 -1
  94. claude_mpm/commands/mpm-agents-detect.md +168 -0
  95. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  96. claude_mpm/commands/mpm-agents.md +75 -1
  97. claude_mpm/commands/mpm-auto-configure.md +217 -0
  98. claude_mpm/commands/mpm-help.md +163 -0
  99. claude_mpm/commands/mpm-init.md +148 -3
  100. claude_mpm/commands/mpm-version.md +113 -0
  101. claude_mpm/commands/mpm.md +1 -0
  102. claude_mpm/config/agent_config.py +2 -2
  103. claude_mpm/config/model_config.py +428 -0
  104. claude_mpm/constants.py +1 -0
  105. claude_mpm/core/base_service.py +13 -12
  106. claude_mpm/core/enums.py +452 -0
  107. claude_mpm/core/factories.py +1 -1
  108. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  109. claude_mpm/core/interactive_session.py +9 -3
  110. claude_mpm/core/log_manager.py +2 -0
  111. claude_mpm/core/logging_config.py +6 -2
  112. claude_mpm/core/oneshot_session.py +8 -4
  113. claude_mpm/core/optimized_agent_loader.py +3 -3
  114. claude_mpm/core/output_style_manager.py +12 -192
  115. claude_mpm/core/service_registry.py +5 -1
  116. claude_mpm/core/types.py +2 -9
  117. claude_mpm/core/typing_utils.py +7 -6
  118. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  119. claude_mpm/dashboard/templates/index.html +3 -41
  120. claude_mpm/hooks/__init__.py +20 -0
  121. claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
  122. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  123. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
  124. claude_mpm/hooks/failure_learning/__init__.py +60 -0
  125. claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
  126. claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
  127. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
  128. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  129. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  130. claude_mpm/hooks/kuzu_memory_hook.py +37 -12
  131. claude_mpm/hooks/kuzu_response_hook.py +183 -0
  132. claude_mpm/models/resume_log.py +340 -0
  133. claude_mpm/services/agents/__init__.py +18 -5
  134. claude_mpm/services/agents/auto_config_manager.py +796 -0
  135. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  136. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  137. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  138. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  139. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  140. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  141. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  142. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  143. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  144. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  145. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  146. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  147. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  148. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  149. claude_mpm/services/agents/local_template_manager.py +1 -1
  150. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  151. claude_mpm/services/agents/observers.py +547 -0
  152. claude_mpm/services/agents/recommender.py +568 -0
  153. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  154. claude_mpm/services/command_handler_service.py +11 -5
  155. claude_mpm/services/core/__init__.py +33 -1
  156. claude_mpm/services/core/interfaces/__init__.py +90 -3
  157. claude_mpm/services/core/interfaces/agent.py +184 -0
  158. claude_mpm/services/core/interfaces/health.py +172 -0
  159. claude_mpm/services/core/interfaces/model.py +281 -0
  160. claude_mpm/services/core/interfaces/process.py +372 -0
  161. claude_mpm/services/core/interfaces/project.py +121 -0
  162. claude_mpm/services/core/interfaces/restart.py +307 -0
  163. claude_mpm/services/core/interfaces/stability.py +260 -0
  164. claude_mpm/services/core/memory_manager.py +11 -24
  165. claude_mpm/services/core/models/__init__.py +79 -0
  166. claude_mpm/services/core/models/agent_config.py +381 -0
  167. claude_mpm/services/core/models/health.py +162 -0
  168. claude_mpm/services/core/models/process.py +235 -0
  169. claude_mpm/services/core/models/restart.py +302 -0
  170. claude_mpm/services/core/models/stability.py +264 -0
  171. claude_mpm/services/core/models/toolchain.py +306 -0
  172. claude_mpm/services/core/path_resolver.py +23 -7
  173. claude_mpm/services/diagnostics/__init__.py +2 -2
  174. claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
  175. claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
  176. claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
  177. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
  178. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  179. claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
  180. claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
  181. claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
  182. claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
  183. claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
  184. claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
  185. claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
  186. claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
  187. claude_mpm/services/diagnostics/models.py +19 -24
  188. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  189. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  190. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  191. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  192. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  193. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  194. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  195. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  196. claude_mpm/services/local_ops/__init__.py +163 -0
  197. claude_mpm/services/local_ops/crash_detector.py +257 -0
  198. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  199. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  200. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  201. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  202. claude_mpm/services/local_ops/health_manager.py +430 -0
  203. claude_mpm/services/local_ops/log_monitor.py +396 -0
  204. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  205. claude_mpm/services/local_ops/process_manager.py +595 -0
  206. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  207. claude_mpm/services/local_ops/restart_manager.py +401 -0
  208. claude_mpm/services/local_ops/restart_policy.py +387 -0
  209. claude_mpm/services/local_ops/state_manager.py +372 -0
  210. claude_mpm/services/local_ops/unified_manager.py +600 -0
  211. claude_mpm/services/mcp_config_manager.py +9 -4
  212. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  213. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  214. claude_mpm/services/mcp_gateway/main.py +30 -0
  215. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
  216. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
  217. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
  218. claude_mpm/services/mcp_service_verifier.py +1 -1
  219. claude_mpm/services/memory/failure_tracker.py +563 -0
  220. claude_mpm/services/memory_hook_service.py +165 -4
  221. claude_mpm/services/model/__init__.py +147 -0
  222. claude_mpm/services/model/base_provider.py +365 -0
  223. claude_mpm/services/model/claude_provider.py +412 -0
  224. claude_mpm/services/model/model_router.py +453 -0
  225. claude_mpm/services/model/ollama_provider.py +415 -0
  226. claude_mpm/services/monitor/daemon_manager.py +3 -2
  227. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  228. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  229. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  230. claude_mpm/services/monitor/server.py +2 -1
  231. claude_mpm/services/project/__init__.py +23 -0
  232. claude_mpm/services/project/detection_strategies.py +719 -0
  233. claude_mpm/services/project/toolchain_analyzer.py +581 -0
  234. claude_mpm/services/self_upgrade_service.py +342 -0
  235. claude_mpm/services/session_management_service.py +3 -2
  236. claude_mpm/services/session_manager.py +205 -1
  237. claude_mpm/services/shared/async_service_base.py +16 -27
  238. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  239. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  240. claude_mpm/services/socketio/handlers/hook.py +13 -2
  241. claude_mpm/services/socketio/handlers/registry.py +4 -2
  242. claude_mpm/services/socketio/server/main.py +10 -8
  243. claude_mpm/services/subprocess_launcher_service.py +14 -5
  244. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
  245. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  246. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  247. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
  248. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  249. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  250. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  251. claude_mpm/services/unified/deployment_strategies/local.py +6 -5
  252. claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
  253. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
  254. claude_mpm/services/unified/interfaces.py +3 -1
  255. claude_mpm/services/unified/unified_analyzer.py +14 -10
  256. claude_mpm/services/unified/unified_config.py +2 -1
  257. claude_mpm/services/unified/unified_deployment.py +9 -4
  258. claude_mpm/services/version_service.py +104 -1
  259. claude_mpm/skills/__init__.py +21 -0
  260. claude_mpm/skills/bundled/__init__.py +6 -0
  261. claude_mpm/skills/bundled/api-documentation.md +393 -0
  262. claude_mpm/skills/bundled/async-testing.md +571 -0
  263. claude_mpm/skills/bundled/code-review.md +143 -0
  264. claude_mpm/skills/bundled/database-migration.md +199 -0
  265. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  266. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  267. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  268. claude_mpm/skills/bundled/git-workflow.md +414 -0
  269. claude_mpm/skills/bundled/imagemagick.md +204 -0
  270. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  271. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  272. claude_mpm/skills/bundled/pdf.md +141 -0
  273. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  274. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  275. claude_mpm/skills/bundled/security-scanning.md +327 -0
  276. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  277. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  278. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  279. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  280. claude_mpm/skills/bundled/xlsx.md +157 -0
  281. claude_mpm/skills/registry.py +286 -0
  282. claude_mpm/skills/skill_manager.py +310 -0
  283. claude_mpm/storage/state_storage.py +15 -15
  284. claude_mpm/tools/code_tree_analyzer.py +177 -141
  285. claude_mpm/tools/code_tree_events.py +4 -2
  286. claude_mpm/utils/agent_dependency_loader.py +40 -20
  287. claude_mpm/utils/display_helper.py +260 -0
  288. claude_mpm/utils/git_analyzer.py +407 -0
  289. claude_mpm/utils/robust_installer.py +73 -19
  290. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
  291. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
  292. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  293. claude_mpm/dashboard/static/index-hub-backup.html +0 -713
  294. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  295. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  296. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  297. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  298. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  299. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  300. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  301. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  302. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  303. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  304. claude_mpm/services/project/analyzer_refactored.py +0 -450
  305. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
  306. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
  307. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
  308. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
@@ -16,6 +16,7 @@ import json
16
16
  import sys
17
17
  from typing import Optional
18
18
 
19
+ from ...core.enums import OutputFormat
19
20
  from ...core.logger import get_logger
20
21
  from ...services.event_aggregator import (
21
22
  aggregator_status,
@@ -110,7 +111,10 @@ def aggregate_command(args):
110
111
  result = command.execute(args)
111
112
 
112
113
  # Print result if structured output format is requested
113
- if hasattr(args, "format") and args.format in ["json", "yaml"]:
114
+ if hasattr(args, "format") and str(args.format).lower() in (
115
+ OutputFormat.JSON,
116
+ OutputFormat.YAML,
117
+ ):
114
118
  command.print_result(result, args)
115
119
 
116
120
  return result.exit_code
@@ -407,7 +411,7 @@ def export_command_legacy(args):
407
411
  output_path = Path(f"session_{session.session_id[:8]}_export.json")
408
412
 
409
413
  # Export based on format
410
- if args.format == "json":
414
+ if str(args.format).lower() == OutputFormat.JSON:
411
415
  # Full JSON export
412
416
  with output_path.open("w") as f:
413
417
  json.dump(session.to_dict(), f, indent=2)
@@ -529,7 +533,7 @@ def add_aggregate_parser(subparsers):
529
533
  "--format",
530
534
  "-f",
531
535
  choices=["json", "summary", "events"],
532
- default="json",
536
+ default=OutputFormat.JSON,
533
537
  help="Export format (default: json)",
534
538
  )
535
539
 
@@ -23,6 +23,7 @@ from datetime import datetime, timezone
23
23
  from pathlib import Path
24
24
  from typing import Dict, List, Optional
25
25
 
26
+ from ...core.enums import OutputFormat
26
27
  from ...core.logging_config import get_logger
27
28
  from ...services.cli.session_manager import SessionManager
28
29
  from ..shared import BaseCommand, CommandResult
@@ -132,7 +133,11 @@ class AnalyzeCommand(BaseCommand):
132
133
  self._save_output(output, args.output)
133
134
 
134
135
  return CommandResult.success_result(
135
- message=output if args.format == "text" else "Analysis completed",
136
+ message=(
137
+ output
138
+ if str(args.format).lower() == OutputFormat.TEXT
139
+ else "Analysis completed"
140
+ ),
136
141
  data=result_data,
137
142
  )
138
143
 
@@ -422,7 +427,7 @@ class AnalyzeCommand(BaseCommand):
422
427
  Returns:
423
428
  Formatted output string
424
429
  """
425
- if format_type == "json":
430
+ if str(format_type).lower() == OutputFormat.JSON:
426
431
  result_data["diagrams"] = diagrams
427
432
  return json.dumps(result_data, indent=2)
428
433
 
@@ -516,7 +521,7 @@ def analyze_command(args):
516
521
  result = command.run(args)
517
522
 
518
523
  if result.success:
519
- if args.format == "json":
524
+ if str(args.format).lower() == OutputFormat.JSON:
520
525
  print(json.dumps(result.data, indent=2))
521
526
  else:
522
527
  print(result.message)
@@ -540,7 +545,7 @@ if __name__ == "__main__":
540
545
  parser.add_argument("--focus", nargs="+")
541
546
  parser.add_argument("--session-id", type=str)
542
547
  parser.add_argument("--no-session", action="store_true")
543
- parser.add_argument("--format", default="text")
548
+ parser.add_argument("--format", default=OutputFormat.TEXT)
544
549
  parser.add_argument("--output", type=Path)
545
550
  parser.add_argument("--verbose", action="store_true")
546
551
 
@@ -37,6 +37,7 @@ except ImportError:
37
37
  RICH_AVAILABLE = False
38
38
  Console = None
39
39
 
40
+ from ...core.enums import OutputFormat
40
41
  from ...core.logging_config import get_logger
41
42
  from ...tools.code_tree_analyzer import CodeTreeAnalyzer
42
43
  from ...tools.code_tree_builder import CodeTreeBuilder
@@ -73,7 +74,11 @@ class AnalyzeCodeCommand(BaseCommand):
73
74
  return f"Path is not a directory: {path}"
74
75
 
75
76
  # Validate output format
76
- if args.output and args.output not in ("json", "tree", "stats"):
77
+ if args.output and str(args.output).lower() not in (
78
+ OutputFormat.JSON,
79
+ "tree",
80
+ "stats",
81
+ ):
77
82
  return f"Invalid output format: {args.output}"
78
83
 
79
84
  return None
@@ -123,7 +128,7 @@ class AnalyzeCodeCommand(BaseCommand):
123
128
  )
124
129
 
125
130
  # Handle output format
126
- if args.output == "json":
131
+ if str(args.output).lower() == OutputFormat.JSON:
127
132
  # Output JSON to stdout
128
133
  json.dump(analysis_result, sys.stdout, indent=2, default=str)
129
134
  sys.stdout.write("\n")
@@ -0,0 +1,570 @@
1
+ """
2
+ Auto-Configuration CLI Command for Claude MPM Framework
3
+ ========================================================
4
+
5
+ WHY: This module provides a user-friendly CLI interface for the auto-configuration
6
+ feature, allowing users to automatically configure agents based on detected toolchain.
7
+
8
+ DESIGN DECISION: Uses rich for beautiful terminal output, implements interactive
9
+ confirmation, and provides comprehensive error handling. Supports both interactive
10
+ and non-interactive modes for flexibility.
11
+
12
+ Part of TSK-0054: Auto-Configuration Feature - Phase 5
13
+ """
14
+
15
+ import json
16
+ from pathlib import Path
17
+ from typing import Optional
18
+
19
+ try:
20
+ from rich.console import Console
21
+ from rich.panel import Panel
22
+ from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
23
+ from rich.table import Table
24
+
25
+ RICH_AVAILABLE = True
26
+ except ImportError:
27
+ RICH_AVAILABLE = False
28
+
29
+ from ...core.enums import OperationResult
30
+ from ...services.agents.auto_config_manager import AutoConfigManagerService
31
+ from ...services.agents.observers import NullObserver
32
+ from ...services.core.models.agent_config import ConfigurationResult
33
+ from ..shared import BaseCommand, CommandResult
34
+
35
+
36
+ class RichProgressObserver(NullObserver):
37
+ """
38
+ Observer that displays deployment progress using Rich.
39
+
40
+ WHY: Extends NullObserver to inherit all required abstract method
41
+ implementations while overriding only the methods needed for
42
+ Rich console output.
43
+ """
44
+
45
+ def __init__(self, console: "Console"):
46
+ """Initialize the observer.
47
+
48
+ Args:
49
+ console: Rich console for output
50
+ """
51
+ self.console = console
52
+ self.progress = None
53
+ self.task_id = None
54
+
55
+ def on_agent_deployment_started(
56
+ self, agent_id: str, agent_name: str, index: int, total: int
57
+ ) -> None:
58
+ """Called when agent deployment starts."""
59
+ if not self.progress:
60
+ self.progress = Progress(
61
+ SpinnerColumn(),
62
+ TextColumn("[progress.description]{task.description}"),
63
+ BarColumn(),
64
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
65
+ console=self.console,
66
+ )
67
+ self.progress.start()
68
+
69
+ self.task_id = self.progress.add_task(f"Deploying {agent_name}...", total=100)
70
+
71
+ def on_agent_deployment_progress(
72
+ self, agent_id: str, progress: int, message: str = ""
73
+ ) -> None:
74
+ """Called when deployment makes progress."""
75
+ if self.progress and self.task_id is not None:
76
+ self.progress.update(self.task_id, completed=progress)
77
+
78
+ def on_agent_deployment_completed(
79
+ self, agent_id: str, agent_name: str, success: bool, error: str | None = None
80
+ ) -> None:
81
+ """Called when agent deployment completes."""
82
+ if self.progress and self.task_id is not None:
83
+ if success:
84
+ self.progress.update(self.task_id, completed=100)
85
+ self.console.print(f"āœ… {agent_name} deployed successfully")
86
+ else:
87
+ error_msg = f": {error}" if error else ""
88
+ self.console.print(f"āŒ {agent_name} deployment failed{error_msg}")
89
+
90
+ def on_deployment_completed(
91
+ self, success_count: int, failure_count: int, duration_ms: float
92
+ ) -> None:
93
+ """Called when all deployments complete."""
94
+ if self.progress:
95
+ self.progress.stop()
96
+
97
+
98
+ class AutoConfigureCommand(BaseCommand):
99
+ """
100
+ Handle auto-configuration CLI commands.
101
+
102
+ This command provides a user-friendly interface for automatically configuring
103
+ agents based on detected project toolchain.
104
+ """
105
+
106
+ def __init__(self):
107
+ """Initialize the auto-configure command."""
108
+ super().__init__("auto-configure")
109
+ self.console = Console() if RICH_AVAILABLE else None
110
+ self._auto_config_manager = None
111
+
112
+ @property
113
+ def auto_config_manager(self) -> AutoConfigManagerService:
114
+ """Get auto-configuration manager (lazy loaded)."""
115
+ if self._auto_config_manager is None:
116
+ from ...services.agents.auto_config_manager import (
117
+ AutoConfigManagerService,
118
+ )
119
+ from ...services.agents.recommender import AgentRecommenderService
120
+ from ...services.agents.registry import AgentRegistry
121
+ from ...services.project.toolchain_analyzer import (
122
+ ToolchainAnalyzerService,
123
+ )
124
+
125
+ # Initialize services with dependency injection
126
+ toolchain_analyzer = ToolchainAnalyzerService()
127
+ agent_registry = AgentRegistry()
128
+ agent_recommender = AgentRecommenderService()
129
+
130
+ # Get deployment service
131
+ try:
132
+ from ...services.agents.deployment import AgentDeploymentService
133
+
134
+ agent_deployment = AgentDeploymentService()
135
+ except ImportError:
136
+ agent_deployment = None
137
+
138
+ self._auto_config_manager = AutoConfigManagerService(
139
+ toolchain_analyzer=toolchain_analyzer,
140
+ agent_recommender=agent_recommender,
141
+ agent_registry=agent_registry,
142
+ agent_deployment=agent_deployment,
143
+ )
144
+
145
+ return self._auto_config_manager
146
+
147
+ def validate_args(self, args) -> Optional[str]:
148
+ """Validate command arguments."""
149
+ # Validate project path
150
+ project_path = (
151
+ Path(args.project_path)
152
+ if hasattr(args, "project_path") and args.project_path
153
+ else Path.cwd()
154
+ )
155
+ if not project_path.exists():
156
+ return f"Project path does not exist: {project_path}"
157
+
158
+ # Validate min_confidence range
159
+ if hasattr(args, "min_confidence") and args.min_confidence:
160
+ if not 0.0 <= args.min_confidence <= 1.0:
161
+ return "min_confidence must be between 0.0 and 1.0"
162
+
163
+ return None
164
+
165
+ def run(self, args) -> CommandResult:
166
+ """
167
+ Execute auto-configuration command.
168
+
169
+ Returns:
170
+ CommandResult with success status and exit code
171
+ """
172
+ try:
173
+ # Setup logging
174
+ self.setup_logging(args)
175
+
176
+ # Validate arguments
177
+ error = self.validate_args(args)
178
+ if error:
179
+ return CommandResult.error_result(error)
180
+
181
+ # Get configuration options
182
+ project_path = (
183
+ Path(args.project_path)
184
+ if hasattr(args, "project_path") and args.project_path
185
+ else Path.cwd()
186
+ )
187
+ min_confidence = (
188
+ args.min_confidence
189
+ if hasattr(args, "min_confidence") and args.min_confidence
190
+ else 0.8
191
+ )
192
+ dry_run = (
193
+ args.preview or args.dry_run if hasattr(args, "preview") else False
194
+ )
195
+ skip_confirmation = args.yes if hasattr(args, "yes") and args.yes else False
196
+ json_output = args.json if hasattr(args, "json") and args.json else False
197
+
198
+ # Run preview or full configuration
199
+ if dry_run or args.preview if hasattr(args, "preview") else False:
200
+ return self._run_preview(project_path, min_confidence, json_output)
201
+ return self._run_full_configuration(
202
+ project_path, min_confidence, skip_confirmation, json_output
203
+ )
204
+
205
+ except KeyboardInterrupt:
206
+ if self.console:
207
+ self.console.print("\n\nāŒ Operation cancelled by user")
208
+ else:
209
+ print("\n\nOperation cancelled by user")
210
+ return CommandResult.error_result("Operation cancelled", exit_code=130)
211
+
212
+ except Exception as e:
213
+ self.logger.exception("Auto-configuration failed")
214
+ error_msg = f"Auto-configuration failed: {e!s}"
215
+ if self.console:
216
+ self.console.print(f"\nāŒ {error_msg}")
217
+ else:
218
+ print(f"\n{error_msg}")
219
+ return CommandResult.error_result(error_msg)
220
+
221
+ def _run_preview(
222
+ self, project_path: Path, min_confidence: float, json_output: bool
223
+ ) -> CommandResult:
224
+ """Run configuration preview without deploying."""
225
+ # Show analysis spinner
226
+ if self.console and not json_output:
227
+ with self.console.status("[bold green]Analyzing project toolchain..."):
228
+ preview = self.auto_config_manager.preview_configuration(
229
+ project_path, min_confidence
230
+ )
231
+ else:
232
+ preview = self.auto_config_manager.preview_configuration(
233
+ project_path, min_confidence
234
+ )
235
+
236
+ # Output results
237
+ if json_output:
238
+ return self._output_preview_json(preview)
239
+ return self._display_preview(preview)
240
+
241
+ def _run_full_configuration(
242
+ self,
243
+ project_path: Path,
244
+ min_confidence: float,
245
+ skip_confirmation: bool,
246
+ json_output: bool,
247
+ ) -> CommandResult:
248
+ """Run full auto-configuration with deployment."""
249
+ # Get preview first
250
+ if self.console and not json_output:
251
+ with self.console.status("[bold green]Analyzing project toolchain..."):
252
+ preview = self.auto_config_manager.preview_configuration(
253
+ project_path, min_confidence
254
+ )
255
+ else:
256
+ preview = self.auto_config_manager.preview_configuration(
257
+ project_path, min_confidence
258
+ )
259
+
260
+ # Display preview (unless JSON output)
261
+ if not json_output:
262
+ self._display_preview(preview)
263
+
264
+ # Ask for confirmation (unless skipped)
265
+ if not skip_confirmation and not json_output:
266
+ if not self._confirm_deployment(preview):
267
+ if self.console:
268
+ self.console.print("\nāŒ Operation cancelled by user")
269
+ else:
270
+ print("\nOperation cancelled by user")
271
+ return CommandResult.error_result("Operation cancelled", exit_code=0)
272
+
273
+ # Execute configuration
274
+ import asyncio
275
+
276
+ observer = RichProgressObserver(self.console) if self.console else None
277
+ result = asyncio.run(
278
+ self.auto_config_manager.auto_configure(
279
+ project_path,
280
+ confirmation_required=False, # Already confirmed above
281
+ dry_run=False,
282
+ min_confidence=min_confidence,
283
+ observer=observer,
284
+ )
285
+ )
286
+
287
+ # Output results
288
+ if json_output:
289
+ return self._output_result_json(result)
290
+ return self._display_result(result)
291
+
292
+ def _display_preview(self, preview) -> CommandResult:
293
+ """Display configuration preview with Rich formatting."""
294
+ if not self.console:
295
+ # Fallback to plain text
296
+ return self._display_preview_plain(preview)
297
+
298
+ # Display detected toolchain
299
+ self.console.print("\nšŸ“Š Detected Toolchain:", style="bold blue")
300
+ if preview.detected_toolchain and preview.detected_toolchain.components:
301
+ toolchain_table = Table(show_header=True, header_style="bold")
302
+ toolchain_table.add_column("Component", style="cyan")
303
+ toolchain_table.add_column("Version", style="yellow")
304
+ toolchain_table.add_column("Confidence", style="green")
305
+
306
+ for component in preview.detected_toolchain.components:
307
+ confidence_pct = int(component.confidence * 100)
308
+ bar = "ā–ˆ" * (confidence_pct // 10) + "ā–‘" * (10 - confidence_pct // 10)
309
+ confidence_str = f"{bar} {confidence_pct}%"
310
+
311
+ toolchain_table.add_row(
312
+ (
313
+ component.type.value
314
+ if hasattr(component.type, "value")
315
+ else str(component.type)
316
+ ),
317
+ component.version or "Unknown",
318
+ confidence_str,
319
+ )
320
+
321
+ self.console.print(toolchain_table)
322
+ else:
323
+ self.console.print(" No toolchain detected", style="yellow")
324
+
325
+ # Display recommended agents
326
+ self.console.print("\nšŸ¤– Recommended Agents:", style="bold blue")
327
+ if preview.recommendations:
328
+ for rec in preview.recommendations:
329
+ confidence_pct = int(rec.confidence * 100)
330
+ icon = "āœ“" if rec.confidence >= 0.8 else "ā—‹"
331
+ self.console.print(
332
+ f" {icon} [bold]{rec.agent_id}[/bold] ({confidence_pct}% confidence)"
333
+ )
334
+ self.console.print(f" Reason: {rec.reasoning}", style="dim")
335
+ else:
336
+ self.console.print(" No agents recommended", style="yellow")
337
+
338
+ # Display validation issues
339
+ if preview.validation_result and preview.validation_result.issues:
340
+ self.console.print("\nāš ļø Validation Issues:", style="bold yellow")
341
+ for issue in preview.validation_result.issues:
342
+ severity_icon = {"error": "āŒ", "warning": "āš ļø", "info": "ā„¹ļø"}.get(
343
+ (
344
+ issue.severity.value
345
+ if hasattr(issue.severity, "value")
346
+ else str(issue.severity)
347
+ ),
348
+ "•",
349
+ )
350
+ self.console.print(f" {severity_icon} {issue.message}", style="yellow")
351
+
352
+ return CommandResult.success_result()
353
+
354
+ def _display_preview_plain(self, preview) -> CommandResult:
355
+ """Display preview in plain text (fallback when Rich not available)."""
356
+ print("\nDetected Toolchain:")
357
+ if preview.detected_toolchain and preview.detected_toolchain.components:
358
+ for component in preview.detected_toolchain.components:
359
+ confidence_pct = int(component.confidence * 100)
360
+ print(f" - {component.type}: {component.version} ({confidence_pct}%)")
361
+ else:
362
+ print(" No toolchain detected")
363
+
364
+ print("\nRecommended Agents:")
365
+ if preview.recommendations:
366
+ for rec in preview.recommendations:
367
+ confidence_pct = int(rec.confidence * 100)
368
+ print(f" - {rec.agent_id} ({confidence_pct}%)")
369
+ print(f" Reason: {rec.reasoning}")
370
+ else:
371
+ print(" No agents recommended")
372
+
373
+ if preview.validation_result and preview.validation_result.issues:
374
+ print("\nValidation Issues:")
375
+ for issue in preview.validation_result.issues:
376
+ print(f" - {issue.severity}: {issue.message}")
377
+
378
+ return CommandResult.success_result()
379
+
380
+ def _confirm_deployment(self, preview) -> bool:
381
+ """Ask user to confirm deployment."""
382
+ if not preview.recommendations:
383
+ return False
384
+
385
+ if self.console:
386
+ self.console.print("\n" + "=" * 60)
387
+ self.console.print("Deploy these agents?", style="bold yellow")
388
+ self.console.print("=" * 60)
389
+ response = (
390
+ self.console.input("\n[bold]Proceed? (y/n/s for select):[/bold] ")
391
+ .strip()
392
+ .lower()
393
+ )
394
+ else:
395
+ print("\n" + "=" * 60)
396
+ print("Deploy these agents?")
397
+ print("=" * 60)
398
+ response = input("\nProceed? (y/n/s for select): ").strip().lower()
399
+
400
+ if response in ["y", "yes"]:
401
+ return True
402
+ if response in ["s", "select"]:
403
+ # TODO: Implement interactive selection
404
+ if self.console:
405
+ self.console.print(
406
+ "\nāš ļø Interactive selection not yet implemented",
407
+ style="yellow",
408
+ )
409
+ else:
410
+ print("\nInteractive selection not yet implemented")
411
+ return False
412
+ return False
413
+
414
+ def _display_result(self, result: ConfigurationResult) -> CommandResult:
415
+ """Display configuration result."""
416
+ if not self.console:
417
+ return self._display_result_plain(result)
418
+
419
+ # Display summary
420
+ if result.status == OperationResult.SUCCESS:
421
+ panel = Panel(
422
+ f"āœ… Auto-configuration completed successfully!\n\n"
423
+ f"Deployed {len(result.deployed_agents)} agent(s)",
424
+ title="Success",
425
+ border_style="green",
426
+ )
427
+ self.console.print(panel)
428
+
429
+ # Show deployed agents
430
+ if result.deployed_agents:
431
+ self.console.print("\nšŸ“¦ Deployed Agents:", style="bold green")
432
+ for agent_id in result.deployed_agents:
433
+ self.console.print(f" āœ“ {agent_id}")
434
+
435
+ return CommandResult.success_result()
436
+
437
+ if result.status == OperationResult.WARNING:
438
+ panel = Panel(
439
+ f"āš ļø Auto-configuration partially completed\n\n"
440
+ f"Deployed: {len(result.deployed_agents)}\n"
441
+ f"Failed: {len(result.failed_agents)}",
442
+ title="Partial Success",
443
+ border_style="yellow",
444
+ )
445
+ self.console.print(panel)
446
+
447
+ if result.failed_agents:
448
+ self.console.print("\nāŒ Failed Agents:", style="bold red")
449
+ for agent_id in result.failed_agents:
450
+ error = result.errors.get(agent_id, "Unknown error")
451
+ self.console.print(f" āœ— {agent_id}: {error}")
452
+
453
+ return CommandResult.error_result("Partial configuration", exit_code=1)
454
+
455
+ panel = Panel(
456
+ f"āŒ Auto-configuration failed\n\n{result.errors.get('general', 'Unknown error')}",
457
+ title="Error",
458
+ border_style="red",
459
+ )
460
+ self.console.print(panel)
461
+
462
+ return CommandResult.error_result("Configuration failed", exit_code=1)
463
+
464
+ def _display_result_plain(self, result: ConfigurationResult) -> CommandResult:
465
+ """Display result in plain text (fallback)."""
466
+ if result.status == OperationResult.SUCCESS:
467
+ print("\nāœ… Auto-configuration completed successfully!")
468
+ print(f"Deployed {len(result.deployed_agents)} agent(s)")
469
+
470
+ if result.deployed_agents:
471
+ print("\nDeployed Agents:")
472
+ for agent_id in result.deployed_agents:
473
+ print(f" - {agent_id}")
474
+
475
+ return CommandResult.success_result()
476
+
477
+ if result.status == OperationResult.WARNING:
478
+ print("\nāš ļø Auto-configuration partially completed")
479
+ print(f"Deployed: {len(result.deployed_agents)}")
480
+ print(f"Failed: {len(result.failed_agents)}")
481
+
482
+ if result.failed_agents:
483
+ print("\nFailed Agents:")
484
+ for agent_id in result.failed_agents:
485
+ error = result.errors.get(agent_id, "Unknown error")
486
+ print(f" - {agent_id}: {error}")
487
+
488
+ return CommandResult.error_result("Partial configuration", exit_code=1)
489
+
490
+ print("\nāŒ Auto-configuration failed")
491
+ print(result.errors.get("general", "Unknown error"))
492
+
493
+ return CommandResult.error_result("Configuration failed", exit_code=1)
494
+
495
+ def _output_preview_json(self, preview) -> CommandResult:
496
+ """Output preview as JSON."""
497
+ output = {
498
+ "detected_toolchain": {
499
+ "components": (
500
+ [
501
+ {
502
+ "type": (
503
+ c.type.value
504
+ if hasattr(c.type, "value")
505
+ else str(c.type)
506
+ ),
507
+ "version": c.version,
508
+ "confidence": c.confidence,
509
+ }
510
+ for c in preview.detected_toolchain.components
511
+ ]
512
+ if preview.detected_toolchain
513
+ else []
514
+ )
515
+ },
516
+ "recommendations": [
517
+ {
518
+ "agent_id": r.agent_id,
519
+ "confidence": r.confidence,
520
+ "reasoning": r.reasoning,
521
+ }
522
+ for r in preview.recommendations
523
+ ],
524
+ "validation": {
525
+ "is_valid": (
526
+ preview.validation_result.is_valid
527
+ if preview.validation_result
528
+ else True
529
+ ),
530
+ "issues": (
531
+ [
532
+ {
533
+ "severity": (
534
+ i.severity.value
535
+ if hasattr(i.severity, "value")
536
+ else str(i.severity)
537
+ ),
538
+ "message": i.message,
539
+ }
540
+ for i in preview.validation_result.issues
541
+ ]
542
+ if preview.validation_result
543
+ else []
544
+ ),
545
+ },
546
+ }
547
+
548
+ print(json.dumps(output, indent=2))
549
+ return CommandResult.success_result(data=output)
550
+
551
+ def _output_result_json(self, result: ConfigurationResult) -> CommandResult:
552
+ """Output result as JSON."""
553
+ output = {
554
+ "status": (
555
+ result.status.value
556
+ if hasattr(result.status, "value")
557
+ else str(result.status)
558
+ ),
559
+ "deployed_agents": result.deployed_agents,
560
+ "failed_agents": result.failed_agents,
561
+ "errors": result.errors,
562
+ }
563
+
564
+ print(json.dumps(output, indent=2))
565
+
566
+ if result.status == OperationResult.SUCCESS:
567
+ return CommandResult.success_result(data=output)
568
+ return CommandResult.error_result(
569
+ "Configuration failed or partial", exit_code=1, data=output
570
+ )