claude-mpm 3.4.24__tar.gz → 3.4.26__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 (239) hide show
  1. {claude_mpm-3.4.24/src/claude_mpm.egg-info → claude_mpm-3.4.26}/PKG-INFO +1 -1
  2. claude_mpm-3.4.26/VERSION +1 -0
  3. claude_mpm-3.4.26/src/claude_mpm/VERSION +1 -0
  4. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/__init__.py +29 -1
  5. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/init.py +2 -0
  6. claude_mpm-3.4.26/src/claude_mpm/services/project_registry.py +602 -0
  7. {claude_mpm-3.4.24 → claude_mpm-3.4.26/src/claude_mpm.egg-info}/PKG-INFO +1 -1
  8. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm.egg-info/SOURCES.txt +1 -0
  9. claude_mpm-3.4.24/VERSION +0 -1
  10. claude_mpm-3.4.24/src/claude_mpm/VERSION +0 -1
  11. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/CLAUDE.md +0 -0
  12. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/LICENSE +0 -0
  13. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/MANIFEST.in +0 -0
  14. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/README.md +0 -0
  15. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/claude-mpm +0 -0
  16. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/pyproject.toml +0 -0
  17. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/requirements.txt +0 -0
  18. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/scripts/run_mpm.py +0 -0
  19. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/scripts/ticket +0 -0
  20. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/setup.cfg +0 -0
  21. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/setup.py +0 -0
  22. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/__init__.py +0 -0
  23. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/__main__.py +0 -0
  24. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -0
  25. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/INSTRUCTIONS.md +0 -0
  26. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/__init__.py +0 -0
  27. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/agent_loader.py +0 -0
  28. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/agent_loader_integration.py +0 -0
  29. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/agents_metadata.py +0 -0
  30. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/backups/INSTRUCTIONS.md +0 -0
  31. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/base_agent.json +0 -0
  32. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/base_agent_loader.py +0 -0
  33. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/schema/agent_schema.json +0 -0
  34. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/system_agent_config.py +0 -0
  35. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -0
  36. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/.claude-mpm/memories/version_control_agent.md +0 -0
  37. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/__init__.py +0 -0
  38. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -0
  39. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -0
  40. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -0
  41. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -0
  42. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -0
  43. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -0
  44. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -0
  45. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -0
  46. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/data_engineer.json +0 -0
  47. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/documentation.json +0 -0
  48. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/engineer.json +0 -0
  49. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/ops.json +0 -0
  50. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/pm.json +0 -0
  51. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/qa.json +0 -0
  52. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/research.json +0 -0
  53. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/security.json +0 -0
  54. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/test_integration.json +0 -0
  55. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/agents/templates/version_control.json +0 -0
  56. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/__init__.py +0 -0
  57. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/agents.py +0 -0
  58. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/info.py +0 -0
  59. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/memory.py +0 -0
  60. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/monitor.py +0 -0
  61. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/run.py +0 -0
  62. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/tickets.py +0 -0
  63. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/commands/ui.py +0 -0
  64. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/parser.py +0 -0
  65. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli/utils.py +0 -0
  66. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli_module/__init__.py +0 -0
  67. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli_module/args.py +0 -0
  68. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli_module/commands.py +0 -0
  69. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/cli_module/migration_example.py +0 -0
  70. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/config/__init__.py +0 -0
  71. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/config/socketio_config.py +0 -0
  72. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/constants.py +0 -0
  73. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/__init__.py +0 -0
  74. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/agent_name_normalizer.py +0 -0
  75. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/agent_registry.py +0 -0
  76. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/agent_session_manager.py +0 -0
  77. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/base_service.py +0 -0
  78. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/claude_runner.py +0 -0
  79. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/config.py +0 -0
  80. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/config_aliases.py +0 -0
  81. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/container.py +0 -0
  82. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/factories.py +0 -0
  83. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/framework_loader.py +0 -0
  84. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/hook_manager.py +0 -0
  85. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/injectable_service.py +0 -0
  86. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/interfaces.py +0 -0
  87. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/logger.py +0 -0
  88. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/minimal_framework_loader.py +0 -0
  89. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/mixins.py +0 -0
  90. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/pm_hook_interceptor.py +0 -0
  91. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/service_registry.py +0 -0
  92. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/session_manager.py +0 -0
  93. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/simple_runner.py +0 -0
  94. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/socketio_pool.py +0 -0
  95. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/core/tool_access_control.py +0 -0
  96. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/index.html +0 -0
  97. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/open_dashboard.py +0 -0
  98. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/css/dashboard.css +0 -0
  99. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/agent-inference.js +0 -0
  100. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/event-processor.js +0 -0
  101. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/event-viewer.js +0 -0
  102. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/export-manager.js +0 -0
  103. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -0
  104. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -0
  105. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/hud-manager.js +0 -0
  106. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -0
  107. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/module-viewer.js +0 -0
  108. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/session-manager.js +0 -0
  109. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/socket-manager.js +0 -0
  110. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -0
  111. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/components/working-directory.js +0 -0
  112. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/dashboard-original.js +0 -0
  113. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/dashboard.js +0 -0
  114. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/static/js/socket-client.js +0 -0
  115. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/templates/index.html +0 -0
  116. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/dashboard/test_dashboard.html +0 -0
  117. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/deployment_paths.py +0 -0
  118. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/experimental/cli_enhancements.py +0 -0
  119. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/generators/__init__.py +0 -0
  120. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/generators/agent_profile_generator.py +0 -0
  121. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/__init__.py +0 -0
  122. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/base_hook.py +0 -0
  123. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/__init__.py +0 -0
  124. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/logging_hook_example.py +0 -0
  125. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/memory_hooks_example.py +0 -0
  126. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/mpm_command_hook.py +0 -0
  127. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -0
  128. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -0
  129. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/submit_hook_example.py +0 -0
  130. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -0
  131. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -0
  132. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/builtin/workflow_start_hook.py +0 -0
  133. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/claude_hooks/__init__.py +0 -0
  134. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/claude_hooks/hook_handler.py +0 -0
  135. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/claude_hooks/hook_wrapper.sh +0 -0
  136. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/memory_integration_hook.py +0 -0
  137. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/tool_call_interceptor.py +0 -0
  138. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/hooks/validation_hooks.py +0 -0
  139. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/models/__init__.py +0 -0
  140. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/models/agent_definition.py +0 -0
  141. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/__init__.py +0 -0
  142. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/direct_orchestrator.py +0 -0
  143. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/factory.py +0 -0
  144. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -0
  145. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/hook_integration_example.py +0 -0
  146. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -0
  147. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/orchestrator.py +0 -0
  148. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -0
  149. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/pty_orchestrator.py +0 -0
  150. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/simple_orchestrator.py +0 -0
  151. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -0
  152. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -0
  153. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -0
  154. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/schemas/workflow_validator.py +0 -0
  155. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/scripts/socketio_daemon.py +0 -0
  156. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/__init__.py +0 -0
  157. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_capabilities_generator.py +0 -0
  158. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_deployment.py +0 -0
  159. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_lifecycle_manager.py +0 -0
  160. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_management_service.py +0 -0
  161. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_memory_manager.py +0 -0
  162. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_modification_tracker.py +0 -0
  163. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_persistence_service.py +0 -0
  164. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_profile_loader.py +0 -0
  165. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_registry.py +0 -0
  166. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/agent_versioning.py +0 -0
  167. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/base_agent_manager.py +0 -0
  168. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/deployed_agent_discovery.py +0 -0
  169. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/exceptions.py +0 -0
  170. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_agent_loader.py +0 -0
  171. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/__init__.py +0 -0
  172. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/content_assembler.py +0 -0
  173. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/content_validator.py +0 -0
  174. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/deployment_manager.py +0 -0
  175. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -0
  176. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -0
  177. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +0 -0
  178. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +0 -0
  179. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +0 -0
  180. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +0 -0
  181. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +0 -0
  182. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/header.py +0 -0
  183. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +0 -0
  184. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +0 -0
  185. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +0 -0
  186. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +0 -0
  187. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +0 -0
  188. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/section_manager.py +0 -0
  189. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator/version_manager.py +0 -0
  190. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/framework_claude_md_generator.py +0 -0
  191. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/health_monitor.py +0 -0
  192. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/hook_service.py +0 -0
  193. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/memory_builder.py +0 -0
  194. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/memory_optimizer.py +0 -0
  195. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/memory_router.py +0 -0
  196. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/__init__.py +0 -0
  197. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/backup_manager.py +0 -0
  198. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/config_manager.py +0 -0
  199. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -0
  200. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/framework_protector.py +0 -0
  201. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/operations.py +0 -0
  202. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/state_manager.py +0 -0
  203. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/template_deployer.py +0 -0
  204. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/validation_manager.py +0 -0
  205. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -0
  206. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/parent_directory_manager/version_manager.py +0 -0
  207. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/project_analyzer.py +0 -0
  208. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/recovery_manager.py +0 -0
  209. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/shared_prompt_cache.py +0 -0
  210. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/socketio_client_manager.py +0 -0
  211. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/socketio_server.py +0 -0
  212. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/standalone_socketio_server.py +0 -0
  213. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/ticket_manager.py +0 -0
  214. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/ticket_manager_di.py +0 -0
  215. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/ticketing_service_original.py +0 -0
  216. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/version_control/__init__.py +0 -0
  217. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/version_control/branch_strategy.py +0 -0
  218. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/version_control/conflict_resolution.py +0 -0
  219. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/version_control/git_operations.py +0 -0
  220. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/services/version_control/semantic_versioning.py +0 -0
  221. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/ticket_wrapper.py +0 -0
  222. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/ui/__init__.py +0 -0
  223. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/ui/rich_terminal_ui.py +0 -0
  224. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/ui/terminal_ui.py +0 -0
  225. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/__init__.py +0 -0
  226. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/config_manager.py +0 -0
  227. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/dependency_manager.py +0 -0
  228. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/error_handler.py +0 -0
  229. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/framework_detection.py +0 -0
  230. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/import_migration_example.py +0 -0
  231. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/imports.py +0 -0
  232. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/path_operations.py +0 -0
  233. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/utils/paths.py +0 -0
  234. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/validation/__init__.py +0 -0
  235. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm/validation/agent_validator.py +0 -0
  236. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm.egg-info/dependency_links.txt +0 -0
  237. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm.egg-info/entry_points.txt +0 -0
  238. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/src/claude_mpm.egg-info/requires.txt +0 -0
  239. {claude_mpm-3.4.24 → claude_mpm-3.4.26}/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.4.24
3
+ Version: 3.4.26
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.4.26
@@ -0,0 +1 @@
1
+ 3.4.26
@@ -24,7 +24,8 @@ from .commands import (
24
24
  manage_agents,
25
25
  run_terminal_ui,
26
26
  manage_memory,
27
- manage_monitor
27
+ manage_monitor,
28
+ run_manager
28
29
  )
29
30
 
30
31
  # Get version from VERSION file - single source of truth
@@ -69,6 +70,9 @@ def main(argv: Optional[list] = None):
69
70
  # Ensure directories are initialized on first run
70
71
  ensure_directories()
71
72
 
73
+ # Initialize or update project registry
74
+ _initialize_project_registry()
75
+
72
76
  # Create parser with version
73
77
  parser = create_parser(version=__version__)
74
78
 
@@ -110,6 +114,29 @@ def main(argv: Optional[list] = None):
110
114
  return 1
111
115
 
112
116
 
117
+ def _initialize_project_registry():
118
+ """
119
+ Initialize or update the project registry for the current session.
120
+
121
+ WHY: The project registry tracks all claude-mpm projects and their metadata
122
+ across sessions. This function ensures the current project is properly
123
+ registered and updates session information.
124
+
125
+ DESIGN DECISION: Registry failures are logged but don't prevent startup
126
+ to ensure claude-mpm remains functional even if registry operations fail.
127
+ """
128
+ try:
129
+ from ..services.project_registry import ProjectRegistry
130
+ registry = ProjectRegistry()
131
+ registry.get_or_create_project_entry()
132
+ except Exception as e:
133
+ # Import logger here to avoid circular imports
134
+ from ..core.logger import get_logger
135
+ logger = get_logger("cli")
136
+ logger.debug(f"Failed to initialize project registry: {e}")
137
+ # Continue execution - registry failure shouldn't block startup
138
+
139
+
113
140
  def _ensure_run_attributes(args):
114
141
  """
115
142
  Ensure run command attributes exist when defaulting to run.
@@ -157,6 +184,7 @@ def _execute_command(command: str, args) -> int:
157
184
  CLICommands.UI.value: run_terminal_ui,
158
185
  CLICommands.MEMORY.value: manage_memory,
159
186
  CLICommands.MONITOR.value: manage_monitor,
187
+ CLICommands.MANAGER.value: run_manager,
160
188
  }
161
189
 
162
190
  # Execute command if found
@@ -30,6 +30,7 @@ class ProjectInitializer:
30
30
  - config/
31
31
  - logs/
32
32
  - templates/
33
+ - registry/
33
34
  """
34
35
  try:
35
36
  # Create main user directory
@@ -41,6 +42,7 @@ class ProjectInitializer:
41
42
  self.user_dir / "config",
42
43
  self.user_dir / "logs",
43
44
  self.user_dir / "templates",
45
+ self.user_dir / "registry",
44
46
  ]
45
47
 
46
48
  for directory in directories:
@@ -0,0 +1,602 @@
1
+ """
2
+ Project Registry Service.
3
+
4
+ WHY: This service manages a persistent registry of claude-mpm projects to enable
5
+ project identification, tracking, and metadata management. The registry stores
6
+ comprehensive project information including git status, environment details,
7
+ runtime information, and project characteristics.
8
+
9
+ DESIGN DECISION: Uses YAML for human-readable registry files stored in the user's
10
+ home directory (~/.claude-mpm/registry/). Each project gets a unique UUID-based
11
+ registry file to avoid conflicts and enable easy project identification.
12
+
13
+ The registry captures both static project information (paths, git info) and
14
+ dynamic runtime information (startup times, process IDs, command line args)
15
+ to provide complete project lifecycle tracking.
16
+ """
17
+
18
+ import os
19
+ import sys
20
+ import uuid
21
+ import subprocess
22
+ import platform
23
+ import shutil
24
+ from datetime import datetime, timezone, timedelta
25
+ from pathlib import Path
26
+ from typing import Dict, Any, Optional, List
27
+ import yaml
28
+
29
+ from claude_mpm.core.logger import get_logger
30
+
31
+
32
+ class ProjectRegistryError(Exception):
33
+ """Base exception for project registry operations."""
34
+ pass
35
+
36
+
37
+ class ProjectRegistry:
38
+ """
39
+ Manages the project registry for claude-mpm installations.
40
+
41
+ WHY: The project registry provides persistent project tracking across sessions,
42
+ enabling project identification, metadata collection, and usage analytics.
43
+ This is crucial for multi-project environments where users switch between
44
+ different codebases.
45
+
46
+ DESIGN DECISION: Registry files are stored in ~/.claude-mpm/registry/ with
47
+ UUID-based filenames to ensure uniqueness and avoid conflicts. The registry
48
+ uses YAML for human readability and ease of manual inspection/editing.
49
+ """
50
+
51
+ def __init__(self):
52
+ """
53
+ Initialize the project registry.
54
+
55
+ WHY: Sets up the registry directory and logger. The registry directory
56
+ is created in the user's home directory to persist across project
57
+ directories and system reboots.
58
+ """
59
+ self.logger = get_logger("project_registry")
60
+ self.registry_dir = Path.home() / ".claude-mpm" / "registry"
61
+ self.current_project_path = Path.cwd().resolve()
62
+
63
+ # Ensure registry directory exists
64
+ try:
65
+ self.registry_dir.mkdir(parents=True, exist_ok=True)
66
+ except Exception as e:
67
+ self.logger.error(f"Failed to create registry directory: {e}")
68
+ raise ProjectRegistryError(f"Cannot create registry directory: {e}")
69
+
70
+ def get_or_create_project_entry(self) -> Dict[str, Any]:
71
+ """
72
+ Get existing project registry entry or create a new one.
73
+
74
+ WHY: This is the main entry point for project registration. It handles
75
+ both new project registration and existing project updates, ensuring
76
+ that every claude-mpm session is properly tracked.
77
+
78
+ DESIGN DECISION: Matching is done by normalized absolute path to handle
79
+ symbolic links and different path representations consistently.
80
+
81
+ Returns:
82
+ Dictionary containing the project registry data
83
+
84
+ Raises:
85
+ ProjectRegistryError: If registry operations fail
86
+ """
87
+ try:
88
+ # Look for existing registry entry
89
+ existing_entry = self._find_existing_entry()
90
+
91
+ if existing_entry:
92
+ self.logger.debug(f"Found existing project entry: {existing_entry['project_id']}")
93
+ # Update existing entry with current session info
94
+ return self._update_existing_entry(existing_entry)
95
+ else:
96
+ self.logger.debug("Creating new project registry entry")
97
+ # Create new entry
98
+ return self._create_new_entry()
99
+
100
+ except Exception as e:
101
+ self.logger.error(f"Failed to get or create project entry: {e}")
102
+ raise ProjectRegistryError(f"Registry operation failed: {e}")
103
+
104
+ def _find_existing_entry(self) -> Optional[Dict[str, Any]]:
105
+ """
106
+ Search for existing registry entry matching current project path.
107
+
108
+ WHY: We need to match projects by their absolute path to avoid creating
109
+ duplicate entries when the same project is accessed from different
110
+ working directories or via different path representations.
111
+
112
+ Returns:
113
+ Existing registry data if found, None otherwise
114
+ """
115
+ try:
116
+ # Normalize current path for consistent matching
117
+ current_path_str = str(self.current_project_path)
118
+
119
+ # Search all registry files
120
+ for registry_file in self.registry_dir.glob("*.yaml"):
121
+ try:
122
+ with open(registry_file, 'r', encoding='utf-8') as f:
123
+ data = yaml.safe_load(f) or {}
124
+
125
+ # Check if project_path matches
126
+ if data.get('project_path') == current_path_str:
127
+ data['_registry_file'] = registry_file # Add file reference
128
+ return data
129
+
130
+ except Exception as e:
131
+ self.logger.warning(f"Failed to read registry file {registry_file}: {e}")
132
+ continue
133
+
134
+ return None
135
+
136
+ except Exception as e:
137
+ self.logger.error(f"Error searching for existing entry: {e}")
138
+ return None
139
+
140
+ def _create_new_entry(self) -> Dict[str, Any]:
141
+ """
142
+ Create a new project registry entry.
143
+
144
+ WHY: New projects need to be registered with comprehensive metadata
145
+ including project information, environment details, and initial runtime
146
+ data. This creates a complete snapshot of the project at first access.
147
+
148
+ Returns:
149
+ Newly created registry data
150
+ """
151
+ project_id = str(uuid.uuid4())
152
+ registry_file = self.registry_dir / f"{project_id}.yaml"
153
+
154
+ # Build comprehensive project data
155
+ project_data = {
156
+ 'project_id': project_id,
157
+ 'project_path': str(self.current_project_path),
158
+ 'project_name': self.current_project_path.name,
159
+ 'metadata': self._build_metadata(is_new=True),
160
+ 'runtime': self._build_runtime_info(),
161
+ 'environment': self._build_environment_info(),
162
+ 'git': self._build_git_info(),
163
+ 'session': self._build_session_info(),
164
+ 'project_info': self._build_project_info()
165
+ }
166
+
167
+ # Save to registry file
168
+ self._save_registry_data(registry_file, project_data)
169
+ project_data['_registry_file'] = registry_file
170
+
171
+ self.logger.info(f"Created new project registry entry: {project_id}")
172
+ return project_data
173
+
174
+ def _update_existing_entry(self, existing_data: Dict[str, Any]) -> Dict[str, Any]:
175
+ """
176
+ Update existing project registry entry with current session information.
177
+
178
+ WHY: Existing projects need their metadata updated to reflect current
179
+ access patterns, runtime information, and any changes in project state.
180
+ This maintains accurate usage tracking and project state history.
181
+
182
+ Args:
183
+ existing_data: The existing registry data to update
184
+
185
+ Returns:
186
+ Updated registry data
187
+ """
188
+ registry_file = existing_data.get('_registry_file')
189
+ if not registry_file:
190
+ raise ProjectRegistryError("Registry file reference missing from existing data")
191
+
192
+ # Update timestamps and counters
193
+ metadata = existing_data.get('metadata', {})
194
+ access_count = metadata.get('access_count', 0) + 1
195
+ now = datetime.now(timezone.utc).isoformat()
196
+
197
+ existing_data['metadata'].update({
198
+ 'updated_at': now,
199
+ 'last_accessed': now,
200
+ 'access_count': access_count
201
+ })
202
+
203
+ # Update runtime information
204
+ existing_data['runtime'] = self._build_runtime_info()
205
+
206
+ # Update session information
207
+ existing_data['session'] = self._build_session_info()
208
+
209
+ # Update git information (may have changed)
210
+ existing_data['git'] = self._build_git_info()
211
+
212
+ # Update project info (may have changed)
213
+ existing_data['project_info'] = self._build_project_info()
214
+
215
+ # Save updated data
216
+ self._save_registry_data(registry_file, existing_data)
217
+
218
+ self.logger.debug(f"Updated project registry entry (access #{access_count})")
219
+ return existing_data
220
+
221
+ def _build_metadata(self, is_new: bool = False) -> Dict[str, Any]:
222
+ """
223
+ Build metadata section for registry entry.
224
+
225
+ WHY: Metadata tracks creation, modification, and access patterns for
226
+ analytics and project lifecycle management.
227
+ """
228
+ now = datetime.now(timezone.utc).isoformat()
229
+
230
+ metadata = {
231
+ 'updated_at': now,
232
+ 'last_accessed': now,
233
+ 'access_count': 1
234
+ }
235
+
236
+ if is_new:
237
+ metadata['created_at'] = now
238
+
239
+ return metadata
240
+
241
+ def _build_runtime_info(self) -> Dict[str, Any]:
242
+ """
243
+ Build runtime information section.
244
+
245
+ WHY: Runtime information helps track session lifecycle, process management,
246
+ and system state. This is valuable for debugging session issues and
247
+ understanding usage patterns.
248
+ """
249
+ # Get claude-mpm version
250
+ try:
251
+ from claude_mpm import __version__ as claude_mpm_version
252
+ except ImportError:
253
+ claude_mpm_version = "unknown"
254
+
255
+ return {
256
+ 'startup_time': datetime.now(timezone.utc).isoformat(),
257
+ 'pid': os.getpid(),
258
+ 'python_version': f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
259
+ 'claude_mpm_version': claude_mpm_version,
260
+ 'command_line': ' '.join(sys.argv),
261
+ 'launch_method': 'subprocess' # Default, could be detected based on parent process
262
+ }
263
+
264
+ def _build_environment_info(self) -> Dict[str, Any]:
265
+ """
266
+ Build environment information section.
267
+
268
+ WHY: Environment information helps with debugging, platform-specific
269
+ behavior analysis, and provides context for project usage patterns
270
+ across different systems and user setups.
271
+ """
272
+ return {
273
+ 'user': os.getenv('USER') or os.getenv('USERNAME', 'unknown'),
274
+ 'hostname': platform.node(),
275
+ 'os': platform.system(),
276
+ 'os_version': platform.release(),
277
+ 'shell': os.getenv('SHELL', 'unknown'),
278
+ 'terminal': os.getenv('TERM', 'unknown'),
279
+ 'cwd': str(Path.cwd())
280
+ }
281
+
282
+ def _build_git_info(self) -> Dict[str, Any]:
283
+ """
284
+ Build git repository information.
285
+
286
+ WHY: Git information is crucial for project identification and tracking
287
+ changes across different branches and commits. This helps understand
288
+ project state and enables better project management features.
289
+ """
290
+ git_info = {
291
+ 'is_repo': False,
292
+ 'branch': None,
293
+ 'remote_url': None,
294
+ 'last_commit': None,
295
+ 'has_uncommitted': False
296
+ }
297
+
298
+ try:
299
+ # Check if we're in a git repository
300
+ result = subprocess.run(
301
+ ['git', 'rev-parse', '--git-dir'],
302
+ cwd=self.current_project_path,
303
+ capture_output=True,
304
+ text=True,
305
+ timeout=5
306
+ )
307
+
308
+ if result.returncode == 0:
309
+ git_info['is_repo'] = True
310
+
311
+ # Get current branch
312
+ try:
313
+ result = subprocess.run(
314
+ ['git', 'branch', '--show-current'],
315
+ cwd=self.current_project_path,
316
+ capture_output=True,
317
+ text=True,
318
+ timeout=5
319
+ )
320
+ if result.returncode == 0:
321
+ git_info['branch'] = result.stdout.strip()
322
+ except Exception:
323
+ pass
324
+
325
+ # Get remote URL
326
+ try:
327
+ result = subprocess.run(
328
+ ['git', 'remote', 'get-url', 'origin'],
329
+ cwd=self.current_project_path,
330
+ capture_output=True,
331
+ text=True,
332
+ timeout=5
333
+ )
334
+ if result.returncode == 0:
335
+ git_info['remote_url'] = result.stdout.strip()
336
+ except Exception:
337
+ pass
338
+
339
+ # Get last commit
340
+ try:
341
+ result = subprocess.run(
342
+ ['git', 'rev-parse', 'HEAD'],
343
+ cwd=self.current_project_path,
344
+ capture_output=True,
345
+ text=True,
346
+ timeout=5
347
+ )
348
+ if result.returncode == 0:
349
+ git_info['last_commit'] = result.stdout.strip()
350
+ except Exception:
351
+ pass
352
+
353
+ # Check for uncommitted changes
354
+ try:
355
+ result = subprocess.run(
356
+ ['git', 'status', '--porcelain'],
357
+ cwd=self.current_project_path,
358
+ capture_output=True,
359
+ text=True,
360
+ timeout=5
361
+ )
362
+ if result.returncode == 0:
363
+ git_info['has_uncommitted'] = bool(result.stdout.strip())
364
+ except Exception:
365
+ pass
366
+
367
+ except Exception as e:
368
+ self.logger.debug(f"Failed to get git info: {e}")
369
+
370
+ return git_info
371
+
372
+ def _build_session_info(self) -> Dict[str, Any]:
373
+ """
374
+ Build session information.
375
+
376
+ WHY: Session information tracks the current claude-mpm session state,
377
+ including active components and configuration. This helps with session
378
+ management and debugging.
379
+ """
380
+ # These would be populated by the actual session manager
381
+ # For now, we provide placeholders that can be updated by the caller
382
+ return {
383
+ 'session_id': None, # Could be set by session manager
384
+ 'ticket_count': 0, # Could be updated by ticket manager
385
+ 'agent_count': 0, # Could be updated by agent manager
386
+ 'hooks_enabled': False, # Could be detected from configuration
387
+ 'monitor_enabled': False # Could be detected from process state
388
+ }
389
+
390
+ def _build_project_info(self) -> Dict[str, Any]:
391
+ """
392
+ Build project information section.
393
+
394
+ WHY: Project information helps identify the type of project and its
395
+ characteristics, enabling better tool selection and project-specific
396
+ optimizations.
397
+ """
398
+ project_info = {
399
+ 'has_claude_config': False,
400
+ 'has_claude_md': False,
401
+ 'has_pyproject': False,
402
+ 'has_package_json': False,
403
+ 'project_type': 'unknown'
404
+ }
405
+
406
+ # Check for various project files
407
+ claude_files = ['.claude', 'claude.toml', '.claude.toml']
408
+ for claude_file in claude_files:
409
+ if (self.current_project_path / claude_file).exists():
410
+ project_info['has_claude_config'] = True
411
+ break
412
+
413
+ claude_md_files = ['CLAUDE.md', 'claude.md', '.claude.md']
414
+ for claude_md in claude_md_files:
415
+ if (self.current_project_path / claude_md).exists():
416
+ project_info['has_claude_md'] = True
417
+ break
418
+
419
+ if (self.current_project_path / 'pyproject.toml').exists():
420
+ project_info['has_pyproject'] = True
421
+
422
+ if (self.current_project_path / 'package.json').exists():
423
+ project_info['has_package_json'] = True
424
+
425
+ # Determine project type
426
+ if project_info['has_pyproject'] or (self.current_project_path / 'setup.py').exists():
427
+ project_info['project_type'] = 'python'
428
+ elif project_info['has_package_json']:
429
+ project_info['project_type'] = 'javascript'
430
+ elif (self.current_project_path / 'Cargo.toml').exists():
431
+ project_info['project_type'] = 'rust'
432
+ elif (self.current_project_path / 'go.mod').exists():
433
+ project_info['project_type'] = 'go'
434
+ elif (self.current_project_path / 'pom.xml').exists():
435
+ project_info['project_type'] = 'java'
436
+ elif any((self.current_project_path / ext).exists() for ext in ['*.c', '*.cpp', '*.h', '*.hpp']):
437
+ project_info['project_type'] = 'c/cpp'
438
+ elif project_info['has_claude_config'] or project_info['has_claude_md']:
439
+ project_info['project_type'] = 'claude'
440
+ else:
441
+ # Try to detect by file extensions
442
+ common_files = list(self.current_project_path.iterdir())[:20] # Check first 20 files
443
+ extensions = {f.suffix.lower() for f in common_files if f.is_file()}
444
+
445
+ if '.py' in extensions:
446
+ project_info['project_type'] = 'python'
447
+ elif any(ext in extensions for ext in ['.js', '.ts', '.jsx', '.tsx']):
448
+ project_info['project_type'] = 'javascript'
449
+ elif any(ext in extensions for ext in ['.rs']):
450
+ project_info['project_type'] = 'rust'
451
+ elif any(ext in extensions for ext in ['.go']):
452
+ project_info['project_type'] = 'go'
453
+ elif any(ext in extensions for ext in ['.java', '.scala', '.kt']):
454
+ project_info['project_type'] = 'jvm'
455
+ elif any(ext in extensions for ext in ['.c', '.cpp', '.cc', '.h', '.hpp']):
456
+ project_info['project_type'] = 'c/cpp'
457
+ elif any(ext in extensions for ext in ['.md', '.txt', '.rst']):
458
+ project_info['project_type'] = 'documentation'
459
+
460
+ return project_info
461
+
462
+ def _save_registry_data(self, registry_file: Path, data: Dict[str, Any]) -> None:
463
+ """
464
+ Save registry data to YAML file.
465
+
466
+ WHY: Centralized saving logic ensures consistent formatting and error
467
+ handling across all registry operations. YAML format provides human
468
+ readability for debugging and manual inspection.
469
+
470
+ Args:
471
+ registry_file: Path to the registry file
472
+ data: Registry data to save
473
+ """
474
+ try:
475
+ # Remove internal fields before saving
476
+ save_data = {k: v for k, v in data.items() if not k.startswith('_')}
477
+
478
+ with open(registry_file, 'w', encoding='utf-8') as f:
479
+ yaml.dump(save_data, f, default_flow_style=False, sort_keys=False, indent=2)
480
+
481
+ self.logger.debug(f"Saved registry data to {registry_file}")
482
+
483
+ except Exception as e:
484
+ self.logger.error(f"Failed to save registry data: {e}")
485
+ raise ProjectRegistryError(f"Failed to save registry: {e}")
486
+
487
+ def list_projects(self) -> List[Dict[str, Any]]:
488
+ """
489
+ List all registered projects.
490
+
491
+ WHY: Provides visibility into all projects managed by claude-mpm,
492
+ useful for project management and analytics.
493
+
494
+ Returns:
495
+ List of project registry data dictionaries
496
+ """
497
+ projects = []
498
+
499
+ try:
500
+ for registry_file in self.registry_dir.glob("*.yaml"):
501
+ try:
502
+ with open(registry_file, 'r', encoding='utf-8') as f:
503
+ data = yaml.safe_load(f) or {}
504
+ projects.append(data)
505
+ except Exception as e:
506
+ self.logger.warning(f"Failed to read registry file {registry_file}: {e}")
507
+ continue
508
+
509
+ except Exception as e:
510
+ self.logger.error(f"Failed to list projects: {e}")
511
+
512
+ return projects
513
+
514
+ def cleanup_old_entries(self, max_age_days: int = 90) -> int:
515
+ """
516
+ Clean up old registry entries that haven't been accessed recently.
517
+
518
+ WHY: Prevents registry directory from growing indefinitely with old
519
+ project entries. Keeps the registry focused on active projects.
520
+
521
+ Args:
522
+ max_age_days: Maximum age in days for keeping entries
523
+
524
+ Returns:
525
+ Number of entries cleaned up
526
+ """
527
+ if max_age_days <= 0:
528
+ return 0
529
+
530
+ cleaned_count = 0
531
+ cutoff_date = datetime.now(timezone.utc) - timedelta(days=max_age_days)
532
+
533
+ try:
534
+ for registry_file in self.registry_dir.glob("*.yaml"):
535
+ try:
536
+ with open(registry_file, 'r', encoding='utf-8') as f:
537
+ data = yaml.safe_load(f) or {}
538
+
539
+ # Check last accessed time
540
+ last_accessed_str = data.get('metadata', {}).get('last_accessed')
541
+ if last_accessed_str:
542
+ last_accessed = datetime.fromisoformat(last_accessed_str.replace('Z', '+00:00'))
543
+ if last_accessed < cutoff_date:
544
+ registry_file.unlink()
545
+ cleaned_count += 1
546
+ self.logger.debug(f"Cleaned up old registry entry: {registry_file}")
547
+
548
+ except Exception as e:
549
+ self.logger.warning(f"Failed to process registry file {registry_file}: {e}")
550
+ continue
551
+
552
+ except Exception as e:
553
+ self.logger.error(f"Failed to cleanup old entries: {e}")
554
+
555
+ if cleaned_count > 0:
556
+ self.logger.info(f"Cleaned up {cleaned_count} old registry entries")
557
+
558
+ return cleaned_count
559
+
560
+ def update_session_info(self, session_updates: Dict[str, Any]) -> bool:
561
+ """
562
+ Update session information for the current project.
563
+
564
+ WHY: Allows other components (session manager, ticket manager, etc.)
565
+ to update the registry with current session state information.
566
+
567
+ Args:
568
+ session_updates: Dictionary of session updates to apply
569
+
570
+ Returns:
571
+ True if update was successful, False otherwise
572
+ """
573
+ try:
574
+ existing_entry = self._find_existing_entry()
575
+ if not existing_entry:
576
+ self.logger.warning("No existing registry entry found for session update")
577
+ return False
578
+
579
+ registry_file = existing_entry.get('_registry_file')
580
+ if not registry_file:
581
+ self.logger.error("Registry file reference missing")
582
+ return False
583
+
584
+ # Update session information
585
+ if 'session' not in existing_entry:
586
+ existing_entry['session'] = {}
587
+
588
+ existing_entry['session'].update(session_updates)
589
+
590
+ # Update metadata timestamp
591
+ now = datetime.now(timezone.utc).isoformat()
592
+ existing_entry['metadata']['updated_at'] = now
593
+
594
+ # Save updated data
595
+ self._save_registry_data(registry_file, existing_entry)
596
+
597
+ self.logger.debug(f"Updated session info: {session_updates}")
598
+ return True
599
+
600
+ except Exception as e:
601
+ self.logger.error(f"Failed to update session info: {e}")
602
+ return False