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 | 
             
            Dependency management strategies for different contexts.
         | 
| 3 5 |  | 
| @@ -5,14 +7,13 @@ This module provides smart dependency checking and installation strategies | |
| 5 7 | 
             
            based on the execution context and user preferences.
         | 
| 6 8 | 
             
            """
         | 
| 7 9 |  | 
| 10 | 
            +
            import json
         | 
| 8 11 | 
             
            import os
         | 
| 9 12 | 
             
            import sys
         | 
| 10 13 | 
             
            import time
         | 
| 11 | 
            -
            import json
         | 
| 12 | 
            -
            from pathlib import Path
         | 
| 13 | 
            -
            from typing import Optional, Dict, Any, Tuple
         | 
| 14 | 
            -
            from enum import Enum
         | 
| 15 14 | 
             
            from datetime import datetime, timedelta
         | 
| 15 | 
            +
            from enum import Enum
         | 
| 16 | 
            +
            from typing import Any, Dict, Optional, Tuple
         | 
| 16 17 |  | 
| 17 18 | 
             
            from ..core.logger import get_logger
         | 
| 18 19 |  | 
| @@ -21,6 +22,7 @@ logger = get_logger(__name__) | |
| 21 22 |  | 
| 22 23 | 
             
            class DependencyMode(Enum):
         | 
| 23 24 | 
             
                """Dependency checking and installation modes."""
         | 
| 25 | 
            +
             | 
| 24 26 | 
             
                OFF = "off"  # No checking at all
         | 
| 25 27 | 
             
                CHECK = "check"  # Check and warn only
         | 
| 26 28 | 
             
                INTERACTIVE = "interactive"  # Prompt user for installation
         | 
| @@ -31,29 +33,29 @@ class DependencyMode(Enum): | |
| 31 33 | 
             
            class DependencyStrategy:
         | 
| 32 34 | 
             
                """
         | 
| 33 35 | 
             
                Smart dependency management based on context and preferences.
         | 
| 34 | 
            -
             | 
| 36 | 
            +
             | 
| 35 37 | 
             
                This class determines the appropriate dependency strategy based on:
         | 
| 36 38 | 
             
                - Execution environment (CI, Docker, TTY, etc.)
         | 
| 37 39 | 
             
                - User configuration
         | 
| 38 40 | 
             
                - Cached check results
         | 
| 39 41 | 
             
                - Command being executed
         | 
| 40 42 | 
             
                """
         | 
| 41 | 
            -
             | 
| 43 | 
            +
             | 
| 42 44 | 
             
                def __init__(self, config_path: Optional[Path] = None):
         | 
| 43 45 | 
             
                    """
         | 
| 44 46 | 
             
                    Initialize dependency strategy manager.
         | 
| 45 | 
            -
             | 
| 47 | 
            +
             | 
| 46 48 | 
             
                    Args:
         | 
| 47 49 | 
             
                        config_path: Optional path to configuration file
         | 
| 48 50 | 
             
                    """
         | 
| 49 51 | 
             
                    self.config_path = config_path or Path.home() / ".claude-mpm" / "config.yaml"
         | 
| 50 52 | 
             
                    self.cache_path = Path.home() / ".claude-mpm" / ".dep_cache.json"
         | 
| 51 53 | 
             
                    self.mode = self._determine_mode()
         | 
| 52 | 
            -
             | 
| 54 | 
            +
             | 
| 53 55 | 
             
                def _determine_mode(self) -> DependencyMode:
         | 
| 54 56 | 
             
                    """
         | 
| 55 57 | 
             
                    Determine the appropriate dependency mode based on context.
         | 
| 56 | 
            -
             | 
| 58 | 
            +
             | 
| 57 59 | 
             
                    Returns:
         | 
| 58 60 | 
             
                        The dependency mode to use
         | 
| 59 61 | 
             
                    """
         | 
| @@ -64,62 +66,69 @@ class DependencyStrategy: | |
| 64 66 | 
             
                            return DependencyMode(env_mode.lower())
         | 
| 65 67 | 
             
                        except ValueError:
         | 
| 66 68 | 
             
                            logger.warning(f"Invalid CLAUDE_MPM_DEP_MODE: {env_mode}")
         | 
| 67 | 
            -
             | 
| 69 | 
            +
             | 
| 68 70 | 
             
                    # Check if in CI environment
         | 
| 69 71 | 
             
                    if self._is_ci_environment():
         | 
| 70 72 | 
             
                        logger.debug("CI environment detected - using CHECK mode")
         | 
| 71 73 | 
             
                        return DependencyMode.CHECK
         | 
| 72 | 
            -
             | 
| 74 | 
            +
             | 
| 73 75 | 
             
                    # Check if in Docker container
         | 
| 74 76 | 
             
                    if self._is_docker():
         | 
| 75 77 | 
             
                        logger.debug("Docker environment detected - using CHECK mode")
         | 
| 76 78 | 
             
                        return DependencyMode.CHECK
         | 
| 77 | 
            -
             | 
| 79 | 
            +
             | 
| 78 80 | 
             
                    # Check if non-interactive terminal
         | 
| 79 81 | 
             
                    if not self._is_interactive():
         | 
| 80 82 | 
             
                        logger.debug("Non-interactive terminal - using CHECK mode")
         | 
| 81 83 | 
             
                        return DependencyMode.CHECK
         | 
| 82 | 
            -
             | 
| 84 | 
            +
             | 
| 83 85 | 
             
                    # Load user configuration
         | 
| 84 86 | 
             
                    user_mode = self._load_user_preference()
         | 
| 85 87 | 
             
                    if user_mode:
         | 
| 86 88 | 
             
                        return user_mode
         | 
| 87 | 
            -
             | 
| 89 | 
            +
             | 
| 88 90 | 
             
                    # Default to interactive for TTY sessions
         | 
| 89 91 | 
             
                    return DependencyMode.INTERACTIVE
         | 
| 90 | 
            -
             | 
| 92 | 
            +
             | 
| 91 93 | 
             
                def _is_ci_environment(self) -> bool:
         | 
| 92 94 | 
             
                    """Check if running in CI environment."""
         | 
| 93 95 | 
             
                    ci_indicators = [
         | 
| 94 | 
            -
                        "CI", | 
| 95 | 
            -
                        " | 
| 96 | 
            +
                        "CI",
         | 
| 97 | 
            +
                        "CONTINUOUS_INTEGRATION",
         | 
| 98 | 
            +
                        "JENKINS",
         | 
| 99 | 
            +
                        "TRAVIS",
         | 
| 100 | 
            +
                        "CIRCLECI",
         | 
| 101 | 
            +
                        "GITHUB_ACTIONS",
         | 
| 102 | 
            +
                        "GITLAB_CI",
         | 
| 103 | 
            +
                        "BUILDKITE",
         | 
| 96 104 | 
             
                    ]
         | 
| 97 105 | 
             
                    return any(os.environ.get(var) for var in ci_indicators)
         | 
| 98 | 
            -
             | 
| 106 | 
            +
             | 
| 99 107 | 
             
                def _is_docker(self) -> bool:
         | 
| 100 108 | 
             
                    """Check if running inside Docker container."""
         | 
| 101 109 | 
             
                    return (
         | 
| 102 | 
            -
                        os.path.exists("/.dockerenv") | 
| 103 | 
            -
                        os.environ.get("KUBERNETES_SERVICE_HOST") is not None
         | 
| 110 | 
            +
                        os.path.exists("/.dockerenv")
         | 
| 111 | 
            +
                        or os.environ.get("KUBERNETES_SERVICE_HOST") is not None
         | 
| 104 112 | 
             
                    )
         | 
| 105 | 
            -
             | 
| 113 | 
            +
             | 
| 106 114 | 
             
                def _is_interactive(self) -> bool:
         | 
| 107 115 | 
             
                    """Check if running in interactive terminal."""
         | 
| 108 116 | 
             
                    return sys.stdin.isatty() and sys.stdout.isatty()
         | 
| 109 | 
            -
             | 
| 117 | 
            +
             | 
| 110 118 | 
             
                def _load_user_preference(self) -> Optional[DependencyMode]:
         | 
| 111 119 | 
             
                    """
         | 
| 112 120 | 
             
                    Load user preference from config file.
         | 
| 113 | 
            -
             | 
| 121 | 
            +
             | 
| 114 122 | 
             
                    Returns:
         | 
| 115 123 | 
             
                        User's preferred dependency mode or None
         | 
| 116 124 | 
             
                    """
         | 
| 117 125 | 
             
                    if not self.config_path.exists():
         | 
| 118 126 | 
             
                        return None
         | 
| 119 | 
            -
             | 
| 127 | 
            +
             | 
| 120 128 | 
             
                    try:
         | 
| 121 129 | 
             
                        # Try to load YAML config
         | 
| 122 130 | 
             
                        import yaml
         | 
| 131 | 
            +
             | 
| 123 132 | 
             
                        with open(self.config_path) as f:
         | 
| 124 133 | 
             
                            config = yaml.safe_load(f)
         | 
| 125 134 | 
             
                            mode_str = config.get("dependency_mode")
         | 
| @@ -127,217 +136,243 @@ class DependencyStrategy: | |
| 127 136 | 
             
                                return DependencyMode(mode_str)
         | 
| 128 137 | 
             
                    except Exception as e:
         | 
| 129 138 | 
             
                        logger.debug(f"Could not load config: {e}")
         | 
| 130 | 
            -
             | 
| 139 | 
            +
             | 
| 131 140 | 
             
                    return None
         | 
| 132 | 
            -
             | 
| 141 | 
            +
             | 
| 133 142 | 
             
                def should_check_now(self, cache_ttl: int = 86400) -> bool:
         | 
| 134 143 | 
             
                    """
         | 
| 135 144 | 
             
                    Determine if dependency check should run now based on cache.
         | 
| 136 | 
            -
             | 
| 145 | 
            +
             | 
| 137 146 | 
             
                    Args:
         | 
| 138 147 | 
             
                        cache_ttl: Cache time-to-live in seconds (default 24 hours)
         | 
| 139 | 
            -
             | 
| 148 | 
            +
             | 
| 140 149 | 
             
                    Returns:
         | 
| 141 150 | 
             
                        True if check should run, False if cached results are fresh
         | 
| 142 151 | 
             
                    """
         | 
| 143 152 | 
             
                    if self.mode == DependencyMode.OFF:
         | 
| 144 153 | 
             
                        return False
         | 
| 145 | 
            -
             | 
| 154 | 
            +
             | 
| 146 155 | 
             
                    if not self.cache_path.exists():
         | 
| 147 156 | 
             
                        return True
         | 
| 148 | 
            -
             | 
| 157 | 
            +
             | 
| 149 158 | 
             
                    try:
         | 
| 150 159 | 
             
                        with open(self.cache_path) as f:
         | 
| 151 160 | 
             
                            cache = json.load(f)
         | 
| 152 161 | 
             
                            last_check = datetime.fromisoformat(cache.get("timestamp", ""))
         | 
| 153 | 
            -
             | 
| 162 | 
            +
             | 
| 154 163 | 
             
                            # Check if cache is still valid
         | 
| 155 164 | 
             
                            if datetime.now() - last_check < timedelta(seconds=cache_ttl):
         | 
| 156 165 | 
             
                                logger.debug(f"Using cached dependency check from {last_check}")
         | 
| 157 166 | 
             
                                return False
         | 
| 158 | 
            -
             | 
| 167 | 
            +
             | 
| 159 168 | 
             
                    except Exception as e:
         | 
| 160 169 | 
             
                        logger.debug(f"Cache invalid or corrupted: {e}")
         | 
| 161 | 
            -
             | 
| 170 | 
            +
             | 
| 162 171 | 
             
                    return True
         | 
| 163 | 
            -
             | 
| 172 | 
            +
             | 
| 164 173 | 
             
                def cache_results(self, results: Dict[str, Any]) -> None:
         | 
| 165 174 | 
             
                    """
         | 
| 166 175 | 
             
                    Cache dependency check results.
         | 
| 167 | 
            -
             | 
| 176 | 
            +
             | 
| 168 177 | 
             
                    Args:
         | 
| 169 178 | 
             
                        results: Dependency check results to cache
         | 
| 170 179 | 
             
                    """
         | 
| 171 180 | 
             
                    try:
         | 
| 172 181 | 
             
                        self.cache_path.parent.mkdir(parents=True, exist_ok=True)
         | 
| 173 | 
            -
             | 
| 174 | 
            -
                        cache_data = {
         | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
                        }
         | 
| 178 | 
            -
                        
         | 
| 179 | 
            -
                        with open(self.cache_path, 'w') as f:
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                        cache_data = {"timestamp": datetime.now().isoformat(), "results": results}
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                        with open(self.cache_path, "w") as f:
         | 
| 180 186 | 
             
                            json.dump(cache_data, f, indent=2)
         | 
| 181 | 
            -
             | 
| 187 | 
            +
             | 
| 182 188 | 
             
                        logger.debug(f"Cached dependency results to {self.cache_path}")
         | 
| 183 | 
            -
             | 
| 189 | 
            +
             | 
| 184 190 | 
             
                    except Exception as e:
         | 
| 185 191 | 
             
                        logger.warning(f"Failed to cache results: {e}")
         | 
| 186 | 
            -
             | 
| 192 | 
            +
             | 
| 187 193 | 
             
                def get_cached_results(self) -> Optional[Dict[str, Any]]:
         | 
| 188 194 | 
             
                    """
         | 
| 189 195 | 
             
                    Get cached dependency check results if available.
         | 
| 190 | 
            -
             | 
| 196 | 
            +
             | 
| 191 197 | 
             
                    Returns:
         | 
| 192 198 | 
             
                        Cached results or None
         | 
| 193 199 | 
             
                    """
         | 
| 194 200 | 
             
                    if not self.cache_path.exists():
         | 
| 195 201 | 
             
                        return None
         | 
| 196 | 
            -
             | 
| 202 | 
            +
             | 
| 197 203 | 
             
                    try:
         | 
| 198 204 | 
             
                        with open(self.cache_path) as f:
         | 
| 199 205 | 
             
                            cache = json.load(f)
         | 
| 200 206 | 
             
                            return cache.get("results")
         | 
| 201 207 | 
             
                    except Exception:
         | 
| 202 208 | 
             
                        return None
         | 
| 203 | 
            -
             | 
| 209 | 
            +
             | 
| 204 210 | 
             
                def prompt_for_installation(self, missing_deps: list) -> str:
         | 
| 205 211 | 
             
                    """
         | 
| 206 212 | 
             
                    Prompt user for dependency installation preference.
         | 
| 207 | 
            -
             | 
| 213 | 
            +
             | 
| 208 214 | 
             
                    Args:
         | 
| 209 215 | 
             
                        missing_deps: List of missing dependencies
         | 
| 210 | 
            -
             | 
| 216 | 
            +
             | 
| 211 217 | 
             
                    Returns:
         | 
| 212 218 | 
             
                        User's choice: 'yes', 'no', 'always', 'never'
         | 
| 213 219 | 
             
                    """
         | 
| 214 220 | 
             
                    if not self._is_interactive():
         | 
| 215 | 
            -
                        return  | 
| 216 | 
            -
             | 
| 221 | 
            +
                        return "no"
         | 
| 222 | 
            +
             | 
| 217 223 | 
             
                    print(f"\n⚠️  Missing {len(missing_deps)} dependencies:")
         | 
| 218 224 | 
             
                    for dep in missing_deps[:5]:  # Show first 5
         | 
| 219 225 | 
             
                        print(f"  - {dep}")
         | 
| 220 226 | 
             
                    if len(missing_deps) > 5:
         | 
| 221 227 | 
             
                        print(f"  ... and {len(missing_deps) - 5} more")
         | 
| 222 | 
            -
             | 
| 228 | 
            +
             | 
| 223 229 | 
             
                    while True:
         | 
| 224 | 
            -
                         | 
| 225 | 
            -
             | 
| 226 | 
            -
                        if  | 
| 227 | 
            -
             | 
| 228 | 
            -
             | 
| 229 | 
            -
                             | 
| 230 | 
            -
             | 
| 230 | 
            +
                        sys.stdout.flush()  # Ensure prompt is displayed before input
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                        # Check if we're in a TTY environment for proper input handling
         | 
| 233 | 
            +
                        if not sys.stdin.isatty():
         | 
| 234 | 
            +
                            # In non-TTY environment (like pipes), use readline
         | 
| 235 | 
            +
                            print(
         | 
| 236 | 
            +
                                "\nInstall missing dependencies? [y/N/always/never]: ",
         | 
| 237 | 
            +
                                end="",
         | 
| 238 | 
            +
                                flush=True,
         | 
| 239 | 
            +
                            )
         | 
| 240 | 
            +
                            try:
         | 
| 241 | 
            +
                                response = sys.stdin.readline().strip().lower()
         | 
| 242 | 
            +
                                # Handle various line endings and control characters
         | 
| 243 | 
            +
                                response = response.replace("\r", "").replace("\n", "").strip()
         | 
| 244 | 
            +
                            except (EOFError, KeyboardInterrupt):
         | 
| 245 | 
            +
                                response = "n"
         | 
| 246 | 
            +
                        else:
         | 
| 247 | 
            +
                            # In TTY environment, use normal input()
         | 
| 248 | 
            +
                            try:
         | 
| 249 | 
            +
                                response = (
         | 
| 250 | 
            +
                                    input("\nInstall missing dependencies? [y/N/always/never]: ")
         | 
| 251 | 
            +
                                    .lower()
         | 
| 252 | 
            +
                                    .strip()
         | 
| 253 | 
            +
                                )
         | 
| 254 | 
            +
                            except (EOFError, KeyboardInterrupt):
         | 
| 255 | 
            +
                                response = "n"
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                        if response in ["y", "yes"]:
         | 
| 258 | 
            +
                            return "yes"
         | 
| 259 | 
            +
                        elif response in ["n", "no", ""]:
         | 
| 260 | 
            +
                            return "no"
         | 
| 261 | 
            +
                        elif response == "always":
         | 
| 231 262 | 
             
                            self._save_preference(DependencyMode.AUTO)
         | 
| 232 | 
            -
                            return  | 
| 233 | 
            -
                        elif response ==  | 
| 263 | 
            +
                            return "yes"
         | 
| 264 | 
            +
                        elif response == "never":
         | 
| 234 265 | 
             
                            self._save_preference(DependencyMode.OFF)
         | 
| 235 | 
            -
                            return  | 
| 266 | 
            +
                            return "no"
         | 
| 236 267 | 
             
                        else:
         | 
| 237 268 | 
             
                            print("Invalid choice. Please enter: y, n, always, or never")
         | 
| 238 | 
            -
             | 
| 269 | 
            +
             | 
| 239 270 | 
             
                def _save_preference(self, mode: DependencyMode) -> None:
         | 
| 240 271 | 
             
                    """
         | 
| 241 272 | 
             
                    Save user's dependency mode preference.
         | 
| 242 | 
            -
             | 
| 273 | 
            +
             | 
| 243 274 | 
             
                    Args:
         | 
| 244 275 | 
             
                        mode: The dependency mode to save
         | 
| 245 276 | 
             
                    """
         | 
| 246 277 | 
             
                    try:
         | 
| 247 278 | 
             
                        self.config_path.parent.mkdir(parents=True, exist_ok=True)
         | 
| 248 | 
            -
             | 
| 279 | 
            +
             | 
| 249 280 | 
             
                        # Load existing config or create new
         | 
| 250 281 | 
             
                        config = {}
         | 
| 251 282 | 
             
                        if self.config_path.exists():
         | 
| 252 283 | 
             
                            import yaml
         | 
| 284 | 
            +
             | 
| 253 285 | 
             
                            with open(self.config_path) as f:
         | 
| 254 286 | 
             
                                config = yaml.safe_load(f) or {}
         | 
| 255 | 
            -
             | 
| 287 | 
            +
             | 
| 256 288 | 
             
                        # Update dependency mode
         | 
| 257 | 
            -
                        config[ | 
| 258 | 
            -
             | 
| 289 | 
            +
                        config["dependency_mode"] = mode.value
         | 
| 290 | 
            +
             | 
| 259 291 | 
             
                        # Save config
         | 
| 260 292 | 
             
                        import yaml
         | 
| 261 | 
            -
             | 
| 293 | 
            +
             | 
| 294 | 
            +
                        with open(self.config_path, "w") as f:
         | 
| 262 295 | 
             
                            yaml.dump(config, f, default_flow_style=False)
         | 
| 263 | 
            -
             | 
| 296 | 
            +
             | 
| 264 297 | 
             
                        print(f"✓ Saved preference: {mode.value}")
         | 
| 265 | 
            -
             | 
| 298 | 
            +
             | 
| 266 299 | 
             
                    except Exception as e:
         | 
| 267 300 | 
             
                        logger.error(f"Failed to save preference: {e}")
         | 
| 268 301 |  | 
| 269 302 |  | 
| 270 | 
            -
            def get_smart_dependency_handler( | 
| 303 | 
            +
            def get_smart_dependency_handler(
         | 
| 304 | 
            +
                command: Optional[str] = None,
         | 
| 305 | 
            +
            ) -> Tuple[DependencyMode, DependencyStrategy]:
         | 
| 271 306 | 
             
                """
         | 
| 272 307 | 
             
                Get the appropriate dependency handler for the current context.
         | 
| 273 | 
            -
             | 
| 308 | 
            +
             | 
| 274 309 | 
             
                Args:
         | 
| 275 310 | 
             
                    command: The command being executed (e.g., 'run', 'agents')
         | 
| 276 | 
            -
             | 
| 311 | 
            +
             | 
| 277 312 | 
             
                Returns:
         | 
| 278 313 | 
             
                    Tuple of (mode, strategy) to use
         | 
| 279 314 | 
             
                """
         | 
| 280 315 | 
             
                strategy = DependencyStrategy()
         | 
| 281 | 
            -
             | 
| 316 | 
            +
             | 
| 282 317 | 
             
                # Override for specific commands
         | 
| 283 | 
            -
                if command ==  | 
| 318 | 
            +
                if command == "agents" and "deps-" in str(sys.argv):
         | 
| 284 319 | 
             
                    # If running agents deps-* commands, don't check automatically
         | 
| 285 320 | 
             
                    return (DependencyMode.OFF, strategy)
         | 
| 286 | 
            -
             | 
| 321 | 
            +
             | 
| 287 322 | 
             
                # Quick commands shouldn't check dependencies
         | 
| 288 | 
            -
                quick_commands = [ | 
| 323 | 
            +
                quick_commands = ["help", "version", "info", "tickets"]
         | 
| 289 324 | 
             
                if command in quick_commands:
         | 
| 290 325 | 
             
                    return (DependencyMode.OFF, strategy)
         | 
| 291 | 
            -
             | 
| 326 | 
            +
             | 
| 292 327 | 
             
                return (strategy.mode, strategy)
         | 
| 293 328 |  | 
| 294 329 |  | 
| 295 330 | 
             
            def lazy_check_agent_dependency(agent_id: str) -> bool:
         | 
| 296 331 | 
             
                """
         | 
| 297 332 | 
             
                Lazily check dependencies when a specific agent is invoked.
         | 
| 298 | 
            -
             | 
| 333 | 
            +
             | 
| 299 334 | 
             
                Args:
         | 
| 300 335 | 
             
                    agent_id: The agent being invoked
         | 
| 301 | 
            -
             | 
| 336 | 
            +
             | 
| 302 337 | 
             
                Returns:
         | 
| 303 338 | 
             
                    True if dependencies are satisfied or installed, False otherwise
         | 
| 304 339 | 
             
                """
         | 
| 305 340 | 
             
                from .agent_dependency_loader import AgentDependencyLoader
         | 
| 306 | 
            -
             | 
| 341 | 
            +
             | 
| 307 342 | 
             
                logger.debug(f"Lazy checking dependencies for agent: {agent_id}")
         | 
| 308 | 
            -
             | 
| 343 | 
            +
             | 
| 309 344 | 
             
                loader = AgentDependencyLoader(auto_install=False)
         | 
| 310 345 | 
             
                loader.discover_deployed_agents()
         | 
| 311 | 
            -
             | 
| 346 | 
            +
             | 
| 312 347 | 
             
                # Only check the specific agent
         | 
| 313 348 | 
             
                if agent_id not in loader.deployed_agents:
         | 
| 314 349 | 
             
                    return True  # Agent not deployed, no deps to check
         | 
| 315 | 
            -
             | 
| 350 | 
            +
             | 
| 316 351 | 
             
                loader.deployed_agents = {agent_id: loader.deployed_agents[agent_id]}
         | 
| 317 352 | 
             
                loader.load_agent_dependencies()
         | 
| 318 353 | 
             
                results = loader.analyze_dependencies()
         | 
| 319 | 
            -
             | 
| 320 | 
            -
                agent_results = results[ | 
| 321 | 
            -
                missing = agent_results.get( | 
| 322 | 
            -
             | 
| 354 | 
            +
             | 
| 355 | 
            +
                agent_results = results["agents"].get(agent_id, {})
         | 
| 356 | 
            +
                missing = agent_results.get("python", {}).get("missing", [])
         | 
| 357 | 
            +
             | 
| 323 358 | 
             
                if not missing:
         | 
| 324 359 | 
             
                    return True
         | 
| 325 | 
            -
             | 
| 360 | 
            +
             | 
| 326 361 | 
             
                # Get strategy for handling missing deps
         | 
| 327 362 | 
             
                strategy = DependencyStrategy()
         | 
| 328 | 
            -
             | 
| 363 | 
            +
             | 
| 329 364 | 
             
                if strategy.mode == DependencyMode.AUTO:
         | 
| 330 365 | 
             
                    logger.info(f"Auto-installing {len(missing)} dependencies for {agent_id}")
         | 
| 331 366 | 
             
                    success, _ = loader.install_missing_dependencies(missing)
         | 
| 332 367 | 
             
                    return success
         | 
| 333 | 
            -
             | 
| 368 | 
            +
             | 
| 334 369 | 
             
                elif strategy.mode == DependencyMode.INTERACTIVE:
         | 
| 335 370 | 
             
                    choice = strategy.prompt_for_installation(missing)
         | 
| 336 | 
            -
                    if choice in [ | 
| 371 | 
            +
                    if choice in ["yes"]:
         | 
| 337 372 | 
             
                        success, _ = loader.install_missing_dependencies(missing)
         | 
| 338 373 | 
             
                        return success
         | 
| 339 374 | 
             
                    return False
         | 
| 340 | 
            -
             | 
| 375 | 
            +
             | 
| 341 376 | 
             
                else:  # CHECK or OFF
         | 
| 342 377 | 
             
                    logger.warning(f"Agent {agent_id} missing {len(missing)} dependencies")
         | 
| 343 | 
            -
                    return False  # Proceed anyway
         | 
| 378 | 
            +
                    return False  # Proceed anyway
         |