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
@@ -1,813 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Agent Registry Service - Consolidated Module
4
- ===========================================
5
-
6
- Provides fully synchronous agent discovery and management system with caching,
7
- validation, and hierarchical organization support.
8
-
9
- Features:
10
- - Two-tier hierarchy discovery (user → system)
11
- - Synchronous directory scanning
12
- - Agent metadata collection and caching
13
- - Agent type detection and classification
14
- - SharedPromptCache integration
15
- - Agent validation and error handling
16
-
17
- This is a consolidated version combining all functionality from the previous
18
- multi-file implementation for better maintainability.
19
- """
20
-
21
- import os
22
- import json
23
- import time
24
- import hashlib
25
- import logging
26
- from pathlib import Path
27
- from typing import Dict, List, Optional, Set, Tuple, Any, Union
28
- from dataclasses import dataclass, field, asdict
29
- from datetime import datetime
30
- from enum import Enum
31
-
32
- from claude_mpm.core.config_paths import ConfigPaths
33
- from claude_mpm.services.memory.cache.simple_cache import SimpleCacheService
34
- from claude_mpm.agents.frontmatter_validator import FrontmatterValidator, ValidationResult
35
-
36
- logger = logging.getLogger(__name__)
37
-
38
-
39
- # ============================================================================
40
- # Constants and Types
41
- # ============================================================================
42
-
43
- CORE_AGENT_TYPES = {
44
- 'engineer', 'architect', 'qa', 'security', 'documentation',
45
- 'ops', 'data', 'research', 'version_control'
46
- }
47
-
48
- SPECIALIZED_AGENT_TYPES = {
49
- 'pm_orchestrator', 'frontend', 'backend', 'devops', 'ml',
50
- 'database', 'api', 'mobile', 'cloud', 'testing'
51
- }
52
-
53
- ALL_AGENT_TYPES = CORE_AGENT_TYPES | SPECIALIZED_AGENT_TYPES
54
-
55
-
56
- class AgentTier(Enum):
57
- """Agent hierarchy tiers."""
58
- PROJECT = "project" # Highest precedence - project-specific agents
59
- USER = "user"
60
- SYSTEM = "system"
61
-
62
-
63
- class AgentType(Enum):
64
- """Agent classification types."""
65
- CORE = "core"
66
- SPECIALIZED = "specialized"
67
- CUSTOM = "custom"
68
- UNKNOWN = "unknown"
69
-
70
-
71
- # ============================================================================
72
- # Data Models
73
- # ============================================================================
74
-
75
- @dataclass
76
- class AgentMetadata:
77
- """Complete metadata for discovered agent."""
78
- name: str
79
- path: str
80
- tier: AgentTier
81
- agent_type: AgentType
82
- description: str = ""
83
- version: str = "0.0.0"
84
- dependencies: List[str] = field(default_factory=list)
85
- capabilities: List[str] = field(default_factory=list)
86
- created_at: float = field(default_factory=time.time)
87
- last_modified: float = field(default_factory=time.time)
88
- file_size: int = 0
89
- checksum: str = ""
90
- is_valid: bool = True
91
- validation_errors: List[str] = field(default_factory=list)
92
- metadata: Dict[str, Any] = field(default_factory=dict)
93
-
94
- def to_dict(self) -> Dict[str, Any]:
95
- """Convert to dictionary for serialization."""
96
- data = asdict(self)
97
- data['tier'] = self.tier.value
98
- data['agent_type'] = self.agent_type.value
99
- return data
100
-
101
- @classmethod
102
- def from_dict(cls, data: Dict[str, Any]) -> 'AgentMetadata':
103
- """Create from dictionary."""
104
- data['tier'] = AgentTier(data['tier'])
105
- data['agent_type'] = AgentType(data['agent_type'])
106
- return cls(**data)
107
-
108
-
109
- # ============================================================================
110
- # Main Registry Class
111
- # ============================================================================
112
-
113
- class AgentRegistry:
114
- """
115
- Core Agent Registry - Fully synchronous agent discovery and management system.
116
-
117
- This consolidated version combines all functionality from the previous
118
- multi-file implementation into a single, maintainable module.
119
- """
120
-
121
- def __init__(self, cache_service=None, model_selector=None):
122
- """Initialize AgentRegistry with optional cache service and model selector."""
123
- # Use provided cache service or create a default one
124
- if cache_service is None:
125
- # Create a simple in-memory cache with 1 hour TTL by default
126
- self.cache_service = SimpleCacheService(default_ttl=3600, max_size=500)
127
- self.cache_enabled = True
128
- else:
129
- self.cache_service = cache_service
130
- self.cache_enabled = True
131
-
132
- self.model_selector = model_selector
133
-
134
- # Initialize frontmatter validator
135
- self.frontmatter_validator = FrontmatterValidator()
136
-
137
- # Registry storage
138
- self.registry: Dict[str, AgentMetadata] = {}
139
- self.discovery_paths: List[Path] = []
140
-
141
- # Cache configuration
142
- self.cache_ttl = 3600 # 1 hour
143
- self.cache_prefix = "agent_registry"
144
-
145
- # Track discovered files for cache invalidation
146
- self.discovered_files: Set[Path] = set()
147
-
148
- # Discovery configuration
149
- self.file_extensions = {'.md', '.json', '.yaml', '.yml'}
150
- self.ignore_patterns = {'__pycache__', '.git', 'node_modules', '.pytest_cache'}
151
-
152
- # Statistics
153
- self.discovery_stats = {
154
- 'last_discovery': None,
155
- 'total_discovered': 0,
156
- 'cache_hits': 0,
157
- 'cache_misses': 0,
158
- 'discovery_duration': 0.0
159
- }
160
-
161
- # Setup discovery paths
162
- self._setup_discovery_paths()
163
-
164
- logger.info(f"AgentRegistry initialized with cache={'enabled' if self.cache_enabled else 'disabled'}")
165
-
166
- def _setup_discovery_paths(self) -> None:
167
- """Setup standard discovery paths for agent files."""
168
- # Project-level agents (highest priority)
169
- project_path = ConfigPaths.get_project_agents_dir()
170
- if project_path.exists():
171
- self.discovery_paths.append(project_path)
172
-
173
- # User-level agents
174
- user_path = ConfigPaths.get_user_agents_dir()
175
- if user_path.exists():
176
- self.discovery_paths.append(user_path)
177
-
178
- # System-level agents - multiple possible locations
179
- system_paths = [
180
- Path(__file__).parent.parent / 'agents' / 'templates',
181
- Path('/opt/claude-pm/agents'),
182
- Path('/usr/local/claude-pm/agents')
183
- ]
184
-
185
- for path in system_paths:
186
- if path.exists():
187
- self.discovery_paths.append(path)
188
-
189
- logger.debug(f"Discovery paths configured: {[str(p) for p in self.discovery_paths]}")
190
-
191
- # ========================================================================
192
- # Discovery Methods
193
- # ========================================================================
194
-
195
- def discover_agents(self, force_refresh: bool = False) -> Dict[str, AgentMetadata]:
196
- """
197
- Discover all available agents across configured paths.
198
-
199
- Args:
200
- force_refresh: Force re-discovery even if cache is valid
201
-
202
- Returns:
203
- Dictionary of agent name to metadata
204
- """
205
- start_time = time.time()
206
-
207
- # Try cache first
208
- if not force_refresh and self.cache_enabled:
209
- cached = self._get_cached_registry()
210
- if cached:
211
- self.registry = cached
212
- self.discovery_stats['cache_hits'] += 1
213
- logger.debug("Using cached agent registry")
214
- return self.registry
215
-
216
- self.discovery_stats['cache_misses'] += 1
217
-
218
- # Clear existing registry and discovered files
219
- self.registry.clear()
220
- self.discovered_files.clear()
221
-
222
- # Discover agents from all paths
223
- for discovery_path in self.discovery_paths:
224
- tier = self._determine_tier(discovery_path)
225
- self._discover_path(discovery_path, tier)
226
-
227
- # Handle tier precedence
228
- self._apply_tier_precedence()
229
-
230
- # Cache the results with file tracking
231
- if self.cache_enabled:
232
- self._cache_registry()
233
-
234
- # Update statistics
235
- self.discovery_stats['last_discovery'] = time.time()
236
- self.discovery_stats['total_discovered'] = len(self.registry)
237
- self.discovery_stats['discovery_duration'] = time.time() - start_time
238
-
239
- logger.info(f"Discovered {len(self.registry)} agents in {self.discovery_stats['discovery_duration']:.2f}s")
240
-
241
- return self.registry
242
-
243
- def _discover_path(self, path: Path, tier: AgentTier) -> None:
244
- """Discover agents in a specific path."""
245
- if not path.exists():
246
- return
247
-
248
- for file_path in path.rglob('*'):
249
- # Skip directories and ignored patterns
250
- if file_path.is_dir():
251
- continue
252
-
253
- if any(pattern in str(file_path) for pattern in self.ignore_patterns):
254
- continue
255
-
256
- # Check file extension
257
- if file_path.suffix not in self.file_extensions:
258
- continue
259
-
260
- # Extract agent name
261
- agent_name = self._extract_agent_name(file_path)
262
- if not agent_name:
263
- continue
264
-
265
- # Track discovered file for cache invalidation
266
- self.discovered_files.add(file_path)
267
-
268
- # Create metadata
269
- metadata = self._create_agent_metadata(file_path, agent_name, tier)
270
-
271
- # Validate agent
272
- if self._validate_agent(metadata):
273
- # Check tier precedence
274
- if agent_name in self.registry:
275
- existing = self.registry[agent_name]
276
- if self._has_tier_precedence(metadata.tier, existing.tier):
277
- self.registry[agent_name] = metadata
278
- logger.debug(f"Replaced {agent_name} with higher precedence version from {tier.value}")
279
- else:
280
- self.registry[agent_name] = metadata
281
-
282
- def _extract_agent_name(self, file_path: Path) -> Optional[str]:
283
- """Extract agent name from file path."""
284
- name = file_path.stem
285
-
286
- # Remove common suffixes
287
- suffixes_to_remove = ['_agent', '-agent', '.agent']
288
- for suffix in suffixes_to_remove:
289
- if name.endswith(suffix):
290
- name = name[:-len(suffix)]
291
- break
292
-
293
- # Skip empty or invalid names
294
- if not name or name.startswith('.'):
295
- return None
296
-
297
- return name
298
-
299
- def _create_agent_metadata(self, file_path: Path, agent_name: str, tier: AgentTier) -> AgentMetadata:
300
- """Create agent metadata from file."""
301
- # Get file stats
302
- stat = file_path.stat()
303
-
304
- # Calculate checksum
305
- checksum = ""
306
- try:
307
- with open(file_path, 'rb') as f:
308
- checksum = hashlib.md5(f.read()).hexdigest()
309
- except Exception as e:
310
- logger.warning(f"Failed to calculate checksum for {file_path}: {e}")
311
-
312
- # Determine agent type
313
- agent_type = self._classify_agent(agent_name)
314
-
315
- # Extract description and metadata from file
316
- description = ""
317
- version = "0.0.0"
318
- capabilities = []
319
- metadata = {}
320
-
321
- try:
322
- content = file_path.read_text()
323
-
324
- # Try to parse as JSON/YAML/MD for structured data
325
- if file_path.suffix in ['.md', '.json', '.yaml', '.yml']:
326
- try:
327
- if file_path.suffix == '.json':
328
- data = json.loads(content)
329
- description = data.get('description', '')
330
- version = data.get('version', '0.0.0')
331
- capabilities = data.get('capabilities', [])
332
- metadata = data.get('metadata', {})
333
- elif file_path.suffix == '.md':
334
- # Parse markdown with YAML frontmatter
335
- import yaml
336
- import re
337
-
338
- # Check for YAML frontmatter
339
- if content.strip().startswith('---'):
340
- parts = re.split(r'^---\s*$', content, 2, re.MULTILINE)
341
- if len(parts) >= 3:
342
- frontmatter_text = parts[1].strip()
343
- data = yaml.safe_load(frontmatter_text)
344
-
345
- # Validate and correct frontmatter
346
- validation_result = self.frontmatter_validator.validate_and_correct(data)
347
- if validation_result.corrections:
348
- logger.info(f"Applied corrections to {file_path.name}:")
349
- for correction in validation_result.corrections:
350
- logger.info(f" - {correction}")
351
-
352
- # Use corrected frontmatter if available
353
- if validation_result.corrected_frontmatter:
354
- data = validation_result.corrected_frontmatter
355
-
356
- if validation_result.errors:
357
- logger.warning(f"Validation errors in {file_path.name}:")
358
- for error in validation_result.errors:
359
- logger.warning(f" - {error}")
360
-
361
- description = data.get('description', '')
362
- version = data.get('version', '0.0.0')
363
- capabilities = data.get('tools', []) # Tools in .md format
364
- metadata = data
365
- else:
366
- # No frontmatter, use defaults
367
- description = f"{file_path.stem} agent"
368
- version = '1.0.0'
369
- capabilities = []
370
- metadata = {}
371
- else:
372
- # No frontmatter, use defaults
373
- description = f"{file_path.stem} agent"
374
- version = '1.0.0'
375
- capabilities = []
376
- metadata = {}
377
- else:
378
- # YAML files
379
- import yaml
380
- data = yaml.safe_load(content)
381
- description = data.get('description', '')
382
- version = data.get('version', '0.0.0')
383
- capabilities = data.get('capabilities', [])
384
- metadata = data.get('metadata', {})
385
- except Exception:
386
- pass
387
-
388
- # Extract from markdown files
389
- elif file_path.suffix == '.md':
390
- lines = content.split('\n')
391
- for i, line in enumerate(lines[:20]): # Check first 20 lines
392
- if line.strip().startswith('#') and i == 0:
393
- description = line.strip('#').strip()
394
- elif line.startswith('Version:'):
395
- version = line.split(':', 1)[1].strip()
396
- elif line.startswith('Description:'):
397
- description = line.split(':', 1)[1].strip()
398
-
399
- except Exception as e:
400
- logger.warning(f"Failed to parse {file_path}: {e}")
401
-
402
- return AgentMetadata(
403
- name=agent_name,
404
- path=str(file_path),
405
- tier=tier,
406
- agent_type=agent_type,
407
- description=description,
408
- version=version,
409
- capabilities=capabilities,
410
- created_at=stat.st_ctime,
411
- last_modified=stat.st_mtime,
412
- file_size=stat.st_size,
413
- checksum=checksum,
414
- metadata=metadata
415
- )
416
-
417
- def _classify_agent(self, agent_name: str) -> AgentType:
418
- """Classify agent based on name."""
419
- name_lower = agent_name.lower()
420
-
421
- # Remove common suffixes for classification
422
- for suffix in ['_agent', '-agent', '.agent']:
423
- if name_lower.endswith(suffix):
424
- name_lower = name_lower[:-len(suffix)]
425
-
426
- if name_lower in CORE_AGENT_TYPES:
427
- return AgentType.CORE
428
- elif name_lower in SPECIALIZED_AGENT_TYPES:
429
- return AgentType.SPECIALIZED
430
- elif any(core in name_lower for core in CORE_AGENT_TYPES):
431
- return AgentType.CORE
432
- elif any(spec in name_lower for spec in SPECIALIZED_AGENT_TYPES):
433
- return AgentType.SPECIALIZED
434
- else:
435
- return AgentType.CUSTOM
436
-
437
- def _determine_tier(self, path: Path) -> AgentTier:
438
- """Determine tier based on path location."""
439
- path_str = str(path)
440
-
441
- # Check if it's a project-level path (in current working directory)
442
- # Project agents are in <project_root>/.claude-mpm/agents
443
- project_agents_dir = ConfigPaths.get_project_agents_dir()
444
- if project_agents_dir.exists() and (path == project_agents_dir or project_agents_dir in path.parents):
445
- return AgentTier.PROJECT
446
-
447
- # Check if it's a user-level path (in home directory)
448
- user_agents_dir = ConfigPaths.get_user_agents_dir()
449
- if user_agents_dir.exists() and (path == user_agents_dir or user_agents_dir in path.parents):
450
- return AgentTier.USER
451
-
452
- # Everything else is system-level
453
- return AgentTier.SYSTEM
454
-
455
- def _has_tier_precedence(self, tier1: AgentTier, tier2: AgentTier) -> bool:
456
- """Check if tier1 has precedence over tier2."""
457
- precedence = {
458
- AgentTier.PROJECT: 3, # Highest precedence
459
- AgentTier.USER: 2,
460
- AgentTier.SYSTEM: 1
461
- }
462
- return precedence.get(tier1, 0) > precedence.get(tier2, 0)
463
-
464
- def _apply_tier_precedence(self) -> None:
465
- """Apply tier precedence rules to discovered agents."""
466
- # Group agents by name
467
- agents_by_name: Dict[str, List[AgentMetadata]] = {}
468
-
469
- for agent in self.registry.values():
470
- if agent.name not in agents_by_name:
471
- agents_by_name[agent.name] = []
472
- agents_by_name[agent.name].append(agent)
473
-
474
- # Apply precedence
475
- self.registry.clear()
476
- for agent_name, agents in agents_by_name.items():
477
- if len(agents) == 1:
478
- self.registry[agent_name] = agents[0]
479
- else:
480
- # Sort by tier precedence
481
- agents.sort(key=lambda a: {AgentTier.PROJECT: 3, AgentTier.USER: 2, AgentTier.SYSTEM: 1}.get(a.tier, 0), reverse=True)
482
- self.registry[agent_name] = agents[0]
483
-
484
- if len(agents) > 1:
485
- logger.debug(f"Applied tier precedence for {agent_name}: using {agents[0].tier.value} version")
486
-
487
- # ========================================================================
488
- # Validation Methods
489
- # ========================================================================
490
-
491
- def _validate_agent(self, metadata: AgentMetadata) -> bool:
492
- """Validate agent metadata and file."""
493
- errors = []
494
-
495
- # Check file exists
496
- if not Path(metadata.path).exists():
497
- errors.append("Agent file does not exist")
498
-
499
- # Check name validity
500
- if not metadata.name or metadata.name.startswith('.'):
501
- errors.append("Invalid agent name")
502
-
503
- # Check for required fields based on file type
504
- if metadata.path.endswith('.json'):
505
- try:
506
- with open(metadata.path) as f:
507
- data = json.load(f)
508
- if 'name' not in data:
509
- errors.append("Missing 'name' field in JSON")
510
- if 'role' not in data:
511
- errors.append("Missing 'role' field in JSON")
512
- except Exception as e:
513
- errors.append(f"Invalid JSON: {e}")
514
-
515
- # Update metadata
516
- metadata.is_valid = len(errors) == 0
517
- metadata.validation_errors = errors
518
-
519
- return metadata.is_valid
520
-
521
- # ========================================================================
522
- # Cache Methods
523
- # ========================================================================
524
-
525
- def _get_cached_registry(self) -> Optional[Dict[str, AgentMetadata]]:
526
- """Get registry from cache if available."""
527
- if not self.cache_service:
528
- return None
529
-
530
- try:
531
- cache_key = f"{self.cache_prefix}_registry"
532
- cached_data = self.cache_service.get(cache_key)
533
-
534
- if cached_data:
535
- # Deserialize metadata
536
- registry = {}
537
- for name, data in cached_data.items():
538
- registry[name] = AgentMetadata.from_dict(data)
539
-
540
- # Also restore discovered files set
541
- files_key = f"{self.cache_prefix}_discovered_files"
542
- discovered_files = self.cache_service.get(files_key)
543
- if discovered_files:
544
- self.discovered_files = {Path(f) for f in discovered_files}
545
-
546
- return registry
547
-
548
- except Exception as e:
549
- logger.warning(f"Failed to get cached registry: {e}")
550
-
551
- return None
552
-
553
- def _cache_registry(self) -> None:
554
- """Cache the current registry with file tracking."""
555
- if not self.cache_service:
556
- return
557
-
558
- try:
559
- cache_key = f"{self.cache_prefix}_registry"
560
-
561
- # Serialize metadata
562
- cache_data = {
563
- name: metadata.to_dict()
564
- for name, metadata in self.registry.items()
565
- }
566
-
567
- # If the cache service supports file tracking, use it
568
- if hasattr(self.cache_service, 'set'):
569
- import inspect
570
- sig = inspect.signature(self.cache_service.set)
571
- if 'tracked_files' in sig.parameters:
572
- # Cache with file tracking for automatic invalidation
573
- self.cache_service.set(
574
- cache_key,
575
- cache_data,
576
- ttl=self.cache_ttl,
577
- tracked_files=list(self.discovered_files)
578
- )
579
- else:
580
- # Fall back to regular caching
581
- self.cache_service.set(cache_key, cache_data, ttl=self.cache_ttl)
582
- else:
583
- # Fall back to regular caching
584
- self.cache_service.set(cache_key, cache_data, ttl=self.cache_ttl)
585
-
586
- # Also cache the discovered files list
587
- files_key = f"{self.cache_prefix}_discovered_files"
588
- self.cache_service.set(
589
- files_key,
590
- [str(f) for f in self.discovered_files],
591
- ttl=self.cache_ttl
592
- )
593
-
594
- logger.debug(f"Cached agent registry with {len(self.discovered_files)} tracked files")
595
-
596
- except Exception as e:
597
- logger.warning(f"Failed to cache registry: {e}")
598
-
599
- def invalidate_cache(self) -> None:
600
- """Invalidate the registry cache."""
601
- if self.cache_service:
602
- try:
603
- # Invalidate both registry and files cache
604
- registry_key = f"{self.cache_prefix}_registry"
605
- files_key = f"{self.cache_prefix}_discovered_files"
606
-
607
- self.cache_service.delete(registry_key)
608
- self.cache_service.delete(files_key)
609
-
610
- # Also clear in-memory registry to force re-discovery
611
- self.registry.clear()
612
- self.discovered_files.clear()
613
-
614
- logger.debug("Invalidated registry cache")
615
- except Exception as e:
616
- logger.warning(f"Failed to invalidate cache: {e}")
617
-
618
- # ========================================================================
619
- # Query Methods
620
- # ========================================================================
621
-
622
- def get_agent(self, name: str) -> Optional[AgentMetadata]:
623
- """Get metadata for a specific agent."""
624
- # Ensure registry is populated
625
- if not self.registry:
626
- self.discover_agents()
627
-
628
- return self.registry.get(name)
629
-
630
- def list_agents(self, tier: Optional[AgentTier] = None,
631
- agent_type: Optional[AgentType] = None) -> List[AgentMetadata]:
632
- """List agents with optional filtering."""
633
- # Ensure registry is populated
634
- if not self.registry:
635
- self.discover_agents()
636
-
637
- agents = list(self.registry.values())
638
-
639
- # Apply filters
640
- if tier:
641
- agents = [a for a in agents if a.tier == tier]
642
-
643
- if agent_type:
644
- agents = [a for a in agents if a.agent_type == agent_type]
645
-
646
- return agents
647
-
648
- def get_agent_names(self) -> List[str]:
649
- """Get list of all agent names."""
650
- if not self.registry:
651
- self.discover_agents()
652
-
653
- return sorted(self.registry.keys())
654
-
655
- def get_core_agents(self) -> List[AgentMetadata]:
656
- """Get all core framework agents."""
657
- return self.list_agents(agent_type=AgentType.CORE)
658
-
659
- def get_specialized_agents(self) -> List[AgentMetadata]:
660
- """Get all specialized agents."""
661
- return self.list_agents(agent_type=AgentType.SPECIALIZED)
662
-
663
- def get_custom_agents(self) -> List[AgentMetadata]:
664
- """Get all custom user-defined agents."""
665
- return self.list_agents(agent_type=AgentType.CUSTOM)
666
-
667
- def search_agents(self, query: str) -> List[AgentMetadata]:
668
- """Search agents by name or description."""
669
- if not self.registry:
670
- self.discover_agents()
671
-
672
- query_lower = query.lower()
673
- results = []
674
-
675
- for agent in self.registry.values():
676
- if (query_lower in agent.name.lower() or
677
- query_lower in agent.description.lower()):
678
- results.append(agent)
679
-
680
- return results
681
-
682
- # ========================================================================
683
- # Statistics and Monitoring
684
- # ========================================================================
685
-
686
- def get_statistics(self) -> Dict[str, Any]:
687
- """Get comprehensive registry statistics."""
688
- if not self.registry:
689
- self.discover_agents()
690
-
691
- stats = {
692
- 'total_agents': len(self.registry),
693
- 'discovery_stats': self.discovery_stats.copy(),
694
- 'agents_by_tier': {},
695
- 'agents_by_type': {},
696
- 'validation_stats': {
697
- 'valid': 0,
698
- 'invalid': 0,
699
- 'errors': []
700
- },
701
- 'cache_metrics': {}
702
- }
703
-
704
- # Add cache metrics if available
705
- if self.cache_enabled and hasattr(self.cache_service, 'get_cache_metrics'):
706
- stats['cache_metrics'] = self.cache_service.get_cache_metrics()
707
-
708
- # Count by tier
709
- for agent in self.registry.values():
710
- tier = agent.tier.value
711
- stats['agents_by_tier'][tier] = stats['agents_by_tier'].get(tier, 0) + 1
712
-
713
- # Count by type
714
- for agent in self.registry.values():
715
- agent_type = agent.agent_type.value
716
- stats['agents_by_type'][agent_type] = stats['agents_by_type'].get(agent_type, 0) + 1
717
-
718
- # Validation stats
719
- for agent in self.registry.values():
720
- if agent.is_valid:
721
- stats['validation_stats']['valid'] += 1
722
- else:
723
- stats['validation_stats']['invalid'] += 1
724
- stats['validation_stats']['errors'].extend(agent.validation_errors)
725
-
726
- return stats
727
-
728
- def validate_all_agents(self) -> Dict[str, List[str]]:
729
- """Validate all discovered agents and return errors."""
730
- if not self.registry:
731
- self.discover_agents()
732
-
733
- errors = {}
734
-
735
- for agent_name, metadata in self.registry.items():
736
- # Re-validate
737
- self._validate_agent(metadata)
738
-
739
- if not metadata.is_valid:
740
- errors[agent_name] = metadata.validation_errors
741
-
742
- return errors
743
-
744
- # ========================================================================
745
- # Utility Methods
746
- # ========================================================================
747
-
748
- def add_discovery_path(self, path: Union[str, Path]) -> None:
749
- """Add a new path for agent discovery."""
750
- path = Path(path)
751
- if path.exists() and path not in self.discovery_paths:
752
- self.discovery_paths.append(path)
753
- logger.info(f"Added discovery path: {path}")
754
- # Invalidate cache since paths changed
755
- self.invalidate_cache()
756
- # Force re-discovery with new path
757
- self.discover_agents(force_refresh=True)
758
-
759
- def remove_discovery_path(self, path: Union[str, Path]) -> None:
760
- """Remove a path from agent discovery."""
761
- path = Path(path)
762
- if path in self.discovery_paths:
763
- self.discovery_paths.remove(path)
764
- logger.info(f"Removed discovery path: {path}")
765
- # Invalidate cache since paths changed
766
- self.invalidate_cache()
767
- # Force re-discovery without the removed path
768
- self.discover_agents(force_refresh=True)
769
-
770
- def export_registry(self, output_path: Union[str, Path]) -> None:
771
- """Export registry to JSON file."""
772
- if not self.registry:
773
- self.discover_agents()
774
-
775
- output_path = Path(output_path)
776
-
777
- # Serialize registry
778
- export_data = {
779
- 'metadata': {
780
- 'exported_at': time.time(),
781
- 'total_agents': len(self.registry),
782
- 'discovery_paths': [str(p) for p in self.discovery_paths]
783
- },
784
- 'agents': {
785
- name: metadata.to_dict()
786
- for name, metadata in self.registry.items()
787
- }
788
- }
789
-
790
- with open(output_path, 'w') as f:
791
- json.dump(export_data, f, indent=2)
792
-
793
- logger.info(f"Exported registry to {output_path}")
794
-
795
- def import_registry(self, input_path: Union[str, Path]) -> None:
796
- """Import registry from JSON file."""
797
- input_path = Path(input_path)
798
-
799
- with open(input_path, 'r') as f:
800
- data = json.load(f)
801
-
802
- # Clear current registry
803
- self.registry.clear()
804
-
805
- # Import agents
806
- for name, agent_data in data.get('agents', {}).items():
807
- self.registry[name] = AgentMetadata.from_dict(agent_data)
808
-
809
- # Cache imported registry
810
- if self.cache_enabled:
811
- self._cache_registry()
812
-
813
- logger.info(f"Imported {len(self.registry)} agents from {input_path}")