claude-mpm 3.9.11__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 (419) 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 +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 +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 +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 -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 +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 +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/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 +233 -199
  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 +30 -13
  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 +13 -20
  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 +87 -84
  298. claude_mpm/services/mcp_gateway/main.py +287 -137
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
  303. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
  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 +109 -119
  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 +19 -533
  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 +2 -2
  358. claude_mpm/storage/state_storage.py +177 -181
  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.11.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +27 -1
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/cli/commands/run_guarded.py +0 -511
  385. claude_mpm/config/memory_guardian_config.py +0 -325
  386. claude_mpm/config/memory_guardian_yaml.py +0 -335
  387. claude_mpm/core/config_paths.py +0 -150
  388. claude_mpm/core/memory_aware_runner.py +0 -353
  389. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  390. claude_mpm/deployment_paths.py +0 -261
  391. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  392. claude_mpm/models/state_models.py +0 -433
  393. claude_mpm/services/agent/__init__.py +0 -24
  394. claude_mpm/services/agent/deployment.py +0 -2548
  395. claude_mpm/services/agent/management.py +0 -598
  396. claude_mpm/services/agent/registry.py +0 -813
  397. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  398. claude_mpm/services/communication/socketio.py +0 -1935
  399. claude_mpm/services/communication/websocket.py +0 -479
  400. claude_mpm/services/framework_claude_md_generator.py +0 -624
  401. claude_mpm/services/health_monitor.py +0 -893
  402. claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
  403. claude_mpm/services/infrastructure/health_monitor.py +0 -775
  404. claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
  405. claude_mpm/services/infrastructure/memory_guardian.py +0 -944
  406. claude_mpm/services/infrastructure/restart_protection.py +0 -642
  407. claude_mpm/services/infrastructure/state_manager.py +0 -774
  408. claude_mpm/services/mcp_gateway/manager.py +0 -334
  409. claude_mpm/services/optimized_hook_service.py +0 -542
  410. claude_mpm/services/project_analyzer.py +0 -864
  411. claude_mpm/services/project_registry.py +0 -608
  412. claude_mpm/services/standalone_socketio_server.py +0 -1300
  413. claude_mpm/services/ticket_manager_di.py +0 -318
  414. claude_mpm/services/ticketing_service_original.py +0 -510
  415. claude_mpm/utils/paths.py +0 -395
  416. claude_mpm/utils/platform_memory.py +0 -524
  417. claude_mpm-3.9.11.dist-info/RECORD +0 -306
  418. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  419. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -6,73 +6,84 @@ Inspired by awesome-claude-code's comprehensive error handling approach.
6
6
 
7
7
  import logging
8
8
  import sys
9
- from typing import Optional, Type, Callable, Any, Dict, List
10
- from functools import wraps
11
9
  import traceback
12
10
  from datetime import datetime
11
+ from functools import wraps
12
+ from typing import Any, Callable, Dict, List, Optional, Type
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
16
 
17
17
  class MPMError(Exception):
18
18
  """Base exception for claude-mpm errors."""
19
-
20
- def __init__(self, message: str, details: Optional[Dict[str, Any]] = None,
21
- suggestions: Optional[List[str]] = None):
19
+
20
+ def __init__(
21
+ self,
22
+ message: str,
23
+ details: Optional[Dict[str, Any]] = None,
24
+ suggestions: Optional[List[str]] = None,
25
+ ):
22
26
  """Initialize MPM error with details and suggestions."""
23
27
  super().__init__(message)
24
28
  self.details = details or {}
25
29
  self.suggestions = suggestions or []
26
30
  self.timestamp = datetime.now()
27
-
31
+
28
32
  def get_user_friendly_message(self) -> str:
29
33
  """Get a user-friendly error message."""
30
34
  lines = [f"❌ Error: {str(self)}"]
31
-
35
+
32
36
  if self.details:
33
37
  lines.append("\nDetails:")
34
38
  for key, value in self.details.items():
35
39
  lines.append(f" {key}: {value}")
36
-
40
+
37
41
  if self.suggestions:
38
42
  lines.append("\n💡 Suggestions:")
39
43
  for suggestion in self.suggestions:
40
44
  lines.append(f" - {suggestion}")
41
-
42
- return '\n'.join(lines)
45
+
46
+ return "\n".join(lines)
43
47
 
44
48
 
45
49
  class AgentLoadError(MPMError):
46
50
  """Raised when agent loading fails."""
51
+
47
52
  pass
48
53
 
49
54
 
50
55
  class ValidationError(MPMError):
51
56
  """Raised when validation fails."""
57
+
52
58
  pass
53
59
 
54
60
 
55
61
  class ExecutionError(MPMError):
56
62
  """Raised when agent execution fails."""
63
+
57
64
  pass
58
65
 
59
66
 
60
67
  class ConfigurationError(MPMError):
61
68
  """Raised when configuration is invalid."""
69
+
62
70
  pass
63
71
 
64
72
 
65
- def handle_errors(error_type: Type[Exception] = Exception,
66
- fallback_value: Any = None,
67
- log_level: int = logging.ERROR) -> Callable:
73
+ def handle_errors(
74
+ error_type: Type[Exception] = Exception,
75
+ fallback_value: Any = None,
76
+ log_level: int = logging.ERROR,
77
+ ) -> Callable:
68
78
  """
69
79
  Decorator for handling errors with detailed logging and user feedback.
70
-
80
+
71
81
  Args:
72
82
  error_type: Type of exception to catch
73
83
  fallback_value: Value to return on error
74
84
  log_level: Logging level for errors
75
85
  """
86
+
76
87
  def decorator(func: Callable) -> Callable:
77
88
  @wraps(func)
78
89
  def wrapper(*args, **kwargs):
@@ -81,76 +92,82 @@ def handle_errors(error_type: Type[Exception] = Exception,
81
92
  except error_type as e:
82
93
  # Log the error with full traceback
83
94
  logger.log(log_level, f"Error in {func.__name__}: {e}", exc_info=True)
84
-
95
+
85
96
  # Provide user-friendly feedback
86
97
  if isinstance(e, MPMError):
87
98
  print(e.get_user_friendly_message(), file=sys.stderr)
88
99
  else:
89
100
  print(f"❌ Error: {e}", file=sys.stderr)
90
-
101
+
91
102
  return fallback_value
92
103
  except Exception as e:
93
104
  # Catch unexpected errors
94
- logger.critical(f"Unexpected error in {func.__name__}: {e}", exc_info=True)
105
+ logger.critical(
106
+ f"Unexpected error in {func.__name__}: {e}", exc_info=True
107
+ )
95
108
  print(f"❌ Unexpected error: {e}", file=sys.stderr)
96
109
  print("💡 This might be a bug. Please report it.", file=sys.stderr)
97
110
  return fallback_value
98
-
111
+
99
112
  return wrapper
113
+
100
114
  return decorator
101
115
 
102
116
 
103
117
  class ErrorContext:
104
118
  """Context manager for enhanced error reporting."""
105
-
119
+
106
120
  def __init__(self, operation: str, details: Optional[Dict[str, Any]] = None):
107
121
  """Initialize error context."""
108
122
  self.operation = operation
109
123
  self.details = details or {}
110
-
124
+
111
125
  def __enter__(self):
112
126
  """Enter the context."""
113
127
  logger.debug(f"Starting operation: {self.operation}")
114
128
  return self
115
-
129
+
116
130
  def __exit__(self, exc_type, exc_val, exc_tb):
117
131
  """Exit the context, handling any errors."""
118
132
  if exc_type is None:
119
133
  logger.debug(f"Completed operation: {self.operation}")
120
134
  return
121
-
135
+
122
136
  # Log the error with context
123
137
  logger.error(
124
138
  f"Error during {self.operation}: {exc_val}",
125
- extra={'operation': self.operation, 'details': self.details},
126
- exc_info=True
139
+ extra={"operation": self.operation, "details": self.details},
140
+ exc_info=True,
127
141
  )
128
-
142
+
129
143
  # Don't suppress the exception
130
144
  return False
131
145
 
132
146
 
133
- def retry_on_error(max_attempts: int = 3,
134
- delay: float = 1.0,
135
- backoff_factor: float = 2.0,
136
- exceptions: tuple = (Exception,)) -> Callable:
147
+ def retry_on_error(
148
+ max_attempts: int = 3,
149
+ delay: float = 1.0,
150
+ backoff_factor: float = 2.0,
151
+ exceptions: tuple = (Exception,),
152
+ ) -> Callable:
137
153
  """
138
154
  Decorator for retrying operations on error.
139
-
155
+
140
156
  Args:
141
157
  max_attempts: Maximum number of attempts
142
158
  delay: Initial delay between attempts
143
159
  backoff_factor: Multiplier for delay after each failure
144
160
  exceptions: Tuple of exceptions to retry on
145
161
  """
162
+
146
163
  def decorator(func: Callable) -> Callable:
147
164
  @wraps(func)
148
165
  async def async_wrapper(*args, **kwargs):
149
166
  import asyncio
150
-
167
+
151
168
  last_exception = None
152
169
  current_delay = delay
153
-
170
+
154
171
  for attempt in range(max_attempts):
155
172
  try:
156
173
  return await func(*args, **kwargs)
@@ -166,16 +183,16 @@ def retry_on_error(max_attempts: int = 3,
166
183
  logger.error(
167
184
  f"All {max_attempts} attempts failed for {func.__name__}"
168
185
  )
169
-
186
+
170
187
  raise last_exception
171
-
188
+
172
189
  @wraps(func)
173
190
  def sync_wrapper(*args, **kwargs):
174
191
  import time
175
-
192
+
176
193
  last_exception = None
177
194
  current_delay = delay
178
-
195
+
179
196
  for attempt in range(max_attempts):
180
197
  try:
181
198
  return func(*args, **kwargs)
@@ -191,16 +208,17 @@ def retry_on_error(max_attempts: int = 3,
191
208
  logger.error(
192
209
  f"All {max_attempts} attempts failed for {func.__name__}"
193
210
  )
194
-
211
+
195
212
  raise last_exception
196
-
213
+
197
214
  # Return appropriate wrapper based on function type
198
215
  import asyncio
216
+
199
217
  if asyncio.iscoroutinefunction(func):
200
218
  return async_wrapper
201
219
  else:
202
220
  return sync_wrapper
203
-
221
+
204
222
  return decorator
205
223
 
206
224
 
@@ -209,18 +227,20 @@ def format_exception_chain(exc: Exception) -> str:
209
227
  lines = []
210
228
  current = exc
211
229
  level = 0
212
-
230
+
213
231
  while current is not None:
214
232
  indent = " " * level
215
- lines.append(f"{indent}{'└─' if level > 0 else ''}{type(current).__name__}: {current}")
216
-
217
- if hasattr(current, '__cause__'):
233
+ lines.append(
234
+ f"{indent}{'└─' if level > 0 else ''}{type(current).__name__}: {current}"
235
+ )
236
+
237
+ if hasattr(current, "__cause__"):
218
238
  current = current.__cause__
219
239
  level += 1
220
240
  else:
221
241
  break
222
-
223
- return '\n'.join(lines)
242
+
243
+ return "\n".join(lines)
224
244
 
225
245
 
226
246
  # Setup patterns from awesome-claude-code
@@ -228,20 +248,20 @@ def suggest_setup_fix(error: Exception) -> List[str]:
228
248
  """Suggest fixes for common setup errors."""
229
249
  suggestions = []
230
250
  error_msg = str(error).lower()
231
-
232
- if 'git' in error_msg and 'not found' in error_msg:
251
+
252
+ if "git" in error_msg and "not found" in error_msg:
233
253
  suggestions.append("Install git from https://git-scm.com/downloads")
234
-
235
- if 'python' in error_msg and 'module' in error_msg:
254
+
255
+ if "python" in error_msg and "module" in error_msg:
236
256
  suggestions.append("Ensure you're in a virtual environment")
237
257
  suggestions.append("Run: pip install -e .")
238
-
239
- if 'permission' in error_msg:
258
+
259
+ if "permission" in error_msg:
240
260
  suggestions.append("Check file permissions")
241
261
  suggestions.append("You may need to run with appropriate privileges")
242
-
243
- if 'config' in error_msg or 'configuration' in error_msg:
262
+
263
+ if "config" in error_msg or "configuration" in error_msg:
244
264
  suggestions.append("Check your configuration files")
245
265
  suggestions.append("Run: mpm validate-config")
246
-
247
- return suggestions
266
+
267
+ return suggestions
@@ -13,22 +13,19 @@ import tempfile
13
13
  from pathlib import Path
14
14
  from typing import Any, Dict, Optional, Union
15
15
 
16
-
17
- class FileOperationError(Exception):
18
- """Exception raised for file operation errors."""
19
- pass
16
+ from ..core.exceptions import FileOperationError
20
17
 
21
18
 
22
19
  def ensure_directory(path: Union[str, Path]) -> Path:
23
20
  """
24
21
  Ensure a directory exists, creating it if necessary.
25
-
22
+
26
23
  Args:
27
24
  path: Directory path to ensure exists
28
-
25
+
29
26
  Returns:
30
27
  Path object for the directory
31
-
28
+
32
29
  Raises:
33
30
  FileOperationError: If directory cannot be created
34
31
  """
@@ -36,46 +33,71 @@ def ensure_directory(path: Union[str, Path]) -> Path:
36
33
  try:
37
34
  path.mkdir(parents=True, exist_ok=True)
38
35
  return path
39
- except Exception as e:
40
- raise FileOperationError(f"Failed to create directory {path}: {e}")
36
+ except (OSError, PermissionError) as e:
37
+ raise FileOperationError(
38
+ f"Failed to create directory: {e}",
39
+ context={
40
+ "path": str(path),
41
+ "operation": "mkdir",
42
+ "error_type": type(e).__name__,
43
+ },
44
+ )
41
45
 
42
46
 
43
- def safe_read_file(path: Union[str, Path], encoding: str = 'utf-8') -> str:
47
+ def safe_read_file(path: Union[str, Path], encoding: str = "utf-8") -> str:
44
48
  """
45
49
  Safely read a file with error handling.
46
-
50
+
47
51
  Args:
48
52
  path: File path to read
49
53
  encoding: Text encoding to use
50
-
54
+
51
55
  Returns:
52
56
  File contents as string
53
-
57
+
54
58
  Raises:
55
59
  FileOperationError: If file cannot be read
56
60
  """
57
61
  path = Path(path)
58
62
  try:
59
63
  return path.read_text(encoding=encoding)
60
- except Exception as e:
61
- raise FileOperationError(f"Failed to read file {path}: {e}")
64
+ except FileNotFoundError as e:
65
+ raise FileOperationError(
66
+ f"File not found: {path}",
67
+ context={
68
+ "path": str(path),
69
+ "operation": "read",
70
+ "encoding": encoding,
71
+ "error_type": "FileNotFoundError",
72
+ },
73
+ )
74
+ except (OSError, PermissionError, UnicodeDecodeError) as e:
75
+ raise FileOperationError(
76
+ f"Failed to read file: {e}",
77
+ context={
78
+ "path": str(path),
79
+ "operation": "read",
80
+ "encoding": encoding,
81
+ "error_type": type(e).__name__,
82
+ },
83
+ )
62
84
 
63
85
 
64
86
  def safe_write_file(
65
- path: Union[str, Path],
66
- content: str,
67
- encoding: str = 'utf-8',
68
- create_dirs: bool = True
87
+ path: Union[str, Path],
88
+ content: str,
89
+ encoding: str = "utf-8",
90
+ create_dirs: bool = True,
69
91
  ) -> None:
70
92
  """
71
93
  Safely write content to a file with directory creation.
72
-
94
+
73
95
  Args:
74
96
  path: File path to write
75
97
  content: Content to write
76
98
  encoding: Text encoding to use
77
99
  create_dirs: Whether to create parent directories
78
-
100
+
79
101
  Raises:
80
102
  FileOperationError: If file cannot be written
81
103
  """
@@ -89,22 +111,22 @@ def safe_write_file(
89
111
 
90
112
 
91
113
  def atomic_write(
92
- path: Union[str, Path],
93
- content: str,
94
- encoding: str = 'utf-8',
95
- create_dirs: bool = True
114
+ path: Union[str, Path],
115
+ content: str,
116
+ encoding: str = "utf-8",
117
+ create_dirs: bool = True,
96
118
  ) -> None:
97
119
  """
98
120
  Atomically write content to a file using a temporary file.
99
-
121
+
100
122
  This prevents corruption if the write operation is interrupted.
101
-
123
+
102
124
  Args:
103
125
  path: File path to write
104
126
  content: Content to write
105
127
  encoding: Text encoding to use
106
128
  create_dirs: Whether to create parent directories
107
-
129
+
108
130
  Raises:
109
131
  FileOperationError: If file cannot be written atomically
110
132
  """
@@ -112,25 +134,21 @@ def atomic_write(
112
134
  try:
113
135
  if create_dirs:
114
136
  ensure_directory(path.parent)
115
-
137
+
116
138
  # Write to temporary file first
117
139
  with tempfile.NamedTemporaryFile(
118
- mode='w',
119
- encoding=encoding,
120
- dir=path.parent,
121
- delete=False,
122
- suffix='.tmp'
140
+ mode="w", encoding=encoding, dir=path.parent, delete=False, suffix=".tmp"
123
141
  ) as temp_file:
124
142
  temp_file.write(content)
125
143
  temp_path = temp_file.name
126
-
144
+
127
145
  # Atomically move temporary file to target
128
146
  shutil.move(temp_path, path)
129
-
147
+
130
148
  except Exception as e:
131
149
  # Clean up temporary file if it exists
132
150
  try:
133
- if 'temp_path' in locals():
151
+ if "temp_path" in locals():
134
152
  os.unlink(temp_path)
135
153
  except:
136
154
  pass
@@ -140,10 +158,10 @@ def atomic_write(
140
158
  def get_file_info(path: Union[str, Path]) -> Optional[Dict[str, Any]]:
141
159
  """
142
160
  Get file metadata safely.
143
-
161
+
144
162
  Args:
145
163
  path: File path to examine
146
-
164
+
147
165
  Returns:
148
166
  Dictionary with file information or None if file doesn't exist
149
167
  """
@@ -151,7 +169,7 @@ def get_file_info(path: Union[str, Path]) -> Optional[Dict[str, Any]]:
151
169
  try:
152
170
  if not path.exists():
153
171
  return None
154
-
172
+
155
173
  stat = path.stat()
156
174
  return {
157
175
  "path": str(path),
@@ -160,40 +178,38 @@ def get_file_info(path: Union[str, Path]) -> Optional[Dict[str, Any]]:
160
178
  "created": stat.st_ctime,
161
179
  "is_file": path.is_file(),
162
180
  "is_dir": path.is_dir(),
163
- "permissions": oct(stat.st_mode)[-3:]
181
+ "permissions": oct(stat.st_mode)[-3:],
164
182
  }
165
183
  except Exception:
166
184
  return None
167
185
 
168
186
 
169
187
  def safe_copy_file(
170
- src: Union[str, Path],
171
- dst: Union[str, Path],
172
- create_dirs: bool = True
188
+ src: Union[str, Path], dst: Union[str, Path], create_dirs: bool = True
173
189
  ) -> None:
174
190
  """
175
191
  Safely copy a file with error handling.
176
-
192
+
177
193
  Args:
178
194
  src: Source file path
179
195
  dst: Destination file path
180
196
  create_dirs: Whether to create destination directories
181
-
197
+
182
198
  Raises:
183
199
  FileOperationError: If file cannot be copied
184
200
  """
185
201
  src = Path(src)
186
202
  dst = Path(dst)
187
-
203
+
188
204
  try:
189
205
  if not src.exists():
190
206
  raise FileOperationError(f"Source file does not exist: {src}")
191
-
207
+
192
208
  if create_dirs:
193
209
  ensure_directory(dst.parent)
194
-
210
+
195
211
  shutil.copy2(src, dst)
196
-
212
+
197
213
  except Exception as e:
198
214
  raise FileOperationError(f"Failed to copy {src} to {dst}: {e}")
199
215
 
@@ -201,13 +217,13 @@ def safe_copy_file(
201
217
  def safe_remove_file(path: Union[str, Path]) -> bool:
202
218
  """
203
219
  Safely remove a file.
204
-
220
+
205
221
  Args:
206
222
  path: File path to remove
207
-
223
+
208
224
  Returns:
209
225
  True if file was removed, False if it didn't exist
210
-
226
+
211
227
  Raises:
212
228
  FileOperationError: If file cannot be removed
213
229
  """
@@ -224,13 +240,13 @@ def safe_remove_file(path: Union[str, Path]) -> bool:
224
240
  def read_json_file(path: Union[str, Path]) -> Any:
225
241
  """
226
242
  Read and parse a JSON file safely.
227
-
243
+
228
244
  Args:
229
245
  path: JSON file path
230
-
246
+
231
247
  Returns:
232
248
  Parsed JSON data
233
-
249
+
234
250
  Raises:
235
251
  FileOperationError: If file cannot be read or parsed
236
252
  """
@@ -242,20 +258,17 @@ def read_json_file(path: Union[str, Path]) -> Any:
242
258
 
243
259
 
244
260
  def write_json_file(
245
- path: Union[str, Path],
246
- data: Any,
247
- indent: int = 2,
248
- atomic: bool = True
261
+ path: Union[str, Path], data: Any, indent: int = 2, atomic: bool = True
249
262
  ) -> None:
250
263
  """
251
264
  Write data to a JSON file safely.
252
-
265
+
253
266
  Args:
254
267
  path: JSON file path
255
268
  data: Data to serialize to JSON
256
269
  indent: JSON indentation level
257
270
  atomic: Whether to use atomic write
258
-
271
+
259
272
  Raises:
260
273
  FileOperationError: If file cannot be written
261
274
  """
@@ -269,23 +282,23 @@ def write_json_file(
269
282
  raise FileOperationError(f"Failed to write JSON file {path}: {e}")
270
283
 
271
284
 
272
- def backup_file(path: Union[str, Path], backup_suffix: str = '.backup') -> Path:
285
+ def backup_file(path: Union[str, Path], backup_suffix: str = ".backup") -> Path:
273
286
  """
274
287
  Create a backup copy of a file.
275
-
288
+
276
289
  Args:
277
290
  path: File path to backup
278
291
  backup_suffix: Suffix to add to backup filename
279
-
292
+
280
293
  Returns:
281
294
  Path to the backup file
282
-
295
+
283
296
  Raises:
284
297
  FileOperationError: If backup cannot be created
285
298
  """
286
299
  path = Path(path)
287
300
  backup_path = path.with_suffix(path.suffix + backup_suffix)
288
-
301
+
289
302
  try:
290
303
  safe_copy_file(path, backup_path)
291
304
  return backup_path
@@ -1,39 +1,40 @@
1
+ from pathlib import Path
2
+
1
3
  """Framework source directory detection utilities.
2
4
 
3
5
  WHY: This module provides utilities to detect if we're in the framework source directory
4
6
  to prevent accidental overwrites of the template files during deployment.
5
7
  """
6
8
 
7
- from pathlib import Path
8
- from typing import Tuple, List
9
+ from typing import List, Tuple
9
10
 
10
11
 
11
12
  def is_framework_source_directory(path: Path) -> Tuple[bool, List[str]]:
12
13
  """
13
14
  Check if the given path is the framework source directory.
14
-
15
+
15
16
  WHY: We need to prevent deployment to the framework source directory itself
16
17
  to avoid overwriting template files.
17
-
18
+
18
19
  Args:
19
20
  path: Path to check
20
-
21
+
21
22
  Returns:
22
23
  Tuple of (is_framework_source, list of detected markers)
23
24
  """
24
25
  markers = []
25
-
26
+
26
27
  # Check for framework source markers
27
28
  if (path / "src" / "claude_mpm").exists():
28
29
  markers.append("src/claude_mpm")
29
-
30
+
30
31
  if (path / "pyproject.toml").exists():
31
32
  markers.append("pyproject.toml")
32
-
33
+
33
34
  if (path / "src" / "claude_mpm" / "agents" / "INSTRUCTIONS.md").exists():
34
35
  markers.append("framework INSTRUCTIONS.md template")
35
-
36
+
36
37
  # If we have multiple markers, it's likely the framework source
37
38
  is_framework = len(markers) >= 2
38
-
39
- return is_framework, markers
39
+
40
+ return is_framework, markers