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,453 @@
1
+ """Agent Format Converter Service
2
+
3
+ This service handles format conversion between different agent file formats,
4
+ particularly YAML to Markdown conversion and format migration utilities.
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 datetime import datetime
13
+ from pathlib import Path
14
+ from typing import Any, Dict, List, Optional
15
+
16
+ from claude_mpm.core.logging_config import get_logger
17
+
18
+
19
+ class AgentFormatConverter:
20
+ """Service for converting agent files between different formats.
21
+
22
+ This service handles:
23
+ - YAML to Markdown conversion with YAML frontmatter
24
+ - Format migration and backward compatibility
25
+ - Field extraction from various formats
26
+ - Content structure transformation
27
+ """
28
+
29
+ def __init__(self):
30
+ """Initialize the agent format converter."""
31
+ self.logger = get_logger(__name__)
32
+
33
+ def convert_yaml_to_md(self, target_dir: Path) -> Dict[str, Any]:
34
+ """
35
+ Convert existing YAML agent files to MD format with YAML frontmatter.
36
+
37
+ This method handles backward compatibility by finding existing .yaml
38
+ agent files and converting them to .md format expected by Claude Code.
39
+
40
+ Args:
41
+ target_dir: Directory containing agent files to convert
42
+
43
+ Returns:
44
+ Dictionary with conversion results
45
+ """
46
+ results = {"converted": [], "errors": [], "skipped": []}
47
+
48
+ if not target_dir.exists():
49
+ self.logger.debug(f"Target directory does not exist: {target_dir}")
50
+ return results
51
+
52
+ try:
53
+ # Find YAML files that need conversion
54
+ yaml_files = list(target_dir.glob("*.yaml"))
55
+
56
+ for yaml_file in yaml_files:
57
+ try:
58
+ # Check if corresponding MD file already exists
59
+ md_file = yaml_file.with_suffix(".md")
60
+
61
+ if md_file.exists():
62
+ # Check modification times
63
+ yaml_mtime = yaml_file.stat().st_mtime
64
+ md_mtime = md_file.stat().st_mtime
65
+
66
+ if md_mtime >= yaml_mtime:
67
+ # MD file is newer or same age, skip conversion
68
+ results["skipped"].append(yaml_file.name)
69
+ continue
70
+ else:
71
+ # MD file is older, proceed with conversion
72
+ self.logger.info(
73
+ f"MD file {md_file.name} is older than YAML, converting..."
74
+ )
75
+
76
+ # Read YAML content
77
+ yaml_content = yaml_file.read_text()
78
+
79
+ # Convert to MD format
80
+ md_content = self.convert_yaml_content_to_md(
81
+ yaml_content, yaml_file.stem
82
+ )
83
+
84
+ # Write MD file
85
+ md_file.write_text(md_content)
86
+
87
+ # Remove original YAML file
88
+ yaml_file.unlink()
89
+
90
+ results["converted"].append(
91
+ {"from": yaml_file.name, "to": md_file.name}
92
+ )
93
+
94
+ self.logger.info(f"Converted {yaml_file.name} to {md_file.name}")
95
+
96
+ except Exception as e:
97
+ error_msg = f"Failed to convert {yaml_file.name}: {e}"
98
+ results["errors"].append(error_msg)
99
+ self.logger.error(error_msg)
100
+
101
+ except Exception as e:
102
+ error_msg = f"YAML to MD conversion failed: {e}"
103
+ self.logger.error(error_msg)
104
+ results["errors"].append(error_msg)
105
+
106
+ return results
107
+
108
+ def convert_yaml_content_to_md(self, yaml_content: str, agent_name: str) -> str:
109
+ """
110
+ Convert YAML agent content to MD format with YAML frontmatter.
111
+
112
+ Args:
113
+ yaml_content: Original YAML content
114
+ agent_name: Name of the agent
115
+
116
+ Returns:
117
+ Converted Markdown content with YAML frontmatter
118
+ """
119
+ # Extract fields from YAML content
120
+ name = self.extract_yaml_field(yaml_content, "name") or agent_name
121
+ description = (
122
+ self.extract_yaml_field(yaml_content, "description")
123
+ or f"{agent_name.title()} agent for specialized tasks"
124
+ )
125
+ version = self.extract_yaml_field(yaml_content, "version") or "1.0.0"
126
+ tools_line = (
127
+ self.extract_yaml_field(yaml_content, "tools")
128
+ or "Read,Write,Edit,Grep,Glob,LS"
129
+ )
130
+
131
+ # Convert tools string to list format if needed
132
+ if isinstance(tools_line, str):
133
+ if tools_line.startswith("[") and tools_line.endswith("]"):
134
+ # Already in list format
135
+ tools_list = tools_line
136
+ else:
137
+ # Convert comma-separated to list
138
+ tools = [tool.strip() for tool in tools_line.split(",")]
139
+ tools_list = str(tools).replace("'", '"')
140
+ else:
141
+ tools_list = '["Read", "Write", "Edit"]'
142
+
143
+ # Extract additional fields
144
+ model = self.extract_yaml_field(yaml_content, "model") or "sonnet"
145
+ author = (
146
+ self.extract_yaml_field(yaml_content, "author")
147
+ or "claude-mpm@anthropic.com"
148
+ )
149
+
150
+ # Extract instructions from YAML content
151
+ instructions = self._extract_instructions_from_yaml(yaml_content, agent_name)
152
+
153
+ # Build new YAML frontmatter
154
+ current_time = datetime.now().isoformat() + "Z"
155
+
156
+ new_frontmatter = f"""---
157
+ name: {name}
158
+ description: "{description}"
159
+ version: "{version}"
160
+ author: "{author}"
161
+ created: "{current_time}"
162
+ updated: "{current_time}"
163
+ tags: ["{agent_name}", "mpm-framework"]
164
+ tools: {tools_list}
165
+ model: "{model}"
166
+ ---
167
+
168
+ """
169
+
170
+ return new_frontmatter + instructions
171
+
172
+ def extract_yaml_field(self, yaml_content: str, field_name: str) -> Optional[str]:
173
+ """
174
+ Extract a field value from YAML content.
175
+
176
+ Args:
177
+ yaml_content: YAML content string
178
+ field_name: Name of the field to extract
179
+
180
+ Returns:
181
+ Field value or None if not found
182
+ """
183
+ # Try to match multi-line field first (with | or >)
184
+ multiline_pattern = rf"^{field_name}:\s*[|>]\s*\n((?:[ \t]+.+\n?)*)"
185
+ multiline_match = re.search(multiline_pattern, yaml_content, re.MULTILINE)
186
+ if multiline_match:
187
+ # Extract indented content and remove common indentation
188
+ lines = multiline_match.group(1).split("\n")
189
+ # Remove empty lines at the end
190
+ while lines and not lines[-1].strip():
191
+ lines.pop()
192
+
193
+ if lines:
194
+ # Find minimum indentation (excluding empty lines)
195
+ min_indent = float("inf")
196
+ for line in lines:
197
+ if line.strip(): # Skip empty lines
198
+ indent = len(line) - len(line.lstrip())
199
+ min_indent = min(min_indent, indent)
200
+
201
+ # Remove common indentation
202
+ if min_indent != float("inf"):
203
+ dedented_lines = []
204
+ for line in lines:
205
+ if line.strip(): # Non-empty line
206
+ dedented_lines.append(line[min_indent:])
207
+ else: # Empty line
208
+ dedented_lines.append("")
209
+ return "\n".join(dedented_lines).strip()
210
+
211
+ # Try to match field with various quote styles
212
+ patterns = [
213
+ rf'^{field_name}:\s*"([^"]*)"', # Double quotes
214
+ rf"^{field_name}:\s*'([^']*)'", # Single quotes
215
+ rf"^{field_name}:\s*([^\n\r]+)", # No quotes
216
+ ]
217
+
218
+ for pattern in patterns:
219
+ match = re.search(pattern, yaml_content, re.MULTILINE)
220
+ if match:
221
+ value = match.group(1).strip()
222
+ if value:
223
+ return value
224
+
225
+ return None
226
+
227
+ def convert_md_to_yaml(self, md_content: str) -> str:
228
+ """
229
+ Convert Markdown with YAML frontmatter back to pure YAML format.
230
+
231
+ Args:
232
+ md_content: Markdown content with YAML frontmatter
233
+
234
+ Returns:
235
+ Pure YAML content
236
+ """
237
+ if not md_content.strip().startswith("---"):
238
+ # No frontmatter, treat as plain YAML
239
+ return md_content
240
+
241
+ # Split frontmatter and markdown content
242
+ parts = md_content.split("---", 2)
243
+ if len(parts) < 3:
244
+ return md_content
245
+
246
+ frontmatter = parts[1].strip()
247
+ markdown_content = parts[2].strip()
248
+
249
+ # Add instructions field if there's markdown content
250
+ if markdown_content:
251
+ frontmatter += f"\ninstructions: |\n"
252
+ # Indent markdown content
253
+ for line in markdown_content.split("\n"):
254
+ frontmatter += f" {line}\n"
255
+
256
+ return frontmatter
257
+
258
+ def detect_format(self, content: str) -> str:
259
+ """
260
+ Detect the format of agent content.
261
+
262
+ Args:
263
+ content: Agent file content
264
+
265
+ Returns:
266
+ Format type: 'markdown_yaml', 'yaml', 'json', or 'unknown'
267
+ """
268
+ content = content.strip()
269
+
270
+ if content.startswith("---") and "---" in content[3:]:
271
+ return "markdown_yaml"
272
+ elif content.startswith("{") and content.endswith("}"):
273
+ return "json"
274
+ elif ":" in content and not content.startswith("#"):
275
+ # Likely YAML if it has key-value pairs and doesn't start with markdown header
276
+ return "yaml"
277
+ else:
278
+ return "unknown"
279
+
280
+ def normalize_agent_content(
281
+ self, content: str, agent_name: str, target_format: str = "markdown_yaml"
282
+ ) -> str:
283
+ """
284
+ Normalize agent content to a specific format.
285
+
286
+ Args:
287
+ content: Original agent content
288
+ agent_name: Name of the agent
289
+ target_format: Target format ('markdown_yaml', 'yaml', 'json')
290
+
291
+ Returns:
292
+ Normalized content in target format
293
+ """
294
+ current_format = self.detect_format(content)
295
+
296
+ if current_format == target_format:
297
+ return content
298
+
299
+ # Convert to intermediate format first (markdown_yaml)
300
+ if current_format == "yaml":
301
+ intermediate = self.convert_yaml_content_to_md(content, agent_name)
302
+ elif current_format == "json":
303
+ intermediate = self._convert_json_to_md(content, agent_name)
304
+ else:
305
+ intermediate = content
306
+
307
+ # Convert to target format
308
+ if target_format == "yaml":
309
+ return self.convert_md_to_yaml(intermediate)
310
+ elif target_format == "json":
311
+ return self._convert_md_to_json(intermediate)
312
+ else:
313
+ return intermediate
314
+
315
+ def get_conversion_stats(self, target_dir: Path) -> Dict[str, Any]:
316
+ """
317
+ Get statistics about files that need conversion.
318
+
319
+ Args:
320
+ target_dir: Directory to analyze
321
+
322
+ Returns:
323
+ Dictionary with conversion statistics
324
+ """
325
+ stats = {
326
+ "total_files": 0,
327
+ "yaml_files": 0,
328
+ "md_files": 0,
329
+ "json_files": 0,
330
+ "needs_conversion": 0,
331
+ "formats": {},
332
+ }
333
+
334
+ if not target_dir.exists():
335
+ return stats
336
+
337
+ # Analyze all agent files
338
+ for file_path in target_dir.glob("*"):
339
+ if file_path.is_file() and file_path.suffix in [
340
+ ".yaml",
341
+ ".yml",
342
+ ".md",
343
+ ".json",
344
+ ]:
345
+ stats["total_files"] += 1
346
+
347
+ if file_path.suffix in [".yaml", ".yml"]:
348
+ stats["yaml_files"] += 1
349
+ # Check if corresponding .md file exists
350
+ md_file = file_path.with_suffix(".md")
351
+ if not md_file.exists():
352
+ stats["needs_conversion"] += 1
353
+ elif file_path.suffix == ".md":
354
+ stats["md_files"] += 1
355
+ elif file_path.suffix == ".json":
356
+ stats["json_files"] += 1
357
+
358
+ # Detect format
359
+ try:
360
+ content = file_path.read_text()
361
+ format_type = self.detect_format(content)
362
+ stats["formats"][format_type] = (
363
+ stats["formats"].get(format_type, 0) + 1
364
+ )
365
+ except Exception:
366
+ stats["formats"]["unreadable"] = (
367
+ stats["formats"].get("unreadable", 0) + 1
368
+ )
369
+
370
+ return stats
371
+
372
+ def _extract_instructions_from_yaml(
373
+ self, yaml_content: str, agent_name: str
374
+ ) -> str:
375
+ """
376
+ Extract instructions from YAML content.
377
+
378
+ Args:
379
+ yaml_content: YAML content
380
+ agent_name: Agent name for default instructions
381
+
382
+ Returns:
383
+ Instructions text
384
+ """
385
+ # Try to extract instructions field
386
+ instructions = self.extract_yaml_field(yaml_content, "instructions")
387
+ if instructions:
388
+ return instructions
389
+
390
+ # Try to extract description as instructions
391
+ description = self.extract_yaml_field(yaml_content, "description")
392
+ if (
393
+ description and len(description) > 50
394
+ ): # Long description might be instructions
395
+ return f"# {agent_name.title()} Agent\n\n{description}"
396
+
397
+ # Default instructions
398
+ return f"# {agent_name.title()} Agent\n\nThis agent provides specialized functionality for your tasks."
399
+
400
+ def _convert_json_to_md(self, json_content: str, agent_name: str) -> str:
401
+ """Convert JSON content to Markdown with YAML frontmatter."""
402
+ try:
403
+ import json
404
+
405
+ data = json.loads(json_content)
406
+
407
+ # Convert JSON data to YAML-like string for processing
408
+ yaml_lines = []
409
+ for key, value in data.items():
410
+ if isinstance(value, str):
411
+ yaml_lines.append(f'{key}: "{value}"')
412
+ elif isinstance(value, list):
413
+ yaml_lines.append(f"{key}: {json.dumps(value)}")
414
+ else:
415
+ yaml_lines.append(f"{key}: {value}")
416
+
417
+ yaml_content = "\n".join(yaml_lines)
418
+ return self.convert_yaml_content_to_md(yaml_content, agent_name)
419
+
420
+ except Exception as e:
421
+ self.logger.error(f"Failed to convert JSON to MD: {e}")
422
+ return f"# {agent_name.title()} Agent\n\nConversion failed: {e}"
423
+
424
+ def _convert_md_to_json(self, md_content: str) -> str:
425
+ """Convert Markdown with YAML frontmatter to JSON."""
426
+ try:
427
+ import json
428
+
429
+ import yaml
430
+
431
+ if not md_content.strip().startswith("---"):
432
+ return json.dumps({"error": "No YAML frontmatter found"})
433
+
434
+ # Extract frontmatter
435
+ parts = md_content.split("---", 2)
436
+ if len(parts) < 3:
437
+ return json.dumps({"error": "Invalid frontmatter format"})
438
+
439
+ frontmatter = parts[1].strip()
440
+ markdown_content = parts[2].strip()
441
+
442
+ # Parse YAML frontmatter
443
+ data = yaml.safe_load(frontmatter)
444
+
445
+ # Add instructions from markdown content
446
+ if markdown_content:
447
+ data["instructions"] = markdown_content
448
+
449
+ return json.dumps(data, indent=2)
450
+
451
+ except Exception as e:
452
+ self.logger.error(f"Failed to convert MD to JSON: {e}")
453
+ return json.dumps({"error": str(e)})
@@ -0,0 +1,161 @@
1
+ """Agent frontmatter validation for deployment service.
2
+
3
+ This module provides validation and repair functionality for agent frontmatter.
4
+ Extracted from AgentDeploymentService to reduce complexity and improve maintainability.
5
+ """
6
+
7
+ import logging
8
+ from pathlib import Path
9
+ from typing import Any, Dict
10
+
11
+
12
+ class AgentFrontmatterValidator:
13
+ """Validates and repairs agent frontmatter."""
14
+
15
+ def __init__(self, logger: logging.Logger):
16
+ """Initialize the validator with a logger."""
17
+ self.logger = logger
18
+
19
+ def validate_and_repair_existing_agents(self, agents_dir: Path) -> Dict[str, Any]:
20
+ """
21
+ Validate and repair broken frontmatter in existing agent files.
22
+
23
+ This method scans existing .claude/agents/*.md files and validates their
24
+ frontmatter. If the frontmatter is broken or missing, it attempts to repair
25
+ it or marks the agent for replacement during deployment.
26
+
27
+ WHY: Ensures all existing agents have valid YAML frontmatter before deployment,
28
+ preventing runtime errors in Claude Code when loading agents.
29
+
30
+ Args:
31
+ agents_dir: Directory containing agent .md files
32
+
33
+ Returns:
34
+ Dictionary with validation results:
35
+ - repaired: List of agent names that were repaired
36
+ - replaced: List of agent names marked for replacement
37
+ - errors: List of validation errors
38
+ """
39
+ results = {"repaired": [], "replaced": [], "errors": []}
40
+
41
+ try:
42
+ # Import frontmatter validator
43
+ from claude_mpm.agents.frontmatter_validator import FrontmatterValidator
44
+
45
+ validator = FrontmatterValidator()
46
+
47
+ # Find existing agent files
48
+ agent_files = list(agents_dir.glob("*.md"))
49
+
50
+ if not agent_files:
51
+ self.logger.debug("No existing agent files to validate")
52
+ return results
53
+
54
+ self.logger.debug(
55
+ f"Validating frontmatter in {len(agent_files)} existing agents"
56
+ )
57
+
58
+ for agent_file in agent_files:
59
+ try:
60
+ agent_name = agent_file.stem
61
+
62
+ # Read agent file content
63
+ content = agent_file.read_text()
64
+
65
+ # Check if this is a system agent (authored by claude-mpm)
66
+ # Only repair system agents, leave user agents alone
67
+ if (
68
+ "author: claude-mpm" not in content
69
+ and "author: 'claude-mpm'" not in content
70
+ ):
71
+ self.logger.debug(
72
+ f"Skipping validation for user agent: {agent_name}"
73
+ )
74
+ continue
75
+
76
+ # Extract and validate frontmatter
77
+ if not content.startswith("---"):
78
+ # No frontmatter at all - mark for replacement
79
+ self.logger.warning(
80
+ f"Agent {agent_name} has no frontmatter, marking for replacement"
81
+ )
82
+ results["replaced"].append(agent_name)
83
+ # Delete the file so it will be recreated
84
+ agent_file.unlink()
85
+ continue
86
+
87
+ # Try to extract frontmatter
88
+ try:
89
+ end_marker = content.find("\n---\n", 4)
90
+ if end_marker == -1:
91
+ end_marker = content.find("\n---\r\n", 4)
92
+
93
+ if end_marker == -1:
94
+ # Broken frontmatter - mark for replacement
95
+ self.logger.warning(
96
+ f"Agent {agent_name} has broken frontmatter, marking for replacement"
97
+ )
98
+ results["replaced"].append(agent_name)
99
+ # Delete the file so it will be recreated
100
+ agent_file.unlink()
101
+ continue
102
+
103
+ # Validate frontmatter with the validator
104
+ validation_result = validator.validate_file(agent_file)
105
+
106
+ if not validation_result.is_valid:
107
+ # Check if it can be corrected
108
+ if validation_result.corrected_frontmatter:
109
+ # Apply corrections
110
+ correction_result = validator.correct_file(
111
+ agent_file, dry_run=False
112
+ )
113
+ if correction_result.corrections:
114
+ results["repaired"].append(agent_name)
115
+ self.logger.info(
116
+ f"Repaired frontmatter for agent {agent_name}"
117
+ )
118
+ for correction in correction_result.corrections:
119
+ self.logger.debug(f" - {correction}")
120
+ else:
121
+ # Cannot be corrected - mark for replacement
122
+ self.logger.warning(
123
+ f"Agent {agent_name} has invalid frontmatter that cannot be repaired, marking for replacement"
124
+ )
125
+ results["replaced"].append(agent_name)
126
+ # Delete the file so it will be recreated
127
+ agent_file.unlink()
128
+ elif validation_result.warnings:
129
+ # Has warnings but is valid
130
+ for warning in validation_result.warnings:
131
+ self.logger.debug(
132
+ f"Agent {agent_name} warning: {warning}"
133
+ )
134
+
135
+ except Exception as e:
136
+ # Any error in parsing - mark for replacement
137
+ self.logger.warning(
138
+ f"Failed to parse frontmatter for {agent_name}: {e}, marking for replacement"
139
+ )
140
+ results["replaced"].append(agent_name)
141
+ # Delete the file so it will be recreated
142
+ try:
143
+ agent_file.unlink()
144
+ except Exception:
145
+ pass
146
+
147
+ except Exception as e:
148
+ error_msg = f"Failed to validate agent {agent_file.name}: {e}"
149
+ self.logger.error(error_msg)
150
+ results["errors"].append(error_msg)
151
+
152
+ except ImportError:
153
+ self.logger.warning(
154
+ "FrontmatterValidator not available, skipping validation"
155
+ )
156
+ except Exception as e:
157
+ error_msg = f"Agent validation failed: {e}"
158
+ self.logger.error(error_msg)
159
+ results["errors"].append(error_msg)
160
+
161
+ return results