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
| @@ -8,7 +8,6 @@ prompting is appropriate for dependency installation. | |
| 8 8 | 
             
            import os
         | 
| 9 9 | 
             
            import sys
         | 
| 10 10 | 
             
            from typing import Dict, Tuple
         | 
| 11 | 
            -
            import logging
         | 
| 12 11 |  | 
| 13 12 | 
             
            from ..core.logger import get_logger
         | 
| 14 13 |  | 
| @@ -18,36 +17,45 @@ logger = get_logger(__name__) | |
| 18 17 | 
             
            class EnvironmentContext:
         | 
| 19 18 | 
             
                """
         | 
| 20 19 | 
             
                Detects and analyzes the execution environment.
         | 
| 21 | 
            -
             | 
| 20 | 
            +
             | 
| 22 21 | 
             
                WHY: We need to know if we're in an environment where prompting makes sense.
         | 
| 23 22 | 
             
                Interactive prompting should only happen in TTY environments where a human
         | 
| 24 23 | 
             
                is present. CI/CD, Docker, and non-interactive contexts should skip prompts.
         | 
| 25 | 
            -
             | 
| 24 | 
            +
             | 
| 26 25 | 
             
                DESIGN DECISION: Use multiple indicators to detect environment type:
         | 
| 27 26 | 
             
                - TTY presence is the primary indicator for interactivity
         | 
| 28 27 | 
             
                - Environment variables help identify CI/CD and containerized environments
         | 
| 29 28 | 
             
                - Command-line flags can override automatic detection
         | 
| 30 29 | 
             
                """
         | 
| 31 | 
            -
             | 
| 30 | 
            +
             | 
| 32 31 | 
             
                # Known CI environment variables
         | 
| 33 32 | 
             
                CI_ENV_VARS = [
         | 
| 34 | 
            -
                     | 
| 35 | 
            -
                     | 
| 36 | 
            -
                     | 
| 37 | 
            -
                     | 
| 33 | 
            +
                    "CI",
         | 
| 34 | 
            +
                    "CONTINUOUS_INTEGRATION",
         | 
| 35 | 
            +
                    "GITHUB_ACTIONS",
         | 
| 36 | 
            +
                    "GITLAB_CI",
         | 
| 37 | 
            +
                    "JENKINS",
         | 
| 38 | 
            +
                    "TRAVIS",
         | 
| 39 | 
            +
                    "CIRCLECI",
         | 
| 40 | 
            +
                    "BUILDKITE",
         | 
| 41 | 
            +
                    "DRONE",
         | 
| 42 | 
            +
                    "TEAMCITY_VERSION",
         | 
| 43 | 
            +
                    "TF_BUILD",
         | 
| 44 | 
            +
                    "CODEBUILD_BUILD_ID",
         | 
| 45 | 
            +
                    "BITBUCKET_BUILD_NUMBER",
         | 
| 38 46 | 
             
                ]
         | 
| 39 | 
            -
             | 
| 47 | 
            +
             | 
| 40 48 | 
             
                # Docker/container indicators
         | 
| 41 49 | 
             
                CONTAINER_INDICATORS = [
         | 
| 42 | 
            -
                     | 
| 43 | 
            -
                     | 
| 50 | 
            +
                    "/.dockerenv",  # Docker creates this file
         | 
| 51 | 
            +
                    "/run/.containerenv",  # Podman creates this file
         | 
| 44 52 | 
             
                ]
         | 
| 45 | 
            -
             | 
| 53 | 
            +
             | 
| 46 54 | 
             
                @classmethod
         | 
| 47 55 | 
             
                def detect_execution_context(cls) -> Dict[str, bool]:
         | 
| 48 56 | 
             
                    """
         | 
| 49 57 | 
             
                    Detect the current execution context.
         | 
| 50 | 
            -
             | 
| 58 | 
            +
             | 
| 51 59 | 
             
                    Returns:
         | 
| 52 60 | 
             
                        Dictionary with context indicators:
         | 
| 53 61 | 
             
                        - is_tty: True if running in a terminal with TTY
         | 
| @@ -57,54 +65,58 @@ class EnvironmentContext: | |
| 57 65 | 
             
                        - is_automated: True if running in automated context (CI or scheduled)
         | 
| 58 66 | 
             
                    """
         | 
| 59 67 | 
             
                    context = {
         | 
| 60 | 
            -
                         | 
| 61 | 
            -
                         | 
| 62 | 
            -
                         | 
| 63 | 
            -
                         | 
| 64 | 
            -
                         | 
| 65 | 
            -
                         | 
| 66 | 
            -
                         | 
| 68 | 
            +
                        "is_tty": cls._detect_tty(),
         | 
| 69 | 
            +
                        "is_ci": cls._detect_ci(),
         | 
| 70 | 
            +
                        "is_docker": cls._detect_docker(),
         | 
| 71 | 
            +
                        "is_interactive": False,
         | 
| 72 | 
            +
                        "is_automated": False,
         | 
| 73 | 
            +
                        "is_jupyter": cls._detect_jupyter(),
         | 
| 74 | 
            +
                        "is_ssh": cls._detect_ssh(),
         | 
| 67 75 | 
             
                    }
         | 
| 68 | 
            -
             | 
| 76 | 
            +
             | 
| 69 77 | 
             
                    # Determine if we're in an automated context
         | 
| 70 | 
            -
                    context[ | 
| 71 | 
            -
             | 
| 78 | 
            +
                    context["is_automated"] = context["is_ci"] or cls._detect_automated()
         | 
| 79 | 
            +
             | 
| 72 80 | 
             
                    # Interactive if TTY is available and not in automated context
         | 
| 73 | 
            -
                    context[ | 
| 74 | 
            -
                        context[ | 
| 75 | 
            -
                        not context[ | 
| 76 | 
            -
                        not context[ | 
| 81 | 
            +
                    context["is_interactive"] = (
         | 
| 82 | 
            +
                        context["is_tty"]
         | 
| 83 | 
            +
                        and not context["is_automated"]
         | 
| 84 | 
            +
                        and not context["is_docker"]  # Docker usually non-interactive
         | 
| 77 85 | 
             
                    )
         | 
| 78 | 
            -
             | 
| 86 | 
            +
             | 
| 79 87 | 
             
                    logger.debug(f"Environment context detected: {context}")
         | 
| 80 88 | 
             
                    return context
         | 
| 81 | 
            -
             | 
| 89 | 
            +
             | 
| 82 90 | 
             
                @classmethod
         | 
| 83 91 | 
             
                def _detect_tty(cls) -> bool:
         | 
| 84 92 | 
             
                    """
         | 
| 85 93 | 
             
                    Detect if we have a TTY (terminal) available.
         | 
| 86 | 
            -
             | 
| 94 | 
            +
             | 
| 87 95 | 
             
                    WHY: TTY presence is the most reliable indicator that a human
         | 
| 88 96 | 
             
                    is present and can respond to prompts.
         | 
| 89 97 | 
             
                    """
         | 
| 90 98 | 
             
                    try:
         | 
| 91 99 | 
             
                        # Check if stdin is a terminal
         | 
| 92 | 
            -
                        has_stdin_tty =  | 
| 93 | 
            -
             | 
| 100 | 
            +
                        has_stdin_tty = (
         | 
| 101 | 
            +
                            sys.stdin.isatty() if hasattr(sys.stdin, "isatty") else False
         | 
| 102 | 
            +
                        )
         | 
| 103 | 
            +
             | 
| 94 104 | 
             
                        # Check if stdout is a terminal (for output)
         | 
| 95 | 
            -
                        has_stdout_tty =  | 
| 96 | 
            -
             | 
| 105 | 
            +
                        has_stdout_tty = (
         | 
| 106 | 
            +
                            sys.stdout.isatty() if hasattr(sys.stdout, "isatty") else False
         | 
| 107 | 
            +
                        )
         | 
| 108 | 
            +
             | 
| 97 109 | 
             
                        # Both should be TTY for interactive use
         | 
| 98 110 | 
             
                        return has_stdin_tty and has_stdout_tty
         | 
| 99 111 | 
             
                    except Exception as e:
         | 
| 100 112 | 
             
                        logger.debug(f"TTY detection failed: {e}")
         | 
| 101 113 | 
             
                        return False
         | 
| 102 | 
            -
             | 
| 114 | 
            +
             | 
| 103 115 | 
             
                @classmethod
         | 
| 104 116 | 
             
                def _detect_ci(cls) -> bool:
         | 
| 105 117 | 
             
                    """
         | 
| 106 118 | 
             
                    Detect if running in a CI/CD environment.
         | 
| 107 | 
            -
             | 
| 119 | 
            +
             | 
| 108 120 | 
             
                    WHY: CI environments should never prompt for user input.
         | 
| 109 121 | 
             
                    They need to run fully automated without human intervention.
         | 
| 110 122 | 
             
                    """
         | 
| @@ -113,18 +125,18 @@ class EnvironmentContext: | |
| 113 125 | 
             
                        if os.environ.get(var):
         | 
| 114 126 | 
             
                            logger.debug(f"CI environment detected via {var}={os.environ.get(var)}")
         | 
| 115 127 | 
             
                            return True
         | 
| 116 | 
            -
             | 
| 128 | 
            +
             | 
| 117 129 | 
             
                    # Additional heuristics for CI detection
         | 
| 118 | 
            -
                    if os.environ.get( | 
| 130 | 
            +
                    if os.environ.get("BUILD_ID") or os.environ.get("BUILD_NUMBER"):
         | 
| 119 131 | 
             
                        return True
         | 
| 120 | 
            -
             | 
| 132 | 
            +
             | 
| 121 133 | 
             
                    return False
         | 
| 122 | 
            -
             | 
| 134 | 
            +
             | 
| 123 135 | 
             
                @classmethod
         | 
| 124 136 | 
             
                def _detect_docker(cls) -> bool:
         | 
| 125 137 | 
             
                    """
         | 
| 126 138 | 
             
                    Detect if running inside a Docker container.
         | 
| 127 | 
            -
             | 
| 139 | 
            +
             | 
| 128 140 | 
             
                    WHY: Docker containers typically run non-interactively,
         | 
| 129 141 | 
             
                    and prompting for input often doesn't make sense.
         | 
| 130 142 | 
             
                    """
         | 
| @@ -133,88 +145,86 @@ class EnvironmentContext: | |
| 133 145 | 
             
                        if os.path.exists(indicator_file):
         | 
| 134 146 | 
             
                            logger.debug(f"Container detected via {indicator_file}")
         | 
| 135 147 | 
             
                            return True
         | 
| 136 | 
            -
             | 
| 148 | 
            +
             | 
| 137 149 | 
             
                    # Check for container-related environment variables
         | 
| 138 | 
            -
                    if os.environ.get( | 
| 150 | 
            +
                    if os.environ.get("KUBERNETES_SERVICE_HOST"):
         | 
| 139 151 | 
             
                        return True
         | 
| 140 | 
            -
             | 
| 152 | 
            +
             | 
| 141 153 | 
             
                    # Check cgroup for docker/containerd references
         | 
| 142 154 | 
             
                    try:
         | 
| 143 | 
            -
                        with open( | 
| 155 | 
            +
                        with open("/proc/1/cgroup", "r") as f:
         | 
| 144 156 | 
             
                            cgroup_content = f.read()
         | 
| 145 | 
            -
                            if  | 
| 157 | 
            +
                            if "docker" in cgroup_content or "containerd" in cgroup_content:
         | 
| 146 158 | 
             
                                return True
         | 
| 147 159 | 
             
                    except (FileNotFoundError, PermissionError):
         | 
| 148 160 | 
             
                        pass
         | 
| 149 | 
            -
             | 
| 161 | 
            +
             | 
| 150 162 | 
             
                    return False
         | 
| 151 | 
            -
             | 
| 163 | 
            +
             | 
| 152 164 | 
             
                @classmethod
         | 
| 153 165 | 
             
                def _detect_automated(cls) -> bool:
         | 
| 154 166 | 
             
                    """
         | 
| 155 167 | 
             
                    Detect if running in an automated context (cron, systemd, etc).
         | 
| 156 | 
            -
             | 
| 168 | 
            +
             | 
| 157 169 | 
             
                    WHY: Automated scripts should not prompt for input even if
         | 
| 158 170 | 
             
                    they technically have TTY access.
         | 
| 159 171 | 
             
                    """
         | 
| 160 172 | 
             
                    # Check for cron execution
         | 
| 161 | 
            -
                    if os.environ.get( | 
| 173 | 
            +
                    if os.environ.get("CRON") or not os.environ.get("TERM"):
         | 
| 162 174 | 
             
                        return True
         | 
| 163 | 
            -
             | 
| 175 | 
            +
             | 
| 164 176 | 
             
                    # Check for systemd service
         | 
| 165 | 
            -
                    if os.environ.get( | 
| 177 | 
            +
                    if os.environ.get("INVOCATION_ID"):  # systemd sets this
         | 
| 166 178 | 
             
                        return True
         | 
| 167 | 
            -
             | 
| 179 | 
            +
             | 
| 168 180 | 
             
                    return False
         | 
| 169 | 
            -
             | 
| 181 | 
            +
             | 
| 170 182 | 
             
                @classmethod
         | 
| 171 183 | 
             
                def _detect_jupyter(cls) -> bool:
         | 
| 172 184 | 
             
                    """
         | 
| 173 185 | 
             
                    Detect if running in Jupyter notebook/lab.
         | 
| 174 | 
            -
             | 
| 186 | 
            +
             | 
| 175 187 | 
             
                    WHY: Jupyter has its own interaction model and standard
         | 
| 176 188 | 
             
                    terminal prompts don't work well.
         | 
| 177 189 | 
             
                    """
         | 
| 178 190 | 
             
                    try:
         | 
| 179 191 | 
             
                        # Check for IPython/Jupyter
         | 
| 180 | 
            -
                        get_ipython = globals().get( | 
| 192 | 
            +
                        get_ipython = globals().get("get_ipython")
         | 
| 181 193 | 
             
                        if get_ipython is not None:
         | 
| 182 194 | 
             
                            return True
         | 
| 183 195 | 
             
                    except:
         | 
| 184 196 | 
             
                        pass
         | 
| 185 | 
            -
             | 
| 197 | 
            +
             | 
| 186 198 | 
             
                    # Check for Jupyter-specific environment variables
         | 
| 187 | 
            -
                    if  | 
| 199 | 
            +
                    if "JPY_PARENT_PID" in os.environ:
         | 
| 188 200 | 
             
                        return True
         | 
| 189 | 
            -
             | 
| 201 | 
            +
             | 
| 190 202 | 
             
                    return False
         | 
| 191 | 
            -
             | 
| 203 | 
            +
             | 
| 192 204 | 
             
                @classmethod
         | 
| 193 205 | 
             
                def _detect_ssh(cls) -> bool:
         | 
| 194 206 | 
             
                    """
         | 
| 195 207 | 
             
                    Detect if running over SSH.
         | 
| 196 | 
            -
             | 
| 208 | 
            +
             | 
| 197 209 | 
             
                    WHY: SSH sessions might have TTY but prompting behavior
         | 
| 198 210 | 
             
                    should be more conservative.
         | 
| 199 211 | 
             
                    """
         | 
| 200 | 
            -
                    return  | 
| 201 | 
            -
             | 
| 212 | 
            +
                    return "SSH_CLIENT" in os.environ or "SSH_TTY" in os.environ
         | 
| 213 | 
            +
             | 
| 202 214 | 
             
                @classmethod
         | 
| 203 215 | 
             
                def should_prompt_for_dependencies(
         | 
| 204 | 
            -
                    cls,
         | 
| 205 | 
            -
                    force_prompt: bool = False,
         | 
| 206 | 
            -
                    force_skip: bool = False
         | 
| 216 | 
            +
                    cls, force_prompt: bool = False, force_skip: bool = False
         | 
| 207 217 | 
             
                ) -> Tuple[bool, str]:
         | 
| 208 218 | 
             
                    """
         | 
| 209 219 | 
             
                    Determine if we should prompt for dependency installation.
         | 
| 210 | 
            -
             | 
| 220 | 
            +
             | 
| 211 221 | 
             
                    Args:
         | 
| 212 222 | 
             
                        force_prompt: Force prompting regardless of environment
         | 
| 213 223 | 
             
                        force_skip: Force skipping prompts regardless of environment
         | 
| 214 | 
            -
             | 
| 224 | 
            +
             | 
| 215 225 | 
             
                    Returns:
         | 
| 216 226 | 
             
                        Tuple of (should_prompt, reason_message)
         | 
| 217 | 
            -
             | 
| 227 | 
            +
             | 
| 218 228 | 
             
                    WHY: This is the main decision point for the smart dependency system.
         | 
| 219 229 | 
             
                    We want to prompt only when it makes sense and is safe to do so.
         | 
| 220 230 | 
             
                    """
         | 
| @@ -223,67 +233,67 @@ class EnvironmentContext: | |
| 223 233 | 
             
                        return False, "Prompting disabled by --no-prompt flag"
         | 
| 224 234 | 
             
                    if force_prompt:
         | 
| 225 235 | 
             
                        return True, "Prompting forced by --prompt flag"
         | 
| 226 | 
            -
             | 
| 236 | 
            +
             | 
| 227 237 | 
             
                    # Get environment context
         | 
| 228 238 | 
             
                    context = cls.detect_execution_context()
         | 
| 229 | 
            -
             | 
| 239 | 
            +
             | 
| 230 240 | 
             
                    # Decision logic with clear reasoning
         | 
| 231 | 
            -
                    if not context[ | 
| 241 | 
            +
                    if not context["is_tty"]:
         | 
| 232 242 | 
             
                        return False, "No TTY available for interactive prompts"
         | 
| 233 | 
            -
             | 
| 234 | 
            -
                    if context[ | 
| 243 | 
            +
             | 
| 244 | 
            +
                    if context["is_ci"]:
         | 
| 235 245 | 
             
                        return False, "Running in CI environment - prompts disabled"
         | 
| 236 | 
            -
             | 
| 237 | 
            -
                    if context[ | 
| 246 | 
            +
             | 
| 247 | 
            +
                    if context["is_docker"]:
         | 
| 238 248 | 
             
                        return False, "Running in Docker container - prompts disabled"
         | 
| 239 | 
            -
             | 
| 240 | 
            -
                    if context[ | 
| 249 | 
            +
             | 
| 250 | 
            +
                    if context["is_automated"]:
         | 
| 241 251 | 
             
                        return False, "Running in automated context - prompts disabled"
         | 
| 242 | 
            -
             | 
| 243 | 
            -
                    if context[ | 
| 252 | 
            +
             | 
| 253 | 
            +
                    if context["is_jupyter"]:
         | 
| 244 254 | 
             
                        return False, "Running in Jupyter - standard prompts not supported"
         | 
| 245 | 
            -
             | 
| 246 | 
            -
                    if context[ | 
| 255 | 
            +
             | 
| 256 | 
            +
                    if context["is_interactive"]:
         | 
| 247 257 | 
             
                        return True, "Interactive TTY environment detected"
         | 
| 248 | 
            -
             | 
| 258 | 
            +
             | 
| 249 259 | 
             
                    # Default to not prompting if uncertain
         | 
| 250 260 | 
             
                    return False, "Environment type uncertain - prompts disabled for safety"
         | 
| 251 | 
            -
             | 
| 261 | 
            +
             | 
| 252 262 | 
             
                @classmethod
         | 
| 253 263 | 
             
                def get_environment_summary(cls) -> str:
         | 
| 254 264 | 
             
                    """
         | 
| 255 265 | 
             
                    Get a human-readable summary of the environment.
         | 
| 256 | 
            -
             | 
| 266 | 
            +
             | 
| 257 267 | 
             
                    Returns:
         | 
| 258 268 | 
             
                        String describing the detected environment.
         | 
| 259 269 | 
             
                    """
         | 
| 260 270 | 
             
                    context = cls.detect_execution_context()
         | 
| 261 | 
            -
             | 
| 271 | 
            +
             | 
| 262 272 | 
             
                    env_types = []
         | 
| 263 | 
            -
                    if context[ | 
| 273 | 
            +
                    if context["is_ci"]:
         | 
| 264 274 | 
             
                        env_types.append("CI/CD")
         | 
| 265 | 
            -
                    if context[ | 
| 275 | 
            +
                    if context["is_docker"]:
         | 
| 266 276 | 
             
                        env_types.append("Docker")
         | 
| 267 | 
            -
                    if context[ | 
| 277 | 
            +
                    if context["is_jupyter"]:
         | 
| 268 278 | 
             
                        env_types.append("Jupyter")
         | 
| 269 | 
            -
                    if context[ | 
| 279 | 
            +
                    if context["is_ssh"]:
         | 
| 270 280 | 
             
                        env_types.append("SSH")
         | 
| 271 | 
            -
                    if context[ | 
| 281 | 
            +
                    if context["is_automated"]:
         | 
| 272 282 | 
             
                        env_types.append("Automated")
         | 
| 273 | 
            -
             | 
| 283 | 
            +
             | 
| 274 284 | 
             
                    if not env_types:
         | 
| 275 | 
            -
                        if context[ | 
| 285 | 
            +
                        if context["is_interactive"]:
         | 
| 276 286 | 
             
                            env_types.append("Interactive Terminal")
         | 
| 277 287 | 
             
                        else:
         | 
| 278 288 | 
             
                            env_types.append("Non-interactive")
         | 
| 279 | 
            -
             | 
| 289 | 
            +
             | 
| 280 290 | 
             
                    return f"Environment: {', '.join(env_types)} (TTY: {context['is_tty']})"
         | 
| 281 291 |  | 
| 282 292 |  | 
| 283 293 | 
             
            def detect_execution_context() -> Dict[str, bool]:
         | 
| 284 294 | 
             
                """
         | 
| 285 295 | 
             
                Convenience function to detect execution context.
         | 
| 286 | 
            -
             | 
| 296 | 
            +
             | 
| 287 297 | 
             
                Returns:
         | 
| 288 298 | 
             
                    Dictionary with context indicators.
         | 
| 289 299 | 
             
                """
         | 
| @@ -291,20 +301,18 @@ def detect_execution_context() -> Dict[str, bool]: | |
| 291 301 |  | 
| 292 302 |  | 
| 293 303 | 
             
            def should_prompt_for_dependencies(
         | 
| 294 | 
            -
                force_prompt: bool = False,
         | 
| 295 | 
            -
                force_skip: bool = False
         | 
| 304 | 
            +
                force_prompt: bool = False, force_skip: bool = False
         | 
| 296 305 | 
             
            ) -> Tuple[bool, str]:
         | 
| 297 306 | 
             
                """
         | 
| 298 307 | 
             
                Convenience function to determine if prompting is appropriate.
         | 
| 299 | 
            -
             | 
| 308 | 
            +
             | 
| 300 309 | 
             
                Args:
         | 
| 301 310 | 
             
                    force_prompt: Force prompting regardless of environment
         | 
| 302 311 | 
             
                    force_skip: Force skipping prompts regardless of environment
         | 
| 303 | 
            -
             | 
| 312 | 
            +
             | 
| 304 313 | 
             
                Returns:
         | 
| 305 314 | 
             
                    Tuple of (should_prompt, reason_message)
         | 
| 306 315 | 
             
                """
         | 
| 307 316 | 
             
                return EnvironmentContext.should_prompt_for_dependencies(
         | 
| 308 | 
            -
                    force_prompt=force_prompt,
         | 
| 309 | 
            -
             | 
| 310 | 
            -
                )
         | 
| 317 | 
            +
                    force_prompt=force_prompt, force_skip=force_skip
         | 
| 318 | 
            +
                )
         |