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
@@ -10,8 +10,6 @@ delegates to specialized components rather than inheriting from them.
10
10
  """
11
11
 
12
12
  import asyncio
13
- import logging
14
- import os
15
13
  import threading
16
14
  import time
17
15
  from collections import deque
@@ -31,15 +29,10 @@ except ImportError:
31
29
  web = None
32
30
 
33
31
  from ....core.constants import (
34
- NetworkConfig,
35
- PerformanceConfig,
36
32
  SystemLimits,
37
- TimeoutConfig,
38
33
  )
34
+ from ....core.logging_config import get_logger
39
35
  from ...core.interfaces.communication import SocketIOServiceInterface
40
- from ....core.logging_config import get_logger, log_operation, log_performance_context
41
- from ....core.unified_paths import get_project_root, get_scripts_dir
42
- from ...exceptions import SocketIOServerError as MPMConnectionError
43
36
  from ..handlers import EventHandlerRegistry, FileEventHandler, GitEventHandler
44
37
  from .broadcaster import SocketIOEventBroadcaster
45
38
  from .core import SocketIOServerCore
@@ -91,10 +84,10 @@ class SocketIOServer(SocketIOServiceInterface):
91
84
  self.claude_status = "unknown"
92
85
  self.claude_pid = None
93
86
  self.event_history = deque(maxlen=SystemLimits.MAX_EVENTS_BUFFER)
94
-
87
+
95
88
  # Active session tracking for heartbeat
96
89
  self.active_sessions: Dict[str, Dict[str, Any]] = {}
97
-
90
+
98
91
  # EventBus integration
99
92
  self.eventbus_integration = None
100
93
 
@@ -106,7 +99,14 @@ class SocketIOServer(SocketIOServiceInterface):
106
99
 
107
100
  # Set reference to main server for session data
108
101
  self.core.main_server = self
109
-
102
+
103
+ # Debug logging for EventBus initialization
104
+ self.logger.info("Starting Socket.IO server with EventBus integration...")
105
+ print(
106
+ f"[{datetime.now().isoformat()}] SocketIOServer.start_sync() called",
107
+ flush=True,
108
+ )
109
+
110
110
  # Start the core server
111
111
  self.core.start_sync()
112
112
 
@@ -127,11 +127,11 @@ class SocketIOServer(SocketIOServiceInterface):
127
127
  max_wait = 5.0 # Maximum wait time in seconds
128
128
  wait_interval = 0.1 # Check interval
129
129
  waited = 0.0
130
-
130
+
131
131
  while self.core.loop is None and waited < max_wait:
132
132
  time.sleep(wait_interval)
133
133
  waited += wait_interval
134
-
134
+
135
135
  if self.core.loop is None:
136
136
  self.logger.warning(
137
137
  f"Event loop not initialized after {max_wait}s wait. "
@@ -139,27 +139,51 @@ class SocketIOServer(SocketIOServiceInterface):
139
139
  )
140
140
  else:
141
141
  self.logger.debug(f"Event loop ready after {waited:.1f}s")
142
-
142
+
143
143
  # Set the loop reference for broadcaster
144
144
  self.broadcaster.loop = self.core.loop
145
-
145
+
146
146
  # Start the retry processor for resilient event delivery
147
147
  self.broadcaster.start_retry_processor()
148
148
 
149
149
  # Register events
150
150
  self._register_events()
151
-
151
+
152
152
  # Setup EventBus integration
153
153
  # WHY: This connects the EventBus to the Socket.IO server, allowing
154
154
  # events from other parts of the system to be broadcast to dashboard
155
+ print(
156
+ f"[{datetime.now().isoformat()}] Setting up EventBus integration...",
157
+ flush=True,
158
+ )
155
159
  try:
156
160
  self.eventbus_integration = EventBusIntegration(self)
161
+ print(
162
+ f"[{datetime.now().isoformat()}] EventBusIntegration instance created",
163
+ flush=True,
164
+ )
165
+
157
166
  if self.eventbus_integration.setup(self.port):
158
167
  self.logger.info("EventBus integration setup successful")
168
+ print(
169
+ f"[{datetime.now().isoformat()}] EventBus integration setup successful",
170
+ flush=True,
171
+ )
159
172
  else:
160
173
  self.logger.warning("EventBus integration setup failed or disabled")
174
+ print(
175
+ f"[{datetime.now().isoformat()}] EventBus integration setup failed or disabled",
176
+ flush=True,
177
+ )
161
178
  except Exception as e:
162
179
  self.logger.error(f"Failed to setup EventBus integration: {e}")
180
+ print(
181
+ f"[{datetime.now().isoformat()}] Failed to setup EventBus integration: {e}",
182
+ flush=True,
183
+ )
184
+ import traceback
185
+
186
+ traceback.print_exc()
163
187
  self.eventbus_integration = None
164
188
 
165
189
  # Update running state
@@ -175,7 +199,7 @@ class SocketIOServer(SocketIOServiceInterface):
175
199
  # Stop the retry processor if running
176
200
  if self.broadcaster:
177
201
  self.broadcaster.stop_retry_processor()
178
-
202
+
179
203
  # Teardown EventBus integration
180
204
  if self.eventbus_integration:
181
205
  try:
@@ -183,14 +207,15 @@ class SocketIOServer(SocketIOServiceInterface):
183
207
  self.logger.info("EventBus integration teardown complete")
184
208
  except Exception as e:
185
209
  self.logger.error(f"Error during EventBus teardown: {e}")
186
-
210
+
187
211
  # Stop health monitoring in connection handler
188
212
  if self.event_registry:
189
213
  from ..handlers import ConnectionEventHandler
214
+
190
215
  conn_handler = self.event_registry.get_handler(ConnectionEventHandler)
191
- if conn_handler and hasattr(conn_handler, 'stop_health_monitoring'):
216
+ if conn_handler and hasattr(conn_handler, "stop_health_monitoring"):
192
217
  conn_handler.stop_health_monitoring()
193
-
218
+
194
219
  self.core.stop_sync()
195
220
  self.running = False
196
221
 
@@ -219,25 +244,27 @@ class SocketIOServer(SocketIOServiceInterface):
219
244
  """Broadcast an event to all connected clients."""
220
245
  if self.broadcaster:
221
246
  self.broadcaster.broadcast_event(event_type, data)
222
-
223
- def send_to_client(self, client_id: str, event_type: str, data: Dict[str, Any]) -> bool:
247
+
248
+ def send_to_client(
249
+ self, client_id: str, event_type: str, data: Dict[str, Any]
250
+ ) -> bool:
224
251
  """Send an event to a specific client.
225
-
226
- WHY: The SocketIOServiceInterface requires this method for targeted
252
+
253
+ WHY: The SocketIOServiceInterface requires this method for targeted
227
254
  messaging. We delegate to the Socket.IO server's emit method with
228
255
  the client's session ID as the room.
229
-
256
+
230
257
  Args:
231
258
  client_id: ID of the target client
232
259
  event_type: Type of event to send
233
260
  data: Event data to send
234
-
261
+
235
262
  Returns:
236
263
  True if message sent successfully
237
264
  """
238
265
  if not self.core or not self.core.sio:
239
266
  return False
240
-
267
+
241
268
  try:
242
269
  # Socket.IO uses session IDs as room names for individual clients
243
270
  # We can send to a specific client by using their session ID as the room
@@ -246,7 +273,7 @@ class SocketIOServer(SocketIOServiceInterface):
246
273
  if self.core.loop:
247
274
  asyncio.run_coroutine_threadsafe(
248
275
  self.core.sio.emit(event_type, data, room=client_id),
249
- self.core.loop
276
+ self.core.loop,
250
277
  )
251
278
  return True
252
279
  return False
@@ -257,7 +284,7 @@ class SocketIOServer(SocketIOServiceInterface):
257
284
  def session_started(self, session_id: str, launch_method: str, working_dir: str):
258
285
  """Notify that a session has started."""
259
286
  self.session_id = session_id
260
-
287
+
261
288
  # Track active session for heartbeat
262
289
  self.active_sessions[session_id] = {
263
290
  "session_id": session_id,
@@ -267,7 +294,7 @@ class SocketIOServer(SocketIOServiceInterface):
267
294
  "launch_method": launch_method,
268
295
  "working_dir": working_dir,
269
296
  }
270
-
297
+
271
298
  if self.broadcaster:
272
299
  self.broadcaster.session_started(session_id, launch_method, working_dir)
273
300
 
@@ -276,7 +303,7 @@ class SocketIOServer(SocketIOServiceInterface):
276
303
  # Remove from active sessions
277
304
  if self.session_id and self.session_id in self.active_sessions:
278
305
  del self.active_sessions[self.session_id]
279
-
306
+
280
307
  if self.broadcaster:
281
308
  self.broadcaster.session_ended()
282
309
 
@@ -300,7 +327,7 @@ class SocketIOServer(SocketIOServiceInterface):
300
327
  if self.session_id and self.session_id in self.active_sessions:
301
328
  self.active_sessions[self.session_id]["agent"] = agent
302
329
  self.active_sessions[self.session_id]["status"] = status
303
-
330
+
304
331
  if self.broadcaster:
305
332
  self.broadcaster.agent_delegated(agent, task, status)
306
333
 
@@ -344,16 +371,16 @@ class SocketIOServer(SocketIOServiceInterface):
344
371
  def is_running(self) -> bool:
345
372
  """Check if server is running."""
346
373
  return self.core.is_running()
347
-
374
+
348
375
  def get_active_sessions(self) -> List[Dict[str, Any]]:
349
376
  """Get list of active sessions for heartbeat.
350
-
377
+
351
378
  WHY: Provides session information for system heartbeat events.
352
379
  """
353
380
  # Clean up old sessions (older than 1 hour)
354
381
  cutoff_time = datetime.now().timestamp() - 3600
355
382
  sessions_to_remove = []
356
-
383
+
357
384
  for session_id, session_data in self.active_sessions.items():
358
385
  try:
359
386
  start_time = datetime.fromisoformat(session_data["start_time"])
@@ -361,14 +388,13 @@ class SocketIOServer(SocketIOServiceInterface):
361
388
  sessions_to_remove.append(session_id)
362
389
  except:
363
390
  pass
364
-
391
+
365
392
  for session_id in sessions_to_remove:
366
393
  del self.active_sessions[session_id]
367
-
394
+
368
395
  # Return list of active sessions
369
396
  return list(self.active_sessions.values())
370
397
 
371
-
372
398
  # Legacy compatibility properties
373
399
  @property
374
400
  def sio(self):
@@ -15,7 +15,6 @@ WHY this approach:
15
15
 
16
16
  import asyncio
17
17
  import importlib.metadata
18
- import json
19
18
  import socket
20
19
  import threading
21
20
  import time
@@ -34,6 +33,8 @@ except ImportError:
34
33
  requests = None
35
34
  socketio = None
36
35
 
36
+ import contextlib
37
+
37
38
  from ..core.logger import get_logger
38
39
 
39
40
  # Get claude-mpm version for compatibility checking
@@ -74,11 +75,10 @@ class ServerInfo:
74
75
  # Simple version comparison - in production use proper semver
75
76
  if client_version >= "0.7.0":
76
77
  return True, warnings
77
- else:
78
- warnings.append(
79
- f"Client version {client_version} may not be fully supported"
80
- )
81
- return False, warnings
78
+ warnings.append(
79
+ f"Client version {client_version} may not be fully supported"
80
+ )
81
+ return False, warnings
82
82
  except Exception as e:
83
83
  warnings.append(f"Could not parse version: {e}")
84
84
  return False, warnings
@@ -106,7 +106,7 @@ class SocketIOClientManager:
106
106
  self.logger.warning("Socket.IO client dependencies not available")
107
107
 
108
108
  def discover_servers(
109
- self, ports: List[int] = None, hosts: List[str] = None
109
+ self, ports: Optional[List[int]] = None, hosts: Optional[List[str]] = None
110
110
  ) -> List[ServerInfo]:
111
111
  """Discover available Socket.IO servers.
112
112
 
@@ -165,7 +165,7 @@ class SocketIOClientManager:
165
165
  return discovered
166
166
 
167
167
  def find_best_server(
168
- self, discovered_servers: List[ServerInfo] = None
168
+ self, discovered_servers: Optional[List[ServerInfo]] = None
169
169
  ) -> Optional[ServerInfo]:
170
170
  """Find the best compatible server from discovered servers."""
171
171
  if discovered_servers is None:
@@ -272,10 +272,8 @@ class SocketIOClientManager:
272
272
  except Exception as e:
273
273
  self.logger.error(f"❌ Failed to connect to server {server_info.url}: {e}")
274
274
  if self.client:
275
- try:
275
+ with contextlib.suppress(Exception):
276
276
  await self.client.disconnect()
277
- except:
278
- pass
279
277
  self.client = None
280
278
  return False
281
279
 
@@ -408,7 +406,7 @@ class SocketIOClientManager:
408
406
  else:
409
407
  # Too many failed attempts, wait longer
410
408
  self.logger.warning(
411
- f"⏳ Max connection attempts reached, waiting 30s..."
409
+ "⏳ Max connection attempts reached, waiting 30s..."
412
410
  )
413
411
  await asyncio.sleep(30)
414
412
  connection_attempts = 0 # Reset after longer wait
@@ -10,6 +10,7 @@ This service handles:
10
10
  Extracted from ClaudeRunner to follow Single Responsibility Principle.
11
11
  """
12
12
 
13
+ import contextlib
13
14
  import os
14
15
  import pty
15
16
  import select
@@ -40,11 +41,9 @@ class SubprocessLauncherService(BaseService, SubprocessLauncherInterface):
40
41
 
41
42
  async def _initialize(self) -> None:
42
43
  """Initialize the service. No special initialization needed."""
43
- pass
44
44
 
45
45
  async def _cleanup(self) -> None:
46
46
  """Cleanup service resources. No cleanup needed."""
47
- pass
48
47
 
49
48
  # Implementation of abstract methods from SubprocessLauncherInterface
50
49
 
@@ -206,10 +205,8 @@ class SubprocessLauncherService(BaseService, SubprocessLauncherInterface):
206
205
  termios.tcsetattr(sys.stdin, termios.TCSADRAIN, original_tty)
207
206
 
208
207
  # Close PTY
209
- try:
208
+ with contextlib.suppress(Exception):
210
209
  os.close(master_fd)
211
- except:
212
- pass
213
210
 
214
211
  # Ensure process is terminated
215
212
  if "process" in locals() and process.poll() is None:
@@ -313,9 +310,9 @@ class SubprocessLauncherService(BaseService, SubprocessLauncherInterface):
313
310
  env = os.environ.copy()
314
311
  if base_env:
315
312
  env.update(base_env)
316
-
313
+
317
314
  # Disable telemetry for Claude Code subprocesses
318
315
  # This ensures Claude Code doesn't send telemetry data during runtime
319
316
  env["DISABLE_TELEMETRY"] = "1"
320
-
317
+
321
318
  return env
@@ -1,5 +1,3 @@
1
- from pathlib import Path
2
-
3
1
  """System instructions service for loading and processing system instructions.
4
2
 
5
3
  This service handles:
@@ -36,11 +34,9 @@ class SystemInstructionsService(BaseService, SystemInstructionsInterface):
36
34
 
37
35
  async def _initialize(self) -> None:
38
36
  """Initialize the service. No special initialization needed."""
39
- pass
40
37
 
41
38
  async def _cleanup(self) -> None:
42
39
  """Cleanup service resources. No cleanup needed."""
43
- pass
44
40
 
45
41
  def load_system_instructions(self, instruction_type: str = "default") -> str:
46
42
  """Load and process system instructions from agents/INSTRUCTIONS.md.
@@ -50,7 +46,7 @@ class SystemInstructionsService(BaseService, SystemInstructionsInterface):
50
46
 
51
47
  Now uses the FrameworkLoader for comprehensive instruction loading including:
52
48
  - INSTRUCTIONS.md
53
- - WORKFLOW.md
49
+ - WORKFLOW.md
54
50
  - MEMORY.md
55
51
  - Actual PM memories from .claude-mpm/memories/PM.md
56
52
  - Agent capabilities
@@ -64,23 +60,28 @@ class SystemInstructionsService(BaseService, SystemInstructionsInterface):
64
60
  if self._loaded_instructions is not None:
65
61
  self.logger.debug("Returning cached system instructions")
66
62
  return self._loaded_instructions
67
-
63
+
68
64
  # Create FrameworkLoader only once
69
65
  if self._framework_loader is None:
70
66
  from claude_mpm.core.framework_loader import FrameworkLoader
67
+
71
68
  self._framework_loader = FrameworkLoader()
72
69
  self.logger.debug("Created new FrameworkLoader instance")
73
-
70
+
74
71
  # Load instructions and cache them
75
72
  instructions = self._framework_loader.get_framework_instructions()
76
-
73
+
77
74
  if instructions:
78
75
  self._loaded_instructions = instructions
79
- self.logger.info("Loaded and cached framework instructions via FrameworkLoader")
76
+ self.logger.info(
77
+ "Loaded and cached framework instructions via FrameworkLoader"
78
+ )
80
79
  return instructions
81
-
80
+
82
81
  # Fallback if FrameworkLoader returns empty
83
- self.logger.warning("FrameworkLoader returned empty instructions, using fallback")
82
+ self.logger.warning(
83
+ "FrameworkLoader returned empty instructions, using fallback"
84
+ )
84
85
  fallback = "# System Instructions\n\nNo specific system instructions found. Using default behavior."
85
86
  self._loaded_instructions = fallback
86
87
  return fallback
@@ -177,9 +178,7 @@ class SystemInstructionsService(BaseService, SystemInstructionsInterface):
177
178
  cleaned = "\n".join(cleaned_lines)
178
179
 
179
180
  # Also remove any leading blank lines that might result
180
- cleaned = cleaned.lstrip("\n")
181
-
182
- return cleaned
181
+ return cleaned.lstrip("\n")
183
182
 
184
183
  except Exception as e:
185
184
  self.logger.warning(f"Error stripping metadata comments: {e}")
@@ -6,7 +6,7 @@ class TicketManager:
6
6
 
7
7
  def create_task(self, *args, **kwargs):
8
8
  """Stub method."""
9
- return None
9
+ return
10
10
 
11
11
  def list_recent_tickets(self, *args, **kwargs):
12
12
  """Stub method."""
@@ -14,7 +14,7 @@ class TicketManager:
14
14
 
15
15
  def get_ticket(self, *args, **kwargs):
16
16
  """Stub method."""
17
- return None
17
+ return
18
18
 
19
19
  def update_task(self, *args, **kwargs):
20
20
  """Stub method."""
@@ -30,11 +30,9 @@ class UtilityService(BaseService, UtilityServiceInterface):
30
30
 
31
31
  async def _initialize(self) -> None:
32
32
  """Initialize the service. No special initialization needed."""
33
- pass
34
33
 
35
34
  async def _cleanup(self) -> None:
36
35
  """Cleanup service resources. No cleanup needed."""
37
- pass
38
36
 
39
37
  def contains_delegation(self, text: str) -> bool:
40
38
  """Check if text contains signs of agent delegation.
@@ -112,7 +110,7 @@ class UtilityService(BaseService, UtilityServiceInterface):
112
110
  with open(log_file, "a") as f:
113
111
  f.write(json.dumps(log_entry) + "\n")
114
112
 
115
- except (OSError, IOError) as e:
113
+ except OSError as e:
116
114
  self.logger.debug(f"IO error logging session event: {e}")
117
115
  except Exception as e:
118
116
  self.logger.debug(f"Failed to log session event: {e}")
@@ -130,10 +128,7 @@ class UtilityService(BaseService, UtilityServiceInterface):
130
128
  return False
131
129
 
132
130
  # Check for minimum length
133
- if len(prompt.strip()) < 3:
134
- return False
135
-
136
- return True
131
+ return not len(prompt.strip()) < 3
137
132
 
138
133
  def sanitize_filename(self, filename: str) -> str:
139
134
  """Sanitize a filename by removing invalid characters.
@@ -174,8 +169,7 @@ class UtilityService(BaseService, UtilityServiceInterface):
174
169
 
175
170
  if context:
176
171
  return f"{context}: {error_type}: {error_msg}"
177
- else:
178
- return f"{error_type}: {error_msg}"
172
+ return f"{error_type}: {error_msg}"
179
173
 
180
174
  def truncate_text(
181
175
  self, text: str, max_length: int = 100, suffix: str = "..."
@@ -210,7 +204,7 @@ class UtilityService(BaseService, UtilityServiceInterface):
210
204
  pattern = r'(\w+)=(["\']?)([^"\'\s]*)\2'
211
205
  matches = re.findall(pattern, text)
212
206
 
213
- for key, quote, value in matches:
207
+ for key, _quote, value in matches:
214
208
  pairs[key] = value
215
209
 
216
210
  return pairs
@@ -280,6 +274,4 @@ class UtilityService(BaseService, UtilityServiceInterface):
280
274
  return False, "Path cannot be empty"
281
275
  return True, None
282
276
  except Exception as e:
283
- return False, f"Path validation error: {str(e)}"
284
-
285
-
277
+ return False, f"Path validation error: {e!s}"
@@ -39,29 +39,29 @@ from .semantic_versioning import (
39
39
  )
40
40
 
41
41
  __all__ = [
42
- # Git Operations
43
- "GitOperationsManager",
44
- "GitBranchInfo",
45
- "GitOperationResult",
46
- "GitOperationError",
47
- # Semantic Versioning
48
- "SemanticVersionManager",
49
- "SemanticVersion",
50
- "VersionBumpType",
51
- "VersionMetadata",
52
- "ChangeAnalysis",
42
+ "BranchLifecycleRule",
43
+ "BranchNamingRule",
53
44
  # Branch Strategy
54
45
  "BranchStrategyManager",
55
46
  "BranchStrategyType",
56
47
  "BranchType",
57
48
  "BranchWorkflow",
58
- "BranchNamingRule",
59
- "BranchLifecycleRule",
49
+ "ChangeAnalysis",
50
+ "ConflictAnalysis",
51
+ "ConflictResolution",
60
52
  # Conflict Resolution
61
53
  "ConflictResolutionManager",
62
54
  "ConflictType",
63
- "ResolutionStrategy",
64
55
  "FileConflict",
65
- "ConflictResolution",
66
- "ConflictAnalysis",
56
+ "GitBranchInfo",
57
+ "GitOperationError",
58
+ "GitOperationResult",
59
+ # Git Operations
60
+ "GitOperationsManager",
61
+ "ResolutionStrategy",
62
+ "SemanticVersion",
63
+ # Semantic Versioning
64
+ "SemanticVersionManager",
65
+ "VersionBumpType",
66
+ "VersionMetadata",
67
67
  ]
@@ -358,9 +358,8 @@ class BranchStrategyManager:
358
358
  self.current_strategy = self.strategies[strategy_type]
359
359
  self.logger.info(f"Set branch strategy to {strategy_type.value}")
360
360
  return True
361
- else:
362
- self.logger.error(f"Unknown strategy type: {strategy_type}")
363
- return False
361
+ self.logger.error(f"Unknown strategy type: {strategy_type}")
362
+ return False
364
363
 
365
364
  def generate_branch_name(
366
365
  self,
@@ -395,10 +394,9 @@ class BranchStrategyManager:
395
394
  prefix = branch_type.value + "/"
396
395
  if ticket_id:
397
396
  return f"{prefix}{ticket_id}"
398
- elif description:
397
+ if description:
399
398
  return f"{prefix}{self._sanitize_branch_name(description)}"
400
- else:
401
- return f"{prefix}{datetime.now().strftime('%Y%m%d')}"
399
+ return f"{prefix}{datetime.now().strftime('%Y%m%d')}"
402
400
 
403
401
  # Generate name based on rule
404
402
  if strategy.strategy_type == BranchStrategyType.ISSUE_DRIVEN:
@@ -614,8 +612,7 @@ class BranchStrategyManager:
614
612
  # Default merge message
615
613
  if ticket_title:
616
614
  return f"Merge {branch_name}: {ticket_title}"
617
- else:
618
- return f"Merge {branch_name}"
615
+ return f"Merge {branch_name}"
619
616
 
620
617
  def get_quality_gates(self) -> List[str]:
621
618
  """Get quality gates for the current strategy."""