claude-mpm 3.9.11__py3-none-any.whl → 4.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/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 +1 -1
- 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 +203 -81
- 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 +305 -197
- 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 +104 -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/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 +74 -70
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
- 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 +120 -54
- 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 +223 -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 +145 -65
- 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 +170 -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.3.dist-info}/METADATA +27 -1
- claude_mpm-4.0.3.dist-info/RECORD +402 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.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.3.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
| @@ -0,0 +1,160 @@ | |
| 1 | 
            +
            """Configuration checking functionality for run commands.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This module provides configuration health checking and memory validation.
         | 
| 4 | 
            +
            Extracted from run.py to reduce complexity and improve maintainability.
         | 
| 5 | 
            +
            """
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            import os
         | 
| 8 | 
            +
            from pathlib import Path
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            from ...core.config import Config
         | 
| 11 | 
            +
             | 
| 12 | 
            +
             | 
| 13 | 
            +
            class RunConfigChecker:
         | 
| 14 | 
            +
                """Handles configuration checking for run commands."""
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def __init__(self, logger):
         | 
| 17 | 
            +
                    """Initialize the config checker."""
         | 
| 18 | 
            +
                    self.logger = logger
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def check_claude_json_memory(self, args):
         | 
| 21 | 
            +
                    """Check .claude.json file size and warn about memory issues.
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    WHY: Large .claude.json files (>500KB) cause significant memory issues when
         | 
| 24 | 
            +
                    using --resume. Claude Desktop loads the entire conversation history into
         | 
| 25 | 
            +
                    memory, leading to 2GB+ memory consumption.
         | 
| 26 | 
            +
                    """
         | 
| 27 | 
            +
                    try:
         | 
| 28 | 
            +
                        # Only check if --resume is being used
         | 
| 29 | 
            +
                        if not getattr(args, "resume", False):
         | 
| 30 | 
            +
                            return
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                        claude_json_path = Path.cwd() / ".claude.json"
         | 
| 33 | 
            +
                        if not claude_json_path.exists():
         | 
| 34 | 
            +
                            self.logger.debug("No .claude.json file found")
         | 
| 35 | 
            +
                            return
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                        file_size = claude_json_path.stat().st_size
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                        def format_size(size_bytes):
         | 
| 40 | 
            +
                            """Format file size in human readable format."""
         | 
| 41 | 
            +
                            if size_bytes < 1024:
         | 
| 42 | 
            +
                                return f"{size_bytes} B"
         | 
| 43 | 
            +
                            elif size_bytes < 1024 * 1024:
         | 
| 44 | 
            +
                                return f"{size_bytes / 1024:.1f} KB"
         | 
| 45 | 
            +
                            else:
         | 
| 46 | 
            +
                                return f"{size_bytes / (1024 * 1024):.1f} MB"
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                        # Warn if file is larger than 500KB
         | 
| 49 | 
            +
                        if file_size > 500 * 1024:  # 500KB threshold
         | 
| 50 | 
            +
                            print(
         | 
| 51 | 
            +
                                f"\n⚠️  WARNING: Large .claude.json file detected ({format_size(file_size)})"
         | 
| 52 | 
            +
                            )
         | 
| 53 | 
            +
                            print("   This may cause memory issues when using --resume")
         | 
| 54 | 
            +
                            print(
         | 
| 55 | 
            +
                                "   💡 Consider running 'claude-mpm cleanup-memory' to archive old conversations\n"
         | 
| 56 | 
            +
                            )
         | 
| 57 | 
            +
                            # Just warn, don't block execution
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                        self.logger.info(f".claude.json size: {format_size(file_size)}")
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    except Exception as e:
         | 
| 62 | 
            +
                        self.logger.warning(f"Failed to check .claude.json size: {e}")
         | 
| 63 | 
            +
                        # Just warn, don't block execution
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def check_configuration_health(self):
         | 
| 66 | 
            +
                    """Check configuration health at startup and warn about issues.
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    WHY: Configuration errors can cause silent failures, especially for response
         | 
| 69 | 
            +
                    logging. This function proactively checks configuration at startup and warns
         | 
| 70 | 
            +
                    users about any issues, providing actionable guidance.
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    DESIGN DECISIONS:
         | 
| 73 | 
            +
                    - Non-blocking: Issues are logged as warnings, not errors
         | 
| 74 | 
            +
                    - Actionable: Provides specific commands to fix issues
         | 
| 75 | 
            +
                    - Focused: Only checks critical configuration that affects runtime
         | 
| 76 | 
            +
                    """
         | 
| 77 | 
            +
                    try:
         | 
| 78 | 
            +
                        config = Config()
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                        # Check response logging configuration
         | 
| 81 | 
            +
                        response_logging = config.get("response_logging", {})
         | 
| 82 | 
            +
                        if response_logging.get("enabled", False):
         | 
| 83 | 
            +
                            log_dir = response_logging.get("directory")
         | 
| 84 | 
            +
                            if log_dir:
         | 
| 85 | 
            +
                                log_path = Path(log_dir)
         | 
| 86 | 
            +
                                if not log_path.exists():
         | 
| 87 | 
            +
                                    self.logger.warning(
         | 
| 88 | 
            +
                                        f"Response logging directory does not exist: {log_path}"
         | 
| 89 | 
            +
                                    )
         | 
| 90 | 
            +
                                    print(f"⚠️  Response logging directory missing: {log_path}")
         | 
| 91 | 
            +
                                    print(f"   Run: mkdir -p {log_path}")
         | 
| 92 | 
            +
                                elif not log_path.is_dir():
         | 
| 93 | 
            +
                                    self.logger.warning(
         | 
| 94 | 
            +
                                        f"Response logging path is not a directory: {log_path}"
         | 
| 95 | 
            +
                                    )
         | 
| 96 | 
            +
                                    print(
         | 
| 97 | 
            +
                                        f"⚠️  Response logging path is not a directory: {log_path}"
         | 
| 98 | 
            +
                                    )
         | 
| 99 | 
            +
                                elif not os.access(log_path, os.W_OK):
         | 
| 100 | 
            +
                                    self.logger.warning(
         | 
| 101 | 
            +
                                        f"Response logging directory is not writable: {log_path}"
         | 
| 102 | 
            +
                                    )
         | 
| 103 | 
            +
                                    print(
         | 
| 104 | 
            +
                                        f"⚠️  Response logging directory is not writable: {log_path}"
         | 
| 105 | 
            +
                                    )
         | 
| 106 | 
            +
                                    print(f"   Run: chmod 755 {log_path}")
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                        # Check agent deployment configuration
         | 
| 109 | 
            +
                        agent_deployment = config.get("agent_deployment", {})
         | 
| 110 | 
            +
                        excluded_agents = agent_deployment.get("excluded_agents", [])
         | 
| 111 | 
            +
                        if excluded_agents:
         | 
| 112 | 
            +
                            self.logger.info(f"Agent exclusions configured: {excluded_agents}")
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                        # Check memory management configuration
         | 
| 115 | 
            +
                        memory_config = config.get("memory_management", {})
         | 
| 116 | 
            +
                        if memory_config.get("auto_cleanup", False):
         | 
| 117 | 
            +
                            cleanup_threshold = memory_config.get("cleanup_threshold_mb", 100)
         | 
| 118 | 
            +
                            if cleanup_threshold < 50:
         | 
| 119 | 
            +
                                self.logger.warning(
         | 
| 120 | 
            +
                                    f"Memory cleanup threshold very low: {cleanup_threshold}MB"
         | 
| 121 | 
            +
                                )
         | 
| 122 | 
            +
                                print(
         | 
| 123 | 
            +
                                    f"⚠️  Memory cleanup threshold is very low: {cleanup_threshold}MB"
         | 
| 124 | 
            +
                                )
         | 
| 125 | 
            +
                                print(f"   Consider increasing to at least 50MB")
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                        # Check for common configuration issues
         | 
| 128 | 
            +
                        self._check_common_config_issues(config)
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                    except Exception as e:
         | 
| 131 | 
            +
                        self.logger.warning(f"Configuration health check failed: {e}")
         | 
| 132 | 
            +
                        # Don't block execution for config check failures
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def _check_common_config_issues(self, config):
         | 
| 135 | 
            +
                    """Check for common configuration issues."""
         | 
| 136 | 
            +
                    try:
         | 
| 137 | 
            +
                        import os
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                        # Check if config file exists and is readable
         | 
| 140 | 
            +
                        config_file = config.config_file
         | 
| 141 | 
            +
                        if config_file and Path(config_file).exists():
         | 
| 142 | 
            +
                            if not os.access(config_file, os.R_OK):
         | 
| 143 | 
            +
                                self.logger.warning(
         | 
| 144 | 
            +
                                    f"Configuration file is not readable: {config_file}"
         | 
| 145 | 
            +
                                )
         | 
| 146 | 
            +
                                print(f"⚠️  Configuration file is not readable: {config_file}")
         | 
| 147 | 
            +
                                print(f"   Run: chmod 644 {config_file}")
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                        # Check for deprecated configuration keys
         | 
| 150 | 
            +
                        deprecated_keys = ["legacy_mode", "old_agent_format", "deprecated_logging"]
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                        for key in deprecated_keys:
         | 
| 153 | 
            +
                            if config.get(key) is not None:
         | 
| 154 | 
            +
                                self.logger.warning(f"Deprecated configuration key found: {key}")
         | 
| 155 | 
            +
                                print(f"⚠️  Deprecated configuration key: {key}")
         | 
| 156 | 
            +
                                print(f"   Consider removing this key from your configuration")
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                    except Exception as e:
         | 
| 159 | 
            +
                        self.logger.debug(f"Common config issues check failed: {e}")
         | 
| 160 | 
            +
                        # Don't propagate errors from this check
         | 
| @@ -0,0 +1,235 @@ | |
| 1 | 
            +
            """Socket.IO monitoring functionality for run commands.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This module provides Socket.IO server management and monitoring dashboard functionality.
         | 
| 4 | 
            +
            Extracted from run.py to reduce complexity and improve maintainability.
         | 
| 5 | 
            +
            """
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            import os
         | 
| 8 | 
            +
            import subprocess
         | 
| 9 | 
            +
            import sys
         | 
| 10 | 
            +
            import time
         | 
| 11 | 
            +
            import webbrowser
         | 
| 12 | 
            +
            from pathlib import Path
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            from ...core.unified_paths import get_package_root
         | 
| 15 | 
            +
            from ...services.port_manager import PortManager
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
            class SocketIOMonitor:
         | 
| 19 | 
            +
                """Handles Socket.IO monitoring and server management."""
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def __init__(self, logger):
         | 
| 22 | 
            +
                    """Initialize the Socket.IO monitor."""
         | 
| 23 | 
            +
                    self.logger = logger
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def launch_monitor(self, port):
         | 
| 26 | 
            +
                    """
         | 
| 27 | 
            +
                    Launch the Socket.IO monitoring dashboard using static HTML file.
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    Returns:
         | 
| 30 | 
            +
                        tuple: (success: bool, browser_opened: bool)
         | 
| 31 | 
            +
                    """
         | 
| 32 | 
            +
                    try:
         | 
| 33 | 
            +
                        # Verify Socket.IO dependencies are available
         | 
| 34 | 
            +
                        try:
         | 
| 35 | 
            +
                            import aiohttp
         | 
| 36 | 
            +
                            import engineio
         | 
| 37 | 
            +
                            import socketio
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                            self.logger.debug("Socket.IO dependencies verified")
         | 
| 40 | 
            +
                        except ImportError as e:
         | 
| 41 | 
            +
                            self.logger.error(f"Socket.IO dependencies not available: {e}")
         | 
| 42 | 
            +
                            print(f"❌ Socket.IO dependencies missing: {e}")
         | 
| 43 | 
            +
                            print("  This is unexpected - dependency installation may have failed.")
         | 
| 44 | 
            +
                            return False, False
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                        print(f"🚀 Setting up Socket.IO monitor...")
         | 
| 47 | 
            +
                        self.logger.info(f"Launching Socket.IO monitor (requested port: {port})")
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                        # First, check if there's already a running SocketIO server
         | 
| 50 | 
            +
                        port_manager = PortManager()
         | 
| 51 | 
            +
                        port_manager.cleanup_dead_instances()
         | 
| 52 | 
            +
                        active_instances = port_manager.list_active_instances()
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                        if active_instances:
         | 
| 55 | 
            +
                            # Use the first active instance (prefer port 8765 if available)
         | 
| 56 | 
            +
                            socketio_port = None
         | 
| 57 | 
            +
                            for instance in active_instances:
         | 
| 58 | 
            +
                                if instance.get("port") == 8765:
         | 
| 59 | 
            +
                                    socketio_port = 8765
         | 
| 60 | 
            +
                                    break
         | 
| 61 | 
            +
                            if not socketio_port:
         | 
| 62 | 
            +
                                socketio_port = active_instances[0].get("port")
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                            print(f"🔍 Found existing SocketIO server on port {socketio_port}")
         | 
| 65 | 
            +
                            server_running = True
         | 
| 66 | 
            +
                        else:
         | 
| 67 | 
            +
                            # No existing server, use requested port
         | 
| 68 | 
            +
                            socketio_port = port
         | 
| 69 | 
            +
                            server_running = self.check_server_running(socketio_port)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                        # Use HTTP URL to access dashboard from Socket.IO server
         | 
| 72 | 
            +
                        dashboard_url = f"http://localhost:{socketio_port}"
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                        if server_running:
         | 
| 75 | 
            +
                            print(f"✅ Socket.IO server already running on port {socketio_port}")
         | 
| 76 | 
            +
                            print(f"📊 Dashboard: {dashboard_url}")
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                            # Open browser with static HTML file
         | 
| 79 | 
            +
                            try:
         | 
| 80 | 
            +
                                # Check if we should suppress browser opening (for tests)
         | 
| 81 | 
            +
                                if os.environ.get("CLAUDE_MPM_NO_BROWSER") != "1":
         | 
| 82 | 
            +
                                    print(f"🌐 Opening dashboard in browser...")
         | 
| 83 | 
            +
                                    self.open_in_browser_tab(dashboard_url)
         | 
| 84 | 
            +
                                    self.logger.info(f"Socket.IO dashboard opened: {dashboard_url}")
         | 
| 85 | 
            +
                                else:
         | 
| 86 | 
            +
                                    print(f"🌐 Browser opening suppressed (CLAUDE_MPM_NO_BROWSER=1)")
         | 
| 87 | 
            +
                                    self.logger.info(
         | 
| 88 | 
            +
                                        f"Browser opening suppressed by environment variable"
         | 
| 89 | 
            +
                                    )
         | 
| 90 | 
            +
                                return True, True
         | 
| 91 | 
            +
                            except Exception as e:
         | 
| 92 | 
            +
                                self.logger.warning(f"Failed to open browser: {e}")
         | 
| 93 | 
            +
                                print(f"⚠️  Could not open browser automatically")
         | 
| 94 | 
            +
                                print(f"📊 Please open manually: {dashboard_url}")
         | 
| 95 | 
            +
                                return True, False
         | 
| 96 | 
            +
                        else:
         | 
| 97 | 
            +
                            # Start standalone Socket.IO server
         | 
| 98 | 
            +
                            print(f"🔧 Starting Socket.IO server...")
         | 
| 99 | 
            +
                            server_started = self.start_standalone_server(socketio_port)
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                            if server_started:
         | 
| 102 | 
            +
                                print(f"✅ Socket.IO server started successfully")
         | 
| 103 | 
            +
                                print(f"📊 Dashboard: {dashboard_url}")
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                                # Open browser
         | 
| 106 | 
            +
                                try:
         | 
| 107 | 
            +
                                    if os.environ.get("CLAUDE_MPM_NO_BROWSER") != "1":
         | 
| 108 | 
            +
                                        print(f"🌐 Opening dashboard in browser...")
         | 
| 109 | 
            +
                                        self.open_in_browser_tab(dashboard_url)
         | 
| 110 | 
            +
                                        self.logger.info(
         | 
| 111 | 
            +
                                            f"Socket.IO dashboard opened: {dashboard_url}"
         | 
| 112 | 
            +
                                        )
         | 
| 113 | 
            +
                                    else:
         | 
| 114 | 
            +
                                        print(
         | 
| 115 | 
            +
                                            f"🌐 Browser opening suppressed (CLAUDE_MPM_NO_BROWSER=1)"
         | 
| 116 | 
            +
                                        )
         | 
| 117 | 
            +
                                    return True, True
         | 
| 118 | 
            +
                                except Exception as e:
         | 
| 119 | 
            +
                                    self.logger.warning(f"Failed to open browser: {e}")
         | 
| 120 | 
            +
                                    print(f"⚠️  Could not open browser automatically")
         | 
| 121 | 
            +
                                    print(f"📊 Please open manually: {dashboard_url}")
         | 
| 122 | 
            +
                                    return True, False
         | 
| 123 | 
            +
                            else:
         | 
| 124 | 
            +
                                print(f"❌ Failed to start Socket.IO server")
         | 
| 125 | 
            +
                                print(f"💡 Troubleshooting tips:")
         | 
| 126 | 
            +
                                print(f"   - Check if port {socketio_port} is already in use")
         | 
| 127 | 
            +
                                print(
         | 
| 128 | 
            +
                                    f"   - Verify Socket.IO dependencies: pip install python-socketio aiohttp"
         | 
| 129 | 
            +
                                )
         | 
| 130 | 
            +
                                print(f"   - Try a different port with --websocket-port")
         | 
| 131 | 
            +
                                return False, False
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                    except Exception as e:
         | 
| 134 | 
            +
                        self.logger.error(f"Failed to launch Socket.IO monitor: {e}")
         | 
| 135 | 
            +
                        print(f"❌ Failed to launch Socket.IO monitor: {e}")
         | 
| 136 | 
            +
                        return False, False
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                def check_server_running(self, port):
         | 
| 139 | 
            +
                    """Check if a Socket.IO server is running on the specified port."""
         | 
| 140 | 
            +
                    try:
         | 
| 141 | 
            +
                        import socket
         | 
| 142 | 
            +
                        import urllib.error
         | 
| 143 | 
            +
                        import urllib.request
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                        # First, do a basic TCP connection check
         | 
| 146 | 
            +
                        try:
         | 
| 147 | 
            +
                            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
         | 
| 148 | 
            +
                                s.settimeout(2.0)
         | 
| 149 | 
            +
                                result = s.connect_ex(("127.0.0.1", port))
         | 
| 150 | 
            +
                                if result != 0:
         | 
| 151 | 
            +
                                    self.logger.debug(f"TCP connection to port {port} failed")
         | 
| 152 | 
            +
                                    return False
         | 
| 153 | 
            +
                        except Exception as e:
         | 
| 154 | 
            +
                            self.logger.debug(f"TCP socket check failed for port {port}: {e}")
         | 
| 155 | 
            +
                            return False
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                        # If TCP connection succeeds, try HTTP health check
         | 
| 158 | 
            +
                        try:
         | 
| 159 | 
            +
                            response = urllib.request.urlopen(
         | 
| 160 | 
            +
                                f"http://localhost:{port}/status", timeout=5
         | 
| 161 | 
            +
                            )
         | 
| 162 | 
            +
                            if response.getcode() == 200:
         | 
| 163 | 
            +
                                self.logger.debug(
         | 
| 164 | 
            +
                                    f"✅ Socket.IO server health check passed on port {port}"
         | 
| 165 | 
            +
                                )
         | 
| 166 | 
            +
                                return True
         | 
| 167 | 
            +
                        except Exception as e:
         | 
| 168 | 
            +
                            self.logger.debug(f"HTTP health check failed for port {port}: {e}")
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                    except Exception as e:
         | 
| 171 | 
            +
                        self.logger.debug(
         | 
| 172 | 
            +
                            f"❌ Unexpected error checking Socket.IO server on port {port}: {e}"
         | 
| 173 | 
            +
                        )
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                    return False
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                def start_standalone_server(self, port):
         | 
| 178 | 
            +
                    """Start a standalone Socket.IO server using the Python daemon."""
         | 
| 179 | 
            +
                    try:
         | 
| 180 | 
            +
                        daemon_script = get_package_root() / "scripts" / "socketio_daemon.py"
         | 
| 181 | 
            +
                        if not daemon_script.exists():
         | 
| 182 | 
            +
                            self.logger.error(f"Daemon script not found: {daemon_script}")
         | 
| 183 | 
            +
                            return False
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                        # Start the daemon
         | 
| 186 | 
            +
                        result = subprocess.run(
         | 
| 187 | 
            +
                            [sys.executable, str(daemon_script), "start", "--port", str(port)],
         | 
| 188 | 
            +
                            capture_output=True,
         | 
| 189 | 
            +
                            text=True,
         | 
| 190 | 
            +
                            timeout=30,
         | 
| 191 | 
            +
                        )
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                        if result.returncode == 0:
         | 
| 194 | 
            +
                            self.logger.info(
         | 
| 195 | 
            +
                                f"Socket.IO daemon started successfully on port {port}"
         | 
| 196 | 
            +
                            )
         | 
| 197 | 
            +
                            return True
         | 
| 198 | 
            +
                        else:
         | 
| 199 | 
            +
                            self.logger.error(f"Failed to start Socket.IO daemon: {result.stderr}")
         | 
| 200 | 
            +
                            return False
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                    except Exception as e:
         | 
| 203 | 
            +
                        self.logger.error(f"Failed to start standalone Socket.IO server: {e}")
         | 
| 204 | 
            +
                        return False
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                def open_in_browser_tab(self, url):
         | 
| 207 | 
            +
                    """Open URL in browser, attempting to reuse existing tabs when possible."""
         | 
| 208 | 
            +
                    try:
         | 
| 209 | 
            +
                        # Try different methods based on platform
         | 
| 210 | 
            +
                        import platform
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                        system = platform.system().lower()
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                        if system == "darwin":  # macOS
         | 
| 215 | 
            +
                            try:
         | 
| 216 | 
            +
                                # Try to open in existing tab
         | 
| 217 | 
            +
                                subprocess.run(["open", "-g", url], check=True, timeout=5)
         | 
| 218 | 
            +
                                return
         | 
| 219 | 
            +
                            except Exception:
         | 
| 220 | 
            +
                                pass
         | 
| 221 | 
            +
                        elif system == "linux":
         | 
| 222 | 
            +
                            try:
         | 
| 223 | 
            +
                                # Try xdg-open
         | 
| 224 | 
            +
                                subprocess.run(["xdg-open", url], check=True, timeout=5)
         | 
| 225 | 
            +
                                return
         | 
| 226 | 
            +
                            except Exception:
         | 
| 227 | 
            +
                                pass
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                        # Fallback to standard webbrowser
         | 
| 230 | 
            +
                        webbrowser.open(url)
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                    except Exception as e:
         | 
| 233 | 
            +
                        self.logger.warning(f"Browser opening failed: {e}")
         | 
| 234 | 
            +
                        # Final fallback
         | 
| 235 | 
            +
                        webbrowser.open(url)
         |