claude-mpm 3.9.2__tar.gz → 3.9.4__tar.gz

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 (283) hide show
  1. {claude_mpm-3.9.2/src/claude_mpm.egg-info → claude_mpm-3.9.4}/PKG-INFO +1 -1
  2. claude_mpm-3.9.4/VERSION +1 -0
  3. claude_mpm-3.9.4/src/claude_mpm/VERSION +1 -0
  4. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/config/paths.py +56 -6
  5. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/claude_hooks/hook_handler.py +167 -105
  6. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/paths.py +112 -8
  7. {claude_mpm-3.9.2 → claude_mpm-3.9.4/src/claude_mpm.egg-info}/PKG-INFO +1 -1
  8. claude_mpm-3.9.2/VERSION +0 -1
  9. claude_mpm-3.9.2/src/claude_mpm/VERSION +0 -1
  10. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/CLAUDE.md +0 -0
  11. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/LICENSE +0 -0
  12. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/MANIFEST.in +0 -0
  13. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/README.md +0 -0
  14. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/claude-mpm +0 -0
  15. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/pyproject.toml +0 -0
  16. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/requirements.txt +0 -0
  17. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/scripts/run_mpm.py +0 -0
  18. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/scripts/ticket +0 -0
  19. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/setup.cfg +0 -0
  20. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/setup.py +0 -0
  21. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/__init__.py +0 -0
  22. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/__main__.py +0 -0
  23. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -0
  24. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/BASE_PM.md +0 -0
  25. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/INSTRUCTIONS.md +0 -0
  26. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/MEMORY.md +0 -0
  27. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/WORKFLOW.md +0 -0
  28. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/__init__.py +0 -0
  29. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/agent_loader.py +0 -0
  30. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/agent_loader_integration.py +0 -0
  31. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/agents_metadata.py +0 -0
  32. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/async_agent_loader.py +0 -0
  33. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/backups/INSTRUCTIONS.md +0 -0
  34. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/base_agent.json +0 -0
  35. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/base_agent_loader.py +0 -0
  36. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/frontmatter_validator.py +0 -0
  37. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/schema/agent_schema.json +0 -0
  38. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/system_agent_config.py +0 -0
  39. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -0
  40. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/.claude-mpm/memories/engineer_agent.md +0 -0
  41. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/.claude-mpm/memories/qa_agent.md +0 -0
  42. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/.claude-mpm/memories/research_agent.md +0 -0
  43. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/.claude-mpm/memories/version_control_agent.md +0 -0
  44. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/__init__.py +0 -0
  45. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -0
  46. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -0
  47. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -0
  48. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -0
  49. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -0
  50. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +0 -0
  51. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -0
  52. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -0
  53. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -0
  54. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/code_analyzer.json +0 -0
  55. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/data_engineer.json +0 -0
  56. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/documentation.json +0 -0
  57. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/engineer.json +0 -0
  58. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/ops.json +0 -0
  59. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/project_organizer.json +0 -0
  60. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/qa.json +0 -0
  61. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/research.json +0 -0
  62. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/security.json +0 -0
  63. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/ticketing.json +0 -0
  64. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/version_control.json +0 -0
  65. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/web_qa.json +0 -0
  66. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/agents/templates/web_ui.json +0 -0
  67. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/__init__.py +0 -0
  68. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/__main__.py +0 -0
  69. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/__init__.py +0 -0
  70. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/agents.py +0 -0
  71. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/aggregate.py +0 -0
  72. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/config.py +0 -0
  73. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/info.py +0 -0
  74. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/memory.py +0 -0
  75. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/monitor.py +0 -0
  76. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/run.py +0 -0
  77. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/commands/tickets.py +0 -0
  78. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/parser.py +0 -0
  79. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/ticket_cli.py +0 -0
  80. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli/utils.py +0 -0
  81. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli_module/__init__.py +0 -0
  82. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli_module/args.py +0 -0
  83. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli_module/commands.py +0 -0
  84. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/cli_module/migration_example.py +0 -0
  85. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/config/__init__.py +0 -0
  86. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/config/agent_config.py +0 -0
  87. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/config/socketio_config.py +0 -0
  88. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/constants.py +0 -0
  89. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/__init__.py +0 -0
  90. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/agent_name_normalizer.py +0 -0
  91. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/agent_registry.py +0 -0
  92. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/agent_session_manager.py +0 -0
  93. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/base_service.py +0 -0
  94. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/cache.py +0 -0
  95. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/claude_runner.py +0 -0
  96. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/config.py +0 -0
  97. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/config_aliases.py +0 -0
  98. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/config_paths.py +0 -0
  99. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/constants.py +0 -0
  100. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/container.py +0 -0
  101. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/exceptions.py +0 -0
  102. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/factories.py +0 -0
  103. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/framework_loader.py +0 -0
  104. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/hook_manager.py +0 -0
  105. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/injectable_service.py +0 -0
  106. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/interactive_session.py +0 -0
  107. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/interfaces.py +0 -0
  108. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/lazy.py +0 -0
  109. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/logger.py +0 -0
  110. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/logging_config.py +0 -0
  111. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/minimal_framework_loader.py +0 -0
  112. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/mixins.py +0 -0
  113. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/oneshot_session.py +0 -0
  114. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/optimized_agent_loader.py +0 -0
  115. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/optimized_startup.py +0 -0
  116. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/pm_hook_interceptor.py +0 -0
  117. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/service_registry.py +0 -0
  118. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/session_manager.py +0 -0
  119. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/socketio_pool.py +0 -0
  120. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/tool_access_control.py +0 -0
  121. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/types.py +0 -0
  122. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/core/typing_utils.py +0 -0
  123. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/index.html +0 -0
  124. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/open_dashboard.py +0 -0
  125. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/css/dashboard.css +0 -0
  126. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/agent-inference.js +0 -0
  127. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/event-processor.js +0 -0
  128. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/event-viewer.js +0 -0
  129. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/export-manager.js +0 -0
  130. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -0
  131. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -0
  132. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/hud-manager.js +0 -0
  133. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -0
  134. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/module-viewer.js +0 -0
  135. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/session-manager.js +0 -0
  136. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/socket-manager.js +0 -0
  137. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -0
  138. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/components/working-directory.js +0 -0
  139. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/dashboard-original.js +0 -0
  140. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/dashboard.js +0 -0
  141. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/static/js/socket-client.js +0 -0
  142. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/templates/index.html +0 -0
  143. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/dashboard/test_dashboard.html +0 -0
  144. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/deployment_paths.py +0 -0
  145. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/experimental/cli_enhancements.py +0 -0
  146. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/generators/__init__.py +0 -0
  147. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/generators/agent_profile_generator.py +0 -0
  148. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/__init__.py +0 -0
  149. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/base_hook.py +0 -0
  150. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/claude_hooks/__init__.py +0 -0
  151. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -0
  152. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/claude_hooks/hook_wrapper.sh +0 -0
  153. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/memory_integration_hook.py +0 -0
  154. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/tool_call_interceptor.py +0 -0
  155. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/hooks/validation_hooks.py +0 -0
  156. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/init.py +0 -0
  157. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/models/__init__.py +0 -0
  158. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/models/agent_definition.py +0 -0
  159. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/models/agent_session.py +0 -0
  160. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/scripts/__init__.py +0 -0
  161. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/scripts/socketio_daemon.py +0 -0
  162. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/scripts/start_activity_logging.py +0 -0
  163. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/__init__.py +0 -0
  164. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agent/__init__.py +0 -0
  165. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agent/deployment.py +0 -0
  166. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agent/management.py +0 -0
  167. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agent/registry.py +0 -0
  168. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/__init__.py +0 -0
  169. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/deployment/__init__.py +0 -0
  170. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/deployment/agent_deployment.py +0 -0
  171. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +0 -0
  172. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/deployment/agent_versioning.py +0 -0
  173. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/deployment/async_agent_deployment.py +0 -0
  174. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/loading/__init__.py +0 -0
  175. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/loading/agent_profile_loader.py +0 -0
  176. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/loading/base_agent_manager.py +0 -0
  177. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/loading/framework_agent_loader.py +0 -0
  178. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/management/__init__.py +0 -0
  179. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/management/agent_capabilities_generator.py +0 -0
  180. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/management/agent_management_service.py +0 -0
  181. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/memory/__init__.py +0 -0
  182. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/memory/agent_memory_manager.py +0 -0
  183. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/memory/agent_persistence_service.py +0 -0
  184. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/registry/__init__.py +0 -0
  185. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/registry/agent_registry.py +0 -0
  186. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/registry/deployed_agent_discovery.py +0 -0
  187. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/agents/registry/modification_tracker.py +0 -0
  188. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/async_session_logger.py +0 -0
  189. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/claude_session_logger.py +0 -0
  190. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/communication/__init__.py +0 -0
  191. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/communication/socketio.py +0 -0
  192. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/communication/websocket.py +0 -0
  193. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/core/__init__.py +0 -0
  194. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/core/base.py +0 -0
  195. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/core/interfaces.py +0 -0
  196. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/event_aggregator.py +0 -0
  197. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/exceptions.py +0 -0
  198. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/__init__.py +0 -0
  199. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/content_assembler.py +0 -0
  200. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/content_validator.py +0 -0
  201. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/deployment_manager.py +0 -0
  202. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -0
  203. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -0
  204. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +0 -0
  205. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +0 -0
  206. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +0 -0
  207. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +0 -0
  208. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +0 -0
  209. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/header.py +0 -0
  210. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +0 -0
  211. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +0 -0
  212. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +0 -0
  213. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +0 -0
  214. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +0 -0
  215. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/section_manager.py +0 -0
  216. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator/version_manager.py +0 -0
  217. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/framework_claude_md_generator.py +0 -0
  218. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/health_monitor.py +0 -0
  219. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/hook_service.py +0 -0
  220. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/infrastructure/__init__.py +0 -0
  221. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/infrastructure/logging.py +0 -0
  222. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/infrastructure/monitoring.py +0 -0
  223. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/__init__.py +0 -0
  224. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/builder.py +0 -0
  225. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/cache/__init__.py +0 -0
  226. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/cache/shared_prompt_cache.py +0 -0
  227. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/cache/simple_cache.py +0 -0
  228. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/indexed_memory.py +0 -0
  229. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/optimizer.py +0 -0
  230. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/memory/router.py +0 -0
  231. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/optimized_hook_service.py +0 -0
  232. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/project/__init__.py +0 -0
  233. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/project/analyzer.py +0 -0
  234. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/project/registry.py +0 -0
  235. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/project_analyzer.py +0 -0
  236. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/project_registry.py +0 -0
  237. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/recovery_manager.py +0 -0
  238. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/response_tracker.py +0 -0
  239. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/__init__.py +0 -0
  240. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/__init__.py +0 -0
  241. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/base.py +0 -0
  242. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/connection.py +0 -0
  243. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/file.py +0 -0
  244. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/git.py +0 -0
  245. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/memory.py +0 -0
  246. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/project.py +0 -0
  247. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio/handlers/registry.py +0 -0
  248. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio_client_manager.py +0 -0
  249. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/socketio_server.py +0 -0
  250. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/standalone_socketio_server.py +0 -0
  251. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/ticket_manager.py +0 -0
  252. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/ticket_manager_di.py +0 -0
  253. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/ticketing_service_original.py +0 -0
  254. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/version_control/__init__.py +0 -0
  255. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/version_control/branch_strategy.py +0 -0
  256. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/version_control/conflict_resolution.py +0 -0
  257. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/version_control/git_operations.py +0 -0
  258. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/version_control/semantic_versioning.py +0 -0
  259. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/services/version_control/version_parser.py +0 -0
  260. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/ticket_wrapper.py +0 -0
  261. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/__init__.py +0 -0
  262. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/agent_dependency_loader.py +0 -0
  263. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/config_manager.py +0 -0
  264. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/console.py +0 -0
  265. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/dependency_cache.py +0 -0
  266. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/dependency_manager.py +0 -0
  267. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/dependency_strategies.py +0 -0
  268. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/environment_context.py +0 -0
  269. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/error_handler.py +0 -0
  270. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/framework_detection.py +0 -0
  271. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/import_migration_example.py +0 -0
  272. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/imports.py +0 -0
  273. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/path_operations.py +0 -0
  274. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/robust_installer.py +0 -0
  275. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/utils/session_logging.py +0 -0
  276. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/validation/__init__.py +0 -0
  277. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/validation/agent_validator.py +0 -0
  278. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm/validation/frontmatter_validator.py +0 -0
  279. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm.egg-info/SOURCES.txt +0 -0
  280. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm.egg-info/dependency_links.txt +0 -0
  281. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm.egg-info/entry_points.txt +0 -0
  282. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm.egg-info/requires.txt +0 -0
  283. {claude_mpm-3.9.2 → claude_mpm-3.9.4}/src/claude_mpm.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 3.9.2
3
+ Version: 3.9.4
4
4
  Summary: Claude Multi-agent Project Manager - Clean orchestration with ticket management
5
5
  Home-page: https://github.com/bobmatnyc/claude-mpm
6
6
  Author: Claude MPM Team
@@ -0,0 +1 @@
1
+ 3.9.4
@@ -0,0 +1 @@
1
+ 3.9.4
@@ -33,6 +33,7 @@ class ClaudeMPMPaths:
33
33
 
34
34
  _instance: Optional['ClaudeMPMPaths'] = None
35
35
  _project_root: Optional[Path] = None
36
+ _is_installed: bool = False
36
37
 
37
38
  def __new__(cls) -> 'ClaudeMPMPaths':
38
39
  """Singleton pattern to ensure single instance."""
@@ -43,6 +44,7 @@ class ClaudeMPMPaths:
43
44
  def __init__(self):
44
45
  """Initialize paths if not already done."""
45
46
  if self._project_root is None:
47
+ self._is_installed = False
46
48
  self._detect_project_root()
47
49
 
48
50
  def _detect_project_root(self) -> None:
@@ -53,16 +55,29 @@ class ClaudeMPMPaths:
53
55
  1. Look for definitive project markers (pyproject.toml, setup.py)
54
56
  2. Look for combination of markers to ensure we're at the right level
55
57
  3. Walk up from current file location
58
+ 4. Handle both development and installed environments
56
59
  """
57
60
  # Start from this file's location
58
61
  current = Path(__file__).resolve()
59
62
 
60
- # Walk up the directory tree
63
+ # Check if we're in an installed environment (site-packages)
64
+ # In pip/pipx installs, the package is directly in site-packages
65
+ if 'site-packages' in str(current) or 'dist-packages' in str(current):
66
+ # We're in an installed environment
67
+ # The claude_mpm package directory itself is the "root" for resources
68
+ import claude_mpm
69
+ self._project_root = Path(claude_mpm.__file__).parent
70
+ self._is_installed = True
71
+ logger.debug(f"Installed environment detected, using package dir: {self._project_root}")
72
+ return
73
+
74
+ # We're in a development environment, look for project markers
61
75
  for parent in current.parents:
62
76
  # Check for definitive project root indicators
63
77
  # Prioritize pyproject.toml and setup.py as they're only at root
64
78
  if (parent / 'pyproject.toml').exists() or (parent / 'setup.py').exists():
65
79
  self._project_root = parent
80
+ self._is_installed = False
66
81
  logger.debug(f"Project root detected at: {parent} (found pyproject.toml or setup.py)")
67
82
  return
68
83
 
@@ -70,6 +85,7 @@ class ClaudeMPMPaths:
70
85
  # This combination is more likely to be the real project root
71
86
  if (parent / '.git').exists() and (parent / 'VERSION').exists():
72
87
  self._project_root = parent
88
+ self._is_installed = False
73
89
  logger.debug(f"Project root detected at: {parent} (found .git and VERSION)")
74
90
  return
75
91
 
@@ -77,12 +93,14 @@ class ClaudeMPMPaths:
77
93
  for parent in current.parents:
78
94
  if parent.name == 'claude-mpm':
79
95
  self._project_root = parent
96
+ self._is_installed = False
80
97
  logger.debug(f"Project root detected at: {parent} (by directory name)")
81
98
  return
82
99
 
83
100
  # Last resort fallback: 3 levels up from this file
84
101
  # paths.py is in src/claude_mpm/config/
85
102
  self._project_root = current.parent.parent.parent
103
+ self._is_installed = False
86
104
  logger.warning(f"Project root fallback to: {self._project_root}")
87
105
 
88
106
  @property
@@ -95,16 +113,26 @@ class ClaudeMPMPaths:
95
113
  @property
96
114
  def src_dir(self) -> Path:
97
115
  """Get the src directory."""
116
+ if hasattr(self, '_is_installed') and self._is_installed:
117
+ # In installed environment, there's no src directory
118
+ # Return the package directory itself
119
+ return self.project_root.parent
98
120
  return self.project_root / "src"
99
121
 
100
122
  @property
101
123
  def claude_mpm_dir(self) -> Path:
102
124
  """Get the main claude_mpm package directory."""
125
+ if hasattr(self, '_is_installed') and self._is_installed:
126
+ # In installed environment, project_root IS the claude_mpm directory
127
+ return self.project_root
103
128
  return self.src_dir / "claude_mpm"
104
129
 
105
130
  @property
106
131
  def agents_dir(self) -> Path:
107
132
  """Get the agents directory."""
133
+ if hasattr(self, '_is_installed') and self._is_installed:
134
+ # In installed environment, agents is directly under the package
135
+ return self.project_root / "agents"
108
136
  return self.claude_mpm_dir / "agents"
109
137
 
110
138
  @property
@@ -140,36 +168,58 @@ class ClaudeMPMPaths:
140
168
  @property
141
169
  def scripts_dir(self) -> Path:
142
170
  """Get the scripts directory."""
171
+ if hasattr(self, '_is_installed') and self._is_installed:
172
+ # In installed environment, scripts might be in a different location or not exist
173
+ # Return a path that won't cause issues but indicates it's not available
174
+ return Path.home() / '.claude-mpm' / 'scripts'
143
175
  return self.project_root / "scripts"
144
176
 
145
177
  @property
146
178
  def tests_dir(self) -> Path:
147
179
  """Get the tests directory."""
180
+ if hasattr(self, '_is_installed') and self._is_installed:
181
+ # Tests aren't distributed with installed packages
182
+ return Path.home() / '.claude-mpm' / 'tests'
148
183
  return self.project_root / "tests"
149
184
 
150
185
  @property
151
186
  def docs_dir(self) -> Path:
152
187
  """Get the documentation directory."""
188
+ if hasattr(self, '_is_installed') and self._is_installed:
189
+ # Docs might be installed separately or not at all
190
+ return Path.home() / '.claude-mpm' / 'docs'
153
191
  return self.project_root / "docs"
154
192
 
155
193
  @property
156
194
  def logs_dir(self) -> Path:
157
195
  """Get the logs directory (creates if doesn't exist)."""
158
- logs = self.project_root / "logs"
159
- logs.mkdir(exist_ok=True)
196
+ if hasattr(self, '_is_installed') and self._is_installed:
197
+ # Use user's home directory for logs in installed environment
198
+ logs = Path.home() / '.claude-mpm' / 'logs'
199
+ else:
200
+ logs = self.project_root / "logs"
201
+ logs.mkdir(parents=True, exist_ok=True)
160
202
  return logs
161
203
 
162
204
  @property
163
205
  def temp_dir(self) -> Path:
164
206
  """Get the temporary files directory (creates if doesn't exist)."""
165
- temp = self.project_root / ".tmp"
166
- temp.mkdir(exist_ok=True)
207
+ if hasattr(self, '_is_installed') and self._is_installed:
208
+ # Use user's home directory for temp files in installed environment
209
+ temp = Path.home() / '.claude-mpm' / '.tmp'
210
+ else:
211
+ temp = self.project_root / ".tmp"
212
+ temp.mkdir(parents=True, exist_ok=True)
167
213
  return temp
168
214
 
169
215
  @property
170
216
  def claude_mpm_dir_hidden(self) -> Path:
171
217
  """Get the hidden .claude-mpm directory (creates if doesn't exist)."""
172
- hidden = self.project_root / ".claude-mpm"
218
+ if hasattr(self, '_is_installed') and self._is_installed:
219
+ # Use current working directory in installed environment
220
+ hidden = Path.cwd() / ".claude-mpm"
221
+ else:
222
+ hidden = self.project_root / ".claude-mpm"
173
223
  hidden.mkdir(exist_ok=True)
174
224
  return hidden
175
225
 
@@ -21,6 +21,7 @@ import time
21
21
  import asyncio
22
22
  from pathlib import Path
23
23
  from collections import deque
24
+ import threading
24
25
 
25
26
  # Import constants for configuration
26
27
  try:
@@ -87,6 +88,102 @@ except ImportError:
87
88
  # No fallback needed - we only use Socket.IO now
88
89
 
89
90
 
91
+
92
+ class SocketIOConnectionPool:
93
+ """Connection pool for Socket.IO clients to prevent connection leaks."""
94
+
95
+ def __init__(self, max_connections=3):
96
+ self.max_connections = max_connections
97
+ self.connections = []
98
+ self.last_cleanup = time.time()
99
+
100
+ def get_connection(self, port):
101
+ """Get or create a connection to the specified port."""
102
+ if time.time() - self.last_cleanup > 60:
103
+ self._cleanup_dead_connections()
104
+ self.last_cleanup = time.time()
105
+
106
+ for conn in self.connections:
107
+ if conn.get('port') == port and conn.get('client'):
108
+ client = conn['client']
109
+ if self._is_connection_alive(client):
110
+ return client
111
+ else:
112
+ self.connections.remove(conn)
113
+
114
+ if len(self.connections) < self.max_connections:
115
+ client = self._create_connection(port)
116
+ if client:
117
+ self.connections.append({
118
+ 'port': port,
119
+ 'client': client,
120
+ 'created': time.time()
121
+ })
122
+ return client
123
+
124
+ if self.connections:
125
+ oldest = min(self.connections, key=lambda x: x['created'])
126
+ self._close_connection(oldest['client'])
127
+ oldest['client'] = self._create_connection(port)
128
+ oldest['port'] = port
129
+ oldest['created'] = time.time()
130
+ return oldest['client']
131
+
132
+ return None
133
+
134
+ def _create_connection(self, port):
135
+ """Create a new Socket.IO connection."""
136
+ if not SOCKETIO_AVAILABLE:
137
+ return None
138
+ try:
139
+ client = socketio.Client(
140
+ reconnection=False, # Disable auto-reconnect
141
+ logger=False,
142
+ engineio_logger=False
143
+ )
144
+ client.connect(f'http://localhost:{port}',
145
+ wait=True,
146
+ wait_timeout=NetworkConfig.SOCKET_WAIT_TIMEOUT)
147
+ if client.connected:
148
+ return client
149
+ except Exception:
150
+ pass
151
+ return None
152
+
153
+ def _is_connection_alive(self, client):
154
+ """Check if a connection is still alive."""
155
+ try:
156
+ return client and client.connected
157
+ except:
158
+ return False
159
+
160
+ def _close_connection(self, client):
161
+ """Safely close a connection."""
162
+ try:
163
+ if client:
164
+ client.disconnect()
165
+ except:
166
+ pass
167
+
168
+ def _cleanup_dead_connections(self):
169
+ """Remove dead connections from the pool."""
170
+ self.connections = [
171
+ conn for conn in self.connections
172
+ if self._is_connection_alive(conn.get('client'))
173
+ ]
174
+
175
+ def close_all(self):
176
+ """Close all connections in the pool."""
177
+ for conn in self.connections:
178
+ self._close_connection(conn.get('client'))
179
+ self.connections.clear()
180
+
181
+
182
+ # Global singleton handler instance
183
+ _global_handler = None
184
+ _handler_lock = threading.Lock()
185
+
186
+
90
187
  class ClaudeHookHandler:
91
188
  """Optimized hook handler with direct Socket.IO client.
92
189
 
@@ -99,8 +196,17 @@ class ClaudeHookHandler:
99
196
 
100
197
  def __init__(self):
101
198
  # Socket.IO client (persistent if possible)
102
- self.sio_client = None
103
- self.sio_connected = False
199
+ self.connection_pool = SocketIOConnectionPool(max_connections=3)
200
+ # Track events for periodic cleanup
201
+ self.events_processed = 0
202
+ self.last_cleanup = time.time()
203
+
204
+ # Maximum sizes for tracking
205
+ self.MAX_DELEGATION_TRACKING = 200
206
+ self.MAX_PROMPT_TRACKING = 100
207
+ self.MAX_CACHE_AGE_SECONDS = 300
208
+ self.CLEANUP_INTERVAL_EVENTS = 100
209
+
104
210
 
105
211
  # Agent delegation tracking
106
212
  # Store recent Task delegations: session_id -> agent_type
@@ -179,6 +285,36 @@ class ClaudeHookHandler:
179
285
  if key in self.delegation_requests:
180
286
  del self.delegation_requests[key]
181
287
 
288
+
289
+ def _cleanup_old_entries(self):
290
+ """Clean up old entries to prevent memory growth."""
291
+ cutoff_time = datetime.now().timestamp() - self.MAX_CACHE_AGE_SECONDS
292
+
293
+ # Clean up delegation tracking dictionaries
294
+ for storage in [self.active_delegations, self.delegation_requests]:
295
+ if len(storage) > self.MAX_DELEGATION_TRACKING:
296
+ # Keep only the most recent entries
297
+ sorted_keys = sorted(storage.keys())
298
+ excess = len(storage) - self.MAX_DELEGATION_TRACKING
299
+ for key in sorted_keys[:excess]:
300
+ del storage[key]
301
+
302
+ # Clean up pending prompts
303
+ if len(self.pending_prompts) > self.MAX_PROMPT_TRACKING:
304
+ sorted_keys = sorted(self.pending_prompts.keys())
305
+ excess = len(self.pending_prompts) - self.MAX_PROMPT_TRACKING
306
+ for key in sorted_keys[:excess]:
307
+ del self.pending_prompts[key]
308
+
309
+ # Clean up git branch cache
310
+ expired_keys = [
311
+ key for key, cache_time in self._git_branch_cache_time.items()
312
+ if datetime.now().timestamp() - cache_time > self.MAX_CACHE_AGE_SECONDS
313
+ ]
314
+ for key in expired_keys:
315
+ self._git_branch_cache.pop(key, None)
316
+ self._git_branch_cache_time.pop(key, None)
317
+
182
318
  def _get_delegation_agent_type(self, session_id: str) -> str:
183
319
  """Get the agent type for a session's active delegation."""
184
320
  # First try exact session match
@@ -455,97 +591,6 @@ class ClaudeHookHandler:
455
591
  self._git_branch_cache_time[cache_key] = current_time
456
592
  return 'Unknown'
457
593
 
458
- def _get_socketio_client(self):
459
- """Get or create Socket.IO client with improved reliability.
460
-
461
- WHY improved approach:
462
- - Implements retry logic with exponential backoff
463
- - Properly tests connection before returning
464
- - Ensures connection persists across events
465
- - Better error handling and recovery
466
- """
467
- if not SOCKETIO_AVAILABLE:
468
- return None
469
-
470
- # Check if we have a connected client
471
- if self.sio_client and self.sio_connected:
472
- try:
473
- # Test if still connected
474
- if self.sio_client.connected:
475
- return self.sio_client
476
- else:
477
- # Connection lost, clear it
478
- if DEBUG:
479
- print("Hook handler: Socket.IO connection lost, reconnecting...", file=sys.stderr)
480
- self.sio_connected = False
481
- except:
482
- self.sio_connected = False
483
-
484
- # Need to create or reconnect client
485
- port = int(os.environ.get('CLAUDE_MPM_SOCKETIO_PORT', '8765'))
486
- max_retries = RetryConfig.MAX_RETRIES
487
- retry_delay = RetryConfig.INITIAL_RETRY_DELAY
488
-
489
- for attempt in range(max_retries):
490
- try:
491
- # Clean up old client if exists
492
- if self.sio_client and not self.sio_connected:
493
- try:
494
- self.sio_client.disconnect()
495
- except:
496
- pass
497
- self.sio_client = None
498
-
499
- # Create new client
500
- self.sio_client = socketio.Client(
501
- reconnection=True, # Enable auto-reconnection
502
- reconnection_attempts=3,
503
- reconnection_delay=NetworkConfig.RECONNECTION_DELAY,
504
- reconnection_delay_max=2,
505
- logger=False,
506
- engineio_logger=False
507
- )
508
-
509
- # Try to connect with proper wait
510
- self.sio_client.connect(
511
- f'http://localhost:{port}',
512
- wait=True,
513
- wait_timeout=NetworkConfig.SOCKET_WAIT_TIMEOUT
514
- )
515
-
516
- # Verify connection
517
- if self.sio_client.connected:
518
- self.sio_connected = True
519
- if DEBUG:
520
- print(f"Hook handler: Successfully connected to Socket.IO server on port {port} (attempt {attempt + 1})", file=sys.stderr)
521
- return self.sio_client
522
-
523
- except Exception as e:
524
- if DEBUG and attempt == max_retries - 1:
525
- print(f"Hook handler: Failed to connect to Socket.IO after {max_retries} attempts: {e}", file=sys.stderr)
526
- elif DEBUG:
527
- print(f"Hook handler: Connection attempt {attempt + 1} failed, retrying...", file=sys.stderr)
528
-
529
- # Exponential backoff with async delay
530
- if attempt < max_retries - 1:
531
- # Use asyncio.sleep if in async context, otherwise fall back to time.sleep
532
- try:
533
- loop = asyncio.get_event_loop()
534
- if loop.is_running():
535
- # We're in an async context, use async sleep
536
- asyncio.create_task(asyncio.sleep(retry_delay))
537
- else:
538
- # Sync context, use regular sleep
539
- time.sleep(retry_delay)
540
- except:
541
- # Fallback to sync sleep if asyncio not available
542
- time.sleep(retry_delay)
543
- retry_delay *= 2 # Double the delay for next attempt
544
-
545
- # All attempts failed
546
- self.sio_client = None
547
- self.sio_connected = False
548
- return None
549
594
 
550
595
  def handle(self):
551
596
  """Process hook event with minimal overhead and zero blocking delays.
@@ -565,6 +610,13 @@ class ClaudeHookHandler:
565
610
  self._continue_execution()
566
611
  return
567
612
 
613
+ # Increment event counter and perform periodic cleanup
614
+ self.events_processed += 1
615
+ if self.events_processed % self.CLEANUP_INTERVAL_EVENTS == 0:
616
+ self._cleanup_old_entries()
617
+ if DEBUG:
618
+ print(f"🧹 Performed cleanup after {self.events_processed} events", file=sys.stderr)
619
+
568
620
  # Route event to appropriate handler
569
621
  self._route_event(event)
570
622
 
@@ -647,7 +699,8 @@ class ClaudeHookHandler:
647
699
  # The daemon should be running when manager is active
648
700
 
649
701
  # Get Socket.IO client
650
- client = self._get_socketio_client()
702
+ port = int(os.environ.get('CLAUDE_MPM_SOCKETIO_PORT', '8765'))
703
+ client = self.connection_pool.get_connection(port)
651
704
  if not client:
652
705
  if DEBUG:
653
706
  print(f"Hook handler: No Socket.IO client available for event: hook.{event}", file=sys.stderr)
@@ -680,22 +733,18 @@ class ClaudeHookHandler:
680
733
  print(f"✅ Successfully emitted Socket.IO event: hook.{event}", file=sys.stderr)
681
734
  else:
682
735
  print(f"⚠️ Event emitted but connection status uncertain: hook.{event}", file=sys.stderr)
683
- self.sio_connected = False # Force reconnection next time
684
736
 
685
737
  except Exception as e:
686
738
  if DEBUG:
687
739
  print(f"❌ Socket.IO emit failed for hook.{event}: {e}", file=sys.stderr)
688
- # Mark as disconnected so next call will reconnect
689
- self.sio_connected = False
690
740
 
691
741
  # Try to reconnect immediately for critical events
692
742
  if event in ['subagent_stop', 'pre_tool']:
693
743
  if DEBUG:
694
744
  print(f"Hook handler: Attempting immediate reconnection for critical event: hook.{event}", file=sys.stderr)
695
- # Clear the client to force reconnection
696
- self.sio_client = None
697
745
  # Try to get a new client and emit again
698
- retry_client = self._get_socketio_client()
746
+ retry_port = int(os.environ.get('CLAUDE_MPM_SOCKETIO_PORT', '8765'))
747
+ retry_client = self.connection_pool.get_connection(retry_port)
699
748
  if retry_client:
700
749
  try:
701
750
  retry_client.emit('claude_event', claude_event_data)
@@ -1667,18 +1716,31 @@ class ClaudeHookHandler:
1667
1716
  # Don't fail the delegation result - memory is optional
1668
1717
 
1669
1718
  def __del__(self):
1670
- """Cleanup Socket.IO client on handler destruction."""
1671
- if self.sio_client and self.sio_connected:
1719
+ """Cleanup Socket.IO connections on handler destruction."""
1720
+ if hasattr(self, 'connection_pool') and self.connection_pool:
1672
1721
  try:
1673
- self.sio_client.disconnect()
1722
+ self.connection_pool.close_all()
1674
1723
  except:
1675
1724
  pass
1676
1725
 
1677
1726
 
1678
1727
  def main():
1679
- """Entry point with comprehensive error handling."""
1728
+ """Entry point with singleton pattern to prevent multiple instances."""
1729
+ global _global_handler
1730
+
1680
1731
  try:
1681
- handler = ClaudeHookHandler()
1732
+ # Use singleton pattern to prevent creating multiple instances
1733
+ with _handler_lock:
1734
+ if _global_handler is None:
1735
+ _global_handler = ClaudeHookHandler()
1736
+ if DEBUG:
1737
+ print(f"✅ Created new ClaudeHookHandler singleton (pid: {os.getpid()})", file=sys.stderr)
1738
+ else:
1739
+ if DEBUG:
1740
+ print(f"♻️ Reusing existing ClaudeHookHandler singleton (pid: {os.getpid()})", file=sys.stderr)
1741
+
1742
+ handler = _global_handler
1743
+
1682
1744
  handler.handle()
1683
1745
  except Exception as e:
1684
1746
  # Always output continue action to not block Claude