claude-mpm 3.9.9__py3-none-any.whl → 4.0.3__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 (411) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +2 -2
  3. claude_mpm/__main__.py +3 -2
  4. claude_mpm/agents/__init__.py +85 -79
  5. claude_mpm/agents/agent_loader.py +464 -1003
  6. claude_mpm/agents/agent_loader_integration.py +45 -45
  7. claude_mpm/agents/agents_metadata.py +29 -30
  8. claude_mpm/agents/async_agent_loader.py +156 -138
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/base_agent_loader.py +179 -151
  11. claude_mpm/agents/frontmatter_validator.py +229 -130
  12. claude_mpm/agents/schema/agent_schema.json +1 -1
  13. claude_mpm/agents/system_agent_config.py +213 -147
  14. claude_mpm/agents/templates/__init__.py +13 -13
  15. claude_mpm/agents/templates/code_analyzer.json +2 -2
  16. claude_mpm/agents/templates/data_engineer.json +1 -1
  17. claude_mpm/agents/templates/documentation.json +23 -11
  18. claude_mpm/agents/templates/engineer.json +22 -6
  19. claude_mpm/agents/templates/memory_manager.json +155 -0
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/project_organizer.json +1 -1
  22. claude_mpm/agents/templates/qa.json +1 -1
  23. claude_mpm/agents/templates/refactoring_engineer.json +222 -0
  24. claude_mpm/agents/templates/research.json +20 -14
  25. claude_mpm/agents/templates/security.json +1 -1
  26. claude_mpm/agents/templates/ticketing.json +1 -1
  27. claude_mpm/agents/templates/version_control.json +1 -1
  28. claude_mpm/agents/templates/web_qa.json +3 -1
  29. claude_mpm/agents/templates/web_ui.json +2 -2
  30. claude_mpm/cli/__init__.py +90 -49
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +21 -18
  33. claude_mpm/cli/commands/agents.py +279 -247
  34. claude_mpm/cli/commands/aggregate.py +138 -157
  35. claude_mpm/cli/commands/cleanup.py +147 -147
  36. claude_mpm/cli/commands/config.py +93 -76
  37. claude_mpm/cli/commands/info.py +17 -16
  38. claude_mpm/cli/commands/mcp.py +143 -762
  39. claude_mpm/cli/commands/mcp_command_router.py +139 -0
  40. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  41. claude_mpm/cli/commands/mcp_install_commands.py +20 -0
  42. claude_mpm/cli/commands/mcp_server_commands.py +175 -0
  43. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  44. claude_mpm/cli/commands/memory.py +239 -203
  45. claude_mpm/cli/commands/monitor.py +203 -81
  46. claude_mpm/cli/commands/run.py +380 -429
  47. claude_mpm/cli/commands/run_config_checker.py +160 -0
  48. claude_mpm/cli/commands/socketio_monitor.py +235 -0
  49. claude_mpm/cli/commands/tickets.py +305 -197
  50. claude_mpm/cli/parser.py +24 -1150
  51. claude_mpm/cli/parsers/__init__.py +29 -0
  52. claude_mpm/cli/parsers/agents_parser.py +136 -0
  53. claude_mpm/cli/parsers/base_parser.py +331 -0
  54. claude_mpm/cli/parsers/config_parser.py +85 -0
  55. claude_mpm/cli/parsers/mcp_parser.py +152 -0
  56. claude_mpm/cli/parsers/memory_parser.py +138 -0
  57. claude_mpm/cli/parsers/monitor_parser.py +104 -0
  58. claude_mpm/cli/parsers/run_parser.py +147 -0
  59. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  60. claude_mpm/cli/ticket_cli.py +7 -3
  61. claude_mpm/cli/utils.py +55 -37
  62. claude_mpm/cli_module/__init__.py +6 -6
  63. claude_mpm/cli_module/args.py +188 -140
  64. claude_mpm/cli_module/commands.py +79 -70
  65. claude_mpm/cli_module/migration_example.py +38 -60
  66. claude_mpm/config/__init__.py +32 -25
  67. claude_mpm/config/agent_config.py +151 -119
  68. claude_mpm/config/experimental_features.py +217 -0
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +36 -18
  72. claude_mpm/core/__init__.py +9 -6
  73. claude_mpm/core/agent_name_normalizer.py +68 -71
  74. claude_mpm/core/agent_registry.py +372 -521
  75. claude_mpm/core/agent_session_manager.py +74 -63
  76. claude_mpm/core/base_service.py +116 -87
  77. claude_mpm/core/cache.py +119 -153
  78. claude_mpm/core/claude_runner.py +425 -1120
  79. claude_mpm/core/config.py +263 -168
  80. claude_mpm/core/config_aliases.py +69 -61
  81. claude_mpm/core/config_constants.py +292 -0
  82. claude_mpm/core/constants.py +57 -99
  83. claude_mpm/core/container.py +211 -178
  84. claude_mpm/core/exceptions.py +233 -89
  85. claude_mpm/core/factories.py +92 -54
  86. claude_mpm/core/framework_loader.py +378 -220
  87. claude_mpm/core/hook_manager.py +198 -83
  88. claude_mpm/core/hook_performance_config.py +136 -0
  89. claude_mpm/core/injectable_service.py +61 -55
  90. claude_mpm/core/interactive_session.py +165 -155
  91. claude_mpm/core/interfaces.py +221 -195
  92. claude_mpm/core/lazy.py +96 -96
  93. claude_mpm/core/logger.py +133 -107
  94. claude_mpm/core/logging_config.py +185 -157
  95. claude_mpm/core/minimal_framework_loader.py +20 -15
  96. claude_mpm/core/mixins.py +30 -29
  97. claude_mpm/core/oneshot_session.py +215 -181
  98. claude_mpm/core/optimized_agent_loader.py +134 -138
  99. claude_mpm/core/optimized_startup.py +159 -157
  100. claude_mpm/core/pm_hook_interceptor.py +85 -72
  101. claude_mpm/core/service_registry.py +103 -101
  102. claude_mpm/core/session_manager.py +97 -87
  103. claude_mpm/core/socketio_pool.py +212 -158
  104. claude_mpm/core/tool_access_control.py +58 -51
  105. claude_mpm/core/types.py +46 -24
  106. claude_mpm/core/typing_utils.py +166 -82
  107. claude_mpm/core/unified_agent_registry.py +721 -0
  108. claude_mpm/core/unified_config.py +550 -0
  109. claude_mpm/core/unified_paths.py +549 -0
  110. claude_mpm/dashboard/index.html +1 -1
  111. claude_mpm/dashboard/open_dashboard.py +51 -17
  112. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  113. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  114. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  115. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  116. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  117. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  118. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  119. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  120. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  121. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  122. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  123. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  124. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  125. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  126. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  127. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  128. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  129. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  130. claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
  131. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  132. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
  133. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  134. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  135. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  136. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  137. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  138. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  139. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  140. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  141. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  142. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  143. claude_mpm/dashboard/static/js/socket-client.js +120 -54
  144. claude_mpm/dashboard/templates/index.html +40 -50
  145. claude_mpm/experimental/cli_enhancements.py +60 -58
  146. claude_mpm/generators/__init__.py +1 -1
  147. claude_mpm/generators/agent_profile_generator.py +75 -65
  148. claude_mpm/hooks/__init__.py +1 -1
  149. claude_mpm/hooks/base_hook.py +33 -28
  150. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  151. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  152. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  153. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  154. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  155. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  156. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  157. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  158. claude_mpm/hooks/memory_integration_hook.py +140 -100
  159. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  160. claude_mpm/hooks/validation_hooks.py +57 -49
  161. claude_mpm/init.py +145 -121
  162. claude_mpm/models/__init__.py +9 -9
  163. claude_mpm/models/agent_definition.py +33 -23
  164. claude_mpm/models/agent_session.py +228 -200
  165. claude_mpm/scripts/__init__.py +1 -1
  166. claude_mpm/scripts/socketio_daemon.py +192 -75
  167. claude_mpm/scripts/socketio_server_manager.py +328 -0
  168. claude_mpm/scripts/start_activity_logging.py +25 -22
  169. claude_mpm/services/__init__.py +68 -43
  170. claude_mpm/services/agent_capabilities_service.py +271 -0
  171. claude_mpm/services/agents/__init__.py +23 -32
  172. claude_mpm/services/agents/deployment/__init__.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  174. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  175. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  176. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  177. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  178. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  179. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  180. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  181. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  182. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  183. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  184. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  185. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  186. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  187. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  188. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  189. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  190. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  191. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  192. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  193. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  194. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  195. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  196. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  197. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  198. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  199. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  200. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  201. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  202. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  203. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  204. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  205. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  206. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  207. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  208. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  209. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  210. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  211. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  212. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  213. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  214. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  215. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  216. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  217. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  218. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  219. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  220. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  221. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  222. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  223. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  224. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  225. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  226. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  227. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  228. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  229. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  230. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  231. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  232. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  233. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  234. claude_mpm/services/agents/loading/__init__.py +2 -2
  235. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  236. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  237. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  238. claude_mpm/services/agents/management/__init__.py +2 -2
  239. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  240. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  241. claude_mpm/services/agents/memory/__init__.py +9 -6
  242. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  243. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  244. claude_mpm/services/agents/memory/analyzer.py +430 -0
  245. claude_mpm/services/agents/memory/content_manager.py +376 -0
  246. claude_mpm/services/agents/memory/template_generator.py +468 -0
  247. claude_mpm/services/agents/registry/__init__.py +7 -10
  248. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  249. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  250. claude_mpm/services/async_session_logger.py +187 -153
  251. claude_mpm/services/claude_session_logger.py +87 -72
  252. claude_mpm/services/command_handler_service.py +217 -0
  253. claude_mpm/services/communication/__init__.py +3 -2
  254. claude_mpm/services/core/__init__.py +50 -97
  255. claude_mpm/services/core/base.py +60 -53
  256. claude_mpm/services/core/interfaces/__init__.py +188 -0
  257. claude_mpm/services/core/interfaces/agent.py +351 -0
  258. claude_mpm/services/core/interfaces/communication.py +343 -0
  259. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  260. claude_mpm/services/core/interfaces/service.py +434 -0
  261. claude_mpm/services/core/interfaces.py +19 -944
  262. claude_mpm/services/event_aggregator.py +208 -170
  263. claude_mpm/services/exceptions.py +387 -308
  264. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  265. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  266. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  267. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  268. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  269. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  270. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  271. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  272. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  273. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  274. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  275. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  276. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  277. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  278. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  279. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  280. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  281. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  283. claude_mpm/services/hook_service.py +106 -114
  284. claude_mpm/services/infrastructure/__init__.py +7 -5
  285. claude_mpm/services/infrastructure/context_preservation.py +571 -0
  286. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  287. claude_mpm/services/infrastructure/logging.py +83 -76
  288. claude_mpm/services/infrastructure/monitoring.py +547 -404
  289. claude_mpm/services/mcp_gateway/__init__.py +40 -23
  290. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  291. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  292. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  293. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  294. claude_mpm/services/mcp_gateway/core/__init__.py +14 -21
  295. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  296. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  297. claude_mpm/services/mcp_gateway/core/interfaces.py +97 -93
  298. claude_mpm/services/mcp_gateway/main.py +307 -127
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +100 -101
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +4 -4
  303. claude_mpm/services/mcp_gateway/server/{mcp_server.py → mcp_gateway.py} +149 -153
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +110 -121
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  309. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  310. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  311. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  312. claude_mpm/services/memory/__init__.py +2 -2
  313. claude_mpm/services/memory/builder.py +451 -362
  314. claude_mpm/services/memory/cache/__init__.py +2 -2
  315. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  316. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  317. claude_mpm/services/memory/indexed_memory.py +195 -193
  318. claude_mpm/services/memory/optimizer.py +267 -234
  319. claude_mpm/services/memory/router.py +571 -263
  320. claude_mpm/services/memory_hook_service.py +237 -0
  321. claude_mpm/services/port_manager.py +223 -0
  322. claude_mpm/services/project/__init__.py +3 -3
  323. claude_mpm/services/project/analyzer.py +451 -305
  324. claude_mpm/services/project/registry.py +262 -240
  325. claude_mpm/services/recovery_manager.py +287 -231
  326. claude_mpm/services/response_tracker.py +87 -67
  327. claude_mpm/services/runner_configuration_service.py +587 -0
  328. claude_mpm/services/session_management_service.py +304 -0
  329. claude_mpm/services/socketio/__init__.py +4 -4
  330. claude_mpm/services/socketio/client_proxy.py +174 -0
  331. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  332. claude_mpm/services/socketio/handlers/base.py +44 -30
  333. claude_mpm/services/socketio/handlers/connection.py +145 -65
  334. claude_mpm/services/socketio/handlers/file.py +123 -108
  335. claude_mpm/services/socketio/handlers/git.py +607 -373
  336. claude_mpm/services/socketio/handlers/hook.py +170 -0
  337. claude_mpm/services/socketio/handlers/memory.py +4 -4
  338. claude_mpm/services/socketio/handlers/project.py +4 -4
  339. claude_mpm/services/socketio/handlers/registry.py +53 -38
  340. claude_mpm/services/socketio/server/__init__.py +18 -0
  341. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  342. claude_mpm/services/socketio/server/core.py +399 -0
  343. claude_mpm/services/socketio/server/main.py +323 -0
  344. claude_mpm/services/socketio_client_manager.py +160 -133
  345. claude_mpm/services/socketio_server.py +36 -1885
  346. claude_mpm/services/subprocess_launcher_service.py +316 -0
  347. claude_mpm/services/system_instructions_service.py +258 -0
  348. claude_mpm/services/ticket_manager.py +20 -534
  349. claude_mpm/services/utility_service.py +285 -0
  350. claude_mpm/services/version_control/__init__.py +18 -21
  351. claude_mpm/services/version_control/branch_strategy.py +20 -10
  352. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  353. claude_mpm/services/version_control/git_operations.py +52 -21
  354. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  355. claude_mpm/services/version_control/version_parser.py +145 -125
  356. claude_mpm/services/version_service.py +270 -0
  357. claude_mpm/storage/__init__.py +9 -0
  358. claude_mpm/storage/state_storage.py +552 -0
  359. claude_mpm/ticket_wrapper.py +2 -2
  360. claude_mpm/utils/__init__.py +2 -2
  361. claude_mpm/utils/agent_dependency_loader.py +453 -243
  362. claude_mpm/utils/config_manager.py +157 -118
  363. claude_mpm/utils/console.py +1 -1
  364. claude_mpm/utils/dependency_cache.py +102 -107
  365. claude_mpm/utils/dependency_manager.py +52 -47
  366. claude_mpm/utils/dependency_strategies.py +131 -96
  367. claude_mpm/utils/environment_context.py +110 -102
  368. claude_mpm/utils/error_handler.py +75 -55
  369. claude_mpm/utils/file_utils.py +80 -67
  370. claude_mpm/utils/framework_detection.py +12 -11
  371. claude_mpm/utils/import_migration_example.py +12 -60
  372. claude_mpm/utils/imports.py +48 -45
  373. claude_mpm/utils/path_operations.py +100 -93
  374. claude_mpm/utils/robust_installer.py +172 -164
  375. claude_mpm/utils/session_logging.py +30 -23
  376. claude_mpm/utils/subprocess_utils.py +99 -61
  377. claude_mpm/validation/__init__.py +1 -1
  378. claude_mpm/validation/agent_validator.py +151 -111
  379. claude_mpm/validation/frontmatter_validator.py +92 -71
  380. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +51 -2
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/config/memory_guardian_config.py +0 -325
  385. claude_mpm/core/config_paths.py +0 -150
  386. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  387. claude_mpm/deployment_paths.py +0 -261
  388. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  389. claude_mpm/models/state_models.py +0 -433
  390. claude_mpm/services/agent/__init__.py +0 -24
  391. claude_mpm/services/agent/deployment.py +0 -2548
  392. claude_mpm/services/agent/management.py +0 -598
  393. claude_mpm/services/agent/registry.py +0 -813
  394. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  395. claude_mpm/services/communication/socketio.py +0 -1935
  396. claude_mpm/services/communication/websocket.py +0 -479
  397. claude_mpm/services/framework_claude_md_generator.py +0 -624
  398. claude_mpm/services/health_monitor.py +0 -893
  399. claude_mpm/services/infrastructure/memory_guardian.py +0 -770
  400. claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +0 -444
  401. claude_mpm/services/optimized_hook_service.py +0 -542
  402. claude_mpm/services/project_analyzer.py +0 -864
  403. claude_mpm/services/project_registry.py +0 -608
  404. claude_mpm/services/standalone_socketio_server.py +0 -1300
  405. claude_mpm/services/ticket_manager_di.py +0 -318
  406. claude_mpm/services/ticketing_service_original.py +0 -510
  407. claude_mpm/utils/paths.py +0 -395
  408. claude_mpm/utils/platform_memory.py +0 -524
  409. claude_mpm-3.9.9.dist-info/RECORD +0 -293
  410. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  411. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,352 @@
1
+ """Agent Validator Service
2
+
3
+ This service handles validation and repair of agent configurations, templates, and deployments.
4
+ Ensures agent files meet Claude Code requirements and can fix common issues.
5
+
6
+ Extracted from AgentDeploymentService as part of the refactoring to improve
7
+ maintainability and testability.
8
+ """
9
+
10
+ import logging
11
+ import re
12
+ from pathlib import Path
13
+ from typing import Any, Dict, List, Optional, Tuple
14
+
15
+ from claude_mpm.core.logging_config import get_logger
16
+
17
+
18
+ class AgentValidator:
19
+ """Service for validating and repairing agent configurations.
20
+
21
+ This service handles:
22
+ - Agent template validation
23
+ - YAML frontmatter validation and repair
24
+ - Agent file structure verification
25
+ - Configuration compliance checking
26
+ """
27
+
28
+ def __init__(self):
29
+ """Initialize the agent validator."""
30
+ self.logger = get_logger(__name__)
31
+
32
+ def validate_agent(self, agent_path: Path) -> Tuple[bool, List[str]]:
33
+ """
34
+ Validate agent configuration and structure.
35
+
36
+ Args:
37
+ agent_path: Path to the agent file to validate
38
+
39
+ Returns:
40
+ Tuple of (is_valid: bool, errors: List[str])
41
+ """
42
+ errors = []
43
+
44
+ try:
45
+ if not agent_path.exists():
46
+ errors.append(f"Agent file does not exist: {agent_path}")
47
+ return False, errors
48
+
49
+ # Read agent content
50
+ content = agent_path.read_text()
51
+
52
+ # Validate YAML frontmatter
53
+ frontmatter_valid, frontmatter_errors = self._validate_yaml_frontmatter(
54
+ content
55
+ )
56
+ errors.extend(frontmatter_errors)
57
+
58
+ # Validate required fields
59
+ required_fields_valid, field_errors = self._validate_required_fields(
60
+ content
61
+ )
62
+ errors.extend(field_errors)
63
+
64
+ # Validate agent name format
65
+ name_valid, name_errors = self._validate_agent_name(content)
66
+ errors.extend(name_errors)
67
+
68
+ # Validate tools format
69
+ tools_valid, tools_errors = self._validate_tools_format(content)
70
+ errors.extend(tools_errors)
71
+
72
+ is_valid = (
73
+ frontmatter_valid
74
+ and required_fields_valid
75
+ and name_valid
76
+ and tools_valid
77
+ )
78
+
79
+ except Exception as e:
80
+ errors.append(f"Error validating agent: {e}")
81
+ is_valid = False
82
+
83
+ return is_valid, errors
84
+
85
+ def validate_and_repair_existing_agents(self, agents_dir: Path) -> Dict[str, Any]:
86
+ """
87
+ Validate and repair broken frontmatter in existing agent files.
88
+
89
+ This method scans all agent files in the directory and attempts to repair
90
+ common issues like malformed YAML frontmatter, missing required fields, etc.
91
+
92
+ Args:
93
+ agents_dir: Directory containing agent files
94
+
95
+ Returns:
96
+ Dictionary with repair results
97
+ """
98
+ results = {"repaired": [], "errors": [], "skipped": [], "total_checked": 0}
99
+
100
+ if not agents_dir.exists():
101
+ self.logger.info(f"Agents directory does not exist: {agents_dir}")
102
+ return results
103
+
104
+ # Find all agent files (both .md and .yaml)
105
+ agent_files = list(agents_dir.glob("*.md")) + list(agents_dir.glob("*.yaml"))
106
+ results["total_checked"] = len(agent_files)
107
+
108
+ for agent_file in agent_files:
109
+ try:
110
+ self.logger.debug(f"Checking agent file: {agent_file.name}")
111
+
112
+ # Read current content
113
+ original_content = agent_file.read_text()
114
+
115
+ # Attempt to repair the file
116
+ repaired_content, was_repaired, repair_issues = self._repair_agent_file(
117
+ original_content
118
+ )
119
+
120
+ if was_repaired:
121
+ # Write repaired content back to file
122
+ agent_file.write_text(repaired_content)
123
+
124
+ repair_info = {
125
+ "file": agent_file.name,
126
+ "issues_fixed": repair_issues,
127
+ }
128
+ results["repaired"].append(repair_info)
129
+ self.logger.info(
130
+ f"Repaired agent file: {agent_file.name} (fixed: {', '.join(repair_issues)})"
131
+ )
132
+ else:
133
+ results["skipped"].append(agent_file.name)
134
+ self.logger.debug(f"No repairs needed for: {agent_file.name}")
135
+
136
+ except Exception as e:
137
+ error_msg = f"Failed to repair {agent_file.name}: {e}"
138
+ results["errors"].append(error_msg)
139
+ self.logger.error(error_msg)
140
+
141
+ self.logger.info(
142
+ f"Agent validation complete: {len(results['repaired'])} repaired, {len(results['errors'])} errors"
143
+ )
144
+ return results
145
+
146
+ def verify_deployment(self, config_dir: Optional[Path] = None) -> Dict[str, Any]:
147
+ """
148
+ Verify agent deployment and Claude configuration.
149
+
150
+ Args:
151
+ config_dir: Claude configuration directory (default: .claude/)
152
+
153
+ Returns:
154
+ Dictionary with verification results
155
+ """
156
+ if not config_dir:
157
+ config_dir = Path.cwd() / ".claude"
158
+
159
+ results = {
160
+ "config_dir": str(config_dir),
161
+ "agents_found": [],
162
+ "agents_needing_migration": [],
163
+ "environment": {},
164
+ "warnings": [],
165
+ }
166
+
167
+ # Check if config directory exists
168
+ if not config_dir.exists():
169
+ results["warnings"].append(f"Config directory does not exist: {config_dir}")
170
+ return results
171
+
172
+ # Check agents directory
173
+ agents_dir = config_dir / "agents"
174
+ if not agents_dir.exists():
175
+ results["warnings"].append(f"Agents directory does not exist: {agents_dir}")
176
+ return results
177
+
178
+ # Scan for agent files
179
+ agent_files = list(agents_dir.glob("*.md")) + list(agents_dir.glob("*.yaml"))
180
+
181
+ for agent_file in agent_files:
182
+ try:
183
+ content = agent_file.read_text()
184
+
185
+ # Extract basic info from YAML frontmatter
186
+ agent_info = self._extract_agent_info(content, agent_file)
187
+
188
+ # Check if agent needs migration (old version format)
189
+ if self._needs_version_migration(content):
190
+ agent_info["needs_migration"] = True
191
+ results["agents_needing_migration"].append(agent_info["name"])
192
+
193
+ results["agents_found"].append(agent_info)
194
+
195
+ except Exception as e:
196
+ self.logger.warning(
197
+ f"Could not process agent file {agent_file.name}: {e}"
198
+ )
199
+
200
+ # Add environment information
201
+ import os
202
+
203
+ results["environment"] = {
204
+ key: value for key, value in os.environ.items() if key.startswith("CLAUDE_")
205
+ }
206
+
207
+ return results
208
+
209
+ def _validate_yaml_frontmatter(self, content: str) -> Tuple[bool, List[str]]:
210
+ """Validate YAML frontmatter structure."""
211
+ errors = []
212
+
213
+ # Check if content starts with YAML frontmatter
214
+ if not content.strip().startswith("---"):
215
+ errors.append("Missing YAML frontmatter")
216
+ return False, errors
217
+
218
+ # Find the end of frontmatter
219
+ lines = content.split("\n")
220
+ frontmatter_end = -1
221
+
222
+ for i, line in enumerate(lines[1:], 1): # Skip first ---
223
+ if line.strip() == "---":
224
+ frontmatter_end = i
225
+ break
226
+
227
+ if frontmatter_end == -1:
228
+ errors.append("YAML frontmatter not properly closed")
229
+ return False, errors
230
+
231
+ return True, errors
232
+
233
+ def _validate_required_fields(self, content: str) -> Tuple[bool, List[str]]:
234
+ """Validate required fields in agent content."""
235
+ errors = []
236
+ required_fields = ["name", "description", "tools"]
237
+
238
+ for field in required_fields:
239
+ field_pattern = rf"^{field}:\s*.+$"
240
+ if not re.search(field_pattern, content, re.MULTILINE):
241
+ errors.append(f"Missing required field: {field}")
242
+
243
+ return len(errors) == 0, errors
244
+
245
+ def _validate_agent_name(self, content: str) -> Tuple[bool, List[str]]:
246
+ """Validate agent name format."""
247
+ errors = []
248
+
249
+ # Extract name from frontmatter
250
+ name_match = re.search(r'^name:\s*["\']?(.+?)["\']?$', content, re.MULTILINE)
251
+ if name_match:
252
+ name = name_match.group(1).strip()
253
+
254
+ # Validate Claude Code name requirements
255
+ if not re.match(r"^[a-z0-9]+(-[a-z0-9]+)*$", name):
256
+ errors.append(
257
+ f"Invalid agent name format: '{name}'. Must match ^[a-z0-9]+(-[a-z0-9]+)*$"
258
+ )
259
+
260
+ return len(errors) == 0, errors
261
+
262
+ def _validate_tools_format(self, content: str) -> Tuple[bool, List[str]]:
263
+ """Validate tools format."""
264
+ errors = []
265
+
266
+ # Extract tools from frontmatter
267
+ tools_match = re.search(r"^tools:\s*(.+)$", content, re.MULTILINE)
268
+ if tools_match:
269
+ tools_str = tools_match.group(1).strip()
270
+
271
+ # Check for spaces in comma-separated tools (not allowed)
272
+ if ", " in tools_str:
273
+ errors.append("Tools must be comma-separated WITHOUT spaces")
274
+
275
+ return len(errors) == 0, errors
276
+
277
+ def _repair_agent_file(self, content: str) -> Tuple[str, bool, List[str]]:
278
+ """
279
+ Attempt to repair common issues in agent file content.
280
+
281
+ Returns:
282
+ Tuple of (repaired_content, was_repaired, issues_fixed)
283
+ """
284
+ repaired_content = content
285
+ issues_fixed = []
286
+ was_repaired = False
287
+
288
+ # Fix tools format (remove spaces after commas)
289
+ tools_pattern = r"^(tools:\s*)([^,\n]+(?:,\s+[^,\n]+)+)$"
290
+ tools_match = re.search(tools_pattern, repaired_content, re.MULTILINE)
291
+ if tools_match:
292
+ tools_prefix = tools_match.group(1)
293
+ tools_value = tools_match.group(2)
294
+
295
+ if ", " in tools_value:
296
+ # Remove spaces after commas
297
+ fixed_tools = tools_value.replace(", ", ",")
298
+ repaired_content = re.sub(
299
+ tools_pattern,
300
+ f"{tools_prefix}{fixed_tools}",
301
+ repaired_content,
302
+ flags=re.MULTILINE,
303
+ )
304
+ issues_fixed.append("tools_spacing")
305
+ was_repaired = True
306
+
307
+ # Add missing required fields with defaults
308
+ if "description:" not in repaired_content:
309
+ # Insert description after name if possible
310
+ name_match = re.search(r"^(name:\s*.+)$", repaired_content, re.MULTILINE)
311
+ if name_match:
312
+ name_line = name_match.group(1)
313
+ repaired_content = repaired_content.replace(
314
+ name_line,
315
+ f'{name_line}\ndescription: "Agent for specialized tasks"',
316
+ )
317
+ issues_fixed.append("missing_description")
318
+ was_repaired = True
319
+
320
+ return repaired_content, was_repaired, issues_fixed
321
+
322
+ def _extract_agent_info(self, content: str, agent_file: Path) -> Dict[str, Any]:
323
+ """Extract basic agent information from content."""
324
+ agent_info = {
325
+ "file": agent_file.name,
326
+ "name": agent_file.stem,
327
+ "description": "No description",
328
+ "version": "unknown",
329
+ }
330
+
331
+ # Extract from YAML frontmatter
332
+ lines = content.split("\n")
333
+ for line in lines:
334
+ if line.startswith("name:"):
335
+ agent_info["name"] = line.split(":", 1)[1].strip().strip("\"'")
336
+ elif line.startswith("description:"):
337
+ agent_info["description"] = line.split(":", 1)[1].strip().strip("\"'")
338
+ elif line.startswith("version:"):
339
+ agent_info["version"] = line.split(":", 1)[1].strip().strip("\"'")
340
+
341
+ return agent_info
342
+
343
+ def _needs_version_migration(self, content: str) -> bool:
344
+ """Check if agent needs version migration."""
345
+ version_match = re.search(
346
+ r'^version:\s*["\']?(.+?)["\']?$', content, re.MULTILINE
347
+ )
348
+ if version_match:
349
+ version_str = version_match.group(1)
350
+ # Check for old format (contains hyphen and all digits)
351
+ return bool(re.match(r"^\d+-\d+$", version_str))
352
+ return False
@@ -0,0 +1,313 @@
1
+ """Agent Version Manager Service
2
+
3
+ This service handles all version-related operations for agent deployment,
4
+ including version parsing, comparison, migration detection, and format conversion.
5
+
6
+ Extracted from AgentDeploymentService as part of the refactoring to improve
7
+ maintainability and testability.
8
+ """
9
+
10
+ import logging
11
+ import re
12
+ from pathlib import Path
13
+ from typing import Any, Dict, Tuple
14
+
15
+ from claude_mpm.core.logging_config import get_logger
16
+
17
+
18
+ class AgentVersionManager:
19
+ """Service for managing agent versions and migrations.
20
+
21
+ This service handles:
22
+ - Version parsing from various formats (integer, semantic, legacy)
23
+ - Version comparison for update decisions
24
+ - Migration detection from old to new formats
25
+ - Version format validation and conversion
26
+ """
27
+
28
+ def __init__(self):
29
+ """Initialize the version manager."""
30
+ self.logger = get_logger(__name__)
31
+
32
+ def parse_version(self, version_value: Any) -> Tuple[int, int, int]:
33
+ """
34
+ Parse version from various formats to semantic version tuple.
35
+
36
+ Handles:
37
+ - Integer values: 5 -> (0, 5, 0)
38
+ - String integers: "5" -> (0, 5, 0)
39
+ - Semantic versions: "2.1.0" -> (2, 1, 0)
40
+ - Invalid formats: returns (0, 0, 0)
41
+
42
+ Args:
43
+ version_value: Version in various formats
44
+
45
+ Returns:
46
+ Tuple of (major, minor, patch) for comparison
47
+ """
48
+ if isinstance(version_value, int):
49
+ # Legacy integer version - treat as minor version
50
+ return (0, version_value, 0)
51
+
52
+ if isinstance(version_value, str):
53
+ # Try to parse as simple integer
54
+ if version_value.isdigit():
55
+ return (0, int(version_value), 0)
56
+
57
+ # Try to parse semantic version (e.g., "2.1.0" or "v2.1.0")
58
+ sem_ver_match = re.match(r"^v?(\d+)\.(\d+)\.(\d+)", version_value)
59
+ if sem_ver_match:
60
+ major = int(sem_ver_match.group(1))
61
+ minor = int(sem_ver_match.group(2))
62
+ patch = int(sem_ver_match.group(3))
63
+ return (major, minor, patch)
64
+
65
+ # Try to extract first number from string as minor version
66
+ num_match = re.search(r"(\d+)", version_value)
67
+ if num_match:
68
+ return (0, int(num_match.group(1)), 0)
69
+
70
+ # Default to 0.0.0 for invalid formats
71
+ return (0, 0, 0)
72
+
73
+ def format_version_display(self, version_tuple: Tuple[int, int, int]) -> str:
74
+ """
75
+ Format version tuple for display.
76
+
77
+ Args:
78
+ version_tuple: Tuple of (major, minor, patch)
79
+
80
+ Returns:
81
+ Formatted version string
82
+ """
83
+ if isinstance(version_tuple, tuple) and len(version_tuple) == 3:
84
+ major, minor, patch = version_tuple
85
+ return f"{major}.{minor}.{patch}"
86
+ else:
87
+ # Fallback for legacy format
88
+ return str(version_tuple)
89
+
90
+ def is_old_version_format(self, version_str: str) -> bool:
91
+ """
92
+ Check if a version string is in the old serial format.
93
+
94
+ Old formats include:
95
+ - Serial format: "0002-0005" (contains hyphen, all digits)
96
+ - Missing version field
97
+ - Non-semantic version formats
98
+
99
+ Args:
100
+ version_str: Version string to check
101
+
102
+ Returns:
103
+ True if old format, False if semantic version
104
+ """
105
+ if not version_str:
106
+ return True
107
+
108
+ # Check for serial format (e.g., "0002-0005")
109
+ if re.match(r"^\d+-\d+$", version_str):
110
+ return True
111
+
112
+ # Check for semantic version format (e.g., "2.1.0")
113
+ if re.match(r"^v?\d+\.\d+\.\d+$", version_str):
114
+ return False
115
+
116
+ # Any other format is considered old
117
+ return True
118
+
119
+ def compare_versions(
120
+ self, v1: Tuple[int, int, int], v2: Tuple[int, int, int]
121
+ ) -> int:
122
+ """
123
+ Compare two version tuples.
124
+
125
+ Args:
126
+ v1: First version tuple
127
+ v2: Second version tuple
128
+
129
+ Returns:
130
+ -1 if v1 < v2, 0 if equal, 1 if v1 > v2
131
+ """
132
+ for a, b in zip(v1, v2):
133
+ if a < b:
134
+ return -1
135
+ elif a > b:
136
+ return 1
137
+ return 0
138
+
139
+ def extract_version_from_content(self, content: str, version_marker: str) -> int:
140
+ """
141
+ Extract version number from content using a marker.
142
+
143
+ Args:
144
+ content: File content
145
+ version_marker: Version marker to look for (e.g., "AGENT_VERSION:" or "BASE_AGENT_VERSION:")
146
+
147
+ Returns:
148
+ Version number or 0 if not found
149
+ """
150
+ pattern = rf"<!-- {version_marker} (\d+) -->"
151
+ match = re.search(pattern, content)
152
+ if match:
153
+ return int(match.group(1))
154
+ return 0
155
+
156
+ def extract_version_from_frontmatter(
157
+ self, content: str
158
+ ) -> Tuple[Tuple[int, int, int], bool, str]:
159
+ """
160
+ Extract version information from YAML frontmatter.
161
+
162
+ Args:
163
+ content: File content with YAML frontmatter
164
+
165
+ Returns:
166
+ Tuple of (version_tuple, is_old_format, version_string)
167
+ """
168
+ is_old_format = False
169
+ version_string = None
170
+
171
+ # Try legacy combined format (e.g., "0002-0005")
172
+ legacy_match = re.search(
173
+ r'^version:\s*["\']?(\d+)-(\d+)["\']?', content, re.MULTILINE
174
+ )
175
+ if legacy_match:
176
+ is_old_format = True
177
+ version_string = f"{legacy_match.group(1)}-{legacy_match.group(2)}"
178
+ # Convert legacy format to semantic version
179
+ # Treat the agent version (second number) as minor version
180
+ version_tuple = (0, int(legacy_match.group(2)), 0)
181
+ self.logger.info(f"Detected old serial version format: {version_string}")
182
+ return version_tuple, is_old_format, version_string
183
+
184
+ # Try to extract semantic version format (e.g., "2.1.0")
185
+ version_match = re.search(
186
+ r'^version:\s*["\']?v?(\d+)\.(\d+)\.(\d+)["\']?', content, re.MULTILINE
187
+ )
188
+ if version_match:
189
+ version_tuple = (
190
+ int(version_match.group(1)),
191
+ int(version_match.group(2)),
192
+ int(version_match.group(3)),
193
+ )
194
+ version_string = f"{version_match.group(1)}.{version_match.group(2)}.{version_match.group(3)}"
195
+ return version_tuple, is_old_format, version_string
196
+
197
+ # Fallback: try separate fields (very old format)
198
+ agent_version_match = re.search(
199
+ r"^agent_version:\s*(\d+)", content, re.MULTILINE
200
+ )
201
+ if agent_version_match:
202
+ is_old_format = True
203
+ version_string = f"agent_version: {agent_version_match.group(1)}"
204
+ version_tuple = (0, int(agent_version_match.group(1)), 0)
205
+ self.logger.info(f"Detected old separate version format: {version_string}")
206
+ return version_tuple, is_old_format, version_string
207
+
208
+ # Check for missing version field
209
+ if "version:" not in content:
210
+ is_old_format = True
211
+ version_string = "missing"
212
+ version_tuple = (0, 0, 0)
213
+ self.logger.info("Detected missing version field")
214
+ return version_tuple, is_old_format, version_string
215
+
216
+ # Default case
217
+ return (0, 0, 0), False, "0.0.0"
218
+
219
+ def check_agent_needs_update(
220
+ self,
221
+ deployed_file: Path,
222
+ template_file: Path,
223
+ current_base_version: Tuple[int, int, int],
224
+ ) -> Tuple[bool, str]:
225
+ """
226
+ Check if a deployed agent needs to be updated.
227
+
228
+ Args:
229
+ deployed_file: Path to the deployed agent file
230
+ template_file: Path to the template file
231
+ current_base_version: Current base agent version (for compatibility)
232
+
233
+ Returns:
234
+ Tuple of (needs_update: bool, reason: str)
235
+ """
236
+ try:
237
+ # Read deployed agent content
238
+ deployed_content = deployed_file.read_text()
239
+
240
+ # Skip non-system agents (user-created)
241
+ if "author: claude-mpm" not in deployed_content:
242
+ return (False, "not a system agent")
243
+
244
+ # Extract version info from YAML frontmatter
245
+ (
246
+ deployed_version,
247
+ is_old_format,
248
+ old_version_str,
249
+ ) = self.extract_version_from_frontmatter(deployed_content)
250
+
251
+ # Read template to get current agent version
252
+ import json
253
+
254
+ template_data = json.loads(template_file.read_text())
255
+
256
+ # Extract agent version from template
257
+ current_agent_version = self.parse_version(
258
+ template_data.get("agent_version") or template_data.get("version", 0)
259
+ )
260
+
261
+ # If old format detected, always trigger update for migration
262
+ if is_old_format:
263
+ new_version_str = self.format_version_display(current_agent_version)
264
+ return (
265
+ True,
266
+ f"migration needed from old format ({old_version_str}) to semantic version ({new_version_str})",
267
+ )
268
+
269
+ # Check if agent template version is newer
270
+ if self.compare_versions(current_agent_version, deployed_version) > 0:
271
+ deployed_str = self.format_version_display(deployed_version)
272
+ current_str = self.format_version_display(current_agent_version)
273
+ return (
274
+ True,
275
+ f"agent template updated ({deployed_str} -> {current_str})",
276
+ )
277
+
278
+ return (False, "up to date")
279
+
280
+ except Exception as e:
281
+ self.logger.warning(f"Error checking agent update status: {e}")
282
+ # On error, assume update is needed
283
+ return (True, "version check failed")
284
+
285
+ def validate_version_in_content(self, content: str) -> Tuple[bool, list]:
286
+ """
287
+ Validate version information in agent content.
288
+
289
+ Args:
290
+ content: Agent file content
291
+
292
+ Returns:
293
+ Tuple of (is_valid: bool, errors: list)
294
+ """
295
+ errors = []
296
+
297
+ # Check for YAML frontmatter
298
+ if not content.strip().startswith("---"):
299
+ errors.append("Missing YAML frontmatter")
300
+ return False, errors
301
+
302
+ # Extract and validate version
303
+ version_match = re.search(
304
+ r'^version:\s*["\']?(.+?)["\']?$', content, re.MULTILINE
305
+ )
306
+ if not version_match:
307
+ errors.append("Missing version field in frontmatter")
308
+ else:
309
+ version_str = version_match.group(1)
310
+ if self.is_old_version_format(version_str):
311
+ errors.append(f"Old version format detected: {version_str}")
312
+
313
+ return len(errors) == 0, errors
@@ -2,28 +2,25 @@
2
2
  Agent Version Manager - Stub implementation for testing
3
3
  """
4
4
 
5
+
5
6
  class AgentVersionManager:
6
7
  """Stub implementation of AgentVersionManager for integration testing."""
7
-
8
- def __init__(self):
9
- """Initialize version manager."""
10
- pass
11
-
8
+
12
9
  def get_next_version(self, current_version: str, change_type: str = "patch") -> str:
13
10
  """Get next version number."""
14
11
  parts = current_version.split(".")
15
12
  if len(parts) != 3:
16
13
  return "1.0.0"
17
-
14
+
18
15
  major, minor, patch = map(int, parts)
19
-
16
+
20
17
  if change_type == "major":
21
18
  return f"{major + 1}.0.0"
22
19
  elif change_type == "minor":
23
20
  return f"{major}.{minor + 1}.0"
24
21
  else: # patch
25
22
  return f"{major}.{minor}.{patch + 1}"
26
-
23
+
27
24
  def validate_version(self, version: str) -> bool:
28
25
  """Validate version format."""
29
26
  try:
@@ -34,4 +31,4 @@ class AgentVersionManager:
34
31
  int(part)
35
32
  return True
36
33
  except:
37
- return False
34
+ return False