claude-mpm 4.1.1__py3-none-any.whl → 4.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/engineer.json +33 -11
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +50 -2
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +648 -1098
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +339 -967
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +233 -542
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +280 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +22 -29
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +500 -680
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -17
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +99 -154
- claude_mpm/hooks/claude_hooks/hook_handler.py +110 -720
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
- claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +129 -511
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +157 -503
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
- claude_mpm/services/agents/memory/memory_file_service.py +103 -0
- claude_mpm/services/agents/memory/memory_format_service.py +201 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +11 -7
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/cli/__init__.py +18 -0
- claude_mpm/services/cli/agent_cleanup_service.py +407 -0
- claude_mpm/services/cli/agent_dependency_service.py +395 -0
- claude_mpm/services/cli/agent_listing_service.py +463 -0
- claude_mpm/services/cli/agent_output_formatter.py +605 -0
- claude_mpm/services/cli/agent_validation_service.py +589 -0
- claude_mpm/services/cli/dashboard_launcher.py +424 -0
- claude_mpm/services/cli/memory_crud_service.py +617 -0
- claude_mpm/services/cli/memory_output_formatter.py +604 -0
- claude_mpm/services/cli/session_manager.py +513 -0
- claude_mpm/services/cli/socketio_manager.py +498 -0
- claude_mpm/services/cli/startup_checker.py +370 -0
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/cache_manager.py +311 -0
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/core/memory_manager.py +637 -0
- claude_mpm/services/core/path_resolver.py +498 -0
- claude_mpm/services/core/service_container.py +520 -0
- claude_mpm/services/core/service_interfaces.py +436 -0
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +152 -97
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/METADATA +1 -1
- claude_mpm-4.1.3.dist-info/RECORD +528 -0
- claude_mpm/cli/commands/run_config_checker.py +0 -160
- claude_mpm-4.1.1.dist-info/RECORD +0 -494
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/top_level.txt +0 -0
claude_mpm/core/claude_runner.py
CHANGED
|
@@ -1,47 +1,22 @@
|
|
|
1
1
|
"""Claude runner with both exec and subprocess launch methods."""
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
import os
|
|
5
|
-
import subprocess
|
|
6
|
-
import sys
|
|
7
|
-
import time
|
|
8
|
-
import uuid
|
|
9
|
-
from datetime import datetime
|
|
10
4
|
from pathlib import Path
|
|
11
|
-
from typing import
|
|
12
|
-
|
|
13
|
-
from claude_mpm.config.paths import paths
|
|
5
|
+
from typing import Optional
|
|
14
6
|
|
|
15
7
|
# Core imports that don't cause circular dependencies
|
|
16
|
-
from claude_mpm.core.
|
|
17
|
-
from claude_mpm.core.container import ServiceLifetime, get_container
|
|
8
|
+
from claude_mpm.core.container import get_container
|
|
18
9
|
from claude_mpm.core.interfaces import (
|
|
19
10
|
AgentDeploymentInterface,
|
|
20
|
-
HookServiceInterface,
|
|
21
|
-
TicketManagerInterface,
|
|
22
11
|
)
|
|
23
|
-
from claude_mpm.core.logger import ProjectLogger, get_project_logger
|
|
24
12
|
from claude_mpm.core.logging_config import (
|
|
25
13
|
get_logger,
|
|
26
|
-
log_operation,
|
|
27
|
-
log_performance_context,
|
|
28
14
|
)
|
|
29
15
|
from claude_mpm.services.core.interfaces import (
|
|
30
|
-
AgentCapabilitiesInterface,
|
|
31
|
-
CommandHandlerInterface,
|
|
32
|
-
MemoryHookInterface,
|
|
33
16
|
RunnerConfigurationInterface,
|
|
34
|
-
SessionManagementInterface,
|
|
35
|
-
SubprocessLauncherInterface,
|
|
36
|
-
SystemInstructionsInterface,
|
|
37
|
-
UtilityServiceInterface,
|
|
38
|
-
VersionServiceInterface,
|
|
39
17
|
)
|
|
40
18
|
|
|
41
19
|
# Type checking imports to avoid circular dependencies
|
|
42
|
-
if TYPE_CHECKING:
|
|
43
|
-
from claude_mpm.services.agents.deployment import AgentDeploymentService
|
|
44
|
-
from claude_mpm.services.hook_service import HookService
|
|
45
20
|
|
|
46
21
|
|
|
47
22
|
class ClaudeRunner:
|
|
@@ -125,9 +100,7 @@ class ClaudeRunner:
|
|
|
125
100
|
try:
|
|
126
101
|
self.deployment_service = container.get(AgentDeploymentInterface)
|
|
127
102
|
except Exception as e:
|
|
128
|
-
self.logger.error(
|
|
129
|
-
f"Failed to resolve AgentDeploymentService", exc_info=True
|
|
130
|
-
)
|
|
103
|
+
self.logger.error("Failed to resolve AgentDeploymentService", exc_info=True)
|
|
131
104
|
raise RuntimeError(
|
|
132
105
|
f"Agent deployment service initialization failed: {e}"
|
|
133
106
|
) from e
|
|
@@ -213,7 +186,7 @@ class ClaudeRunner:
|
|
|
213
186
|
# Deploy output style early (before Claude Code launches)
|
|
214
187
|
# This ensures the "Claude MPM" output style is active on startup
|
|
215
188
|
self._deploy_output_style()
|
|
216
|
-
|
|
189
|
+
|
|
217
190
|
# Create session log file using configuration service
|
|
218
191
|
self.session_log_file = self.configuration_service.create_session_log_file(
|
|
219
192
|
self.project_logger, self.log_level, config_data
|
|
@@ -260,15 +233,14 @@ class ClaudeRunner:
|
|
|
260
233
|
# Set Claude environment
|
|
261
234
|
self.deployment_service.set_claude_environment()
|
|
262
235
|
return True
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return True
|
|
236
|
+
self.logger.info("All agents already up to date")
|
|
237
|
+
if self.project_logger:
|
|
238
|
+
self.project_logger.log_system(
|
|
239
|
+
"All agents already up to date",
|
|
240
|
+
level="INFO",
|
|
241
|
+
component="deployment",
|
|
242
|
+
)
|
|
243
|
+
return True
|
|
272
244
|
|
|
273
245
|
except PermissionError as e:
|
|
274
246
|
error_msg = f"Permission denied deploying agents to .claude/agents/: {e}"
|
|
@@ -366,15 +338,14 @@ class ClaudeRunner:
|
|
|
366
338
|
self.logger.info(f"Updated {updated_count} agents in project")
|
|
367
339
|
|
|
368
340
|
return True
|
|
369
|
-
|
|
341
|
+
if results.get("skipped", []):
|
|
370
342
|
# Agents already exist and are current
|
|
371
343
|
self.logger.debug(
|
|
372
344
|
f"Project agents up to date: {len(results['skipped'])} agents"
|
|
373
345
|
)
|
|
374
346
|
return True
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
return False
|
|
347
|
+
self.logger.warning("No agents deployed to project")
|
|
348
|
+
return False
|
|
378
349
|
|
|
379
350
|
except Exception as e:
|
|
380
351
|
self.logger.error(f"Failed to ensure project agents: {e}")
|
|
@@ -502,8 +473,13 @@ class ClaudeRunner:
|
|
|
502
473
|
if needs_update:
|
|
503
474
|
# Build the agent markdown using the pre-initialized service and base agent data
|
|
504
475
|
# Use template_builder service instead of removed _build_agent_markdown method
|
|
505
|
-
agent_content =
|
|
506
|
-
|
|
476
|
+
agent_content = (
|
|
477
|
+
project_deployment.template_builder.build_agent_markdown(
|
|
478
|
+
agent_name,
|
|
479
|
+
json_file,
|
|
480
|
+
base_agent_data,
|
|
481
|
+
source_info="project",
|
|
482
|
+
)
|
|
507
483
|
)
|
|
508
484
|
|
|
509
485
|
# Mark as project agent
|
|
@@ -584,15 +560,13 @@ class ClaudeRunner:
|
|
|
584
560
|
"""
|
|
585
561
|
if self.session_management_service:
|
|
586
562
|
return self.session_management_service.run_oneshot_session(prompt, context)
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
return False
|
|
563
|
+
self.logger.error("Session management service not available")
|
|
564
|
+
print("Error: Session management service not available")
|
|
565
|
+
return False
|
|
591
566
|
|
|
592
567
|
def _extract_tickets(self, text: str):
|
|
593
568
|
"""Extract tickets from Claude's response (disabled - use claude-mpm tickets CLI)."""
|
|
594
569
|
# Ticket extraction disabled - users should use claude-mpm tickets CLI commands
|
|
595
|
-
pass
|
|
596
570
|
|
|
597
571
|
def _load_system_instructions(self) -> Optional[str]:
|
|
598
572
|
"""Load and process system instructions.
|
|
@@ -601,12 +575,11 @@ class ClaudeRunner:
|
|
|
601
575
|
"""
|
|
602
576
|
if self.system_instructions_service:
|
|
603
577
|
return self.system_instructions_service.load_system_instructions()
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
return None
|
|
578
|
+
# Fallback if service is not available
|
|
579
|
+
self.logger.warning(
|
|
580
|
+
"System instructions service not available, using basic fallback"
|
|
581
|
+
)
|
|
582
|
+
return None
|
|
610
583
|
|
|
611
584
|
def _process_base_pm_content(self, base_pm_content: str) -> str:
|
|
612
585
|
"""Process BASE_PM.md content with dynamic injections.
|
|
@@ -617,12 +590,11 @@ class ClaudeRunner:
|
|
|
617
590
|
return self.system_instructions_service.process_base_pm_content(
|
|
618
591
|
base_pm_content
|
|
619
592
|
)
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
return base_pm_content
|
|
593
|
+
# Fallback if service is not available
|
|
594
|
+
self.logger.warning(
|
|
595
|
+
"System instructions service not available for BASE_PM processing"
|
|
596
|
+
)
|
|
597
|
+
return base_pm_content
|
|
626
598
|
|
|
627
599
|
def _strip_metadata_comments(self, content: str) -> str:
|
|
628
600
|
"""Strip HTML metadata comments from content.
|
|
@@ -631,12 +603,11 @@ class ClaudeRunner:
|
|
|
631
603
|
"""
|
|
632
604
|
if self.system_instructions_service:
|
|
633
605
|
return self.system_instructions_service.strip_metadata_comments(content)
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
return content
|
|
606
|
+
# Fallback if service is not available
|
|
607
|
+
self.logger.warning(
|
|
608
|
+
"System instructions service not available for metadata stripping"
|
|
609
|
+
)
|
|
610
|
+
return content
|
|
640
611
|
|
|
641
612
|
def _generate_deployed_agent_capabilities(self) -> str:
|
|
642
613
|
"""Generate agent capabilities from deployed agents.
|
|
@@ -647,20 +618,16 @@ class ClaudeRunner:
|
|
|
647
618
|
return (
|
|
648
619
|
self.agent_capabilities_service.generate_deployed_agent_capabilities()
|
|
649
620
|
)
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
"Agent capabilities service not available, using fallback"
|
|
654
|
-
)
|
|
655
|
-
return self._get_fallback_capabilities()
|
|
621
|
+
# Fallback if service is not available
|
|
622
|
+
self.logger.warning("Agent capabilities service not available, using fallback")
|
|
623
|
+
return self._get_fallback_capabilities()
|
|
656
624
|
|
|
657
625
|
def _get_fallback_capabilities(self) -> str:
|
|
658
626
|
"""Return fallback agent capabilities when deployed agents can't be read."""
|
|
659
627
|
# Delegate to the service if available, otherwise use basic fallback
|
|
660
628
|
if self.agent_capabilities_service:
|
|
661
629
|
return self.agent_capabilities_service._get_fallback_capabilities()
|
|
662
|
-
|
|
663
|
-
return """
|
|
630
|
+
return """
|
|
664
631
|
## Available Agent Capabilities
|
|
665
632
|
|
|
666
633
|
You have the following specialized agents available for delegation:
|
|
@@ -682,28 +649,24 @@ Use these agents to delegate specialized work via the Task tool.
|
|
|
682
649
|
return self.system_instructions_service.create_system_prompt(
|
|
683
650
|
self.system_instructions
|
|
684
651
|
)
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
else:
|
|
690
|
-
return create_simple_context()
|
|
652
|
+
# Fallback if service is not available
|
|
653
|
+
if self.system_instructions:
|
|
654
|
+
return self.system_instructions
|
|
655
|
+
return create_simple_context()
|
|
691
656
|
|
|
692
657
|
def _contains_delegation(self, text: str) -> bool:
|
|
693
658
|
"""Check if text contains signs of agent delegation using the utility service."""
|
|
694
659
|
if self.utility_service:
|
|
695
660
|
return self.utility_service.contains_delegation(text)
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
return False
|
|
661
|
+
# Fallback if service not available
|
|
662
|
+
return False
|
|
699
663
|
|
|
700
664
|
def _extract_agent_from_response(self, text: str) -> Optional[str]:
|
|
701
665
|
"""Try to extract agent name from delegation response using the utility service."""
|
|
702
666
|
if self.utility_service:
|
|
703
667
|
return self.utility_service.extract_agent_from_response(text)
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
return None
|
|
668
|
+
# Fallback if service not available
|
|
669
|
+
return None
|
|
707
670
|
|
|
708
671
|
def _handle_mpm_command(self, prompt: str) -> bool:
|
|
709
672
|
"""Handle /mpm: commands using the command handler service.
|
|
@@ -712,10 +675,9 @@ Use these agents to delegate specialized work via the Task tool.
|
|
|
712
675
|
"""
|
|
713
676
|
if self.command_handler_service:
|
|
714
677
|
return self.command_handler_service.handle_mpm_command(prompt)
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
return False
|
|
678
|
+
# Fallback if service not available
|
|
679
|
+
print("Command handler service not available")
|
|
680
|
+
return False
|
|
719
681
|
|
|
720
682
|
def _log_session_event(self, event_data: dict):
|
|
721
683
|
"""Log an event to the session log file using the utility service."""
|
|
@@ -732,23 +694,22 @@ Use these agents to delegate specialized work via the Task tool.
|
|
|
732
694
|
"""
|
|
733
695
|
if self.version_service:
|
|
734
696
|
return self.version_service.get_version()
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
return "v0.0.0"
|
|
697
|
+
# Fallback if service not available
|
|
698
|
+
return "v0.0.0"
|
|
738
699
|
|
|
739
700
|
def _deploy_output_style(self) -> None:
|
|
740
701
|
"""Deploy the Claude MPM output style before Claude Code launches.
|
|
741
|
-
|
|
702
|
+
|
|
742
703
|
This method ensures the output style is set to "Claude MPM" on startup
|
|
743
704
|
by deploying the style file and updating Claude Code settings.
|
|
744
705
|
Only works for Claude Code >= 1.0.83.
|
|
745
706
|
"""
|
|
746
707
|
try:
|
|
747
708
|
from claude_mpm.core.output_style_manager import OutputStyleManager
|
|
748
|
-
|
|
709
|
+
|
|
749
710
|
# Create OutputStyleManager instance
|
|
750
711
|
output_style_manager = OutputStyleManager()
|
|
751
|
-
|
|
712
|
+
|
|
752
713
|
# Check if Claude Code supports output styles
|
|
753
714
|
if not output_style_manager.supports_output_styles():
|
|
754
715
|
self.logger.debug(
|
|
@@ -756,48 +717,59 @@ Use these agents to delegate specialized work via the Task tool.
|
|
|
756
717
|
"does not support output styles (requires >= 1.0.83)"
|
|
757
718
|
)
|
|
758
719
|
return
|
|
759
|
-
|
|
720
|
+
|
|
760
721
|
# Check if output style is already deployed and active
|
|
761
722
|
settings_file = Path.home() / ".claude" / "settings.json"
|
|
762
723
|
if settings_file.exists():
|
|
763
724
|
try:
|
|
764
725
|
import json
|
|
726
|
+
|
|
765
727
|
settings = json.loads(settings_file.read_text())
|
|
766
728
|
if settings.get("activeOutputStyle") == "claude-mpm":
|
|
767
729
|
# Already active, check if file exists
|
|
768
|
-
output_style_file =
|
|
730
|
+
output_style_file = (
|
|
731
|
+
Path.home() / ".claude" / "output-styles" / "claude-mpm.md"
|
|
732
|
+
)
|
|
769
733
|
if output_style_file.exists():
|
|
770
|
-
self.logger.debug(
|
|
734
|
+
self.logger.debug(
|
|
735
|
+
"Output style 'Claude MPM' already deployed and active"
|
|
736
|
+
)
|
|
771
737
|
return
|
|
772
738
|
except Exception:
|
|
773
739
|
pass # Continue with deployment if we can't read settings
|
|
774
|
-
|
|
740
|
+
|
|
775
741
|
# Read the OUTPUT_STYLE.md content if it exists
|
|
776
|
-
output_style_path =
|
|
777
|
-
|
|
742
|
+
output_style_path = (
|
|
743
|
+
Path(__file__).parent.parent / "agents" / "OUTPUT_STYLE.md"
|
|
744
|
+
)
|
|
745
|
+
|
|
778
746
|
if output_style_path.exists():
|
|
779
747
|
# Use existing OUTPUT_STYLE.md content
|
|
780
748
|
output_style_content = output_style_path.read_text()
|
|
781
749
|
self.logger.debug("Using existing OUTPUT_STYLE.md content")
|
|
782
750
|
else:
|
|
783
751
|
# Extract output style content from framework instructions
|
|
784
|
-
output_style_content =
|
|
752
|
+
output_style_content = (
|
|
753
|
+
output_style_manager.extract_output_style_content()
|
|
754
|
+
)
|
|
785
755
|
self.logger.debug("Extracted output style from framework instructions")
|
|
786
|
-
|
|
756
|
+
|
|
787
757
|
# Deploy the output style
|
|
788
758
|
deployed = output_style_manager.deploy_output_style(output_style_content)
|
|
789
|
-
|
|
759
|
+
|
|
790
760
|
if deployed:
|
|
791
|
-
self.logger.info(
|
|
761
|
+
self.logger.info(
|
|
762
|
+
"✅ Output style 'Claude MPM' deployed and activated on startup"
|
|
763
|
+
)
|
|
792
764
|
if self.project_logger:
|
|
793
765
|
self.project_logger.log_system(
|
|
794
766
|
"Output style 'Claude MPM' deployed and activated on startup",
|
|
795
767
|
level="INFO",
|
|
796
|
-
component="output_style"
|
|
768
|
+
component="output_style",
|
|
797
769
|
)
|
|
798
770
|
else:
|
|
799
771
|
self.logger.warning("Failed to deploy output style")
|
|
800
|
-
|
|
772
|
+
|
|
801
773
|
except ImportError as e:
|
|
802
774
|
self.logger.warning(f"Could not import OutputStyleManager: {e}")
|
|
803
775
|
except Exception as e:
|
|
@@ -806,8 +778,8 @@ Use these agents to delegate specialized work via the Task tool.
|
|
|
806
778
|
if self.project_logger:
|
|
807
779
|
self.project_logger.log_system(
|
|
808
780
|
f"Output style deployment error: {e}",
|
|
809
|
-
level="WARNING",
|
|
810
|
-
component="output_style"
|
|
781
|
+
level="WARNING",
|
|
782
|
+
component="output_style",
|
|
811
783
|
)
|
|
812
784
|
|
|
813
785
|
def _launch_subprocess_interactive(self, cmd: list, env: dict):
|
claude_mpm/core/config.py
CHANGED
|
@@ -37,12 +37,14 @@ class Config:
|
|
|
37
37
|
|
|
38
38
|
_instance = None
|
|
39
39
|
_initialized = False
|
|
40
|
-
_success_logged =
|
|
40
|
+
_success_logged = (
|
|
41
|
+
False # Class-level flag to track if success message was already logged
|
|
42
|
+
)
|
|
41
43
|
_lock = threading.Lock() # Thread safety for singleton initialization
|
|
42
44
|
|
|
43
45
|
def __new__(cls, *args, **kwargs):
|
|
44
46
|
"""Implement singleton pattern to ensure single configuration instance.
|
|
45
|
-
|
|
47
|
+
|
|
46
48
|
WHY: Configuration was being loaded 11 times during startup, once for each service.
|
|
47
49
|
This singleton pattern ensures configuration is loaded only once and reused.
|
|
48
50
|
Thread-safe implementation prevents race conditions during concurrent initialization.
|
|
@@ -54,7 +56,9 @@ class Config:
|
|
|
54
56
|
cls._instance = super().__new__(cls)
|
|
55
57
|
logger.info("Creating new Config singleton instance")
|
|
56
58
|
else:
|
|
57
|
-
logger.debug(
|
|
59
|
+
logger.debug(
|
|
60
|
+
"Reusing existing Config singleton instance (concurrent init)"
|
|
61
|
+
)
|
|
58
62
|
else:
|
|
59
63
|
logger.debug("Reusing existing Config singleton instance")
|
|
60
64
|
return cls._instance
|
|
@@ -79,23 +83,25 @@ class Config:
|
|
|
79
83
|
logger.debug("Config already initialized, skipping re-initialization")
|
|
80
84
|
# If someone tries to load a different config file after initialization,
|
|
81
85
|
# log a debug message but don't reload
|
|
82
|
-
if config_file and str(config_file) != getattr(self,
|
|
86
|
+
if config_file and str(config_file) != getattr(self, "_loaded_from", None):
|
|
83
87
|
logger.debug(
|
|
84
88
|
f"Ignoring config_file parameter '{config_file}' - "
|
|
85
89
|
f"configuration already loaded from '{getattr(self, '_loaded_from', 'defaults')}'"
|
|
86
90
|
)
|
|
87
91
|
return
|
|
88
|
-
|
|
92
|
+
|
|
89
93
|
# Thread-safe initialization - acquire lock for ENTIRE initialization process
|
|
90
94
|
with Config._lock:
|
|
91
95
|
# Double-check pattern - check again inside the lock
|
|
92
96
|
if Config._initialized:
|
|
93
|
-
logger.debug(
|
|
97
|
+
logger.debug(
|
|
98
|
+
"Config already initialized (concurrent), skipping re-initialization"
|
|
99
|
+
)
|
|
94
100
|
return
|
|
95
|
-
|
|
101
|
+
|
|
96
102
|
Config._initialized = True
|
|
97
103
|
logger.info("Initializing Config singleton for the first time")
|
|
98
|
-
|
|
104
|
+
|
|
99
105
|
# Initialize instance variables inside the lock to ensure thread safety
|
|
100
106
|
self._config: Dict[str, Any] = {}
|
|
101
107
|
self._env_prefix = env_prefix
|
|
@@ -121,7 +127,9 @@ class Config:
|
|
|
121
127
|
if default_config.exists():
|
|
122
128
|
self.load_file(default_config, is_initial_load=True)
|
|
123
129
|
self._loaded_from = str(default_config)
|
|
124
|
-
elif (
|
|
130
|
+
elif (
|
|
131
|
+
alt_config := Path.cwd() / ".claude-mpm" / "configuration.yml"
|
|
132
|
+
).exists():
|
|
125
133
|
# Also try .yml extension (using walrus operator for cleaner code)
|
|
126
134
|
self.load_file(alt_config, is_initial_load=True)
|
|
127
135
|
self._loaded_from = str(alt_config)
|
|
@@ -133,21 +141,27 @@ class Config:
|
|
|
133
141
|
# Apply defaults
|
|
134
142
|
self._apply_defaults()
|
|
135
143
|
|
|
136
|
-
def load_file(
|
|
144
|
+
def load_file(
|
|
145
|
+
self, file_path: Union[str, Path], is_initial_load: bool = True
|
|
146
|
+
) -> None:
|
|
137
147
|
"""Load configuration from file with enhanced error handling.
|
|
138
148
|
|
|
139
149
|
WHY: Configuration loading failures can cause silent issues. We need
|
|
140
150
|
to provide clear, actionable error messages to help users fix problems.
|
|
141
|
-
|
|
151
|
+
|
|
142
152
|
Args:
|
|
143
153
|
file_path: Path to the configuration file
|
|
144
154
|
is_initial_load: Whether this is the initial configuration load (for logging control)
|
|
145
155
|
"""
|
|
146
156
|
file_path = Path(file_path)
|
|
147
|
-
|
|
157
|
+
|
|
148
158
|
# Check if we've already loaded from this exact file to prevent duplicate messages
|
|
149
|
-
if hasattr(self,
|
|
150
|
-
|
|
159
|
+
if hasattr(self, "_actual_loaded_file") and self._actual_loaded_file == str(
|
|
160
|
+
file_path
|
|
161
|
+
):
|
|
162
|
+
logger.debug(
|
|
163
|
+
f"Configuration already loaded from {file_path}, skipping reload"
|
|
164
|
+
)
|
|
151
165
|
return
|
|
152
166
|
|
|
153
167
|
if not file_path.exists():
|
|
@@ -177,7 +191,7 @@ class Config:
|
|
|
177
191
|
self._config = self._config_mgr.merge_configs(self._config, file_config)
|
|
178
192
|
# Track that we've successfully loaded from this file
|
|
179
193
|
self._actual_loaded_file = str(file_path)
|
|
180
|
-
|
|
194
|
+
|
|
181
195
|
# Only log success message once using class-level flag to avoid duplicate messages
|
|
182
196
|
# Check if we should log success message (thread-safe for reads after initialization)
|
|
183
197
|
if is_initial_load:
|
|
@@ -185,10 +199,14 @@ class Config:
|
|
|
185
199
|
# Set flag IMMEDIATELY before logging to prevent any possibility of duplicate
|
|
186
200
|
# messages. No lock needed here since we're already inside __init__ lock
|
|
187
201
|
Config._success_logged = True
|
|
188
|
-
logger.info(
|
|
202
|
+
logger.info(
|
|
203
|
+
f"✓ Successfully loaded configuration from {file_path}"
|
|
204
|
+
)
|
|
189
205
|
else:
|
|
190
206
|
# Configuration already successfully loaded before, just debug log
|
|
191
|
-
logger.debug(
|
|
207
|
+
logger.debug(
|
|
208
|
+
f"Configuration already loaded, skipping success message for {file_path}"
|
|
209
|
+
)
|
|
192
210
|
else:
|
|
193
211
|
# Not initial load (shouldn't happen in normal flow, but handle gracefully)
|
|
194
212
|
logger.debug(f"Configuration reloaded from {file_path}")
|
|
@@ -225,7 +243,7 @@ class Config:
|
|
|
225
243
|
logger.info("TIP: Validate your JSON at https://jsonlint.com/")
|
|
226
244
|
self._config["_load_error"] = str(e)
|
|
227
245
|
|
|
228
|
-
except (OSError,
|
|
246
|
+
except (OSError, PermissionError) as e:
|
|
229
247
|
raise FileOperationError(
|
|
230
248
|
f"Failed to read configuration file: {e}",
|
|
231
249
|
context={
|
|
@@ -285,15 +303,14 @@ class Config:
|
|
|
285
303
|
# Boolean conversion
|
|
286
304
|
if value.lower() in ("true", "yes", "1", "on"):
|
|
287
305
|
return True
|
|
288
|
-
|
|
306
|
+
if value.lower() in ("false", "no", "0", "off"):
|
|
289
307
|
return False
|
|
290
308
|
|
|
291
309
|
# Numeric conversion
|
|
292
310
|
try:
|
|
293
311
|
if "." in value:
|
|
294
312
|
return float(value)
|
|
295
|
-
|
|
296
|
-
return int(value)
|
|
313
|
+
return int(value)
|
|
297
314
|
except ValueError:
|
|
298
315
|
pass
|
|
299
316
|
|
|
@@ -580,7 +597,7 @@ class Config:
|
|
|
580
597
|
|
|
581
598
|
logger.info(f"Configuration saved to {file_path}")
|
|
582
599
|
|
|
583
|
-
except (OSError,
|
|
600
|
+
except (OSError, PermissionError) as e:
|
|
584
601
|
raise FileOperationError(
|
|
585
602
|
f"Failed to write configuration file: {e}",
|
|
586
603
|
context={
|
|
@@ -809,7 +826,7 @@ class Config:
|
|
|
809
826
|
if "enabled" in memory_config and not isinstance(
|
|
810
827
|
memory_config["enabled"], bool
|
|
811
828
|
):
|
|
812
|
-
errors.append(
|
|
829
|
+
errors.append("memory.enabled must be boolean")
|
|
813
830
|
|
|
814
831
|
# Check limits
|
|
815
832
|
limits = memory_config.get("limits", {})
|
|
@@ -850,7 +867,7 @@ class Config:
|
|
|
850
867
|
"""
|
|
851
868
|
is_valid, errors, warnings = self.validate_configuration()
|
|
852
869
|
|
|
853
|
-
|
|
870
|
+
return {
|
|
854
871
|
"valid": is_valid,
|
|
855
872
|
"errors": errors,
|
|
856
873
|
"warnings": warnings,
|
|
@@ -862,16 +879,14 @@ class Config:
|
|
|
862
879
|
"memory_enabled": self.get("memory.enabled", False),
|
|
863
880
|
}
|
|
864
881
|
|
|
865
|
-
return status
|
|
866
|
-
|
|
867
882
|
def __repr__(self) -> str:
|
|
868
883
|
"""String representation of configuration."""
|
|
869
884
|
return f"<Config({len(self._config)} keys)>"
|
|
870
|
-
|
|
885
|
+
|
|
871
886
|
@classmethod
|
|
872
887
|
def reset_singleton(cls):
|
|
873
888
|
"""Reset the singleton instance (mainly for testing purposes).
|
|
874
|
-
|
|
889
|
+
|
|
875
890
|
WHY: During testing, we may need to reset the singleton to test different
|
|
876
891
|
configurations. This method allows controlled reset of the singleton state.
|
|
877
892
|
"""
|
|
@@ -15,7 +15,6 @@ Aliases are stored in ~/.claude-mpm/config_aliases.json
|
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
17
|
import logging
|
|
18
|
-
import os
|
|
19
18
|
from typing import Dict, List, Optional, Tuple
|
|
20
19
|
|
|
21
20
|
from ..utils.config_manager import ConfigurationManager
|
|
@@ -27,26 +26,18 @@ logger = logging.getLogger(__name__)
|
|
|
27
26
|
class ConfigAliasError(Exception):
|
|
28
27
|
"""Base exception for configuration alias errors."""
|
|
29
28
|
|
|
30
|
-
pass
|
|
31
|
-
|
|
32
29
|
|
|
33
30
|
class AliasNotFoundError(ConfigAliasError):
|
|
34
31
|
"""Raised when attempting to resolve a non-existent alias."""
|
|
35
32
|
|
|
36
|
-
pass
|
|
37
|
-
|
|
38
33
|
|
|
39
34
|
class DuplicateAliasError(ConfigAliasError):
|
|
40
35
|
"""Raised when attempting to create an alias that already exists."""
|
|
41
36
|
|
|
42
|
-
pass
|
|
43
|
-
|
|
44
37
|
|
|
45
38
|
class InvalidDirectoryError(ConfigAliasError):
|
|
46
39
|
"""Raised when a directory path is invalid or cannot be created."""
|
|
47
40
|
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
41
|
|
|
51
42
|
class ConfigAliasManager:
|
|
52
43
|
"""
|