claude-mpm 3.9.11__py3-none-any.whl → 4.0.4__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 (434) 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 +1 -1
  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 +2 -2
  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 +79 -51
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +20 -20
  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 +140 -905
  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 +330 -86
  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 +363 -220
  50. claude_mpm/cli/parser.py +24 -1156
  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 +124 -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 +71 -73
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +35 -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/built/components/agent-inference.js +2 -0
  113. claude_mpm/dashboard/static/built/components/event-processor.js +2 -0
  114. claude_mpm/dashboard/static/built/components/event-viewer.js +2 -0
  115. claude_mpm/dashboard/static/built/components/export-manager.js +2 -0
  116. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +2 -0
  117. claude_mpm/dashboard/static/built/components/hud-library-loader.js +2 -0
  118. claude_mpm/dashboard/static/built/components/hud-manager.js +2 -0
  119. claude_mpm/dashboard/static/built/components/hud-visualizer.js +2 -0
  120. claude_mpm/dashboard/static/built/components/module-viewer.js +2 -0
  121. claude_mpm/dashboard/static/built/components/session-manager.js +2 -0
  122. claude_mpm/dashboard/static/built/components/socket-manager.js +2 -0
  123. claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -0
  124. claude_mpm/dashboard/static/built/components/working-directory.js +2 -0
  125. claude_mpm/dashboard/static/built/dashboard.js +2 -0
  126. claude_mpm/dashboard/static/built/socket-client.js +2 -0
  127. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  128. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  129. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  130. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  131. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  132. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  133. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  134. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  135. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  136. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  137. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  138. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  139. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  140. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  141. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  142. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  143. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  144. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  145. claude_mpm/dashboard/static/js/components/event-viewer.js +93 -72
  146. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  147. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +110 -96
  148. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  149. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  150. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  151. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  152. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  153. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  154. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  155. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  156. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  157. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  158. claude_mpm/dashboard/static/js/socket-client.js +133 -53
  159. claude_mpm/dashboard/templates/index.html +40 -50
  160. claude_mpm/experimental/cli_enhancements.py +60 -58
  161. claude_mpm/generators/__init__.py +1 -1
  162. claude_mpm/generators/agent_profile_generator.py +75 -65
  163. claude_mpm/hooks/__init__.py +1 -1
  164. claude_mpm/hooks/base_hook.py +33 -28
  165. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  166. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  167. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  168. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  169. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  170. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  171. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  172. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  173. claude_mpm/hooks/memory_integration_hook.py +140 -100
  174. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  175. claude_mpm/hooks/validation_hooks.py +57 -49
  176. claude_mpm/init.py +145 -121
  177. claude_mpm/models/__init__.py +9 -9
  178. claude_mpm/models/agent_definition.py +33 -23
  179. claude_mpm/models/agent_session.py +228 -200
  180. claude_mpm/scripts/__init__.py +1 -1
  181. claude_mpm/scripts/socketio_daemon.py +192 -75
  182. claude_mpm/scripts/socketio_server_manager.py +328 -0
  183. claude_mpm/scripts/start_activity_logging.py +25 -22
  184. claude_mpm/services/__init__.py +68 -43
  185. claude_mpm/services/agent_capabilities_service.py +271 -0
  186. claude_mpm/services/agents/__init__.py +23 -32
  187. claude_mpm/services/agents/deployment/__init__.py +3 -3
  188. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  189. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  190. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  191. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  192. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  193. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  194. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  195. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  196. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  197. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  198. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  199. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  200. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  201. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  202. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  203. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  204. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  205. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  206. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  207. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  208. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  209. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  210. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  211. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  212. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  213. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  214. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  215. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  216. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  217. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  218. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  219. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  220. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  221. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  222. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  223. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  224. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  225. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  226. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  227. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  228. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  229. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  230. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  231. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  232. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  233. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  234. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  235. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  236. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  237. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  238. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  239. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  240. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  241. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  242. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  243. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  244. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  245. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  246. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  247. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  248. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  249. claude_mpm/services/agents/loading/__init__.py +2 -2
  250. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  251. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  252. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  253. claude_mpm/services/agents/management/__init__.py +2 -2
  254. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  255. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  256. claude_mpm/services/agents/memory/__init__.py +9 -6
  257. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  258. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  259. claude_mpm/services/agents/memory/analyzer.py +430 -0
  260. claude_mpm/services/agents/memory/content_manager.py +376 -0
  261. claude_mpm/services/agents/memory/template_generator.py +468 -0
  262. claude_mpm/services/agents/registry/__init__.py +7 -10
  263. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  264. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  265. claude_mpm/services/async_session_logger.py +187 -153
  266. claude_mpm/services/claude_session_logger.py +87 -72
  267. claude_mpm/services/command_handler_service.py +217 -0
  268. claude_mpm/services/communication/__init__.py +3 -2
  269. claude_mpm/services/core/__init__.py +50 -97
  270. claude_mpm/services/core/base.py +60 -53
  271. claude_mpm/services/core/interfaces/__init__.py +188 -0
  272. claude_mpm/services/core/interfaces/agent.py +351 -0
  273. claude_mpm/services/core/interfaces/communication.py +343 -0
  274. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  275. claude_mpm/services/core/interfaces/service.py +434 -0
  276. claude_mpm/services/core/interfaces.py +19 -944
  277. claude_mpm/services/event_aggregator.py +208 -170
  278. claude_mpm/services/exceptions.py +387 -308
  279. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  280. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  281. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  282. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  283. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  284. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  285. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  286. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  287. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  288. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  289. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  290. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  291. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  292. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  293. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  294. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  295. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  296. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  297. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  298. claude_mpm/services/hook_service.py +106 -114
  299. claude_mpm/services/infrastructure/__init__.py +7 -5
  300. claude_mpm/services/infrastructure/context_preservation.py +233 -199
  301. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  302. claude_mpm/services/infrastructure/logging.py +83 -76
  303. claude_mpm/services/infrastructure/monitoring.py +547 -404
  304. claude_mpm/services/mcp_gateway/__init__.py +30 -13
  305. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  306. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  307. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  308. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  309. claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
  310. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  311. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  312. claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
  313. claude_mpm/services/mcp_gateway/main.py +287 -137
  314. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  315. claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
  316. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  317. claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
  318. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
  319. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  320. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  321. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  322. claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
  323. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  324. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  325. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  326. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  327. claude_mpm/services/memory/__init__.py +2 -2
  328. claude_mpm/services/memory/builder.py +451 -362
  329. claude_mpm/services/memory/cache/__init__.py +2 -2
  330. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  331. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  332. claude_mpm/services/memory/indexed_memory.py +195 -193
  333. claude_mpm/services/memory/optimizer.py +267 -234
  334. claude_mpm/services/memory/router.py +571 -263
  335. claude_mpm/services/memory_hook_service.py +237 -0
  336. claude_mpm/services/port_manager.py +575 -0
  337. claude_mpm/services/project/__init__.py +3 -3
  338. claude_mpm/services/project/analyzer.py +451 -305
  339. claude_mpm/services/project/registry.py +262 -240
  340. claude_mpm/services/recovery_manager.py +287 -231
  341. claude_mpm/services/response_tracker.py +87 -67
  342. claude_mpm/services/runner_configuration_service.py +587 -0
  343. claude_mpm/services/session_management_service.py +304 -0
  344. claude_mpm/services/socketio/__init__.py +4 -4
  345. claude_mpm/services/socketio/client_proxy.py +174 -0
  346. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  347. claude_mpm/services/socketio/handlers/base.py +44 -30
  348. claude_mpm/services/socketio/handlers/connection.py +166 -64
  349. claude_mpm/services/socketio/handlers/file.py +123 -108
  350. claude_mpm/services/socketio/handlers/git.py +607 -373
  351. claude_mpm/services/socketio/handlers/hook.py +185 -0
  352. claude_mpm/services/socketio/handlers/memory.py +4 -4
  353. claude_mpm/services/socketio/handlers/project.py +4 -4
  354. claude_mpm/services/socketio/handlers/registry.py +53 -38
  355. claude_mpm/services/socketio/server/__init__.py +18 -0
  356. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  357. claude_mpm/services/socketio/server/core.py +399 -0
  358. claude_mpm/services/socketio/server/main.py +323 -0
  359. claude_mpm/services/socketio_client_manager.py +160 -133
  360. claude_mpm/services/socketio_server.py +36 -1885
  361. claude_mpm/services/subprocess_launcher_service.py +316 -0
  362. claude_mpm/services/system_instructions_service.py +258 -0
  363. claude_mpm/services/ticket_manager.py +19 -533
  364. claude_mpm/services/utility_service.py +285 -0
  365. claude_mpm/services/version_control/__init__.py +18 -21
  366. claude_mpm/services/version_control/branch_strategy.py +20 -10
  367. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  368. claude_mpm/services/version_control/git_operations.py +52 -21
  369. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  370. claude_mpm/services/version_control/version_parser.py +145 -125
  371. claude_mpm/services/version_service.py +270 -0
  372. claude_mpm/storage/__init__.py +2 -2
  373. claude_mpm/storage/state_storage.py +177 -181
  374. claude_mpm/ticket_wrapper.py +2 -2
  375. claude_mpm/utils/__init__.py +2 -2
  376. claude_mpm/utils/agent_dependency_loader.py +453 -243
  377. claude_mpm/utils/config_manager.py +157 -118
  378. claude_mpm/utils/console.py +1 -1
  379. claude_mpm/utils/dependency_cache.py +102 -107
  380. claude_mpm/utils/dependency_manager.py +52 -47
  381. claude_mpm/utils/dependency_strategies.py +131 -96
  382. claude_mpm/utils/environment_context.py +110 -102
  383. claude_mpm/utils/error_handler.py +75 -55
  384. claude_mpm/utils/file_utils.py +80 -67
  385. claude_mpm/utils/framework_detection.py +12 -11
  386. claude_mpm/utils/import_migration_example.py +12 -60
  387. claude_mpm/utils/imports.py +48 -45
  388. claude_mpm/utils/path_operations.py +100 -93
  389. claude_mpm/utils/robust_installer.py +172 -164
  390. claude_mpm/utils/session_logging.py +30 -23
  391. claude_mpm/utils/subprocess_utils.py +99 -61
  392. claude_mpm/validation/__init__.py +1 -1
  393. claude_mpm/validation/agent_validator.py +151 -111
  394. claude_mpm/validation/frontmatter_validator.py +92 -71
  395. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/METADATA +90 -22
  396. claude_mpm-4.0.4.dist-info/RECORD +417 -0
  397. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/entry_points.txt +1 -0
  398. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/licenses/LICENSE +1 -1
  399. claude_mpm/cli/commands/run_guarded.py +0 -511
  400. claude_mpm/config/memory_guardian_config.py +0 -325
  401. claude_mpm/config/memory_guardian_yaml.py +0 -335
  402. claude_mpm/core/config_paths.py +0 -150
  403. claude_mpm/core/memory_aware_runner.py +0 -353
  404. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  405. claude_mpm/deployment_paths.py +0 -261
  406. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  407. claude_mpm/models/state_models.py +0 -433
  408. claude_mpm/services/agent/__init__.py +0 -24
  409. claude_mpm/services/agent/deployment.py +0 -2548
  410. claude_mpm/services/agent/management.py +0 -598
  411. claude_mpm/services/agent/registry.py +0 -813
  412. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  413. claude_mpm/services/communication/socketio.py +0 -1935
  414. claude_mpm/services/communication/websocket.py +0 -479
  415. claude_mpm/services/framework_claude_md_generator.py +0 -624
  416. claude_mpm/services/health_monitor.py +0 -893
  417. claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
  418. claude_mpm/services/infrastructure/health_monitor.py +0 -775
  419. claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
  420. claude_mpm/services/infrastructure/memory_guardian.py +0 -944
  421. claude_mpm/services/infrastructure/restart_protection.py +0 -642
  422. claude_mpm/services/infrastructure/state_manager.py +0 -774
  423. claude_mpm/services/mcp_gateway/manager.py +0 -334
  424. claude_mpm/services/optimized_hook_service.py +0 -542
  425. claude_mpm/services/project_analyzer.py +0 -864
  426. claude_mpm/services/project_registry.py +0 -608
  427. claude_mpm/services/standalone_socketio_server.py +0 -1300
  428. claude_mpm/services/ticket_manager_di.py +0 -318
  429. claude_mpm/services/ticketing_service_original.py +0 -510
  430. claude_mpm/utils/paths.py +0 -395
  431. claude_mpm/utils/platform_memory.py +0 -524
  432. claude_mpm-3.9.11.dist-info/RECORD +0 -306
  433. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/WHEEL +0 -0
  434. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/top_level.txt +0 -0
claude_mpm/core/logger.py CHANGED
@@ -6,17 +6,17 @@ This module consolidates features from:
6
6
  - core/project_logger.py (project-local logging, statistics)
7
7
  """
8
8
 
9
+ import functools
9
10
  import json
10
11
  import logging
11
12
  import logging.handlers
12
13
  import sys
13
14
  import time
14
- from pathlib import Path
15
+ from collections import defaultdict
15
16
  from datetime import datetime
16
- from typing import Optional, Dict, Any, List
17
17
  from enum import Enum
18
- from collections import defaultdict
19
- import functools
18
+ from pathlib import Path
19
+ from typing import Any, Dict, List, Optional
20
20
 
21
21
  # Rich support has been removed
22
22
  HAS_RICH = False
@@ -24,6 +24,7 @@ HAS_RICH = False
24
24
 
25
25
  class LogLevel(Enum):
26
26
  """Log levels for different verbosity."""
27
+
27
28
  OFF = "off"
28
29
  DEBUG = "debug"
29
30
  INFO = "info"
@@ -35,58 +36,58 @@ class LogLevel(Enum):
35
36
  class StreamingHandler(logging.StreamHandler):
36
37
  """
37
38
  Custom handler for single-line streaming INFO messages.
38
-
39
+
39
40
  Shows progress indicators that update in place using carriage returns
40
41
  while keeping ERROR and WARNING messages on separate lines.
41
42
  """
42
-
43
+
43
44
  def __init__(self, stream=None):
44
45
  super().__init__(stream)
45
46
  self._last_info_message = False
46
47
  self._info_line_active = False
47
-
48
+
48
49
  def emit(self, record):
49
50
  """Emit a log record with streaming support for INFO messages."""
50
51
  try:
51
52
  msg = self.format(record)
52
53
  stream = self.stream
53
-
54
+
54
55
  # Handle different log levels
55
56
  if record.levelno == logging.INFO:
56
57
  # For INFO messages, use carriage return for streaming
57
58
  if self._info_line_active:
58
59
  # Clear the previous line by overwriting with spaces
59
- stream.write('\r' + ' ' * 100 + '\r')
60
-
60
+ stream.write("\r" + " " * 100 + "\r")
61
+
61
62
  # Write INFO message with carriage return (no newline)
62
- stream.write(f'\r{msg}')
63
+ stream.write(f"\r{msg}")
63
64
  stream.flush()
64
65
  self._info_line_active = True
65
66
  self._last_info_message = True
66
-
67
+
67
68
  else:
68
69
  # For WARNING, ERROR, CRITICAL - always on new lines
69
70
  if self._info_line_active:
70
71
  # Finish the INFO line first
71
- stream.write('\n')
72
+ stream.write("\n")
72
73
  self._info_line_active = False
73
-
74
- stream.write(f'{msg}\n')
74
+
75
+ stream.write(f"{msg}\n")
75
76
  stream.flush()
76
77
  self._last_info_message = False
77
-
78
+
78
79
  except (KeyboardInterrupt, SystemExit):
79
80
  raise
80
81
  except:
81
82
  self.handleError(record)
82
-
83
+
83
84
  def finalize_info_line(self):
84
85
  """
85
86
  Finalize any active INFO line by adding a newline.
86
87
  Call this when you want to ensure the final INFO message remains visible.
87
88
  """
88
89
  if self._info_line_active:
89
- self.stream.write('\n')
90
+ self.stream.write("\n")
90
91
  self.stream.flush()
91
92
  self._info_line_active = False
92
93
 
@@ -113,11 +114,27 @@ class JsonFormatter(logging.Formatter):
113
114
  # Add extra fields
114
115
  for key, value in record.__dict__.items():
115
116
  if key not in {
116
- "name", "msg", "args", "levelname", "levelno", "pathname",
117
- "filename", "module", "lineno", "funcName", "created",
118
- "msecs", "relativeCreated", "thread", "threadName",
119
- "processName", "process", "message", "exc_info",
120
- "exc_text", "stack_info"
117
+ "name",
118
+ "msg",
119
+ "args",
120
+ "levelname",
121
+ "levelno",
122
+ "pathname",
123
+ "filename",
124
+ "module",
125
+ "lineno",
126
+ "funcName",
127
+ "created",
128
+ "msecs",
129
+ "relativeCreated",
130
+ "thread",
131
+ "threadName",
132
+ "processName",
133
+ "process",
134
+ "message",
135
+ "exc_info",
136
+ "exc_text",
137
+ "stack_info",
121
138
  }:
122
139
  log_entry[key] = value
123
140
 
@@ -137,7 +154,7 @@ def setup_logging(
137
154
  ) -> logging.Logger:
138
155
  """
139
156
  Set up logging with both console and file handlers.
140
-
157
+
141
158
  Args:
142
159
  name: Logger name
143
160
  level: Logging level (OFF, DEBUG, INFO, WARNING, ERROR, CRITICAL)
@@ -148,34 +165,34 @@ def setup_logging(
148
165
  use_rich: (Deprecated) Rich support has been removed
149
166
  json_format: Use JSON format for structured logging
150
167
  use_streaming: Use streaming handler for single-line INFO messages
151
-
168
+
152
169
  Returns:
153
170
  Configured logger
154
171
  """
155
172
  logger = logging.getLogger(name)
156
-
173
+
157
174
  # Handle OFF level
158
175
  if level.upper() == "OFF":
159
176
  logger.setLevel(logging.CRITICAL + 1) # Higher than CRITICAL
160
177
  logger.handlers.clear()
161
178
  return logger
162
-
179
+
163
180
  # Set log level
164
181
  log_level = getattr(logging, level.upper(), logging.INFO)
165
182
  logger.setLevel(log_level)
166
-
183
+
167
184
  # Prevent duplicate handlers
168
185
  logger.handlers.clear()
169
-
186
+
170
187
  # Create formatters
171
188
  if json_format:
172
189
  formatter = JsonFormatter()
173
190
  else:
174
191
  detailed_formatter = logging.Formatter(
175
- '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
192
+ "%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s"
176
193
  )
177
- simple_formatter = logging.Formatter('%(levelname)s: %(message)s')
178
-
194
+ simple_formatter = logging.Formatter("%(levelname)s: %(message)s")
195
+
179
196
  # Console handler
180
197
  if console_output:
181
198
  if use_streaming:
@@ -189,17 +206,17 @@ def setup_logging(
189
206
  else:
190
207
  console_handler = logging.StreamHandler(sys.stdout)
191
208
  console_handler.setFormatter(formatter if json_format else simple_formatter)
192
-
209
+
193
210
  console_handler.setLevel(logging.INFO)
194
211
  logger.addHandler(console_handler)
195
-
212
+
196
213
  # File handler
197
214
  if file_output and level.upper() in ["INFO", "DEBUG"]:
198
215
  if log_file:
199
216
  # Use specific log file
200
217
  log_file = Path(log_file)
201
218
  log_file.parent.mkdir(parents=True, exist_ok=True)
202
-
219
+
203
220
  # Use rotating file handler
204
221
  file_handler = logging.handlers.RotatingFileHandler(
205
222
  log_file, maxBytes=10 * 1024 * 1024, backupCount=5 # 10 MB
@@ -208,32 +225,33 @@ def setup_logging(
208
225
  # Use default log directory
209
226
  if log_dir is None:
210
227
  # Use deployment root for logs to keep everything centralized
211
- from claude_mpm.deployment_paths import get_project_root
228
+ from claude_mpm.core.unified_paths import get_project_root
229
+
212
230
  deployment_root = get_project_root()
213
231
  log_dir = deployment_root / ".claude-mpm" / "logs"
214
-
232
+
215
233
  log_dir.mkdir(parents=True, exist_ok=True)
216
-
234
+
217
235
  # Create timestamped log file
218
236
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
219
237
  log_file = log_dir / f"mpm_{timestamp}.log"
220
-
238
+
221
239
  file_handler = logging.FileHandler(log_file)
222
-
240
+
223
241
  # Also create a symlink to latest log
224
242
  latest_link = log_dir / "latest.log"
225
243
  if latest_link.exists() and latest_link.is_symlink():
226
244
  latest_link.unlink()
227
245
  if not latest_link.exists():
228
246
  latest_link.symlink_to(log_file.name)
229
-
247
+
230
248
  file_handler.setLevel(logging.DEBUG)
231
249
  file_handler.setFormatter(formatter if json_format else detailed_formatter)
232
250
  logger.addHandler(file_handler)
233
-
251
+
234
252
  # Prevent propagation to root logger
235
253
  logger.propagate = False
236
-
254
+
237
255
  return logger
238
256
 
239
257
 
@@ -245,26 +263,21 @@ def get_logger(name: str) -> logging.Logger:
245
263
  def setup_streaming_logger(name: str, level: str = "INFO") -> logging.Logger:
246
264
  """
247
265
  Convenience function to setup a logger with streaming INFO support.
248
-
266
+
249
267
  Args:
250
268
  name: Logger name
251
269
  level: Log level (default: INFO)
252
-
270
+
253
271
  Returns:
254
272
  Logger configured with streaming handler
255
273
  """
256
- return setup_logging(
257
- name=name,
258
- level=level,
259
- use_rich=False,
260
- use_streaming=True
261
- )
274
+ return setup_logging(name=name, level=level, use_rich=False, use_streaming=True)
262
275
 
263
276
 
264
277
  def finalize_streaming_logs(logger: logging.Logger):
265
278
  """
266
279
  Finalize any active streaming INFO lines for a logger.
267
-
280
+
268
281
  This ensures the final INFO message remains visible by adding
269
282
  a newline to complete any streaming output.
270
283
  """
@@ -275,6 +288,7 @@ def finalize_streaming_logs(logger: logging.Logger):
275
288
 
276
289
  def log_performance(func):
277
290
  """Decorator to log function execution time."""
291
+
278
292
  @functools.wraps(func)
279
293
  def wrapper(*args, **kwargs):
280
294
  logger = get_logger(func.__module__)
@@ -295,6 +309,7 @@ def log_performance(func):
295
309
 
296
310
  async def log_async_performance(func):
297
311
  """Decorator to log async function execution time."""
312
+
298
313
  @functools.wraps(func)
299
314
  async def wrapper(*args, **kwargs):
300
315
  logger = get_logger(func.__module__)
@@ -316,17 +331,19 @@ async def log_async_performance(func):
316
331
  class ProjectLogger:
317
332
  """
318
333
  Manages project-local logging in ./claude-mpm directory.
319
-
334
+
320
335
  This is a simplified version of the original ProjectLogger,
321
336
  focused on essential features for backwards compatibility.
322
337
  """
323
-
324
- def __init__(self,
325
- project_dir: Optional[Path] = None,
326
- log_level: str = "INFO",
327
- create_structure: bool = True):
338
+
339
+ def __init__(
340
+ self,
341
+ project_dir: Optional[Path] = None,
342
+ log_level: str = "INFO",
343
+ create_structure: bool = True,
344
+ ):
328
345
  """Initialize project logger.
329
-
346
+
330
347
  Args:
331
348
  project_dir: Project directory (defaults to cwd)
332
349
  log_level: Logging level (INFO, DEBUG, OFF)
@@ -335,7 +352,7 @@ class ProjectLogger:
335
352
  self.project_dir = project_dir or Path.cwd()
336
353
  self.claude_mpm_dir = self.project_dir / ".claude-mpm"
337
354
  self.log_level = LogLevel(log_level.lower())
338
-
355
+
339
356
  # Basic directory structure
340
357
  self.dirs = {
341
358
  "base": self.claude_mpm_dir,
@@ -345,75 +362,83 @@ class ProjectLogger:
345
362
  "logs_sessions": self.claude_mpm_dir / "logs" / "sessions",
346
363
  "stats": self.claude_mpm_dir / "stats",
347
364
  }
348
-
365
+
349
366
  if create_structure:
350
367
  for path in self.dirs.values():
351
368
  path.mkdir(parents=True, exist_ok=True)
352
-
369
+
353
370
  # Create session directory
354
371
  self.session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
355
372
  self.session_start_time = datetime.now()
356
373
  self.session_dir = self.dirs["logs_sessions"] / self.session_id
357
374
  self.session_dir.mkdir(parents=True, exist_ok=True)
358
-
375
+
359
376
  # Statistics tracking
360
- self.stats = defaultdict(lambda: {
361
- "total_calls": 0,
362
- "total_tokens": 0,
363
- "total_time_seconds": 0,
364
- "by_agent": defaultdict(lambda: {
365
- "calls": 0,
366
- "tokens": 0,
367
- "time_seconds": 0,
368
- "success_rate": 0.0,
369
- "tasks": []
370
- })
371
- })
372
-
377
+ self.stats = defaultdict(
378
+ lambda: {
379
+ "total_calls": 0,
380
+ "total_tokens": 0,
381
+ "total_time_seconds": 0,
382
+ "by_agent": defaultdict(
383
+ lambda: {
384
+ "calls": 0,
385
+ "tokens": 0,
386
+ "time_seconds": 0,
387
+ "success_rate": 0.0,
388
+ "tasks": [],
389
+ }
390
+ ),
391
+ }
392
+ )
393
+
373
394
  def log_system(self, message: str, level: str = "INFO", component: str = "general"):
374
395
  """Log system-level message."""
375
396
  if self.log_level == LogLevel.OFF:
376
397
  return
377
-
398
+
378
399
  timestamp = datetime.now().isoformat()
379
400
  log_entry = {
380
401
  "timestamp": timestamp,
381
402
  "level": level,
382
403
  "component": component,
383
- "message": message
404
+ "message": message,
384
405
  }
385
-
406
+
386
407
  # Write to daily log file
387
- log_file = self.dirs["logs_system"] / f"{datetime.now().strftime('%Y%m%d')}.jsonl"
388
- with open(log_file, 'a') as f:
389
- f.write(json.dumps(log_entry) + '\n')
390
-
391
- def log_agent_invocation(self,
392
- agent: str,
393
- task: str,
394
- prompt: str,
395
- response: str,
396
- execution_time: float,
397
- tokens: int,
398
- success: bool = True,
399
- metadata: Optional[Dict[str, Any]] = None):
408
+ log_file = (
409
+ self.dirs["logs_system"] / f"{datetime.now().strftime('%Y%m%d')}.jsonl"
410
+ )
411
+ with open(log_file, "a") as f:
412
+ f.write(json.dumps(log_entry) + "\n")
413
+
414
+ def log_agent_invocation(
415
+ self,
416
+ agent: str,
417
+ task: str,
418
+ prompt: str,
419
+ response: str,
420
+ execution_time: float,
421
+ tokens: int,
422
+ success: bool = True,
423
+ metadata: Optional[Dict[str, Any]] = None,
424
+ ):
400
425
  """Log agent invocation with configurable detail level."""
401
426
  if self.log_level == LogLevel.OFF:
402
427
  return
403
-
428
+
404
429
  timestamp = datetime.now().isoformat()
405
-
430
+
406
431
  # Update statistics
407
432
  today = datetime.now().strftime("%Y-%m-%d")
408
433
  self.stats[today]["total_calls"] += 1
409
434
  self.stats[today]["total_tokens"] += tokens
410
435
  self.stats[today]["total_time_seconds"] += execution_time
411
-
436
+
412
437
  agent_stats = self.stats[today]["by_agent"][agent.lower()]
413
438
  agent_stats["calls"] += 1
414
439
  agent_stats["tokens"] += tokens
415
440
  agent_stats["time_seconds"] += execution_time
416
-
441
+
417
442
  # Prepare log entry
418
443
  log_entry = {
419
444
  "timestamp": timestamp,
@@ -422,45 +447,46 @@ class ProjectLogger:
422
447
  "execution_time": execution_time,
423
448
  "tokens": tokens,
424
449
  "success": success,
425
- "metadata": metadata or {}
450
+ "metadata": metadata or {},
426
451
  }
427
-
452
+
428
453
  # Add full details in DEBUG mode
429
454
  if self.log_level == LogLevel.DEBUG:
430
455
  log_entry["prompt"] = prompt
431
456
  log_entry["response"] = response
432
-
457
+
433
458
  # Write to agent-specific log
434
459
  agent_log_dir = self.dirs["logs_agents"] / agent.lower()
435
460
  agent_log_dir.mkdir(exist_ok=True)
436
-
461
+
437
462
  daily_log = agent_log_dir / f"{datetime.now().strftime('%Y%m%d')}.jsonl"
438
- with open(daily_log, 'a') as f:
439
- f.write(json.dumps(log_entry) + '\n')
440
-
463
+ with open(daily_log, "a") as f:
464
+ f.write(json.dumps(log_entry) + "\n")
465
+
441
466
  def get_session_summary(self) -> Dict[str, Any]:
442
467
  """Get summary of current session."""
443
468
  return {
444
469
  "session_id": self.session_id,
445
470
  "session_dir": str(self.session_dir),
446
471
  "start_time": self.session_id,
447
- "stats": self.stats.get(datetime.now().strftime("%Y-%m-%d"), {})
472
+ "stats": self.stats.get(datetime.now().strftime("%Y-%m-%d"), {}),
448
473
  }
449
474
 
450
475
 
451
476
  # Singleton instance for project logger
452
477
  _project_logger = None
453
478
 
479
+
454
480
  def get_project_logger(log_level: str = "INFO") -> ProjectLogger:
455
481
  """Get or create the project logger singleton.
456
-
482
+
457
483
  Args:
458
484
  log_level: Log level (INFO, DEBUG, OFF)
459
-
485
+
460
486
  Returns:
461
487
  ProjectLogger instance
462
488
  """
463
489
  global _project_logger
464
490
  if _project_logger is None:
465
491
  _project_logger = ProjectLogger(log_level=log_level)
466
- return _project_logger
492
+ return _project_logger