claude-mpm 4.1.1__py3-none-any.whl → 4.1.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 (357) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/__main__.py +1 -1
  4. claude_mpm/agents/BASE_PM.md +74 -46
  5. claude_mpm/agents/INSTRUCTIONS.md +11 -153
  6. claude_mpm/agents/WORKFLOW.md +61 -321
  7. claude_mpm/agents/__init__.py +11 -11
  8. claude_mpm/agents/agent_loader.py +23 -20
  9. claude_mpm/agents/agent_loader_integration.py +1 -1
  10. claude_mpm/agents/agents_metadata.py +27 -0
  11. claude_mpm/agents/async_agent_loader.py +5 -8
  12. claude_mpm/agents/base_agent_loader.py +36 -25
  13. claude_mpm/agents/frontmatter_validator.py +6 -6
  14. claude_mpm/agents/schema/agent_schema.json +1 -1
  15. claude_mpm/agents/system_agent_config.py +9 -9
  16. claude_mpm/agents/templates/api_qa.json +47 -2
  17. claude_mpm/agents/templates/imagemagick.json +256 -0
  18. claude_mpm/agents/templates/qa.json +41 -2
  19. claude_mpm/agents/templates/ticketing.json +5 -5
  20. claude_mpm/agents/templates/web_qa.json +50 -2
  21. claude_mpm/cli/__init__.py +51 -46
  22. claude_mpm/cli/__main__.py +1 -1
  23. claude_mpm/cli/commands/__init__.py +10 -12
  24. claude_mpm/cli/commands/agent_manager.py +186 -181
  25. claude_mpm/cli/commands/agents.py +271 -268
  26. claude_mpm/cli/commands/aggregate.py +30 -29
  27. claude_mpm/cli/commands/cleanup.py +50 -44
  28. claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
  29. claude_mpm/cli/commands/config.py +162 -127
  30. claude_mpm/cli/commands/doctor.py +52 -62
  31. claude_mpm/cli/commands/info.py +37 -25
  32. claude_mpm/cli/commands/mcp.py +3 -7
  33. claude_mpm/cli/commands/mcp_command_router.py +14 -18
  34. claude_mpm/cli/commands/mcp_install_commands.py +28 -23
  35. claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
  36. claude_mpm/cli/commands/mcp_server_commands.py +23 -17
  37. claude_mpm/cli/commands/memory.py +192 -141
  38. claude_mpm/cli/commands/monitor.py +117 -88
  39. claude_mpm/cli/commands/run.py +120 -84
  40. claude_mpm/cli/commands/run_config_checker.py +4 -5
  41. claude_mpm/cli/commands/socketio_monitor.py +17 -19
  42. claude_mpm/cli/commands/tickets.py +92 -92
  43. claude_mpm/cli/parser.py +1 -5
  44. claude_mpm/cli/parsers/__init__.py +1 -1
  45. claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
  46. claude_mpm/cli/parsers/agents_parser.py +2 -3
  47. claude_mpm/cli/parsers/base_parser.py +7 -5
  48. claude_mpm/cli/parsers/mcp_parser.py +4 -2
  49. claude_mpm/cli/parsers/monitor_parser.py +26 -18
  50. claude_mpm/cli/shared/__init__.py +10 -10
  51. claude_mpm/cli/shared/argument_patterns.py +57 -71
  52. claude_mpm/cli/shared/base_command.py +61 -53
  53. claude_mpm/cli/shared/error_handling.py +62 -58
  54. claude_mpm/cli/shared/output_formatters.py +78 -77
  55. claude_mpm/cli/startup_logging.py +204 -172
  56. claude_mpm/cli/utils.py +10 -11
  57. claude_mpm/cli_module/__init__.py +1 -1
  58. claude_mpm/cli_module/args.py +1 -1
  59. claude_mpm/cli_module/migration_example.py +5 -5
  60. claude_mpm/config/__init__.py +9 -9
  61. claude_mpm/config/agent_config.py +15 -14
  62. claude_mpm/config/experimental_features.py +4 -4
  63. claude_mpm/config/paths.py +0 -1
  64. claude_mpm/config/socketio_config.py +5 -6
  65. claude_mpm/constants.py +1 -2
  66. claude_mpm/core/__init__.py +8 -8
  67. claude_mpm/core/agent_name_normalizer.py +1 -1
  68. claude_mpm/core/agent_registry.py +20 -23
  69. claude_mpm/core/agent_session_manager.py +3 -3
  70. claude_mpm/core/base_service.py +7 -15
  71. claude_mpm/core/cache.py +4 -6
  72. claude_mpm/core/claude_runner.py +85 -113
  73. claude_mpm/core/config.py +43 -28
  74. claude_mpm/core/config_aliases.py +0 -9
  75. claude_mpm/core/config_constants.py +52 -30
  76. claude_mpm/core/constants.py +0 -1
  77. claude_mpm/core/container.py +18 -27
  78. claude_mpm/core/exceptions.py +2 -2
  79. claude_mpm/core/factories.py +10 -12
  80. claude_mpm/core/framework_loader.py +581 -280
  81. claude_mpm/core/hook_manager.py +26 -22
  82. claude_mpm/core/hook_performance_config.py +58 -47
  83. claude_mpm/core/injectable_service.py +1 -1
  84. claude_mpm/core/interactive_session.py +61 -152
  85. claude_mpm/core/interfaces.py +1 -100
  86. claude_mpm/core/lazy.py +5 -5
  87. claude_mpm/core/log_manager.py +587 -0
  88. claude_mpm/core/logger.py +125 -8
  89. claude_mpm/core/logging_config.py +15 -15
  90. claude_mpm/core/minimal_framework_loader.py +5 -8
  91. claude_mpm/core/oneshot_session.py +15 -33
  92. claude_mpm/core/optimized_agent_loader.py +4 -6
  93. claude_mpm/core/optimized_startup.py +2 -1
  94. claude_mpm/core/output_style_manager.py +147 -106
  95. claude_mpm/core/pm_hook_interceptor.py +0 -1
  96. claude_mpm/core/service_registry.py +11 -8
  97. claude_mpm/core/session_manager.py +1 -2
  98. claude_mpm/core/shared/__init__.py +1 -1
  99. claude_mpm/core/shared/config_loader.py +101 -97
  100. claude_mpm/core/shared/path_resolver.py +72 -68
  101. claude_mpm/core/shared/singleton_manager.py +56 -50
  102. claude_mpm/core/socketio_pool.py +26 -6
  103. claude_mpm/core/tool_access_control.py +4 -5
  104. claude_mpm/core/typing_utils.py +50 -59
  105. claude_mpm/core/unified_agent_registry.py +14 -19
  106. claude_mpm/core/unified_config.py +4 -6
  107. claude_mpm/core/unified_paths.py +197 -109
  108. claude_mpm/dashboard/open_dashboard.py +2 -4
  109. claude_mpm/experimental/cli_enhancements.py +51 -36
  110. claude_mpm/generators/agent_profile_generator.py +2 -4
  111. claude_mpm/hooks/base_hook.py +1 -2
  112. claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
  113. claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
  114. claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
  115. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
  116. claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
  117. claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
  118. claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
  119. claude_mpm/hooks/memory_integration_hook.py +5 -5
  120. claude_mpm/hooks/tool_call_interceptor.py +1 -1
  121. claude_mpm/hooks/validation_hooks.py +4 -4
  122. claude_mpm/init.py +4 -9
  123. claude_mpm/models/__init__.py +2 -2
  124. claude_mpm/models/agent_session.py +11 -14
  125. claude_mpm/scripts/mcp_server.py +20 -11
  126. claude_mpm/scripts/mcp_wrapper.py +5 -5
  127. claude_mpm/scripts/mpm_doctor.py +321 -0
  128. claude_mpm/scripts/socketio_daemon.py +28 -25
  129. claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
  130. claude_mpm/scripts/socketio_server_manager.py +116 -95
  131. claude_mpm/services/__init__.py +49 -49
  132. claude_mpm/services/agent_capabilities_service.py +12 -18
  133. claude_mpm/services/agents/__init__.py +22 -22
  134. claude_mpm/services/agents/agent_builder.py +140 -119
  135. claude_mpm/services/agents/deployment/__init__.py +3 -3
  136. claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
  137. claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
  138. claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
  139. claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
  140. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
  141. claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
  142. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
  143. claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
  144. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
  145. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
  146. claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
  147. claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
  148. claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
  149. claude_mpm/services/agents/deployment/agent_validator.py +0 -1
  150. claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
  151. claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
  152. claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
  153. claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
  154. claude_mpm/services/agents/deployment/config/__init__.py +1 -1
  155. claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
  156. claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
  157. claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
  158. claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
  159. claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
  160. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
  161. claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
  162. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
  163. claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
  164. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
  165. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
  166. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
  167. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
  168. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
  169. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
  170. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
  171. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
  172. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
  173. claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
  174. claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
  175. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
  176. claude_mpm/services/agents/deployment/results/__init__.py +1 -1
  177. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
  178. claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
  179. claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
  180. claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
  181. claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
  182. claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
  183. claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
  184. claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
  185. claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
  186. claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
  187. claude_mpm/services/agents/loading/__init__.py +1 -1
  188. claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
  189. claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
  190. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
  191. claude_mpm/services/agents/management/__init__.py +1 -1
  192. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
  193. claude_mpm/services/agents/management/agent_management_service.py +5 -9
  194. claude_mpm/services/agents/memory/__init__.py +4 -4
  195. claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
  196. claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
  197. claude_mpm/services/agents/memory/content_manager.py +44 -38
  198. claude_mpm/services/agents/memory/template_generator.py +4 -6
  199. claude_mpm/services/agents/registry/__init__.py +10 -6
  200. claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
  201. claude_mpm/services/agents/registry/modification_tracker.py +3 -6
  202. claude_mpm/services/async_session_logger.py +1 -2
  203. claude_mpm/services/claude_session_logger.py +1 -2
  204. claude_mpm/services/command_deployment_service.py +173 -0
  205. claude_mpm/services/command_handler_service.py +20 -22
  206. claude_mpm/services/core/__init__.py +25 -25
  207. claude_mpm/services/core/base.py +0 -5
  208. claude_mpm/services/core/interfaces/__init__.py +32 -32
  209. claude_mpm/services/core/interfaces/agent.py +0 -21
  210. claude_mpm/services/core/interfaces/communication.py +0 -27
  211. claude_mpm/services/core/interfaces/infrastructure.py +0 -56
  212. claude_mpm/services/core/interfaces/service.py +0 -29
  213. claude_mpm/services/diagnostics/__init__.py +1 -1
  214. claude_mpm/services/diagnostics/checks/__init__.py +6 -6
  215. claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
  216. claude_mpm/services/diagnostics/checks/base_check.py +12 -16
  217. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
  218. claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
  219. claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
  220. claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
  221. claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
  222. claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
  223. claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
  224. claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
  225. claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
  226. claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
  227. claude_mpm/services/diagnostics/models.py +21 -19
  228. claude_mpm/services/event_aggregator.py +10 -17
  229. claude_mpm/services/event_bus/__init__.py +1 -1
  230. claude_mpm/services/event_bus/config.py +54 -35
  231. claude_mpm/services/event_bus/event_bus.py +76 -71
  232. claude_mpm/services/event_bus/relay.py +74 -64
  233. claude_mpm/services/events/__init__.py +11 -11
  234. claude_mpm/services/events/consumers/__init__.py +3 -3
  235. claude_mpm/services/events/consumers/dead_letter.py +71 -63
  236. claude_mpm/services/events/consumers/logging.py +39 -37
  237. claude_mpm/services/events/consumers/metrics.py +56 -57
  238. claude_mpm/services/events/consumers/socketio.py +82 -81
  239. claude_mpm/services/events/core.py +110 -99
  240. claude_mpm/services/events/interfaces.py +56 -72
  241. claude_mpm/services/events/producers/__init__.py +1 -1
  242. claude_mpm/services/events/producers/hook.py +38 -38
  243. claude_mpm/services/events/producers/system.py +46 -44
  244. claude_mpm/services/exceptions.py +81 -80
  245. claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
  246. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
  247. claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
  248. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
  249. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
  250. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
  251. claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
  252. claude_mpm/services/hook_service.py +6 -9
  253. claude_mpm/services/infrastructure/__init__.py +1 -1
  254. claude_mpm/services/infrastructure/context_preservation.py +8 -12
  255. claude_mpm/services/infrastructure/monitoring.py +21 -23
  256. claude_mpm/services/mcp_gateway/__init__.py +37 -37
  257. claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
  258. claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
  259. claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
  260. claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
  261. claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
  262. claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
  263. claude_mpm/services/mcp_gateway/core/base.py +0 -3
  264. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
  265. claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
  266. claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
  267. claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
  268. claude_mpm/services/mcp_gateway/main.py +2 -1
  269. claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
  270. claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
  271. claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
  272. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
  273. claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
  274. claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
  275. claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
  276. claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
  277. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
  278. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
  279. claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
  280. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
  281. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
  282. claude_mpm/services/memory/__init__.py +3 -3
  283. claude_mpm/services/memory/builder.py +3 -6
  284. claude_mpm/services/memory/cache/__init__.py +1 -1
  285. claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
  286. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  287. claude_mpm/services/memory/indexed_memory.py +5 -7
  288. claude_mpm/services/memory/optimizer.py +7 -10
  289. claude_mpm/services/memory/router.py +8 -9
  290. claude_mpm/services/memory_hook_service.py +48 -34
  291. claude_mpm/services/monitor_build_service.py +77 -73
  292. claude_mpm/services/port_manager.py +130 -108
  293. claude_mpm/services/project/analyzer.py +12 -10
  294. claude_mpm/services/project/registry.py +11 -11
  295. claude_mpm/services/recovery_manager.py +10 -19
  296. claude_mpm/services/response_tracker.py +0 -1
  297. claude_mpm/services/runner_configuration_service.py +19 -20
  298. claude_mpm/services/session_management_service.py +7 -11
  299. claude_mpm/services/shared/__init__.py +1 -1
  300. claude_mpm/services/shared/async_service_base.py +58 -50
  301. claude_mpm/services/shared/config_service_base.py +73 -67
  302. claude_mpm/services/shared/lifecycle_service_base.py +82 -78
  303. claude_mpm/services/shared/manager_base.py +94 -82
  304. claude_mpm/services/shared/service_factory.py +96 -98
  305. claude_mpm/services/socketio/__init__.py +3 -3
  306. claude_mpm/services/socketio/client_proxy.py +5 -5
  307. claude_mpm/services/socketio/event_normalizer.py +199 -181
  308. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  309. claude_mpm/services/socketio/handlers/base.py +5 -4
  310. claude_mpm/services/socketio/handlers/connection.py +163 -136
  311. claude_mpm/services/socketio/handlers/file.py +13 -14
  312. claude_mpm/services/socketio/handlers/git.py +12 -7
  313. claude_mpm/services/socketio/handlers/hook.py +49 -44
  314. claude_mpm/services/socketio/handlers/memory.py +0 -1
  315. claude_mpm/services/socketio/handlers/project.py +0 -1
  316. claude_mpm/services/socketio/handlers/registry.py +37 -19
  317. claude_mpm/services/socketio/migration_utils.py +98 -84
  318. claude_mpm/services/socketio/server/__init__.py +1 -1
  319. claude_mpm/services/socketio/server/broadcaster.py +81 -87
  320. claude_mpm/services/socketio/server/core.py +65 -54
  321. claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
  322. claude_mpm/services/socketio/server/main.py +64 -38
  323. claude_mpm/services/socketio_client_manager.py +10 -12
  324. claude_mpm/services/subprocess_launcher_service.py +4 -7
  325. claude_mpm/services/system_instructions_service.py +13 -14
  326. claude_mpm/services/ticket_manager.py +2 -2
  327. claude_mpm/services/utility_service.py +5 -13
  328. claude_mpm/services/version_control/__init__.py +16 -16
  329. claude_mpm/services/version_control/branch_strategy.py +5 -8
  330. claude_mpm/services/version_control/conflict_resolution.py +9 -23
  331. claude_mpm/services/version_control/git_operations.py +5 -7
  332. claude_mpm/services/version_control/semantic_versioning.py +16 -17
  333. claude_mpm/services/version_control/version_parser.py +13 -18
  334. claude_mpm/services/version_service.py +10 -11
  335. claude_mpm/storage/__init__.py +1 -1
  336. claude_mpm/storage/state_storage.py +22 -28
  337. claude_mpm/utils/__init__.py +6 -6
  338. claude_mpm/utils/agent_dependency_loader.py +47 -33
  339. claude_mpm/utils/config_manager.py +11 -14
  340. claude_mpm/utils/dependency_cache.py +1 -1
  341. claude_mpm/utils/dependency_manager.py +13 -17
  342. claude_mpm/utils/dependency_strategies.py +8 -10
  343. claude_mpm/utils/environment_context.py +3 -9
  344. claude_mpm/utils/error_handler.py +3 -13
  345. claude_mpm/utils/file_utils.py +1 -1
  346. claude_mpm/utils/path_operations.py +8 -12
  347. claude_mpm/utils/robust_installer.py +110 -33
  348. claude_mpm/utils/subprocess_utils.py +5 -6
  349. claude_mpm/validation/agent_validator.py +3 -6
  350. claude_mpm/validation/frontmatter_validator.py +1 -1
  351. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
  352. claude_mpm-4.1.2.dist-info/RECORD +498 -0
  353. claude_mpm-4.1.1.dist-info/RECORD +0 -494
  354. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
  355. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
  356. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
  357. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
@@ -65,12 +65,10 @@ class AgentPersistenceService:
65
65
  async def start(self) -> None:
66
66
  """Start the persistence service."""
67
67
  # No-op for stub
68
- pass
69
68
 
70
69
  async def stop(self) -> None:
71
70
  """Stop the persistence service."""
72
71
  # No-op for stub
73
- pass
74
72
 
75
73
  async def persist_agent(
76
74
  self,
@@ -67,7 +67,7 @@ class MemoryContentManager:
67
67
  item_indices.append(i)
68
68
  existing_item = line.strip()[2:] # Remove "- " prefix
69
69
  similarity = self._calculate_similarity(existing_item, new_item)
70
-
70
+
71
71
  # If highly similar (>80%), mark for removal
72
72
  if similarity > 0.8:
73
73
  items_to_remove.append(i)
@@ -99,7 +99,7 @@ class MemoryContentManager:
99
99
  if lines[i].strip():
100
100
  insert_point = i + 1
101
101
  break
102
-
102
+
103
103
  lines.insert(insert_point, f"- {new_item}")
104
104
 
105
105
  # Update timestamp
@@ -108,12 +108,12 @@ class MemoryContentManager:
108
108
 
109
109
  def add_item_to_section(self, content: str, section: str, new_item: str) -> str:
110
110
  """Legacy method for backward compatibility - delegates to add_item_to_list.
111
-
111
+
112
112
  Args:
113
113
  content: Current memory file content
114
114
  section: Section name (ignored in simple list format)
115
115
  new_item: Item to add
116
-
116
+
117
117
  Returns:
118
118
  str: Updated content with new item added
119
119
  """
@@ -172,12 +172,12 @@ class MemoryContentManager:
172
172
  # Also check max_items limit
173
173
  max_items = limits.get("max_items", 100)
174
174
  item_count = sum(1 for line in lines if line.strip().startswith("- "))
175
-
175
+
176
176
  if item_count > max_items:
177
177
  # Remove oldest items to fit within max_items
178
178
  items_removed = 0
179
179
  target_removals = item_count - max_items
180
-
180
+
181
181
  i = 0
182
182
  while i < len(lines) and items_removed < target_removals:
183
183
  if lines[i].strip().startswith("- "):
@@ -187,7 +187,7 @@ class MemoryContentManager:
187
187
  i += 1
188
188
 
189
189
  return "\n".join(lines)
190
-
190
+
191
191
  def truncate_to_limits(
192
192
  self, content: str, agent_limits: Optional[Dict[str, Any]] = None
193
193
  ) -> str:
@@ -211,12 +211,11 @@ class MemoryContentManager:
211
211
  content,
212
212
  )
213
213
  # Also handle legacy format
214
- content = re.sub(
214
+ return re.sub(
215
215
  r"<!-- Last Updated: .+ \| Auto-updated by: .+ -->",
216
216
  f"<!-- Last Updated: {timestamp} -->",
217
217
  content,
218
218
  )
219
- return content
220
219
 
221
220
  def validate_and_repair(self, content: str, agent_id: str) -> str:
222
221
  """Validate memory file and repair if needed.
@@ -232,22 +231,23 @@ class MemoryContentManager:
232
231
  str: Validated and repaired content
233
232
  """
234
233
  lines = content.split("\n")
235
-
234
+
236
235
  # Ensure proper header format
237
236
  has_header = False
238
237
  has_timestamp = False
239
-
240
- for i, line in enumerate(lines[:5]): # Check first 5 lines
238
+
239
+ for _i, line in enumerate(lines[:5]): # Check first 5 lines
241
240
  if line.startswith("# Agent Memory:"):
242
241
  has_header = True
243
242
  elif line.startswith("<!-- Last Updated:"):
244
243
  has_timestamp = True
245
-
244
+
246
245
  # Add missing header or timestamp
247
246
  if not has_header or not has_timestamp:
248
247
  from datetime import datetime
248
+
249
249
  new_lines = []
250
-
250
+
251
251
  if not has_header:
252
252
  new_lines.append(f"# Agent Memory: {agent_id}")
253
253
  else:
@@ -257,9 +257,11 @@ class MemoryContentManager:
257
257
  new_lines.append(line)
258
258
  lines.remove(line)
259
259
  break
260
-
260
+
261
261
  if not has_timestamp:
262
- new_lines.append(f"<!-- Last Updated: {datetime.now().isoformat()}Z -->")
262
+ new_lines.append(
263
+ f"<!-- Last Updated: {datetime.now().isoformat()}Z -->"
264
+ )
263
265
  new_lines.append("")
264
266
  else:
265
267
  # Keep existing timestamp
@@ -268,14 +270,16 @@ class MemoryContentManager:
268
270
  new_lines.append(line)
269
271
  lines.remove(line)
270
272
  break
271
-
273
+
272
274
  # Add remaining content
273
275
  for line in lines:
274
- if not line.startswith("# ") and not line.startswith("<!-- Last Updated:"):
276
+ if not line.startswith("# ") and not line.startswith(
277
+ "<!-- Last Updated:"
278
+ ):
275
279
  new_lines.append(line)
276
-
280
+
277
281
  return "\n".join(new_lines)
278
-
282
+
279
283
  return "\n".join(lines)
280
284
 
281
285
  def parse_memory_content_to_list(self, content: str) -> List[str]:
@@ -296,7 +300,7 @@ class MemoryContentManager:
296
300
  line = line.strip()
297
301
 
298
302
  # Skip empty lines, headers, and metadata
299
- if not line or line.startswith("#") or line.startswith("<!--"):
303
+ if not line or line.startswith(("#", "<!--")):
300
304
  continue
301
305
 
302
306
  if line.startswith("- "):
@@ -306,15 +310,15 @@ class MemoryContentManager:
306
310
  items.append(item)
307
311
 
308
312
  return items
309
-
313
+
310
314
  def parse_memory_content_to_dict(self, content: str) -> Dict[str, List[str]]:
311
315
  """Legacy method for backward compatibility.
312
-
316
+
313
317
  Returns a dict with single key 'memories' containing all items.
314
-
318
+
315
319
  Args:
316
320
  content: Raw memory file content
317
-
321
+
318
322
  Returns:
319
323
  Dict with 'memories' key mapping to list of items
320
324
  """
@@ -344,23 +348,23 @@ class MemoryContentManager:
344
348
  # Normalize strings for comparison
345
349
  str1_normalized = str1.lower().strip()
346
350
  str2_normalized = str2.lower().strip()
347
-
351
+
348
352
  # Handle exact matches quickly
349
353
  if str1_normalized == str2_normalized:
350
354
  return 1.0
351
-
355
+
352
356
  # Use SequenceMatcher for fuzzy matching
353
357
  # None as first param tells it to use automatic junk heuristic
354
358
  matcher = SequenceMatcher(None, str1_normalized, str2_normalized)
355
359
  similarity = matcher.ratio()
356
-
360
+
357
361
  # Additional check: if one string contains the other (substring match)
358
362
  # This catches cases where one item is a more detailed version of another
359
363
  if len(str1_normalized) > 20 and len(str2_normalized) > 20:
360
364
  if str1_normalized in str2_normalized or str2_normalized in str1_normalized:
361
365
  # Boost similarity for substring matches
362
366
  similarity = max(similarity, 0.85)
363
-
367
+
364
368
  return similarity
365
369
 
366
370
  def deduplicate_list(self, content: str) -> Tuple[str, int]:
@@ -377,7 +381,7 @@ class MemoryContentManager:
377
381
  Tuple of (updated content, number of items removed)
378
382
  """
379
383
  lines = content.split("\n")
380
-
384
+
381
385
  # Collect all items in the list
382
386
  items = []
383
387
  item_indices = []
@@ -385,7 +389,7 @@ class MemoryContentManager:
385
389
  if line.strip().startswith("- "):
386
390
  items.append(line.strip()[2:]) # Remove "- " prefix
387
391
  item_indices.append(i)
388
-
392
+
389
393
  # Find duplicates using pairwise comparison
390
394
  duplicates_to_remove = set()
391
395
  for i in range(len(items)):
@@ -403,21 +407,21 @@ class MemoryContentManager:
403
407
  f"(keeping newer: '{items[j][:50]}...')"
404
408
  )
405
409
  break # Move to next item
406
-
410
+
407
411
  # Remove duplicates (in reverse order to maintain indices)
408
412
  removed_count = len(duplicates_to_remove)
409
413
  for idx in sorted(duplicates_to_remove, reverse=True):
410
414
  lines.pop(item_indices[idx])
411
-
415
+
412
416
  return "\n".join(lines), removed_count
413
-
417
+
414
418
  def deduplicate_section(self, content: str, section: str) -> Tuple[str, int]:
415
419
  """Legacy method for backward compatibility - delegates to deduplicate_list.
416
-
420
+
417
421
  Args:
418
422
  content: Current memory file content
419
423
  section: Section name (ignored in simple list format)
420
-
424
+
421
425
  Returns:
422
426
  Tuple of (updated content, number of items removed)
423
427
  """
@@ -444,7 +448,9 @@ class MemoryContentManager:
444
448
  )
445
449
 
446
450
  # Check item count
447
- items = sum(1 for line in content.split("\n") if line.strip().startswith("- "))
451
+ items = sum(
452
+ 1 for line in content.split("\n") if line.strip().startswith("- ")
453
+ )
448
454
  max_items = self.memory_limits.get("max_items", 100)
449
455
 
450
456
  if items > max_items:
@@ -453,4 +459,4 @@ class MemoryContentManager:
453
459
  return True, None
454
460
 
455
461
  except Exception as e:
456
- return False, f"Validation error: {str(e)}"
462
+ return False, f"Validation error: {e!s}"
@@ -15,7 +15,7 @@ This module provides:
15
15
  import logging
16
16
  from datetime import datetime
17
17
  from pathlib import Path
18
- from typing import Any, Dict, List
18
+ from typing import Any, Dict
19
19
 
20
20
  from claude_mpm.core.config import Config
21
21
 
@@ -35,9 +35,7 @@ class MemoryTemplateGenerator:
35
35
  "Current Technical Context",
36
36
  ]
37
37
 
38
- def __init__(
39
- self, config: Config, working_directory: Path
40
- ):
38
+ def __init__(self, config: Config, working_directory: Path):
41
39
  """Initialize the template generator.
42
40
 
43
41
  Args:
@@ -59,8 +57,8 @@ class MemoryTemplateGenerator:
59
57
  str: The basic memory template content
60
58
  """
61
59
  # Convert agent_id to proper name, handling cases like "test_agent" -> "Test"
62
- agent_name = agent_id.replace("_agent", "").replace("_", " ").title()
63
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
60
+ agent_id.replace("_agent", "").replace("_", " ").title()
61
+ datetime.now().strftime("%Y-%m-%d %H:%M:%S")
64
62
 
65
63
  # Create a simple template that agents will populate through learning
66
64
  return self._create_basic_memory_template(agent_id, limits)
@@ -1,6 +1,10 @@
1
1
  """Agent registry services for discovery and tracking."""
2
2
 
3
- from claude_mpm.core.unified_agent_registry import AgentMetadata, AgentTier, AgentType
3
+ from claude_mpm.core.unified_agent_registry import (
4
+ AgentMetadata,
5
+ AgentTier,
6
+ AgentType,
7
+ )
4
8
  from claude_mpm.core.unified_agent_registry import UnifiedAgentRegistry as AgentRegistry
5
9
 
6
10
  from .deployed_agent_discovery import DeployedAgentDiscovery
@@ -13,14 +17,14 @@ from .modification_tracker import (
13
17
  )
14
18
 
15
19
  __all__ = [
16
- "AgentRegistry",
17
20
  "AgentMetadata",
21
+ "AgentModification",
22
+ "AgentModificationTracker",
23
+ "AgentRegistry",
18
24
  "AgentTier",
19
25
  "AgentType",
20
26
  "DeployedAgentDiscovery",
21
- "AgentModificationTracker",
22
- "ModificationType",
23
- "ModificationTier",
24
- "AgentModification",
25
27
  "ModificationHistory",
28
+ "ModificationTier",
29
+ "ModificationType",
26
30
  ]
@@ -19,7 +19,11 @@ logger = logging.getLogger(__name__)
19
19
  class DeployedAgentDiscovery(ConfigServiceBase):
20
20
  """Discovers and analyzes deployed agents in the project."""
21
21
 
22
- def __init__(self, project_root: Path = None, config: Optional[Dict[str, Any]] = None):
22
+ def __init__(
23
+ self,
24
+ project_root: Optional[Path] = None,
25
+ config: Optional[Dict[str, Any]] = None,
26
+ ):
23
27
  """Initialize the discovery service.
24
28
 
25
29
  Args:
@@ -32,7 +36,7 @@ class DeployedAgentDiscovery(ConfigServiceBase):
32
36
  self.project_root = self.get_config_value(
33
37
  "project_root",
34
38
  default=project_root or get_path_manager().project_root,
35
- config_type=Path
39
+ config_type=Path,
36
40
  )
37
41
  self.agent_registry = AgentRegistryAdapter()
38
42
  self.logger.debug(
@@ -111,7 +115,7 @@ class DeployedAgentDiscovery(ConfigServiceBase):
111
115
  "tools": agent.get("tools", []),
112
116
  }
113
117
  # Handle object format with metadata (new standardized schema)
114
- elif hasattr(agent, "metadata"):
118
+ if hasattr(agent, "metadata"):
115
119
  return {
116
120
  "id": agent.agent_id,
117
121
  "name": agent.metadata.name,
@@ -125,28 +129,27 @@ class DeployedAgentDiscovery(ConfigServiceBase):
125
129
  else []
126
130
  ),
127
131
  }
128
- else:
129
- # Legacy object format fallback
130
- agent_type = getattr(agent, "type", None)
131
- agent_name = getattr(agent, "name", None)
132
-
133
- # Generate name from type if name not present
134
- if not agent_name and agent_type:
135
- agent_name = agent_type.replace("_", " ").title()
136
- elif not agent_name:
137
- agent_name = "Unknown Agent"
138
-
139
- return {
140
- "id": getattr(agent, "agent_id", agent_type or "unknown"),
141
- "name": agent_name,
142
- "description": getattr(
143
- agent, "description", "No description available"
144
- ),
145
- "specializations": getattr(agent, "specializations", []),
146
- "capabilities": {},
147
- "source_tier": self._determine_source_tier(agent),
148
- "tools": getattr(agent, "tools", []),
149
- }
132
+ # Legacy object format fallback
133
+ agent_type = getattr(agent, "type", None)
134
+ agent_name = getattr(agent, "name", None)
135
+
136
+ # Generate name from type if name not present
137
+ if not agent_name and agent_type:
138
+ agent_name = agent_type.replace("_", " ").title()
139
+ elif not agent_name:
140
+ agent_name = "Unknown Agent"
141
+
142
+ return {
143
+ "id": getattr(agent, "agent_id", agent_type or "unknown"),
144
+ "name": agent_name,
145
+ "description": getattr(
146
+ agent, "description", "No description available"
147
+ ),
148
+ "specializations": getattr(agent, "specializations", []),
149
+ "capabilities": {},
150
+ "source_tier": self._determine_source_tier(agent),
151
+ "tools": getattr(agent, "tools", []),
152
+ }
150
153
  except Exception as e:
151
154
  logger.error(f"Error extracting agent info: {e}")
152
155
  return None
@@ -163,7 +166,7 @@ class DeployedAgentDiscovery(ConfigServiceBase):
163
166
  try:
164
167
  path = Path(agent_path)
165
168
  if path.exists() and path.suffix == ".json":
166
- with open(path, "r") as f:
169
+ with open(path) as f:
167
170
  return json.load(f)
168
171
  except Exception as e:
169
172
  logger.warning(f"Failed to load full agent data from {agent_path}: {e}")
@@ -223,7 +226,7 @@ class DeployedAgentDiscovery(ConfigServiceBase):
223
226
  source_path = str(agent.source_path)
224
227
  if ".claude/agents" in source_path:
225
228
  return "project"
226
- elif str(Path.home()) in source_path:
229
+ if str(Path.home()) in source_path:
227
230
  return "user"
228
231
 
229
232
  # Default to system tier
@@ -26,7 +26,6 @@ import asyncio
26
26
  import hashlib
27
27
  import json
28
28
  import logging
29
- import os
30
29
  import shutil
31
30
  import time
32
31
  import uuid
@@ -42,8 +41,6 @@ from claude_mpm.core.base_service import BaseService
42
41
  from claude_mpm.core.unified_agent_registry import UnifiedAgentRegistry as AgentRegistry
43
42
  from claude_mpm.core.unified_paths import get_path_manager
44
43
  from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
45
- from claude_mpm.utils.config_manager import ConfigurationManager
46
- from claude_mpm.utils.path_operations import path_ops
47
44
 
48
45
  # ============================================================================
49
46
  # Data Models
@@ -664,7 +661,7 @@ class AgentModificationTracker(BaseService):
664
661
  # Load active modifications
665
662
  active_path = self.persistence_root / "active_modifications.json"
666
663
  if active_path.exists():
667
- with open(active_path, "r") as f:
664
+ with open(active_path) as f:
668
665
  data = json.load(f)
669
666
  self.active_modifications = {
670
667
  k: AgentModification.from_dict(v) for k, v in data.items()
@@ -672,7 +669,7 @@ class AgentModificationTracker(BaseService):
672
669
 
673
670
  # Load modification history
674
671
  for history_file in self.history_root.glob("*.json"):
675
- with open(history_file, "r") as f:
672
+ with open(history_file) as f:
676
673
  data = json.load(f)
677
674
  agent_name = data["agent_name"]
678
675
  history = ModificationHistory(agent_name=agent_name)
@@ -770,7 +767,7 @@ class AgentModificationTracker(BaseService):
770
767
  if backup_dir.is_dir():
771
768
  metadata_path = backup_dir / "metadata.json"
772
769
  if metadata_path.exists():
773
- with open(metadata_path, "r") as f:
770
+ with open(metadata_path) as f:
774
771
  metadata = json.load(f)
775
772
  if metadata.get("backup_time", 0) < cutoff_time:
776
773
  shutil.rmtree(backup_dir)
@@ -15,7 +15,6 @@ Key Features:
15
15
  - Configuration via .claude-mpm/configuration.yaml
16
16
  """
17
17
 
18
- import asyncio
19
18
  import json
20
19
  import logging
21
20
  import logging.handlers
@@ -27,7 +26,7 @@ from datetime import datetime
27
26
  from enum import Enum
28
27
  from queue import Full, Queue
29
28
  from threading import Lock, Thread
30
- from typing import Any, Callable, Dict, Optional
29
+ from typing import Any, Dict, Optional
31
30
 
32
31
  from claude_mpm.core.constants import PerformanceConfig, SystemLimits, TimeoutConfig
33
32
 
@@ -159,8 +159,7 @@ class ClaudeSessionLogger:
159
159
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
160
160
 
161
161
  # Create filename: session_id-agent-timestamp.json
162
- filename = f"{self.session_id}-{agent_name}-{timestamp}.json"
163
- return filename
162
+ return f"{self.session_id}-{agent_name}-{timestamp}.json"
164
163
 
165
164
  def log_response(
166
165
  self,
@@ -0,0 +1,173 @@
1
+ """Service for deploying MPM slash commands to user's Claude configuration.
2
+
3
+ This service handles:
4
+ 1. Copying command markdown files from source to user's ~/.claude/commands directory
5
+ 2. Creating the commands directory if it doesn't exist
6
+ 3. Overwriting existing commands to ensure they're up-to-date
7
+ """
8
+
9
+ import shutil
10
+ from pathlib import Path
11
+ from typing import Any, Dict, List
12
+
13
+ from claude_mpm.core.base_service import BaseService
14
+ from claude_mpm.core.logger import get_logger
15
+
16
+
17
+ class CommandDeploymentService(BaseService):
18
+ """Service for deploying MPM slash commands."""
19
+
20
+ def __init__(self):
21
+ """Initialize the command deployment service."""
22
+ super().__init__(name="command_deployment")
23
+
24
+ # Source commands directory in the package
25
+ self.source_dir = Path(__file__).parent.parent / "commands"
26
+
27
+ # Target directory in user's home
28
+ self.target_dir = Path.home() / ".claude" / "commands"
29
+
30
+ async def _initialize(self) -> None:
31
+ """Initialize the service."""
32
+
33
+ async def _cleanup(self) -> None:
34
+ """Cleanup service resources."""
35
+
36
+ def deploy_commands(self, force: bool = False) -> Dict[str, Any]:
37
+ """Deploy MPM slash commands to user's Claude configuration.
38
+
39
+ Args:
40
+ force: Force deployment even if files exist
41
+
42
+ Returns:
43
+ Dictionary with deployment results
44
+ """
45
+ result = {
46
+ "success": False,
47
+ "deployed": [],
48
+ "errors": [],
49
+ "target_dir": str(self.target_dir),
50
+ }
51
+
52
+ try:
53
+ # Check if source directory exists
54
+ if not self.source_dir.exists():
55
+ self.logger.warning(
56
+ f"Source commands directory not found: {self.source_dir}"
57
+ )
58
+ result["errors"].append(
59
+ f"Source directory not found: {self.source_dir}"
60
+ )
61
+ return result
62
+
63
+ # Create target directory if it doesn't exist
64
+ self.target_dir.mkdir(parents=True, exist_ok=True)
65
+ self.logger.debug(f"Ensured target directory exists: {self.target_dir}")
66
+
67
+ # Get all .md files from source directory
68
+ command_files = list(self.source_dir.glob("*.md"))
69
+
70
+ if not command_files:
71
+ self.logger.info("No command files found to deploy")
72
+ result["success"] = True
73
+ return result
74
+
75
+ # Deploy each command file
76
+ for source_file in command_files:
77
+ target_file = self.target_dir / source_file.name
78
+
79
+ try:
80
+ # Check if file exists and if we should overwrite
81
+ if target_file.exists() and not force:
82
+ # Check if source is newer
83
+ if source_file.stat().st_mtime <= target_file.stat().st_mtime:
84
+ self.logger.debug(
85
+ f"Skipping {source_file.name} - target is up to date"
86
+ )
87
+ continue
88
+
89
+ # Copy the file
90
+ shutil.copy2(source_file, target_file)
91
+ self.logger.info(f"Deployed command: {source_file.name}")
92
+ result["deployed"].append(source_file.name)
93
+
94
+ except Exception as e:
95
+ error_msg = f"Failed to deploy {source_file.name}: {e}"
96
+ self.logger.error(error_msg)
97
+ result["errors"].append(error_msg)
98
+
99
+ result["success"] = len(result["errors"]) == 0
100
+
101
+ if result["deployed"]:
102
+ self.logger.info(
103
+ f"Successfully deployed {len(result['deployed'])} commands to {self.target_dir}"
104
+ )
105
+
106
+ return result
107
+
108
+ except Exception as e:
109
+ error_msg = f"Command deployment failed: {e}"
110
+ self.logger.error(error_msg)
111
+ result["errors"].append(error_msg)
112
+ return result
113
+
114
+ def list_available_commands(self) -> List[str]:
115
+ """List available commands in the source directory.
116
+
117
+ Returns:
118
+ List of command file names
119
+ """
120
+ if not self.source_dir.exists():
121
+ return []
122
+
123
+ return [f.name for f in self.source_dir.glob("*.md")]
124
+
125
+ def list_deployed_commands(self) -> List[str]:
126
+ """List deployed commands in the target directory.
127
+
128
+ Returns:
129
+ List of deployed command file names
130
+ """
131
+ if not self.target_dir.exists():
132
+ return []
133
+
134
+ return [f.name for f in self.target_dir.glob("mpm*.md")]
135
+
136
+ def remove_deployed_commands(self) -> int:
137
+ """Remove all deployed MPM commands from target directory.
138
+
139
+ Returns:
140
+ Number of files removed
141
+ """
142
+ if not self.target_dir.exists():
143
+ return 0
144
+
145
+ removed = 0
146
+ for file in self.target_dir.glob("mpm*.md"):
147
+ try:
148
+ file.unlink()
149
+ self.logger.info(f"Removed command: {file.name}")
150
+ removed += 1
151
+ except Exception as e:
152
+ self.logger.error(f"Failed to remove {file.name}: {e}")
153
+
154
+ return removed
155
+
156
+
157
+ def deploy_commands_on_startup(force: bool = False) -> None:
158
+ """Convenience function to deploy commands during startup.
159
+
160
+ Args:
161
+ force: Force deployment even if files exist
162
+ """
163
+ service = CommandDeploymentService()
164
+ result = service.deploy_commands(force=force)
165
+
166
+ if result["deployed"]:
167
+ logger = get_logger("startup")
168
+ logger.info(f"MPM commands deployed: {', '.join(result['deployed'])}")
169
+
170
+ if result["errors"]:
171
+ logger = get_logger("startup")
172
+ for error in result["errors"]:
173
+ logger.warning(f"Command deployment issue: {error}")