claude-mpm 3.9.11__py3-none-any.whl → 4.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +79 -51
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +20 -20
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +140 -905
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +330 -86
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +363 -220
- claude_mpm/cli/parser.py +24 -1156
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +124 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +71 -73
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +35 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/built/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/built/dashboard.js +2 -0
- claude_mpm/dashboard/static/built/socket-client.js +2 -0
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +93 -72
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +110 -96
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +133 -53
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +233 -199
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +30 -13
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
- claude_mpm/services/mcp_gateway/main.py +287 -137
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +575 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +166 -64
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +185 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +19 -533
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +2 -2
- claude_mpm/storage/state_storage.py +177 -181
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/METADATA +90 -22
- claude_mpm-4.0.4.dist-info/RECORD +417 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/cli/commands/run_guarded.py +0 -511
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/config/memory_guardian_yaml.py +0 -335
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/core/memory_aware_runner.py +0 -353
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
- claude_mpm/services/infrastructure/health_monitor.py +0 -775
- claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
- claude_mpm/services/infrastructure/memory_guardian.py +0 -944
- claude_mpm/services/infrastructure/restart_protection.py +0 -642
- claude_mpm/services/infrastructure/state_manager.py +0 -774
- claude_mpm/services/mcp_gateway/manager.py +0 -334
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.11.dist-info/RECORD +0 -306
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/top_level.txt +0 -0
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            from pathlib import Path
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            """
         | 
| 2 4 | 
             
            Enhanced version parsing system with multiple source support and fallback mechanisms.
         | 
| 3 5 |  | 
| @@ -14,26 +16,26 @@ The system includes caching for performance and validation for data integrity. | |
| 14 16 | 
             
            """
         | 
| 15 17 |  | 
| 16 18 | 
             
            import json
         | 
| 19 | 
            +
            import logging
         | 
| 17 20 | 
             
            import re
         | 
| 18 21 | 
             
            import subprocess
         | 
| 19 22 | 
             
            from datetime import datetime, timedelta
         | 
| 20 | 
            -
            from pathlib import Path
         | 
| 21 | 
            -
            from typing import Dict, List, Optional, Tuple, Union
         | 
| 22 23 | 
             
            from functools import lru_cache
         | 
| 23 | 
            -
            import  | 
| 24 | 
            +
            from typing import Dict, List, Optional, Tuple, Union
         | 
| 24 25 |  | 
| 25 26 | 
             
            from claude_mpm.services.version_control.semantic_versioning import SemanticVersion
         | 
| 26 27 |  | 
| 27 28 |  | 
| 28 29 | 
             
            class VersionSource:
         | 
| 29 30 | 
             
                """Enumeration of version sources with priority ordering."""
         | 
| 31 | 
            +
             | 
| 30 32 | 
             
                GIT_TAGS = "git_tags"
         | 
| 31 33 | 
             
                CHANGELOG = "changelog"
         | 
| 32 34 | 
             
                VERSION_FILE = "version_file"
         | 
| 33 35 | 
             
                PACKAGE_JSON = "package_json"
         | 
| 34 36 | 
             
                PYPROJECT_TOML = "pyproject_toml"
         | 
| 35 37 | 
             
                SETUP_PY = "setup_py"
         | 
| 36 | 
            -
             | 
| 38 | 
            +
             | 
| 37 39 | 
             
                # Priority order for fallback mechanism
         | 
| 38 40 | 
             
                PRIORITY_ORDER = [
         | 
| 39 41 | 
             
                    GIT_TAGS,
         | 
| @@ -41,13 +43,13 @@ class VersionSource: | |
| 41 43 | 
             
                    VERSION_FILE,
         | 
| 42 44 | 
             
                    PACKAGE_JSON,
         | 
| 43 45 | 
             
                    PYPROJECT_TOML,
         | 
| 44 | 
            -
                    SETUP_PY
         | 
| 46 | 
            +
                    SETUP_PY,
         | 
| 45 47 | 
             
                ]
         | 
| 46 48 |  | 
| 47 49 |  | 
| 48 50 | 
             
            class VersionMetadata:
         | 
| 49 51 | 
             
                """Extended metadata for version information."""
         | 
| 50 | 
            -
             | 
| 52 | 
            +
             | 
| 51 53 | 
             
                def __init__(
         | 
| 52 54 | 
             
                    self,
         | 
| 53 55 | 
             
                    version: str,
         | 
| @@ -56,7 +58,7 @@ class VersionMetadata: | |
| 56 58 | 
             
                    commit_hash: Optional[str] = None,
         | 
| 57 59 | 
             
                    author: Optional[str] = None,
         | 
| 58 60 | 
             
                    message: Optional[str] = None,
         | 
| 59 | 
            -
                    changes: Optional[List[str]] = None
         | 
| 61 | 
            +
                    changes: Optional[List[str]] = None,
         | 
| 60 62 | 
             
                ):
         | 
| 61 63 | 
             
                    self.version = version
         | 
| 62 64 | 
             
                    self.source = source
         | 
| @@ -65,24 +67,26 @@ class VersionMetadata: | |
| 65 67 | 
             
                    self.author = author
         | 
| 66 68 | 
             
                    self.message = message
         | 
| 67 69 | 
             
                    self.changes = changes or []
         | 
| 68 | 
            -
             | 
| 70 | 
            +
             | 
| 69 71 | 
             
                def to_dict(self) -> Dict:
         | 
| 70 72 | 
             
                    """Convert metadata to dictionary format."""
         | 
| 71 73 | 
             
                    return {
         | 
| 72 74 | 
             
                        "version": self.version,
         | 
| 73 75 | 
             
                        "source": self.source,
         | 
| 74 | 
            -
                        "release_date": self.release_date.isoformat() | 
| 76 | 
            +
                        "release_date": self.release_date.isoformat()
         | 
| 77 | 
            +
                        if self.release_date
         | 
| 78 | 
            +
                        else None,
         | 
| 75 79 | 
             
                        "commit_hash": self.commit_hash,
         | 
| 76 80 | 
             
                        "author": self.author,
         | 
| 77 81 | 
             
                        "message": self.message,
         | 
| 78 | 
            -
                        "changes": self.changes
         | 
| 82 | 
            +
                        "changes": self.changes,
         | 
| 79 83 | 
             
                    }
         | 
| 80 84 |  | 
| 81 85 |  | 
| 82 86 | 
             
            class EnhancedVersionParser:
         | 
| 83 87 | 
             
                """
         | 
| 84 88 | 
             
                Enhanced version parser with multiple source support and intelligent fallback.
         | 
| 85 | 
            -
             | 
| 89 | 
            +
             | 
| 86 90 | 
             
                This parser provides:
         | 
| 87 91 | 
             
                - Multiple version source support
         | 
| 88 92 | 
             
                - Intelligent fallback mechanisms
         | 
| @@ -90,11 +94,11 @@ class EnhancedVersionParser: | |
| 90 94 | 
             
                - Validation and error handling
         | 
| 91 95 | 
             
                - Comprehensive version history retrieval
         | 
| 92 96 | 
             
                """
         | 
| 93 | 
            -
             | 
| 97 | 
            +
             | 
| 94 98 | 
             
                def __init__(self, project_root: Optional[Path] = None, cache_ttl: int = 300):
         | 
| 95 99 | 
             
                    """
         | 
| 96 100 | 
             
                    Initialize the enhanced version parser.
         | 
| 97 | 
            -
             | 
| 101 | 
            +
             | 
| 98 102 | 
             
                    Args:
         | 
| 99 103 | 
             
                        project_root: Root directory of the project (defaults to current directory)
         | 
| 100 104 | 
             
                        cache_ttl: Cache time-to-live in seconds (default: 5 minutes)
         | 
| @@ -103,11 +107,15 @@ class EnhancedVersionParser: | |
| 103 107 | 
             
                    self.cache_ttl = cache_ttl
         | 
| 104 108 | 
             
                    self.logger = logging.getLogger(__name__)
         | 
| 105 109 | 
             
                    self._cache: Dict[str, Tuple[datetime, any]] = {}
         | 
| 106 | 
            -
             | 
| 110 | 
            +
             | 
| 107 111 | 
             
                    # Compile regex patterns once for efficiency
         | 
| 108 | 
            -
                    self._version_pattern = re.compile( | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 112 | 
            +
                    self._version_pattern = re.compile(
         | 
| 113 | 
            +
                        r"(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9\-\.]+))?(?:\+([a-zA-Z0-9\-\.]+))?"
         | 
| 114 | 
            +
                    )
         | 
| 115 | 
            +
                    self._changelog_version_pattern = re.compile(
         | 
| 116 | 
            +
                        r"##\s*\[?([0-9]+\.[0-9]+\.[0-9]+[^\]]*)\]?\s*[-–]\s*(\d{4}-\d{2}-\d{2})?"
         | 
| 117 | 
            +
                    )
         | 
| 118 | 
            +
             | 
| 111 119 | 
             
                def _get_cached(self, key: str) -> Optional[any]:
         | 
| 112 120 | 
             
                    """Get cached value if still valid."""
         | 
| 113 121 | 
             
                    if key in self._cache:
         | 
| @@ -116,19 +124,21 @@ class EnhancedVersionParser: | |
| 116 124 | 
             
                            return value
         | 
| 117 125 | 
             
                        del self._cache[key]
         | 
| 118 126 | 
             
                    return None
         | 
| 119 | 
            -
             | 
| 127 | 
            +
             | 
| 120 128 | 
             
                def _set_cached(self, key: str, value: any) -> any:
         | 
| 121 129 | 
             
                    """Set cached value with timestamp."""
         | 
| 122 130 | 
             
                    self._cache[key] = (datetime.now(), value)
         | 
| 123 131 | 
             
                    return value
         | 
| 124 | 
            -
             | 
| 125 | 
            -
                def get_current_version( | 
| 132 | 
            +
             | 
| 133 | 
            +
                def get_current_version(
         | 
| 134 | 
            +
                    self, prefer_source: Optional[str] = None
         | 
| 135 | 
            +
                ) -> Optional[VersionMetadata]:
         | 
| 126 136 | 
             
                    """
         | 
| 127 137 | 
             
                    Get the current version from the most reliable available source.
         | 
| 128 | 
            -
             | 
| 138 | 
            +
             | 
| 129 139 | 
             
                    Args:
         | 
| 130 140 | 
             
                        prefer_source: Preferred source to check first (optional)
         | 
| 131 | 
            -
             | 
| 141 | 
            +
             | 
| 132 142 | 
             
                    Returns:
         | 
| 133 143 | 
             
                        VersionMetadata with current version information, or None if not found
         | 
| 134 144 | 
             
                    """
         | 
| @@ -136,12 +146,12 @@ class EnhancedVersionParser: | |
| 136 146 | 
             
                    cached = self._get_cached(cache_key)
         | 
| 137 147 | 
             
                    if cached:
         | 
| 138 148 | 
             
                        return cached
         | 
| 139 | 
            -
             | 
| 149 | 
            +
             | 
| 140 150 | 
             
                    sources = VersionSource.PRIORITY_ORDER.copy()
         | 
| 141 151 | 
             
                    if prefer_source and prefer_source in sources:
         | 
| 142 152 | 
             
                        sources.remove(prefer_source)
         | 
| 143 153 | 
             
                        sources.insert(0, prefer_source)
         | 
| 144 | 
            -
             | 
| 154 | 
            +
             | 
| 145 155 | 
             
                    for source in sources:
         | 
| 146 156 | 
             
                        try:
         | 
| 147 157 | 
             
                            version = self._get_version_from_source(source, latest_only=True)
         | 
| @@ -149,21 +159,19 @@ class EnhancedVersionParser: | |
| 149 159 | 
             
                                return self._set_cached(cache_key, version)
         | 
| 150 160 | 
             
                        except Exception as e:
         | 
| 151 161 | 
             
                            self.logger.debug(f"Failed to get version from {source}: {e}")
         | 
| 152 | 
            -
             | 
| 162 | 
            +
             | 
| 153 163 | 
             
                    return None
         | 
| 154 | 
            -
             | 
| 164 | 
            +
             | 
| 155 165 | 
             
                def get_version_history(
         | 
| 156 | 
            -
                    self,
         | 
| 157 | 
            -
                    include_prereleases: bool = False,
         | 
| 158 | 
            -
                    limit: Optional[int] = None
         | 
| 166 | 
            +
                    self, include_prereleases: bool = False, limit: Optional[int] = None
         | 
| 159 167 | 
             
                ) -> List[VersionMetadata]:
         | 
| 160 168 | 
             
                    """
         | 
| 161 169 | 
             
                    Get complete version history from all available sources.
         | 
| 162 | 
            -
             | 
| 170 | 
            +
             | 
| 163 171 | 
             
                    Args:
         | 
| 164 172 | 
             
                        include_prereleases: Include pre-release versions (alpha, beta, rc)
         | 
| 165 173 | 
             
                        limit: Maximum number of versions to return
         | 
| 166 | 
            -
             | 
| 174 | 
            +
             | 
| 167 175 | 
             
                    Returns:
         | 
| 168 176 | 
             
                        List of VersionMetadata objects sorted by version (descending)
         | 
| 169 177 | 
             
                    """
         | 
| @@ -171,9 +179,9 @@ class EnhancedVersionParser: | |
| 171 179 | 
             
                    cached = self._get_cached(cache_key)
         | 
| 172 180 | 
             
                    if cached:
         | 
| 173 181 | 
             
                        return cached
         | 
| 174 | 
            -
             | 
| 182 | 
            +
             | 
| 175 183 | 
             
                    all_versions: Dict[str, VersionMetadata] = {}
         | 
| 176 | 
            -
             | 
| 184 | 
            +
             | 
| 177 185 | 
             
                    # Try each source and merge results
         | 
| 178 186 | 
             
                    for source in VersionSource.PRIORITY_ORDER:
         | 
| 179 187 | 
             
                        try:
         | 
| @@ -184,25 +192,23 @@ class EnhancedVersionParser: | |
| 184 192 | 
             
                                    all_versions[version.version] = version
         | 
| 185 193 | 
             
                        except Exception as e:
         | 
| 186 194 | 
             
                            self.logger.debug(f"Failed to get versions from {source}: {e}")
         | 
| 187 | 
            -
             | 
| 195 | 
            +
             | 
| 188 196 | 
             
                    # Filter and sort versions
         | 
| 189 197 | 
             
                    result = list(all_versions.values())
         | 
| 190 | 
            -
             | 
| 198 | 
            +
             | 
| 191 199 | 
             
                    if not include_prereleases:
         | 
| 192 200 | 
             
                        result = [v for v in result if not self._is_prerelease(v.version)]
         | 
| 193 | 
            -
             | 
| 201 | 
            +
             | 
| 194 202 | 
             
                    # Sort by semantic version
         | 
| 195 203 | 
             
                    result.sort(key=lambda v: self._parse_semver(v.version), reverse=True)
         | 
| 196 | 
            -
             | 
| 204 | 
            +
             | 
| 197 205 | 
             
                    if limit:
         | 
| 198 206 | 
             
                        result = result[:limit]
         | 
| 199 | 
            -
             | 
| 207 | 
            +
             | 
| 200 208 | 
             
                    return self._set_cached(cache_key, result)
         | 
| 201 | 
            -
             | 
| 209 | 
            +
             | 
| 202 210 | 
             
                def _get_version_from_source(
         | 
| 203 | 
            -
                    self,
         | 
| 204 | 
            -
                    source: str,
         | 
| 205 | 
            -
                    latest_only: bool = False
         | 
| 211 | 
            +
                    self, source: str, latest_only: bool = False
         | 
| 206 212 | 
             
                ) -> Optional[VersionMetadata]:
         | 
| 207 213 | 
             
                    """Get version(s) from a specific source."""
         | 
| 208 214 | 
             
                    if source == VersionSource.GIT_TAGS:
         | 
| @@ -217,20 +223,26 @@ class EnhancedVersionParser: | |
| 217 223 | 
             
                        versions = self._get_versions_from_changelog()
         | 
| 218 224 | 
             
                        return versions[0] if versions else None
         | 
| 219 225 | 
             
                    return None
         | 
| 220 | 
            -
             | 
| 226 | 
            +
             | 
| 221 227 | 
             
                def _get_versions_from_source(self, source: str) -> List[VersionMetadata]:
         | 
| 222 228 | 
             
                    """Get all versions from a specific source."""
         | 
| 223 229 | 
             
                    if source == VersionSource.GIT_TAGS:
         | 
| 224 230 | 
             
                        return self._get_all_versions_from_git()
         | 
| 225 231 | 
             
                    elif source == VersionSource.CHANGELOG:
         | 
| 226 232 | 
             
                        return self._get_versions_from_changelog()
         | 
| 227 | 
            -
                    elif source in [ | 
| 233 | 
            +
                    elif source in [
         | 
| 234 | 
            +
                        VersionSource.VERSION_FILE,
         | 
| 235 | 
            +
                        VersionSource.PACKAGE_JSON,
         | 
| 236 | 
            +
                        VersionSource.PYPROJECT_TOML,
         | 
| 237 | 
            +
                    ]:
         | 
| 228 238 | 
             
                        # These sources only provide current version
         | 
| 229 239 | 
             
                        version = self._get_version_from_source(source, latest_only=True)
         | 
| 230 240 | 
             
                        return [version] if version else []
         | 
| 231 241 | 
             
                    return []
         | 
| 232 | 
            -
             | 
| 233 | 
            -
                def _get_version_from_git( | 
| 242 | 
            +
             | 
| 243 | 
            +
                def _get_version_from_git(
         | 
| 244 | 
            +
                    self, latest_only: bool = True
         | 
| 245 | 
            +
                ) -> Optional[VersionMetadata]:
         | 
| 234 246 | 
             
                    """Get version information from git tags."""
         | 
| 235 247 | 
             
                    try:
         | 
| 236 248 | 
             
                        if latest_only:
         | 
| @@ -240,70 +252,77 @@ class EnhancedVersionParser: | |
| 240 252 | 
             
                                capture_output=True,
         | 
| 241 253 | 
             
                                text=True,
         | 
| 242 254 | 
             
                                cwd=self.project_root,
         | 
| 243 | 
            -
                                check=False
         | 
| 255 | 
            +
                                check=False,
         | 
| 244 256 | 
             
                            )
         | 
| 245 257 | 
             
                            if result.returncode == 0:
         | 
| 246 258 | 
             
                                tag = result.stdout.strip()
         | 
| 247 259 | 
             
                                return self._parse_git_tag(tag)
         | 
| 248 260 | 
             
                        else:
         | 
| 249 | 
            -
                            return  | 
| 261 | 
            +
                            return (
         | 
| 262 | 
            +
                                self._get_all_versions_from_git()[0]
         | 
| 263 | 
            +
                                if self._get_all_versions_from_git()
         | 
| 264 | 
            +
                                else None
         | 
| 265 | 
            +
                            )
         | 
| 250 266 | 
             
                    except Exception as e:
         | 
| 251 267 | 
             
                        self.logger.debug(f"Failed to get git version: {e}")
         | 
| 252 268 | 
             
                    return None
         | 
| 253 | 
            -
             | 
| 269 | 
            +
             | 
| 254 270 | 
             
                def _get_all_versions_from_git(self) -> List[VersionMetadata]:
         | 
| 255 271 | 
             
                    """Get all versions from git tags with metadata."""
         | 
| 256 272 | 
             
                    versions = []
         | 
| 257 273 | 
             
                    try:
         | 
| 258 274 | 
             
                        # Get all tags with dates and messages
         | 
| 259 275 | 
             
                        result = subprocess.run(
         | 
| 260 | 
            -
                            [ | 
| 276 | 
            +
                            [
         | 
| 277 | 
            +
                                "git",
         | 
| 278 | 
            +
                                "for-each-ref",
         | 
| 279 | 
            +
                                "--sort=-version:refname",
         | 
| 280 | 
            +
                                "--format=%(refname:short)|%(creatordate:iso)|%(subject)",
         | 
| 281 | 
            +
                                "refs/tags",
         | 
| 282 | 
            +
                            ],
         | 
| 261 283 | 
             
                            capture_output=True,
         | 
| 262 284 | 
             
                            text=True,
         | 
| 263 285 | 
             
                            cwd=self.project_root,
         | 
| 264 | 
            -
                            check=False
         | 
| 286 | 
            +
                            check=False,
         | 
| 265 287 | 
             
                        )
         | 
| 266 | 
            -
             | 
| 288 | 
            +
             | 
| 267 289 | 
             
                        if result.returncode == 0:
         | 
| 268 | 
            -
                            for line in result.stdout.strip().split( | 
| 290 | 
            +
                            for line in result.stdout.strip().split("\n"):
         | 
| 269 291 | 
             
                                if line:
         | 
| 270 | 
            -
                                    parts = line.split( | 
| 292 | 
            +
                                    parts = line.split("|", 2)
         | 
| 271 293 | 
             
                                    if len(parts) >= 1:
         | 
| 272 294 | 
             
                                        tag = parts[0]
         | 
| 273 295 | 
             
                                        date_str = parts[1] if len(parts) > 1 else None
         | 
| 274 296 | 
             
                                        message = parts[2] if len(parts) > 2 else None
         | 
| 275 | 
            -
             | 
| 297 | 
            +
             | 
| 276 298 | 
             
                                        # Parse the tag
         | 
| 277 299 | 
             
                                        metadata = self._parse_git_tag(tag, date_str, message)
         | 
| 278 300 | 
             
                                        if metadata:
         | 
| 279 301 | 
             
                                            versions.append(metadata)
         | 
| 280 302 | 
             
                    except Exception as e:
         | 
| 281 303 | 
             
                        self.logger.debug(f"Failed to get git versions: {e}")
         | 
| 282 | 
            -
             | 
| 304 | 
            +
             | 
| 283 305 | 
             
                    return versions
         | 
| 284 | 
            -
             | 
| 306 | 
            +
             | 
| 285 307 | 
             
                def _parse_git_tag(
         | 
| 286 | 
            -
                    self,
         | 
| 287 | 
            -
                    tag: str,
         | 
| 288 | 
            -
                    date_str: Optional[str] = None,
         | 
| 289 | 
            -
                    message: Optional[str] = None
         | 
| 308 | 
            +
                    self, tag: str, date_str: Optional[str] = None, message: Optional[str] = None
         | 
| 290 309 | 
             
                ) -> Optional[VersionMetadata]:
         | 
| 291 310 | 
             
                    """Parse a git tag into VersionMetadata."""
         | 
| 292 311 | 
             
                    # Remove 'v' prefix if present
         | 
| 293 | 
            -
                    version = tag[1:] if tag.startswith( | 
| 294 | 
            -
             | 
| 312 | 
            +
                    version = tag[1:] if tag.startswith("v") else tag
         | 
| 313 | 
            +
             | 
| 295 314 | 
             
                    # Validate version format
         | 
| 296 315 | 
             
                    if not self._version_pattern.match(version):
         | 
| 297 316 | 
             
                        return None
         | 
| 298 | 
            -
             | 
| 317 | 
            +
             | 
| 299 318 | 
             
                    # Parse date if provided
         | 
| 300 319 | 
             
                    release_date = None
         | 
| 301 320 | 
             
                    if date_str:
         | 
| 302 321 | 
             
                        try:
         | 
| 303 | 
            -
                            release_date = datetime.fromisoformat(date_str.replace( | 
| 322 | 
            +
                            release_date = datetime.fromisoformat(date_str.replace(" ", "T"))
         | 
| 304 323 | 
             
                        except:
         | 
| 305 324 | 
             
                            pass
         | 
| 306 | 
            -
             | 
| 325 | 
            +
             | 
| 307 326 | 
             
                    # Get commit hash for this tag
         | 
| 308 327 | 
             
                    commit_hash = None
         | 
| 309 328 | 
             
                    try:
         | 
| @@ -312,21 +331,21 @@ class EnhancedVersionParser: | |
| 312 331 | 
             
                            capture_output=True,
         | 
| 313 332 | 
             
                            text=True,
         | 
| 314 333 | 
             
                            cwd=self.project_root,
         | 
| 315 | 
            -
                            check=False
         | 
| 334 | 
            +
                            check=False,
         | 
| 316 335 | 
             
                        )
         | 
| 317 336 | 
             
                        if result.returncode == 0:
         | 
| 318 337 | 
             
                            commit_hash = result.stdout.strip()[:7]
         | 
| 319 338 | 
             
                    except:
         | 
| 320 339 | 
             
                        pass
         | 
| 321 | 
            -
             | 
| 340 | 
            +
             | 
| 322 341 | 
             
                    return VersionMetadata(
         | 
| 323 342 | 
             
                        version=version,
         | 
| 324 343 | 
             
                        source=VersionSource.GIT_TAGS,
         | 
| 325 344 | 
             
                        release_date=release_date,
         | 
| 326 345 | 
             
                        commit_hash=commit_hash,
         | 
| 327 | 
            -
                        message=message
         | 
| 346 | 
            +
                        message=message,
         | 
| 328 347 | 
             
                    )
         | 
| 329 | 
            -
             | 
| 348 | 
            +
             | 
| 330 349 | 
             
                def _get_version_from_file(self) -> Optional[VersionMetadata]:
         | 
| 331 350 | 
             
                    """Get version from VERSION file."""
         | 
| 332 351 | 
             
                    version_file = self.project_root / "VERSION"
         | 
| @@ -335,13 +354,12 @@ class EnhancedVersionParser: | |
| 335 354 | 
             
                            version = version_file.read_text().strip()
         | 
| 336 355 | 
             
                            if self._version_pattern.match(version):
         | 
| 337 356 | 
             
                                return VersionMetadata(
         | 
| 338 | 
            -
                                    version=version,
         | 
| 339 | 
            -
                                    source=VersionSource.VERSION_FILE
         | 
| 357 | 
            +
                                    version=version, source=VersionSource.VERSION_FILE
         | 
| 340 358 | 
             
                                )
         | 
| 341 359 | 
             
                        except Exception as e:
         | 
| 342 360 | 
             
                            self.logger.debug(f"Failed to read VERSION file: {e}")
         | 
| 343 361 | 
             
                    return None
         | 
| 344 | 
            -
             | 
| 362 | 
            +
             | 
| 345 363 | 
             
                def _get_version_from_package_json(self) -> Optional[VersionMetadata]:
         | 
| 346 364 | 
             
                    """Get version from package.json."""
         | 
| 347 365 | 
             
                    package_file = self.project_root / "package.json"
         | 
| @@ -352,13 +370,12 @@ class EnhancedVersionParser: | |
| 352 370 | 
             
                                version = data.get("version")
         | 
| 353 371 | 
             
                                if version and self._version_pattern.match(version):
         | 
| 354 372 | 
             
                                    return VersionMetadata(
         | 
| 355 | 
            -
                                        version=version,
         | 
| 356 | 
            -
                                        source=VersionSource.PACKAGE_JSON
         | 
| 373 | 
            +
                                        version=version, source=VersionSource.PACKAGE_JSON
         | 
| 357 374 | 
             
                                    )
         | 
| 358 375 | 
             
                        except Exception as e:
         | 
| 359 376 | 
             
                            self.logger.debug(f"Failed to read package.json: {e}")
         | 
| 360 377 | 
             
                    return None
         | 
| 361 | 
            -
             | 
| 378 | 
            +
             | 
| 362 379 | 
             
                def _get_version_from_pyproject(self) -> Optional[VersionMetadata]:
         | 
| 363 380 | 
             
                    """Get version from pyproject.toml."""
         | 
| 364 381 | 
             
                    pyproject_file = self.project_root / "pyproject.toml"
         | 
| @@ -368,41 +385,40 @@ class EnhancedVersionParser: | |
| 368 385 | 
             
                            # Look for version in [tool.poetry] or [project] sections
         | 
| 369 386 | 
             
                            patterns = [
         | 
| 370 387 | 
             
                                r'version\s*=\s*["\']([^"\']+)["\']',
         | 
| 371 | 
            -
                                r | 
| 388 | 
            +
                                r"version\s*=\s*\{[^}]*\}",  # Dynamic version
         | 
| 372 389 | 
             
                            ]
         | 
| 373 | 
            -
             | 
| 390 | 
            +
             | 
| 374 391 | 
             
                            for pattern in patterns:
         | 
| 375 392 | 
             
                                match = re.search(pattern, content)
         | 
| 376 393 | 
             
                                if match:
         | 
| 377 394 | 
             
                                    version = match.group(1) if match.lastindex else None
         | 
| 378 395 | 
             
                                    if version and self._version_pattern.match(version):
         | 
| 379 396 | 
             
                                        return VersionMetadata(
         | 
| 380 | 
            -
                                            version=version,
         | 
| 381 | 
            -
                                            source=VersionSource.PYPROJECT_TOML
         | 
| 397 | 
            +
                                            version=version, source=VersionSource.PYPROJECT_TOML
         | 
| 382 398 | 
             
                                        )
         | 
| 383 399 | 
             
                        except Exception as e:
         | 
| 384 400 | 
             
                            self.logger.debug(f"Failed to read pyproject.toml: {e}")
         | 
| 385 401 | 
             
                    return None
         | 
| 386 | 
            -
             | 
| 402 | 
            +
             | 
| 387 403 | 
             
                def _get_versions_from_changelog(self) -> List[VersionMetadata]:
         | 
| 388 404 | 
             
                    """Parse version history from CHANGELOG.md."""
         | 
| 389 405 | 
             
                    versions = []
         | 
| 390 406 | 
             
                    changelog_paths = [
         | 
| 391 407 | 
             
                        self.project_root / "CHANGELOG.md",
         | 
| 392 408 | 
             
                        self.project_root / "docs" / "CHANGELOG.md",
         | 
| 393 | 
            -
                        self.project_root / "HISTORY.md"
         | 
| 409 | 
            +
                        self.project_root / "HISTORY.md",
         | 
| 394 410 | 
             
                    ]
         | 
| 395 | 
            -
             | 
| 411 | 
            +
             | 
| 396 412 | 
             
                    for changelog_path in changelog_paths:
         | 
| 397 413 | 
             
                        if changelog_path.exists():
         | 
| 398 414 | 
             
                            try:
         | 
| 399 415 | 
             
                                content = changelog_path.read_text()
         | 
| 400 | 
            -
             | 
| 416 | 
            +
             | 
| 401 417 | 
             
                                # Find all version entries
         | 
| 402 418 | 
             
                                for match in self._changelog_version_pattern.finditer(content):
         | 
| 403 419 | 
             
                                    version = match.group(1).strip()
         | 
| 404 420 | 
             
                                    date_str = match.group(2) if match.lastindex >= 2 else None
         | 
| 405 | 
            -
             | 
| 421 | 
            +
             | 
| 406 422 | 
             
                                    # Parse release date
         | 
| 407 423 | 
             
                                    release_date = None
         | 
| 408 424 | 
             
                                    if date_str:
         | 
| @@ -410,63 +426,67 @@ class EnhancedVersionParser: | |
| 410 426 | 
             
                                            release_date = datetime.strptime(date_str, "%Y-%m-%d")
         | 
| 411 427 | 
             
                                        except:
         | 
| 412 428 | 
             
                                            pass
         | 
| 413 | 
            -
             | 
| 429 | 
            +
             | 
| 414 430 | 
             
                                    # Extract changes for this version
         | 
| 415 | 
            -
                                    changes = self._extract_changelog_changes( | 
| 416 | 
            -
             | 
| 417 | 
            -
                                     | 
| 418 | 
            -
             | 
| 419 | 
            -
             | 
| 420 | 
            -
                                         | 
| 421 | 
            -
             | 
| 422 | 
            -
             | 
| 423 | 
            -
             | 
| 431 | 
            +
                                    changes = self._extract_changelog_changes(
         | 
| 432 | 
            +
                                        content, match.start()
         | 
| 433 | 
            +
                                    )
         | 
| 434 | 
            +
             | 
| 435 | 
            +
                                    versions.append(
         | 
| 436 | 
            +
                                        VersionMetadata(
         | 
| 437 | 
            +
                                            version=version,
         | 
| 438 | 
            +
                                            source=VersionSource.CHANGELOG,
         | 
| 439 | 
            +
                                            release_date=release_date,
         | 
| 440 | 
            +
                                            changes=changes,
         | 
| 441 | 
            +
                                        )
         | 
| 442 | 
            +
                                    )
         | 
| 443 | 
            +
             | 
| 424 444 | 
             
                                if versions:
         | 
| 425 445 | 
             
                                    break
         | 
| 426 446 | 
             
                            except Exception as e:
         | 
| 427 447 | 
             
                                self.logger.debug(f"Failed to parse changelog: {e}")
         | 
| 428 | 
            -
             | 
| 448 | 
            +
             | 
| 429 449 | 
             
                    return versions
         | 
| 430 | 
            -
             | 
| 450 | 
            +
             | 
| 431 451 | 
             
                def _extract_changelog_changes(self, content: str, start_pos: int) -> List[str]:
         | 
| 432 452 | 
             
                    """Extract change entries for a specific version from changelog."""
         | 
| 433 453 | 
             
                    changes = []
         | 
| 434 | 
            -
                    lines = content[start_pos:].split( | 
| 435 | 
            -
             | 
| 454 | 
            +
                    lines = content[start_pos:].split("\n")
         | 
| 455 | 
            +
             | 
| 436 456 | 
             
                    in_changes = False
         | 
| 437 457 | 
             
                    for line in lines[1:]:  # Skip the version header line
         | 
| 438 458 | 
             
                        # Stop at next version header
         | 
| 439 | 
            -
                        if line.startswith( | 
| 459 | 
            +
                        if line.startswith("##"):
         | 
| 440 460 | 
             
                            break
         | 
| 441 | 
            -
             | 
| 461 | 
            +
             | 
| 442 462 | 
             
                        # Collect change lines (usually start with -, *, or +)
         | 
| 443 | 
            -
                        if line.strip().startswith(( | 
| 463 | 
            +
                        if line.strip().startswith(("-", "*", "+")):
         | 
| 444 464 | 
             
                            changes.append(line.strip()[1:].strip())
         | 
| 445 465 | 
             
                            in_changes = True
         | 
| 446 | 
            -
                        elif in_changes and line.strip() and not line.startswith( | 
| 466 | 
            +
                        elif in_changes and line.strip() and not line.startswith("#"):
         | 
| 447 467 | 
             
                            # Continuation of previous change
         | 
| 448 468 | 
             
                            if changes:
         | 
| 449 | 
            -
                                changes[-1] +=  | 
| 450 | 
            -
             | 
| 469 | 
            +
                                changes[-1] += " " + line.strip()
         | 
| 470 | 
            +
             | 
| 451 471 | 
             
                    return changes
         | 
| 452 | 
            -
             | 
| 472 | 
            +
             | 
| 453 473 | 
             
                def _is_prerelease(self, version: str) -> bool:
         | 
| 454 474 | 
             
                    """Check if a version is a pre-release."""
         | 
| 455 475 | 
             
                    prerelease_patterns = [
         | 
| 456 | 
            -
                        r | 
| 457 | 
            -
                        r | 
| 458 | 
            -
                        r | 
| 476 | 
            +
                        r"-(?:alpha|beta|rc|dev|pre)",
         | 
| 477 | 
            +
                        r"\.(?:alpha|beta|rc|dev|pre)",
         | 
| 478 | 
            +
                        r"(?:a|b|rc)\d+$",
         | 
| 459 479 | 
             
                    ]
         | 
| 460 | 
            -
             | 
| 480 | 
            +
             | 
| 461 481 | 
             
                    for pattern in prerelease_patterns:
         | 
| 462 482 | 
             
                        if re.search(pattern, version, re.IGNORECASE):
         | 
| 463 483 | 
             
                            return True
         | 
| 464 484 | 
             
                    return False
         | 
| 465 | 
            -
             | 
| 485 | 
            +
             | 
| 466 486 | 
             
                def _parse_semver(self, version: str) -> Tuple[int, int, int, str, str]:
         | 
| 467 487 | 
             
                    """
         | 
| 468 488 | 
             
                    Parse semantic version for sorting.
         | 
| 469 | 
            -
             | 
| 489 | 
            +
             | 
| 470 490 | 
             
                    Returns tuple of (major, minor, patch, prerelease, build)
         | 
| 471 491 | 
             
                    """
         | 
| 472 492 | 
             
                    match = self._version_pattern.match(version)
         | 
| @@ -474,20 +494,20 @@ class EnhancedVersionParser: | |
| 474 494 | 
             
                        major = int(match.group(1))
         | 
| 475 495 | 
             
                        minor = int(match.group(2))
         | 
| 476 496 | 
             
                        patch = int(match.group(3))
         | 
| 477 | 
            -
                        prerelease = match.group(4) or  | 
| 478 | 
            -
                        build = match.group(5) or  | 
| 497 | 
            +
                        prerelease = match.group(4) or ""
         | 
| 498 | 
            +
                        build = match.group(5) or ""
         | 
| 479 499 | 
             
                        return (major, minor, patch, prerelease, build)
         | 
| 480 | 
            -
                    return (0, 0, 0,  | 
| 481 | 
            -
             | 
| 500 | 
            +
                    return (0, 0, 0, "", "")
         | 
| 501 | 
            +
             | 
| 482 502 | 
             
                def validate_version_consistency(self) -> Dict[str, str]:
         | 
| 483 503 | 
             
                    """
         | 
| 484 504 | 
             
                    Validate version consistency across all sources.
         | 
| 485 | 
            -
             | 
| 505 | 
            +
             | 
| 486 506 | 
             
                    Returns:
         | 
| 487 507 | 
             
                        Dictionary mapping source names to versions found
         | 
| 488 508 | 
             
                    """
         | 
| 489 509 | 
             
                    versions = {}
         | 
| 490 | 
            -
             | 
| 510 | 
            +
             | 
| 491 511 | 
             
                    for source in VersionSource.PRIORITY_ORDER:
         | 
| 492 512 | 
             
                        try:
         | 
| 493 513 | 
             
                            version = self._get_version_from_source(source, latest_only=True)
         | 
| @@ -495,16 +515,16 @@ class EnhancedVersionParser: | |
| 495 515 | 
             
                                versions[source] = version.version
         | 
| 496 516 | 
             
                        except Exception as e:
         | 
| 497 517 | 
             
                            self.logger.debug(f"Failed to check {source}: {e}")
         | 
| 498 | 
            -
             | 
| 518 | 
            +
             | 
| 499 519 | 
             
                    return versions
         | 
| 500 | 
            -
             | 
| 520 | 
            +
             | 
| 501 521 | 
             
                def get_version_for_release(self) -> Optional[str]:
         | 
| 502 522 | 
             
                    """
         | 
| 503 523 | 
             
                    Get the version that should be used for the next release.
         | 
| 504 | 
            -
             | 
| 524 | 
            +
             | 
| 505 525 | 
             
                    This prioritizes git tags as the source of truth, falling back
         | 
| 506 526 | 
             
                    to VERSION file if no git tags exist.
         | 
| 507 | 
            -
             | 
| 527 | 
            +
             | 
| 508 528 | 
             
                    Returns:
         | 
| 509 529 | 
             
                        Version string for release, or None if no version found
         | 
| 510 530 | 
             
                    """
         | 
| @@ -512,12 +532,12 @@ class EnhancedVersionParser: | |
| 512 532 | 
             
                    git_version = self._get_version_from_git(latest_only=True)
         | 
| 513 533 | 
             
                    if git_version:
         | 
| 514 534 | 
             
                        return git_version.version
         | 
| 515 | 
            -
             | 
| 535 | 
            +
             | 
| 516 536 | 
             
                    # Fall back to VERSION file
         | 
| 517 537 | 
             
                    file_version = self._get_version_from_file()
         | 
| 518 538 | 
             
                    if file_version:
         | 
| 519 539 | 
             
                        return file_version.version
         | 
| 520 | 
            -
             | 
| 540 | 
            +
             | 
| 521 541 | 
             
                    return None
         | 
| 522 542 |  | 
| 523 543 |  | 
| @@ -525,4 +545,4 @@ class EnhancedVersionParser: | |
| 525 545 | 
             
            @lru_cache(maxsize=1)
         | 
| 526 546 | 
             
            def get_version_parser(project_root: Optional[Path] = None) -> EnhancedVersionParser:
         | 
| 527 547 | 
             
                """Get a singleton instance of the version parser."""
         | 
| 528 | 
            -
                return EnhancedVersionParser(project_root)
         | 
| 548 | 
            +
                return EnhancedVersionParser(project_root)
         |