claude-mpm 4.20.3__py3-none-any.whl → 4.25.10__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +23 -6
- claude_mpm/agents/OUTPUT_STYLE.md +3 -48
- claude_mpm/agents/PM_INSTRUCTIONS.md +1783 -34
- claude_mpm/agents/WORKFLOW.md +75 -2
- claude_mpm/agents/base_agent.json +6 -3
- claude_mpm/agents/frontmatter_validator.py +1 -1
- claude_mpm/agents/templates/api_qa.json +5 -2
- claude_mpm/agents/templates/circuit_breakers.md +108 -2
- claude_mpm/agents/templates/documentation.json +33 -6
- claude_mpm/agents/templates/javascript_engineer_agent.json +380 -0
- claude_mpm/agents/templates/php-engineer.json +10 -4
- claude_mpm/agents/templates/pm_red_flags.md +89 -19
- claude_mpm/agents/templates/project_organizer.json +7 -3
- claude_mpm/agents/templates/qa.json +2 -1
- claude_mpm/agents/templates/react_engineer.json +1 -0
- claude_mpm/agents/templates/research.json +82 -12
- claude_mpm/agents/templates/security.json +4 -4
- claude_mpm/agents/templates/tauri_engineer.json +274 -0
- claude_mpm/agents/templates/ticketing.json +10 -6
- claude_mpm/agents/templates/version_control.json +4 -2
- claude_mpm/agents/templates/web_qa.json +2 -1
- claude_mpm/cli/README.md +253 -0
- claude_mpm/cli/__init__.py +11 -1
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/analyze.py +3 -3
- claude_mpm/cli/commands/cleanup.py +1 -1
- claude_mpm/cli/commands/configure_agent_display.py +4 -4
- claude_mpm/cli/commands/debug.py +12 -12
- claude_mpm/cli/commands/hook_errors.py +277 -0
- claude_mpm/cli/commands/mcp_install_commands.py +1 -1
- claude_mpm/cli/commands/mcp_install_commands.py.backup +284 -0
- claude_mpm/cli/commands/mpm_init/README.md +365 -0
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +573 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +67 -1
- claude_mpm/cli/commands/run.py +124 -128
- claude_mpm/cli/commands/skills.py +522 -34
- claude_mpm/cli/executor.py +56 -0
- claude_mpm/cli/interactive/agent_wizard.py +5 -5
- claude_mpm/cli/parsers/base_parser.py +28 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
- claude_mpm/cli/parsers/skills_parser.py +138 -0
- claude_mpm/cli/startup.py +111 -8
- claude_mpm/cli/startup_display.py +480 -0
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/cli_module/commands.py +1 -1
- claude_mpm/cli_module/refactoring_guide.md +253 -0
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/mpm-init.md +19 -3
- claude_mpm/commands/mpm-resume.md +372 -0
- claude_mpm/commands/mpm-tickets.md +56 -7
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_capabilities.yaml +658 -0
- claude_mpm/config/async_logging_config.yaml +145 -0
- claude_mpm/constants.py +12 -0
- claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +34 -0
- claude_mpm/core/api_validator.py +1 -1
- claude_mpm/core/claude_runner.py +14 -1
- claude_mpm/core/config.py +8 -0
- claude_mpm/core/constants.py +1 -1
- claude_mpm/core/framework/processors/metadata_processor.py +1 -1
- claude_mpm/core/hook_error_memory.py +381 -0
- claude_mpm/core/hook_manager.py +41 -2
- claude_mpm/core/interactive_session.py +48 -3
- claude_mpm/core/interfaces.py +56 -1
- claude_mpm/core/logger.py +3 -1
- claude_mpm/core/oneshot_session.py +39 -0
- claude_mpm/d2/.gitignore +22 -0
- claude_mpm/d2/ARCHITECTURE_COMPARISON.md +273 -0
- claude_mpm/d2/FLASK_INTEGRATION.md +156 -0
- claude_mpm/d2/IMPLEMENTATION_SUMMARY.md +452 -0
- claude_mpm/d2/QUICKSTART.md +186 -0
- claude_mpm/d2/README.md +232 -0
- claude_mpm/d2/STORE_FIX_SUMMARY.md +167 -0
- claude_mpm/d2/SVELTE5_STORES_GUIDE.md +180 -0
- claude_mpm/d2/TESTING.md +288 -0
- claude_mpm/d2/index.html +118 -0
- claude_mpm/d2/package.json +19 -0
- claude_mpm/d2/src/App.svelte +110 -0
- claude_mpm/d2/src/components/Header.svelte +153 -0
- claude_mpm/d2/src/components/MainContent.svelte +74 -0
- claude_mpm/d2/src/components/Sidebar.svelte +85 -0
- claude_mpm/d2/src/components/tabs/EventsTab.svelte +326 -0
- claude_mpm/d2/src/lib/socketio.js +144 -0
- claude_mpm/d2/src/main.js +7 -0
- claude_mpm/d2/src/stores/events.js +114 -0
- claude_mpm/d2/src/stores/socket.js +108 -0
- claude_mpm/d2/src/stores/theme.js +65 -0
- claude_mpm/d2/svelte.config.js +12 -0
- claude_mpm/d2/vite.config.js +15 -0
- claude_mpm/dashboard/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/BUILD_NUMBER +1 -0
- claude_mpm/dashboard/README.md +121 -0
- claude_mpm/dashboard/VERSION +1 -0
- claude_mpm/dashboard/react/components/DataInspector/DataInspector.tsx +273 -0
- claude_mpm/dashboard/react/components/ErrorBoundary.tsx +75 -0
- claude_mpm/dashboard/react/components/EventViewer/EventViewer.tsx +141 -0
- claude_mpm/dashboard/react/components/shared/ConnectionStatus.tsx +36 -0
- claude_mpm/dashboard/react/components/shared/FilterBar.tsx +89 -0
- claude_mpm/dashboard/react/contexts/DashboardContext.tsx +215 -0
- claude_mpm/dashboard/react/entries/events.tsx +165 -0
- claude_mpm/dashboard/react/hooks/useEvents.ts +191 -0
- claude_mpm/dashboard/react/hooks/useSocket.ts +225 -0
- claude_mpm/dashboard/static/built/REFACTORING_SUMMARY.md +170 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js.map +1 -0
- claude_mpm/dashboard/static/built/components/agent-hierarchy.js +101 -101
- claude_mpm/dashboard/static/built/components/agent-inference.js.map +1 -0
- claude_mpm/dashboard/static/built/components/build-tracker.js +59 -59
- claude_mpm/dashboard/static/built/components/code-simple.js +107 -107
- claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +29 -29
- claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +24 -24
- claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +27 -27
- claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +25 -25
- claude_mpm/dashboard/static/built/components/code-tree.js.map +1 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/connection-debug.js +101 -101
- claude_mpm/dashboard/static/built/components/diff-viewer.js +113 -113
- claude_mpm/dashboard/static/built/components/event-processor.js.map +1 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/export-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/file-change-tracker.js +57 -57
- claude_mpm/dashboard/static/built/components/file-change-viewer.js +74 -74
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js.map +1 -0
- claude_mpm/dashboard/static/built/components/file-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/hud-library-loader.js.map +1 -0
- claude_mpm/dashboard/static/built/components/hud-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/hud-visualizer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/session-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/socket-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/ui-state-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/unified-data-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/working-directory.js.map +1 -0
- claude_mpm/dashboard/static/built/connection-manager.js +76 -76
- claude_mpm/dashboard/static/built/dashboard.js.map +1 -0
- claude_mpm/dashboard/static/built/extension-error-handler.js +22 -22
- claude_mpm/dashboard/static/built/react/events.js.map +1 -0
- claude_mpm/dashboard/static/built/shared/dom-helpers.js +9 -9
- claude_mpm/dashboard/static/built/shared/event-bus.js +5 -5
- claude_mpm/dashboard/static/built/shared/logger.js +16 -16
- claude_mpm/dashboard/static/built/shared/tooltip-service.js +6 -6
- claude_mpm/dashboard/static/built/socket-client.js.map +1 -0
- claude_mpm/dashboard/static/css/activity.css +69 -69
- claude_mpm/dashboard/static/css/connection-status.css +10 -10
- claude_mpm/dashboard/static/css/dashboard.css +15 -15
- claude_mpm/dashboard/static/index.html +22 -22
- claude_mpm/dashboard/static/js/REFACTORING_SUMMARY.md +170 -0
- claude_mpm/dashboard/static/js/components/activity-tree.js +178 -178
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +101 -101
- claude_mpm/dashboard/static/js/components/agent-inference.js +31 -31
- claude_mpm/dashboard/static/js/components/build-tracker.js +59 -59
- claude_mpm/dashboard/static/js/components/code-simple.js +107 -107
- claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
- claude_mpm/dashboard/static/js/components/diff-viewer.js +113 -113
- claude_mpm/dashboard/static/js/components/event-viewer.js +12 -12
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +57 -57
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +74 -74
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +6 -6
- claude_mpm/dashboard/static/js/components/file-viewer.js +42 -42
- claude_mpm/dashboard/static/js/components/module-viewer.js +27 -27
- claude_mpm/dashboard/static/js/components/session-manager.js +14 -14
- claude_mpm/dashboard/static/js/components/socket-manager.js +1 -1
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +14 -14
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +110 -110
- claude_mpm/dashboard/static/js/components/working-directory.js +8 -8
- claude_mpm/dashboard/static/js/connection-manager.js +76 -76
- claude_mpm/dashboard/static/js/dashboard.js +76 -58
- claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
- claude_mpm/dashboard/static/js/shared/dom-helpers.js +9 -9
- claude_mpm/dashboard/static/js/shared/event-bus.js +5 -5
- claude_mpm/dashboard/static/js/shared/logger.js +16 -16
- claude_mpm/dashboard/static/js/shared/tooltip-service.js +6 -6
- claude_mpm/dashboard/static/js/socket-client.js +138 -121
- claude_mpm/dashboard/static/navigation-test-results.md +118 -0
- claude_mpm/dashboard/static/production/main.html +21 -21
- claude_mpm/dashboard/static/test-archive/dashboard.html +22 -22
- claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +39 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +38 -0
- claude_mpm/dashboard/templates/code_simple.html +23 -23
- claude_mpm/dashboard/templates/index.html +18 -18
- claude_mpm/hooks/README.md +143 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +3 -1
- claude_mpm/hooks/claude_hooks/hook_handler.py +24 -7
- claude_mpm/hooks/claude_hooks/installer.py +45 -0
- claude_mpm/hooks/templates/README.md +180 -0
- claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
- claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
- claude_mpm/hooks/templates/settings.json.example +147 -0
- claude_mpm/schemas/agent_schema.json +596 -0
- claude_mpm/schemas/frontmatter_schema.json +165 -0
- claude_mpm/scripts/claude-hook-handler.sh +3 -3
- claude_mpm/scripts/start_activity_logging.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +8 -8
- claude_mpm/services/agents/local_template_manager.py +3 -1
- claude_mpm/services/cli/session_pause_manager.py +504 -0
- claude_mpm/services/cli/session_resume_helper.py +36 -16
- claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
- claude_mpm/services/core/base.py +26 -11
- claude_mpm/services/core/interfaces.py +56 -1
- claude_mpm/services/core/models/agent_config.py +3 -0
- claude_mpm/services/core/models/process.py +4 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +0 -2
- claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
- claude_mpm/services/diagnostics/checks/mcp_check.py +0 -1
- claude_mpm/services/diagnostics/checks/monitor_check.py +0 -1
- claude_mpm/services/diagnostics/doctor_reporter.py +6 -4
- claude_mpm/services/diagnostics/models.py +21 -0
- claude_mpm/services/event_bus/README.md +244 -0
- claude_mpm/services/event_bus/direct_relay.py +3 -3
- claude_mpm/services/event_bus/event_bus.py +36 -3
- claude_mpm/services/event_bus/relay.py +23 -7
- claude_mpm/services/events/README.md +303 -0
- claude_mpm/services/events/consumers/logging.py +1 -2
- claude_mpm/services/framework_claude_md_generator/README.md +119 -0
- claude_mpm/services/infrastructure/monitoring/resources.py +1 -1
- claude_mpm/services/local_ops/__init__.py +2 -0
- claude_mpm/services/local_ops/process_manager.py +1 -1
- claude_mpm/services/local_ops/resource_monitor.py +2 -2
- claude_mpm/services/mcp_gateway/README.md +185 -0
- claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/core/process_pool.py +19 -10
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -2
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +26 -21
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +6 -2
- claude_mpm/services/memory/failure_tracker.py +19 -4
- claude_mpm/services/memory/optimizer.py +1 -1
- claude_mpm/services/model/model_router.py +8 -9
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/server.py +2 -2
- claude_mpm/services/native_agent_converter.py +356 -0
- claude_mpm/services/port_manager.py +1 -1
- claude_mpm/services/project/documentation_manager.py +2 -1
- claude_mpm/services/project/toolchain_analyzer.py +3 -1
- claude_mpm/services/runner_configuration_service.py +1 -0
- claude_mpm/services/self_upgrade_service.py +165 -7
- claude_mpm/services/skills_config.py +547 -0
- claude_mpm/services/skills_deployer.py +955 -0
- claude_mpm/services/socketio/handlers/connection.py +1 -1
- claude_mpm/services/socketio/handlers/connection.py.backup +217 -0
- claude_mpm/services/socketio/handlers/git.py +2 -2
- claude_mpm/services/socketio/handlers/hook.py.backup +154 -0
- claude_mpm/services/static/.gitkeep +2 -0
- claude_mpm/services/system_instructions_service.py +1 -3
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +0 -3
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +0 -1
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +1 -1
- claude_mpm/services/version_control/VERSION +1 -0
- claude_mpm/services/version_control/conflict_resolution.py +6 -4
- claude_mpm/services/visualization/mermaid_generator.py +2 -3
- claude_mpm/skills/__init__.py +3 -3
- claude_mpm/skills/agent_skills_injector.py +42 -49
- claude_mpm/skills/bundled/.gitkeep +2 -0
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +4 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +108 -114
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +46 -41
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +36 -73
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +100 -125
- claude_mpm/skills/bundled/debugging/root-cause-tracing/find-polluter.sh +63 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +28 -72
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +11 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +272 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/main/artifacts-builder/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +13 -1
- claude_mpm/skills/bundled/main/artifacts-builder/scripts/bundle-artifact.sh +54 -0
- claude_mpm/skills/bundled/main/artifacts-builder/scripts/init-artifact.sh +322 -0
- claude_mpm/skills/bundled/main/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- claude_mpm/skills/bundled/main/internal-comms/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +11 -0
- claude_mpm/skills/bundled/main/mcp-builder/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +109 -277
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +17 -10
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +92 -39
- claude_mpm/skills/bundled/main/mcp-builder/scripts/example_evaluation.xml +22 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/requirements.txt +2 -0
- claude_mpm/skills/bundled/main/skill-creator/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +135 -155
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +13 -12
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +5 -3
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +19 -12
- claude_mpm/skills/bundled/performance-profiling.md +6 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +21 -25
- claude_mpm/skills/bundled/testing/condition-based-waiting/example.ts +158 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +86 -250
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +145 -57
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +6 -6
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +13 -9
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +8 -8
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +37 -15
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/skills_registry.py +44 -48
- claude_mpm/skills/skills_service.py +117 -108
- claude_mpm/templates/questions/EXAMPLES.md +501 -0
- claude_mpm/templates/questions/__init__.py +43 -0
- claude_mpm/templates/questions/base.py +193 -0
- claude_mpm/templates/questions/pr_strategy.py +314 -0
- claude_mpm/templates/questions/project_init.py +388 -0
- claude_mpm/templates/questions/ticket_mgmt.py +397 -0
- claude_mpm/tools/README_SOCKETIO_DEBUG.md +224 -0
- claude_mpm/tools/__main__.py +8 -8
- claude_mpm/tools/code_tree_analyzer/README.md +64 -0
- claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/utils/agent_dependency_loader.py +3 -3
- claude_mpm/utils/dependency_cache.py +3 -1
- claude_mpm/utils/gitignore.py +241 -0
- claude_mpm/utils/log_cleanup.py +3 -3
- claude_mpm/utils/robust_installer.py +3 -5
- claude_mpm/utils/structured_questions.py +619 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/METADATA +218 -31
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/RECORD +409 -246
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +0 -400
- claude_mpm/cli/commands/mpm_init.py +0 -2093
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
- claude_mpm/dashboard/static/archive/activity_dashboard_test.html +0 -61
- claude_mpm/dashboard/static/archive/test_activity_connection.html +0 -179
- claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +0 -68
- claude_mpm/dashboard/static/archive/test_dashboard.html +0 -409
- claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +0 -519
- claude_mpm/dashboard/static/archive/test_dashboard_verification.html +0 -181
- claude_mpm/dashboard/static/archive/test_file_data.html +0 -315
- claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +0 -243
- claude_mpm/dashboard/static/archive/test_file_tree_fix.html +0 -234
- claude_mpm/dashboard/static/archive/test_file_tree_rename.html +0 -117
- claude_mpm/dashboard/static/archive/test_file_tree_tab.html +0 -115
- claude_mpm/dashboard/static/archive/test_file_viewer.html +0 -224
- claude_mpm/dashboard/static/archive/test_final_activity.html +0 -220
- claude_mpm/dashboard/static/archive/test_tab_fix.html +0 -139
- claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +0 -1
- claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/dist/components/file-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
- claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
- claude_mpm/dashboard/static/dist/dashboard.js +0 -2
- claude_mpm/dashboard/static/dist/react/events.js +0 -30
- claude_mpm/dashboard/static/dist/socket-client.js +0 -2
- claude_mpm/dashboard/static/test-archive/test_debug.html +0 -25
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +0 -213
- claude_mpm/tools/code_tree_analyzer.py +0 -1825
- /claude_mpm/skills/bundled/collaboration/requesting-code-review/{code-reviewer.md → references/code-reviewer-template.md} +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/WHEEL +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DOM Helper Utilities
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Common DOM manipulation utilities for dashboard components.
|
|
5
5
|
* Provides safe, consistent methods for element creation and manipulation.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* @module dom-helpers
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -17,7 +17,7 @@ const domHelpers = {
|
|
|
17
17
|
*/
|
|
18
18
|
createElement(tag, attrs = {}, content = null) {
|
|
19
19
|
const element = document.createElement(tag);
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
// Set attributes
|
|
22
22
|
for (const [key, value] of Object.entries(attrs)) {
|
|
23
23
|
if (key === 'className') {
|
|
@@ -35,12 +35,12 @@ const domHelpers = {
|
|
|
35
35
|
element.setAttribute(key, value);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
// Add content
|
|
40
40
|
if (content !== null) {
|
|
41
41
|
this.setContent(element, content);
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
return element;
|
|
45
45
|
},
|
|
46
46
|
|
|
@@ -296,19 +296,19 @@ const domHelpers = {
|
|
|
296
296
|
*/
|
|
297
297
|
isInViewport(element, partial = false) {
|
|
298
298
|
if (!element) return false;
|
|
299
|
-
|
|
299
|
+
|
|
300
300
|
const rect = element.getBoundingClientRect();
|
|
301
301
|
const windowHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
302
302
|
const windowWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
303
|
-
|
|
303
|
+
|
|
304
304
|
const vertInView = partial
|
|
305
305
|
? rect.top < windowHeight && rect.bottom > 0
|
|
306
306
|
: rect.top >= 0 && rect.bottom <= windowHeight;
|
|
307
|
-
|
|
307
|
+
|
|
308
308
|
const horInView = partial
|
|
309
309
|
? rect.left < windowWidth && rect.right > 0
|
|
310
310
|
: rect.left >= 0 && rect.right <= windowWidth;
|
|
311
|
-
|
|
311
|
+
|
|
312
312
|
return vertInView && horInView;
|
|
313
313
|
},
|
|
314
314
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Event Bus Service
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Central event management for decoupled component communication.
|
|
5
5
|
* Implements a simple pub/sub pattern for dashboard components.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* @module event-bus
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -82,8 +82,8 @@ class EventBus {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
const handlers = this.events.get(event);
|
|
85
|
-
const index = handlers.findIndex(wrapper =>
|
|
86
|
-
wrapper.id === handlerOrId ||
|
|
85
|
+
const index = handlers.findIndex(wrapper =>
|
|
86
|
+
wrapper.id === handlerOrId ||
|
|
87
87
|
wrapper.handler === handlerOrId ||
|
|
88
88
|
wrapper.handler._originalHandler === handlerOrId
|
|
89
89
|
);
|
|
@@ -177,7 +177,7 @@ class EventBus {
|
|
|
177
177
|
waitFor(event, timeout) {
|
|
178
178
|
return new Promise((resolve, reject) => {
|
|
179
179
|
let timeoutId;
|
|
180
|
-
|
|
180
|
+
|
|
181
181
|
const handler = (...args) => {
|
|
182
182
|
if (timeoutId) {
|
|
183
183
|
clearTimeout(timeoutId);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Logger Service
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Centralized logging service with levels, formatting, and performance timing.
|
|
5
5
|
* Provides consistent logging across dashboard components.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* @module logger
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ class Logger {
|
|
|
16
16
|
ERROR: 3,
|
|
17
17
|
NONE: 4
|
|
18
18
|
};
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
this.currentLevel = this.logLevels.INFO;
|
|
21
21
|
this.enableTimestamps = true;
|
|
22
22
|
this.enableColors = true;
|
|
@@ -116,7 +116,7 @@ class Logger {
|
|
|
116
116
|
log(level, args, color) {
|
|
117
117
|
const timestamp = this.enableTimestamps ? new Date().toISOString() : '';
|
|
118
118
|
const prefix = this.formatPrefix(level, timestamp, color);
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
// Console output
|
|
121
121
|
const method = level === 'ERROR' ? 'error' : level === 'WARN' ? 'warn' : 'log';
|
|
122
122
|
if (this.enableColors && color) {
|
|
@@ -124,7 +124,7 @@ class Logger {
|
|
|
124
124
|
} else {
|
|
125
125
|
console[method](prefix, ...args);
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
// Add to history
|
|
129
129
|
this.addToHistory(level, timestamp, args);
|
|
130
130
|
}
|
|
@@ -157,11 +157,11 @@ class Logger {
|
|
|
157
157
|
this.logHistory.push({
|
|
158
158
|
level,
|
|
159
159
|
timestamp,
|
|
160
|
-
message: args.map(arg =>
|
|
160
|
+
message: args.map(arg =>
|
|
161
161
|
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
|
|
162
162
|
).join(' ')
|
|
163
163
|
});
|
|
164
|
-
|
|
164
|
+
|
|
165
165
|
// Limit history size
|
|
166
166
|
if (this.logHistory.length > this.maxHistorySize) {
|
|
167
167
|
this.logHistory.shift();
|
|
@@ -191,19 +191,19 @@ class Logger {
|
|
|
191
191
|
this.warn(`Timer not found: ${label}`);
|
|
192
192
|
return null;
|
|
193
193
|
}
|
|
194
|
-
|
|
194
|
+
|
|
195
195
|
const elapsed = performance.now() - mark.start;
|
|
196
|
-
const memoryDelta = performance.memory
|
|
197
|
-
? performance.memory.usedJSHeapSize - mark.memory
|
|
196
|
+
const memoryDelta = performance.memory
|
|
197
|
+
? performance.memory.usedJSHeapSize - mark.memory
|
|
198
198
|
: null;
|
|
199
|
-
|
|
199
|
+
|
|
200
200
|
this.performanceMarks.delete(label);
|
|
201
|
-
|
|
201
|
+
|
|
202
202
|
const message = [`Timer ended: ${label} - ${elapsed.toFixed(2)}ms`];
|
|
203
203
|
if (memoryDelta !== null) {
|
|
204
204
|
message.push(`(Memory: ${this.formatBytes(memoryDelta)})`);
|
|
205
205
|
}
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
this.info(...message);
|
|
208
208
|
return elapsed;
|
|
209
209
|
}
|
|
@@ -327,13 +327,13 @@ class Logger {
|
|
|
327
327
|
formatBytes(bytes) {
|
|
328
328
|
const sign = bytes < 0 ? '-' : '+';
|
|
329
329
|
bytes = Math.abs(bytes);
|
|
330
|
-
|
|
330
|
+
|
|
331
331
|
if (bytes === 0) return '0 B';
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
const units = ['B', 'KB', 'MB', 'GB'];
|
|
334
334
|
const index = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
335
335
|
const value = bytes / Math.pow(1024, index);
|
|
336
|
-
|
|
336
|
+
|
|
337
337
|
return `${sign}${value.toFixed(2)} ${units[index]}`;
|
|
338
338
|
}
|
|
339
339
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unified Tooltip Service
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Provides a consistent tooltip implementation for all dashboard components.
|
|
5
5
|
* Supports different tooltip types and behaviors.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* @module tooltip-service
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -26,7 +26,7 @@ class TooltipService {
|
|
|
26
26
|
*/
|
|
27
27
|
create(id, options = {}) {
|
|
28
28
|
const config = { ...this.defaultOptions, ...options };
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
// Check if tooltip already exists
|
|
31
31
|
if (this.tooltips.has(id)) {
|
|
32
32
|
return this.tooltips.get(id);
|
|
@@ -72,7 +72,7 @@ class TooltipService {
|
|
|
72
72
|
|
|
73
73
|
// Format content
|
|
74
74
|
const html = this.formatContent(content);
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
tooltip.html(html)
|
|
77
77
|
.style('left', (event.pageX + config.offset.x) + 'px')
|
|
78
78
|
.style('top', (event.pageY + config.offset.y) + 'px');
|
|
@@ -122,7 +122,7 @@ class TooltipService {
|
|
|
122
122
|
|
|
123
123
|
if (typeof content === 'object' && content !== null) {
|
|
124
124
|
const lines = [];
|
|
125
|
-
|
|
125
|
+
|
|
126
126
|
// Handle title
|
|
127
127
|
if (content.title) {
|
|
128
128
|
lines.push(`<strong>${this.escapeHtml(content.title)}</strong>`);
|
|
@@ -166,7 +166,7 @@ class TooltipService {
|
|
|
166
166
|
const rect = node.getBoundingClientRect();
|
|
167
167
|
const viewportWidth = window.innerWidth;
|
|
168
168
|
const viewportHeight = window.innerHeight;
|
|
169
|
-
|
|
169
|
+
|
|
170
170
|
let left = event.pageX + config.offset.x;
|
|
171
171
|
let top = event.pageY + config.offset.y;
|
|
172
172
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-client.js","sources":["../js/socket-client.js","../js/components/socket-manager.js","../js/components/ui-state-manager.js"],"sourcesContent":["/**\n * Socket.IO Client for Claude MPM Dashboard\n * \n * This module provides real-time WebSocket communication between the Claude MPM dashboard\n * and the backend Socket.IO server. It handles connection management, event processing,\n * retry logic, and health monitoring.\n * \n * Architecture:\n * - Maintains persistent WebSocket connection to Claude MPM backend\n * - Implements robust retry logic with exponential backoff\n * - Provides event queuing during disconnections\n * - Validates event schemas for data integrity\n * - Monitors connection health with ping/pong mechanisms\n * \n * Event Flow:\n * 1. Events from Claude Code hooks → Socket.IO server → Dashboard client\n * 2. Dashboard requests → Socket.IO server → Backend services\n * 3. Status updates → Socket.IO server → All connected clients\n * \n * Thread Safety:\n * - Single-threaded JavaScript execution model ensures safety\n * - Event callbacks are queued and executed sequentially\n * - Connection state changes are atomic\n * \n * Performance Considerations:\n * - Event queue limited to 100 items to prevent memory leaks\n * - Health checks run every 45s to match server ping interval\n * - Exponential backoff prevents connection spam\n * - Lazy event validation reduces overhead\n * \n * Security:\n * - Connects only to localhost to prevent external access\n * - Event schema validation prevents malformed data processing\n * - Connection timeout prevents hanging connections\n * \n * @author Claude MPM Team\n * @version 1.0\n * @since v4.0.25\n */\n\n// Access the global io from window object in ES6 module context\n// WHY: Socket.IO is loaded via CDN in HTML, available as window.io\nconst io = window.io;\n\n/**\n * Primary Socket.IO client for dashboard communication.\n * \n * Manages WebSocket connection lifecycle, event processing, and error handling.\n * Implements connection resilience with automatic retry and health monitoring.\n * \n * Key Features:\n * - Automatic connection retry with exponential backoff\n * - Event queue management during disconnections \n * - Schema validation for incoming events\n * - Health monitoring with ping/pong\n * - Session management and event history\n * \n * Connection States:\n * - isConnected: Currently connected to server\n * - isConnecting: Connection attempt in progress\n * - disconnectTime: Timestamp of last disconnection\n * \n * Event Processing:\n * - Validates against schema before processing\n * - Queues events during disconnection (max 100)\n * - Maintains event history and session tracking\n * \n * @class SocketClient\n */\nclass SocketClient {\n /**\n * Initialize Socket.IO client with default configuration.\n * \n * Sets up connection management, event processing, and health monitoring.\n * Configures retry logic and event queue management.\n * \n * WHY this initialization approach:\n * - Lazy socket creation allows for port specification\n * - Event queue prevents data loss during reconnections\n * - Health monitoring detects server issues early\n * - Schema validation ensures data integrity\n * \n * @constructor\n */\n constructor() {\n /**\n * Socket.IO connection instance.\n * @type {Socket|null}\n * @private\n */\n this.socket = null;\n \n /**\n * Current connection port.\n * @type {string|null}\n * @private\n */\n this.port = null; // Store the current port\n \n /**\n * Event callback registry for connection lifecycle events.\n * WHY: Allows multiple components to register for connection events.\n * @type {Object.<string, Function[]>}\n * @private\n */\n this.connectionCallbacks = {\n connect: [], // Called on successful connection\n disconnect: [], // Called on disconnection \n error: [], // Called on connection errors\n event: [] // Called on incoming events\n };\n \n /**\n * Event schema definition for validation.\n * WHY: Ensures data integrity and prevents processing malformed events.\n * @type {Object}\n * @private\n */\n this.eventSchema = {\n required: ['source', 'type', 'subtype', 'timestamp', 'data'],\n optional: ['event', 'session_id']\n };\n\n /**\n * Current connection state.\n * @type {boolean}\n * @private\n */\n this.isConnected = false;\n \n /**\n * Connection attempt in progress flag.\n * WHY: Prevents multiple simultaneous connection attempts.\n * @type {boolean}\n * @private\n */\n this.isConnecting = false;\n \n /**\n * Timestamp of last successful connection.\n * @type {number|null}\n * @private\n */\n this.lastConnectTime = null;\n \n /**\n * Timestamp of last disconnection.\n * WHY: Used to calculate downtime and trigger reconnection logic.\n * @type {number|null}\n * @private\n */\n this.disconnectTime = null;\n\n /**\n * Event history storage.\n * WHY: Maintains event history for dashboard display and analysis.\n * @type {Array.<Object>}\n * @private\n */\n this.events = [];\n \n /**\n * Session tracking map.\n * WHY: Groups events by session for better organization.\n * @type {Map<string, Object>}\n * @private\n */\n this.sessions = new Map();\n \n /**\n * Current active session identifier.\n * @type {string|null}\n * @private\n */\n this.currentSessionId = null;\n\n /**\n * Event queue for disconnection periods.\n * WHY: Prevents event loss during temporary disconnections.\n * @type {Array.<Object>}\n * @private\n */\n this.eventQueue = [];\n \n /**\n * Maximum queue size to prevent memory leaks.\n * WHY: Limits memory usage during extended disconnections.\n * @type {number}\n * @private\n * @const\n */\n this.maxQueueSize = 100;\n \n /**\n * Current retry attempt counter.\n * WHY: Tracks retry attempts for exponential backoff logic.\n * @type {number}\n * @private\n */\n this.retryAttempts = 0;\n \n /**\n * Maximum retry attempts before giving up.\n * WHY: Prevents infinite retry loops that could impact performance.\n * @type {number}\n * @private\n * @const\n */\n this.maxRetryAttempts = 5; // Increased from 3 to 5 for better stability\n \n /**\n * Retry delay intervals in milliseconds (exponential backoff).\n * WHY: Prevents server overload during connection issues.\n * @type {number[]}\n * @private\n * @const\n */\n this.retryDelays = [1000, 2000, 3000, 4000, 5000]; // Exponential backoff with 5 attempts\n \n /**\n * Map of pending emissions for retry logic.\n * WHY: Tracks failed emissions that need to be retried.\n * @type {Map<string, Object>}\n * @private\n */\n this.pendingEmissions = new Map(); // Track pending emissions for retry\n \n /**\n * Timestamp of last ping sent to server.\n * WHY: Used for health monitoring and connection validation.\n * @type {number|null}\n * @private\n */\n this.lastPingTime = null;\n \n /**\n * Timestamp of last pong received from server.\n * WHY: Confirms server is responsive and connection is healthy.\n * @type {number|null}\n * @private\n */\n this.lastPongTime = null;\n \n /**\n * Health check timeout in milliseconds.\n * WHY: More lenient than Socket.IO timeout to prevent false positives.\n * @type {number}\n * @private\n * @const\n */\n this.pingTimeout = 120000; // 120 seconds for health check (more lenient for stability)\n \n /**\n * Health check interval timer.\n * @type {number|null}\n * @private\n */\n this.healthCheckInterval = null;\n \n // Initialize background monitoring\n this.startStatusCheckFallback();\n this.startHealthMonitoring();\n }\n\n /**\n * Connect to Socket.IO server on specified port.\n * \n * Initiates WebSocket connection to the Claude MPM Socket.IO server.\n * Handles connection conflicts and ensures clean state transitions.\n * \n * Connection Process:\n * 1. Validates port and constructs localhost URL\n * 2. Checks for existing connections and cleans up if needed\n * 3. Delegates to doConnect() for actual connection logic\n * \n * Thread Safety:\n * - Uses setTimeout for async cleanup to prevent race conditions\n * - Connection state flags prevent multiple simultaneous attempts\n * \n * @param {string} [port='8765'] - Port number to connect to (defaults to 8765)\n * \n * @throws {Error} If Socket.IO library is not loaded\n * \n * @example\n * // Connect to default port\n * socketClient.connect();\n * \n * // Connect to specific port\n * socketClient.connect('8766');\n */\n connect(port = '8765') {\n // Store the port for later use in reconnections\n this.port = port;\n const url = `http://localhost:${port}`;\n\n // WHY this check: Prevents connection conflicts that can cause memory leaks\n if (this.socket && (this.socket.connected || this.socket.connecting)) {\n console.log('Already connected or connecting, disconnecting first...');\n this.socket.disconnect();\n // WHY 100ms delay: Allows cleanup to complete before new connection\n setTimeout(() => this.doConnect(url), 100);\n return;\n }\n\n this.doConnect(url);\n }\n\n /**\n * Execute the actual Socket.IO connection with full configuration.\n * \n * Creates and configures Socket.IO client with appropriate timeouts,\n * retry logic, and transport settings. Sets up event handlers for\n * connection lifecycle management.\n * \n * Configuration Details:\n * - autoConnect: true - Immediate connection attempt\n * - reconnection: true - Built-in reconnection enabled\n * - pingInterval: 25000ms - Matches server configuration\n * - pingTimeout: 20000ms - Health check timeout\n * - transports: ['websocket', 'polling'] - Fallback options\n * \n * WHY these settings:\n * - Ping intervals must match server to prevent timeouts\n * - Limited reconnection attempts prevent infinite loops\n * - forceNew prevents socket reuse issues\n * \n * @param {string} url - Complete Socket.IO server URL (http://localhost:port)\n * @private\n * \n * @throws {Error} If Socket.IO library is not available\n */\n doConnect(url) {\n console.log(`Connecting to Socket.IO server at ${url}`);\n \n // Check if io is available\n if (typeof io === 'undefined') {\n console.error('Socket.IO library not loaded! Make sure socket.io.min.js is loaded before this script.');\n this.notifyConnectionStatus('Socket.IO library not loaded', 'error');\n return;\n }\n \n this.isConnecting = true;\n this.notifyConnectionStatus('Connecting...', 'connecting');\n\n this.socket = io(url, {\n autoConnect: true,\n reconnection: true,\n reconnectionDelay: 1000,\n reconnectionDelayMax: 10000, // Increased max delay for stability\n reconnectionAttempts: 10, // Increased attempts for better resilience \n timeout: 30000, // Increased connection timeout to 30 seconds\n forceNew: true,\n transports: ['websocket', 'polling'],\n // Remove client-side ping configuration - let server control this\n // The server now properly configures: ping_interval=30s, ping_timeout=60s\n });\n\n this.setupSocketHandlers();\n }\n\n /**\n * Setup Socket.IO event handlers\n */\n setupSocketHandlers() {\n this.socket.on('connect', () => {\n console.log('Connected to Socket.IO server');\n const previouslyConnected = this.isConnected;\n this.isConnected = true;\n this.isConnecting = false;\n this.lastConnectTime = Date.now();\n this.retryAttempts = 0; // Reset retry counter on successful connect\n \n // Calculate downtime if this is a reconnection\n if (this.disconnectTime && previouslyConnected === false) {\n const downtime = (Date.now() - this.disconnectTime) / 1000;\n console.log(`Reconnected after ${downtime.toFixed(1)}s downtime`);\n \n // Flush queued events after reconnection\n this.flushEventQueue();\n }\n \n this.notifyConnectionStatus('Connected', 'connected');\n\n // Expose socket globally for components that need direct access\n window.socket = this.socket;\n console.log('SocketClient: Exposed socket globally as window.socket');\n\n // Emit connect callback\n this.connectionCallbacks.connect.forEach(callback =>\n callback(this.socket.id)\n );\n\n this.requestStatus();\n // History is now automatically sent by server on connection\n // No need to explicitly request it\n });\n\n this.socket.on('disconnect', (reason) => {\n // Enhanced logging for debugging disconnection issues\n const disconnectInfo = {\n reason: reason,\n timestamp: new Date().toISOString(),\n wasConnected: this.isConnected,\n uptimeSeconds: this.lastConnectTime ? ((Date.now() - this.lastConnectTime) / 1000).toFixed(1) : 0,\n lastPing: this.lastPingTime ? ((Date.now() - this.lastPingTime) / 1000).toFixed(1) + 's ago' : 'never',\n lastPong: this.lastPongTime ? ((Date.now() - this.lastPongTime) / 1000).toFixed(1) + 's ago' : 'never'\n };\n \n console.log('Disconnected from server:', disconnectInfo);\n \n this.isConnected = false;\n this.isConnecting = false;\n this.disconnectTime = Date.now();\n \n this.notifyConnectionStatus(`Disconnected: ${reason}`, 'disconnected');\n\n // Emit disconnect callback\n this.connectionCallbacks.disconnect.forEach(callback =>\n callback(reason)\n );\n \n // Detailed reason analysis for auto-reconnect decision\n const reconnectReasons = [\n 'transport close', // Network issue\n 'ping timeout', // Server not responding\n 'transport error', // Connection error\n 'io server disconnect', // Server initiated disconnect (might be restart)\n ];\n \n if (reconnectReasons.includes(reason)) {\n console.log(`Auto-reconnect triggered for reason: ${reason}`);\n this.scheduleReconnect();\n } else if (reason === 'io client disconnect') {\n console.log('Client-initiated disconnect, not auto-reconnecting');\n } else {\n console.log(`Unknown disconnect reason: ${reason}, attempting reconnect anyway`);\n this.scheduleReconnect();\n }\n });\n\n this.socket.on('connect_error', (error) => {\n console.error('Connection error:', error);\n this.isConnecting = false;\n const errorMsg = error.message || error.description || 'Unknown error';\n this.notifyConnectionStatus(`Connection Error: ${errorMsg}`, 'disconnected');\n\n // Add error event\n this.addEvent({\n type: 'connection.error',\n timestamp: new Date().toISOString(),\n data: { \n error: errorMsg, \n url: this.socket.io.uri,\n retry_attempt: this.retryAttempts\n }\n });\n\n // Emit error callback\n this.connectionCallbacks.error.forEach(callback =>\n callback(errorMsg)\n );\n \n // Schedule reconnect with backoff\n this.scheduleReconnect();\n });\n\n // Primary event handler - this is what the server actually emits\n this.socket.on('claude_event', (data) => {\n console.log('Received claude_event:', data);\n \n // Validate event schema\n const validatedEvent = this.validateEventSchema(data);\n if (!validatedEvent) {\n console.warn('Invalid event schema received:', data);\n return;\n }\n \n // Code analysis events are now allowed to flow through to the events list for troubleshooting\n // They will appear in both the Events tab and the Code tab\n if (validatedEvent.type && validatedEvent.type.startsWith('code:')) {\n console.log('Code analysis event received via claude_event, adding to events list for troubleshooting:', validatedEvent.type);\n }\n \n // Transform event to match expected format (for backward compatibility)\n const transformedEvent = this.transformEvent(validatedEvent);\n console.log('Transformed event:', transformedEvent);\n this.addEvent(transformedEvent);\n });\n\n // Add ping/pong handlers for health monitoring\n this.socket.on('ping', (data) => {\n // console.log('Received ping from server');\n this.lastPingTime = Date.now();\n \n // Send pong response immediately\n this.socket.emit('pong', { \n timestamp: data.timestamp,\n client_time: Date.now()\n });\n });\n \n // Track pong responses from server\n this.socket.on('pong', (data) => {\n this.lastPongTime = Date.now();\n // console.log('Received pong from server');\n });\n \n // Listen for heartbeat events from server (every 3 minutes)\n this.socket.on('heartbeat', (data) => {\n console.log('🫀 Received server heartbeat:', data);\n // Add heartbeat to event list for visibility\n this.addEvent({\n type: 'system',\n subtype: 'heartbeat',\n timestamp: data.timestamp || new Date().toISOString(),\n data: data\n });\n \n // Update last ping time to indicate server is alive\n this.lastPingTime = Date.now();\n \n // Log to console for debugging\n console.log(`Server heartbeat #${data.heartbeat_number}: ${data.server_uptime_formatted} uptime, ${data.connected_clients} clients connected`);\n });\n \n // Session and event handlers (legacy/fallback)\n this.socket.on('session.started', (data) => {\n this.addEvent({ type: 'session', subtype: 'started', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('session.ended', (data) => {\n this.addEvent({ type: 'session', subtype: 'ended', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('claude.request', (data) => {\n this.addEvent({ type: 'claude', subtype: 'request', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('claude.response', (data) => {\n this.addEvent({ type: 'claude', subtype: 'response', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('agent.loaded', (data) => {\n this.addEvent({ type: 'agent', subtype: 'loaded', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('agent.executed', (data) => {\n this.addEvent({ type: 'agent', subtype: 'executed', timestamp: new Date().toISOString(), data });\n });\n\n // DISABLED: Legacy hook handlers - events now come through claude_event pathway\n // to prevent duplication. Hook events are processed by the claude_event handler above.\n // this.socket.on('hook.pre', (data) => {\n // this.addEvent({ type: 'hook', subtype: 'pre', timestamp: new Date().toISOString(), data });\n // });\n\n // this.socket.on('hook.post', (data) => {\n // this.addEvent({ type: 'hook', subtype: 'post', timestamp: new Date().toISOString(), data });\n // });\n\n this.socket.on('todo.updated', (data) => {\n this.addEvent({ type: 'todo', subtype: 'updated', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('memory.operation', (data) => {\n this.addEvent({ type: 'memory', subtype: 'operation', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('log.entry', (data) => {\n this.addEvent({ type: 'log', subtype: 'entry', timestamp: new Date().toISOString(), data });\n });\n\n // Code analysis events - now allowed to flow through for troubleshooting\n // These are ALSO handled by the code-tree component and shown in the footer\n // They will appear in both places: Events tab (for troubleshooting) and Code tab (for visualization)\n this.socket.on('code:analysis:queued', (data) => {\n // Add to events list for troubleshooting\n console.log('Code analysis queued event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'analysis:queued', timestamp: new Date().toISOString(), data });\n });\n \n this.socket.on('code:analysis:accepted', (data) => {\n // Add to events list for troubleshooting\n console.log('Code analysis accepted event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'analysis:accepted', timestamp: new Date().toISOString(), data });\n });\n \n this.socket.on('code:analysis:start', (data) => {\n // Add to events list for troubleshooting\n console.log('Code analysis start event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'analysis:start', timestamp: new Date().toISOString(), data });\n });\n \n this.socket.on('code:analysis:complete', (data) => {\n // Add to events list for troubleshooting\n console.log('Code analysis complete event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'analysis:complete', timestamp: new Date().toISOString(), data });\n });\n \n this.socket.on('code:analysis:error', (data) => {\n // Add to events list for troubleshooting\n console.log('Code analysis error event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'analysis:error', timestamp: new Date().toISOString(), data });\n });\n \n this.socket.on('code:file:start', (data) => {\n // Add to events list for troubleshooting\n console.log('Code file start event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'file:start', timestamp: new Date().toISOString(), data });\n });\n \n this.socket.on('code:node:found', (data) => {\n // Add to events list for troubleshooting\n console.log('Code node found event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'node:found', timestamp: new Date().toISOString(), data });\n });\n \n this.socket.on('code:analysis:progress', (data) => {\n // Add to events list for troubleshooting\n console.log('Code analysis progress event received, adding to events list for troubleshooting');\n this.addEvent({ type: 'code', subtype: 'analysis:progress', timestamp: new Date().toISOString(), data });\n });\n\n this.socket.on('history', (data) => {\n console.log('Received event history:', data);\n if (data && Array.isArray(data.events)) {\n console.log(`Processing ${data.events.length} historical events (${data.count} sent, ${data.total_available} total available)`);\n // Add events in the order received (should already be chronological - oldest first)\n // Transform each historical event to match expected format\n data.events.forEach(event => {\n const transformedEvent = this.transformEvent(event);\n this.addEvent(transformedEvent, false);\n });\n this.notifyEventUpdate();\n console.log(`Event history loaded: ${data.events.length} events added to dashboard`);\n } else if (Array.isArray(data)) {\n // Handle legacy format for backward compatibility\n console.log('Received legacy event history format:', data.length, 'events');\n data.forEach(event => {\n const transformedEvent = this.transformEvent(event);\n this.addEvent(transformedEvent, false);\n });\n this.notifyEventUpdate();\n }\n });\n\n this.socket.on('system.status', (data) => {\n console.log('Received system status:', data);\n if (data.sessions) {\n this.updateSessions(data.sessions);\n }\n if (data.current_session) {\n this.currentSessionId = data.current_session;\n }\n });\n }\n\n /**\n * Disconnect from Socket.IO server\n */\n disconnect() {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n }\n this.port = null; // Clear the stored port\n this.isConnected = false;\n this.isConnecting = false;\n }\n\n /**\n * Emit an event with retry support\n * @param {string} event - Event name\n * @param {any} data - Event data\n * @param {Object} options - Options for retry behavior\n */\n emitWithRetry(event, data = null, options = {}) {\n const { \n maxRetries = 3,\n retryDelays = [1000, 2000, 4000],\n onSuccess = null,\n onFailure = null\n } = options;\n \n const emissionId = `${event}_${Date.now()}_${Math.random()}`;\n \n const attemptEmission = (attemptNum = 0) => {\n if (!this.socket || !this.socket.connected) {\n // Queue for later if disconnected\n if (attemptNum === 0) {\n this.queueEvent(event, data);\n console.log(`Queued ${event} for later emission (disconnected)`);\n if (onFailure) onFailure('disconnected');\n }\n return;\n }\n \n try {\n // Attempt emission\n this.socket.emit(event, data);\n console.log(`Emitted ${event} successfully`);\n \n // Remove from pending\n this.pendingEmissions.delete(emissionId);\n \n if (onSuccess) onSuccess();\n \n } catch (error) {\n console.error(`Failed to emit ${event} (attempt ${attemptNum + 1}):`, error);\n \n if (attemptNum < maxRetries - 1) {\n const delay = retryDelays[attemptNum] || retryDelays[retryDelays.length - 1];\n console.log(`Retrying ${event} in ${delay}ms...`);\n \n // Store pending emission\n this.pendingEmissions.set(emissionId, {\n event,\n data,\n attemptNum: attemptNum + 1,\n scheduledTime: Date.now() + delay\n });\n \n setTimeout(() => attemptEmission(attemptNum + 1), delay);\n } else {\n console.error(`Failed to emit ${event} after ${maxRetries} attempts`);\n this.pendingEmissions.delete(emissionId);\n if (onFailure) onFailure('max_retries_exceeded');\n }\n }\n };\n \n attemptEmission();\n }\n \n /**\n * Queue an event for later emission\n * @param {string} event - Event name\n * @param {any} data - Event data\n */\n queueEvent(event, data) {\n if (this.eventQueue.length >= this.maxQueueSize) {\n // Remove oldest event if queue is full\n const removed = this.eventQueue.shift();\n console.warn(`Event queue full, dropped oldest event: ${removed.event}`);\n }\n \n this.eventQueue.push({\n event,\n data,\n timestamp: Date.now()\n });\n }\n \n /**\n * Flush queued events after reconnection\n */\n flushEventQueue() {\n if (this.eventQueue.length === 0) return;\n \n console.log(`Flushing ${this.eventQueue.length} queued events...`);\n const events = [...this.eventQueue];\n this.eventQueue = [];\n \n // Emit each queued event with a small delay between them\n events.forEach((item, index) => {\n setTimeout(() => {\n if (this.socket && this.socket.connected) {\n this.socket.emit(item.event, item.data);\n console.log(`Flushed queued event: ${item.event}`);\n }\n }, index * 100); // 100ms between each event\n });\n }\n \n /**\n * Schedule a reconnection attempt with exponential backoff\n */\n scheduleReconnect() {\n if (this.retryAttempts >= this.maxRetryAttempts) {\n console.log('Max reconnection attempts reached, stopping auto-reconnect');\n this.notifyConnectionStatus('Reconnection failed', 'disconnected');\n return;\n }\n \n const delay = this.retryDelays[this.retryAttempts] || this.retryDelays[this.retryDelays.length - 1];\n this.retryAttempts++;\n \n console.log(`Scheduling reconnect attempt ${this.retryAttempts}/${this.maxRetryAttempts} in ${delay}ms...`);\n this.notifyConnectionStatus(`Reconnecting in ${delay/1000}s...`, 'connecting');\n \n setTimeout(() => {\n if (!this.isConnected && this.port) {\n console.log(`Attempting reconnection ${this.retryAttempts}/${this.maxRetryAttempts}...`);\n this.connect(this.port);\n }\n }, delay);\n }\n \n /**\n * Request server status\n */\n requestStatus() {\n if (this.socket && this.socket.connected) {\n console.log('Requesting server status...');\n this.emitWithRetry('request.status', null, {\n maxRetries: 2,\n retryDelays: [500, 1000]\n });\n }\n }\n\n /**\n * Request event history from server\n * @param {Object} options - History request options\n * @param {number} options.limit - Maximum number of events to retrieve (default: 50)\n * @param {Array<string>} options.event_types - Optional filter by event types\n */\n requestHistory(options = {}) {\n if (this.socket && this.socket.connected) {\n const params = {\n limit: options.limit || 50,\n event_types: options.event_types || []\n };\n console.log('Requesting event history...', params);\n this.emitWithRetry('get_history', params, {\n maxRetries: 3,\n retryDelays: [1000, 2000, 3000],\n onFailure: (reason) => {\n console.error(`Failed to request history: ${reason}`);\n }\n });\n } else {\n console.warn('Cannot request history: not connected to server');\n }\n }\n\n /**\n * Add event to local storage and notify listeners\n * @param {Object} eventData - Event data\n * @param {boolean} notify - Whether to notify listeners (default: true)\n */\n addEvent(eventData, notify = true) {\n // Ensure event has required fields\n if (!eventData.timestamp) {\n eventData.timestamp = new Date().toISOString();\n }\n if (!eventData.id) {\n eventData.id = Date.now() + Math.random();\n }\n\n this.events.push(eventData);\n\n // Update session tracking\n if (eventData.data && eventData.data.session_id) {\n const sessionId = eventData.data.session_id;\n if (!this.sessions.has(sessionId)) {\n this.sessions.set(sessionId, {\n id: sessionId,\n startTime: eventData.timestamp,\n lastActivity: eventData.timestamp,\n eventCount: 0,\n working_directory: null,\n git_branch: null\n });\n }\n const session = this.sessions.get(sessionId);\n session.lastActivity = eventData.timestamp;\n session.eventCount++;\n \n // Extract working directory from event data if available (prioritize newer data)\n // Check multiple possible locations for working directory\n const possiblePaths = [\n eventData.data.cwd,\n eventData.data.working_directory,\n eventData.data.working_dir,\n eventData.data.workingDirectory,\n eventData.data.instance_info?.working_dir,\n eventData.data.instance_info?.working_directory,\n eventData.data.instance_info?.cwd,\n eventData.cwd,\n eventData.working_directory,\n eventData.working_dir\n ];\n \n for (const path of possiblePaths) {\n if (path && typeof path === 'string' && path.trim()) {\n session.working_directory = path;\n console.log(`[SOCKET-CLIENT] Found working directory for session ${sessionId}:`, path);\n break;\n }\n }\n \n // Extract git branch if available\n if (eventData.data.git_branch) {\n session.git_branch = eventData.data.git_branch;\n } else if (eventData.data.instance_info && eventData.data.instance_info.git_branch) {\n session.git_branch = eventData.data.instance_info.git_branch;\n }\n }\n\n if (notify) {\n this.notifyEventUpdate();\n }\n }\n\n /**\n * Update sessions from server data\n * @param {Array} sessionsData - Sessions data from server\n */\n updateSessions(sessionsData) {\n if (Array.isArray(sessionsData)) {\n sessionsData.forEach(session => {\n this.sessions.set(session.id, session);\n });\n }\n }\n\n /**\n * Clear all events\n */\n clearEvents() {\n this.events = [];\n this.sessions.clear();\n this.notifyEventUpdate();\n }\n\n /**\n * Clear events and request fresh history from server\n * @param {Object} options - History request options (same as requestHistory)\n */\n refreshHistory(options = {}) {\n this.clearEvents();\n this.requestHistory(options);\n }\n\n /**\n * Get filtered events by session\n * @param {string} sessionId - Session ID to filter by (null for all)\n * @returns {Array} Filtered events\n */\n getEventsBySession(sessionId = null) {\n if (!sessionId) {\n return this.events;\n }\n return this.events.filter(event =>\n event.data && event.data.session_id === sessionId\n );\n }\n\n /**\n * Register callback for connection events\n * @param {string} eventType - Type of event (connect, disconnect, error)\n * @param {Function} callback - Callback function\n */\n onConnection(eventType, callback) {\n if (this.connectionCallbacks[eventType]) {\n this.connectionCallbacks[eventType].push(callback);\n }\n }\n\n /**\n * Register callback for event updates\n * @param {Function} callback - Callback function\n */\n onEventUpdate(callback) {\n this.connectionCallbacks.event.push(callback);\n }\n\n /**\n * Subscribe to socket events (proxy to underlying socket)\n * @param {string} event - Event name\n * @param {Function} callback - Callback function\n */\n on(event, callback) {\n if (this.socket) {\n return this.socket.on(event, callback);\n } else {\n console.warn(`Cannot subscribe to '${event}': socket not initialized`);\n }\n }\n\n /**\n * Unsubscribe from socket events (proxy to underlying socket)\n * @param {string} event - Event name\n * @param {Function} callback - Callback function (optional)\n */\n off(event, callback) {\n if (this.socket) {\n return this.socket.off(event, callback);\n } else {\n console.warn(`Cannot unsubscribe from '${event}': socket not initialized`);\n }\n }\n\n /**\n * Notify connection status change\n * @param {string} status - Status message\n * @param {string} type - Status type (connected, disconnected, connecting)\n */\n notifyConnectionStatus(status, type) {\n console.log(`SocketClient: Connection status changed to '${status}' (${type})`);\n\n // Direct DOM update - immediate and reliable\n this.updateConnectionStatusDOM(status, type);\n\n // Also dispatch custom event for other modules\n document.dispatchEvent(new CustomEvent('socketConnectionStatus', {\n detail: { status, type }\n }));\n }\n\n /**\n * Directly update the connection status DOM element\n * @param {string} status - Status message\n * @param {string} type - Status type (connected, disconnected, connecting)\n */\n updateConnectionStatusDOM(status, type) {\n const statusElement = document.getElementById('connection-status');\n if (statusElement) {\n // Update the text content while preserving the indicator span\n statusElement.innerHTML = `<span>●</span> ${status}`;\n\n // Update the CSS class for styling\n statusElement.className = `status-badge status-${type}`;\n\n console.log(`SocketClient: Direct DOM update - status: '${status}' (${type})`);\n } else {\n console.warn('SocketClient: Could not find connection-status element in DOM');\n }\n }\n\n /**\n * Notify event update\n */\n notifyEventUpdate() {\n this.connectionCallbacks.event.forEach(callback =>\n callback(this.events, this.sessions)\n );\n\n // Also dispatch custom event\n document.dispatchEvent(new CustomEvent('socketEventUpdate', {\n detail: { events: this.events, sessions: this.sessions }\n }));\n }\n\n /**\n * Get connection state\n * @returns {Object} Connection state\n */\n getConnectionState() {\n return {\n isConnected: this.isConnected,\n isConnecting: this.isConnecting,\n socketId: this.socket ? this.socket.id : null\n };\n }\n\n /**\n * Validate event against expected schema\n * @param {Object} eventData - Raw event data\n * @returns {Object|null} Validated event or null if invalid\n */\n validateEventSchema(eventData) {\n if (!eventData || typeof eventData !== 'object') {\n console.warn('Event data is not an object:', eventData);\n return null;\n }\n \n // Make a copy to avoid modifying the original\n const validated = { ...eventData };\n \n // Check and provide defaults for required fields\n if (!validated.source) {\n validated.source = 'system'; // Default source for backward compatibility\n }\n if (!validated.type) {\n // If there's an event field, use it as the type\n if (validated.event) {\n validated.type = validated.event;\n } else {\n validated.type = 'unknown';\n }\n }\n if (!validated.subtype) {\n validated.subtype = 'generic';\n }\n if (!validated.timestamp) {\n validated.timestamp = new Date().toISOString();\n }\n if (!validated.data) {\n validated.data = {};\n }\n \n // Ensure data field is an object\n if (validated.data && typeof validated.data !== 'object') {\n validated.data = { value: validated.data };\n }\n \n console.log('Validated event:', validated);\n return validated;\n }\n \n /**\n * Transform received event to match expected dashboard format\n * @param {Object} eventData - Raw event data from server\n * @returns {Object} Transformed event\n */\n transformEvent(eventData) {\n // Handle multiple event structures:\n // 1. Hook events: { type: 'hook.pre_tool', timestamp: '...', data: {...} }\n // 2. Legacy events: { event: 'TestStart', timestamp: '...', ... }\n // 3. Standard events: { type: 'session', subtype: 'started', ... }\n // 4. Normalized events: { type: 'code', subtype: 'progress', ... } - already normalized, keep as-is\n\n if (!eventData) {\n return eventData; // Return as-is if null/undefined\n }\n\n let transformedEvent = { ...eventData };\n\n // Check if event is already normalized (has both type and subtype as separate fields)\n // This prevents double-transformation of events that were normalized on the backend\n const isAlreadyNormalized = eventData.type && eventData.subtype && \n !eventData.type.includes('.') && \n !eventData.type.includes(':');\n\n if (isAlreadyNormalized) {\n // Event is already properly normalized from backend, just preserve it\n // Store a composite originalEventName for display if needed\n if (!transformedEvent.originalEventName) {\n if (eventData.subtype === 'generic' || eventData.type === eventData.subtype) {\n transformedEvent.originalEventName = eventData.type;\n } else {\n transformedEvent.originalEventName = `${eventData.type}.${eventData.subtype}`;\n }\n }\n // Return early to avoid further transformation\n }\n // Handle legacy format with 'event' field but no 'type'\n else if (!eventData.type && eventData.event) {\n // Map common event names to proper type/subtype\n const eventName = eventData.event;\n \n // Check for known event patterns\n if (eventName === 'TestStart' || eventName === 'TestEnd') {\n transformedEvent.type = 'test';\n transformedEvent.subtype = eventName.toLowerCase().replace('test', '');\n } else if (eventName === 'SubagentStart' || eventName === 'SubagentStop') {\n transformedEvent.type = 'subagent';\n transformedEvent.subtype = eventName.toLowerCase().replace('subagent', '');\n } else if (eventName === 'ToolCall') {\n transformedEvent.type = 'tool';\n transformedEvent.subtype = 'call';\n } else if (eventName === 'UserPrompt') {\n transformedEvent.type = 'hook';\n transformedEvent.subtype = 'user_prompt';\n } else {\n // Generic fallback for unknown event names\n // Use 'unknown' for type and the actual eventName for subtype\n transformedEvent.type = 'unknown';\n transformedEvent.subtype = eventName.toLowerCase();\n \n // Prevent duplicate type/subtype values\n if (transformedEvent.type === transformedEvent.subtype) {\n transformedEvent.subtype = 'event';\n }\n }\n \n // Remove the 'event' field to avoid confusion\n delete transformedEvent.event;\n // Store original event name for display purposes\n transformedEvent.originalEventName = eventName;\n }\n // Handle standard format with 'type' field that needs transformation\n else if (eventData.type) {\n const type = eventData.type;\n \n // Transform 'hook.subtype' format to separate type and subtype\n if (type.startsWith('hook.')) {\n const subtype = type.substring(5); // Remove 'hook.' prefix\n transformedEvent.type = 'hook';\n transformedEvent.subtype = subtype;\n transformedEvent.originalEventName = type;\n }\n // Transform 'code:*' events to proper code type\n // Handle multi-level subtypes like 'code:analysis:queued'\n else if (type.startsWith('code:')) {\n transformedEvent.type = 'code';\n // Replace colons with underscores in subtype for consistency\n const subtypePart = type.substring(5); // Remove 'code:' prefix\n transformedEvent.subtype = subtypePart.replace(/:/g, '_');\n transformedEvent.originalEventName = type;\n }\n // Transform other dotted types like 'session.started' -> type: 'session', subtype: 'started'\n else if (type.includes('.')) {\n const [mainType, ...subtypeParts] = type.split('.');\n transformedEvent.type = mainType;\n transformedEvent.subtype = subtypeParts.join('.');\n transformedEvent.originalEventName = type;\n }\n // Transform any remaining colon-separated types generically\n else if (type.includes(':')) {\n const parts = type.split(':', 2); // Split into max 2 parts\n transformedEvent.type = parts[0];\n // Replace any remaining colons with underscores in subtype\n transformedEvent.subtype = parts.length > 1 ? parts[1].replace(/:/g, '_') : 'generic';\n transformedEvent.originalEventName = type;\n }\n // If type doesn't need transformation but has no subtype, set a default\n else if (!eventData.subtype) {\n transformedEvent.subtype = 'generic';\n transformedEvent.originalEventName = type;\n }\n }\n // If no type and no event field, mark as unknown\n else {\n transformedEvent.type = 'unknown';\n transformedEvent.subtype = '';\n transformedEvent.originalEventName = 'unknown';\n }\n\n // Extract and flatten data fields to top level for dashboard compatibility\n // The dashboard expects fields like tool_name, agent_type, etc. at the top level\n if (eventData.data && typeof eventData.data === 'object') {\n // Protected fields that should never be overwritten by data fields\n const protectedFields = ['type', 'subtype', 'timestamp', 'id', 'event', 'event_type', 'originalEventName'];\n \n // Copy all data fields to the top level, except protected ones\n Object.keys(eventData.data).forEach(key => {\n // Only copy if not a protected field\n if (!protectedFields.includes(key)) {\n // Special handling for tool_parameters to ensure it's properly preserved\n // This is critical for file path extraction in file-tool-tracker\n if (key === 'tool_parameters' && typeof eventData.data[key] === 'object') {\n // Deep copy the tool_parameters object to preserve all nested fields\n transformedEvent[key] = JSON.parse(JSON.stringify(eventData.data[key]));\n } else {\n transformedEvent[key] = eventData.data[key];\n }\n } else {\n // Log debug info if data field would overwrite a protected field\n // Only log for non-timestamp fields to reduce noise\n if (key !== 'timestamp') {\n console.debug(`Protected field '${key}' in data object was not copied to top level to preserve event structure`);\n }\n }\n });\n \n // Keep the original data object for backward compatibility\n transformedEvent.data = eventData.data;\n }\n\n // Add hook_event_name for ActivityTree compatibility\n // Map the type/subtype structure to the expected hook_event_name format\n if (transformedEvent.type === 'hook') {\n if (transformedEvent.subtype === 'pre_tool') {\n transformedEvent.hook_event_name = 'PreToolUse';\n } else if (transformedEvent.subtype === 'post_tool') {\n transformedEvent.hook_event_name = 'PostToolUse';\n } else if (transformedEvent.subtype === 'subagent_start') {\n transformedEvent.hook_event_name = 'SubagentStart';\n } else if (transformedEvent.subtype === 'subagent_stop') {\n transformedEvent.hook_event_name = 'SubagentStop';\n } else if (transformedEvent.subtype === 'todo_write') {\n transformedEvent.hook_event_name = 'TodoWrite';\n } else if (transformedEvent.subtype === 'start') {\n transformedEvent.hook_event_name = 'Start';\n } else if (transformedEvent.subtype === 'stop') {\n transformedEvent.hook_event_name = 'Stop';\n }\n } else if (transformedEvent.type === 'subagent') {\n if (transformedEvent.subtype === 'start') {\n transformedEvent.hook_event_name = 'SubagentStart';\n } else if (transformedEvent.subtype === 'stop') {\n transformedEvent.hook_event_name = 'SubagentStop';\n }\n } else if (transformedEvent.type === 'todo' && transformedEvent.subtype === 'updated') {\n transformedEvent.hook_event_name = 'TodoWrite';\n }\n\n // Debug logging for tool events\n if (transformedEvent.type === 'hook' && (transformedEvent.subtype === 'pre_tool' || transformedEvent.subtype === 'post_tool')) {\n console.log('Transformed tool event:', {\n type: transformedEvent.type,\n subtype: transformedEvent.subtype,\n hook_event_name: transformedEvent.hook_event_name,\n tool_name: transformedEvent.tool_name,\n has_tool_parameters: !!transformedEvent.tool_parameters,\n tool_parameters: transformedEvent.tool_parameters,\n has_data: !!transformedEvent.data,\n keys: Object.keys(transformedEvent).filter(k => k !== 'data')\n });\n \n // Extra debug logging for file-related tools\n const fileTools = ['Read', 'Write', 'Edit', 'MultiEdit', 'NotebookEdit'];\n if (fileTools.includes(transformedEvent.tool_name)) {\n console.log('File tool event details:', {\n tool_name: transformedEvent.tool_name,\n file_path: transformedEvent.tool_parameters?.file_path,\n path: transformedEvent.tool_parameters?.path,\n notebook_path: transformedEvent.tool_parameters?.notebook_path,\n full_parameters: transformedEvent.tool_parameters\n });\n }\n }\n\n return transformedEvent;\n }\n\n /**\n * Get current events and sessions\n * @returns {Object} Current state\n */\n getState() {\n return {\n events: this.events,\n sessions: this.sessions,\n currentSessionId: this.currentSessionId\n };\n }\n\n /**\n * Start health monitoring\n * Detects stale connections and triggers reconnection\n */\n startHealthMonitoring() {\n this.healthCheckInterval = setInterval(() => {\n if (this.isConnected && this.lastPingTime) {\n const timeSinceLastPing = Date.now() - this.lastPingTime;\n \n if (timeSinceLastPing > this.pingTimeout) {\n console.warn(`No ping from server for ${timeSinceLastPing/1000}s, connection may be stale`);\n \n // Force reconnection\n if (this.socket) {\n console.log('Forcing reconnection due to stale connection...');\n this.socket.disconnect();\n setTimeout(() => {\n if (this.port) {\n this.connect(this.port);\n }\n }, 1000);\n }\n }\n }\n }, 10000); // Check every 10 seconds\n }\n \n /**\n * Stop health monitoring\n */\n stopHealthMonitoring() {\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n this.healthCheckInterval = null;\n }\n }\n \n /**\n * Start periodic status check as fallback mechanism\n * This ensures the UI stays in sync with actual socket state\n */\n startStatusCheckFallback() {\n // Check status every 2 seconds\n setInterval(() => {\n this.checkAndUpdateStatus();\n }, 2000);\n\n // Initial check after DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n setTimeout(() => this.checkAndUpdateStatus(), 100);\n });\n } else {\n setTimeout(() => this.checkAndUpdateStatus(), 100);\n }\n }\n\n /**\n * Check actual socket state and update UI if necessary\n */\n checkAndUpdateStatus() {\n let actualStatus = 'Disconnected';\n let actualType = 'disconnected';\n\n if (this.socket) {\n if (this.socket.connected) {\n actualStatus = 'Connected';\n actualType = 'connected';\n this.isConnected = true;\n this.isConnecting = false;\n } else if (this.socket.connecting || this.isConnecting) {\n actualStatus = 'Connecting...';\n actualType = 'connecting';\n this.isConnected = false;\n } else {\n actualStatus = 'Disconnected';\n actualType = 'disconnected';\n this.isConnected = false;\n this.isConnecting = false;\n }\n }\n\n // Check if UI needs updating\n const statusElement = document.getElementById('connection-status');\n if (statusElement) {\n const currentText = statusElement.textContent.replace('●', '').trim();\n const currentClass = statusElement.className;\n const expectedClass = `status-badge status-${actualType}`;\n\n // Update if status text or class doesn't match\n if (currentText !== actualStatus || currentClass !== expectedClass) {\n console.log(`SocketClient: Fallback update - was '${currentText}' (${currentClass}), now '${actualStatus}' (${expectedClass})`);\n this.updateConnectionStatusDOM(actualStatus, actualType);\n }\n }\n }\n\n /**\n * Clean up resources\n */\n destroy() {\n this.stopHealthMonitoring();\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n }\n this.eventQueue = [];\n this.pendingEmissions.clear();\n }\n \n /**\n * Get connection metrics\n * @returns {Object} Connection metrics\n */\n getConnectionMetrics() {\n return {\n isConnected: this.isConnected,\n uptime: this.lastConnectTime ? (Date.now() - this.lastConnectTime) / 1000 : 0,\n lastPing: this.lastPingTime ? (Date.now() - this.lastPingTime) / 1000 : null,\n queuedEvents: this.eventQueue.length,\n pendingEmissions: this.pendingEmissions.size,\n retryAttempts: this.retryAttempts\n };\n }\n}\n\n// ES6 Module export\nexport { SocketClient };\nexport default SocketClient;\n\n// Backward compatibility - keep window export for non-module usage\nwindow.SocketClient = SocketClient;\n","/**\n * Socket Manager Module\n *\n * Handles all socket connection management, event dispatching, and connection state.\n * Provides a centralized interface for socket operations across the dashboard.\n *\n * WHY: Extracted from main dashboard to centralize socket connection logic and\n * provide better separation of concerns. This allows for easier testing and\n * maintenance of connection handling code.\n *\n * DESIGN DECISION: Acts as a wrapper around SocketClient to provide dashboard-specific\n * connection management while maintaining the existing SocketClient interface.\n * Uses event dispatching to notify other modules of connection state changes.\n */\n\n// Import SocketClient (assuming it will be converted to ES6 modules too)\nimport { SocketClient } from '../socket-client.js';\nclass SocketManager {\n constructor() {\n this.socketClient = null;\n this.connectionCallbacks = new Set();\n this.eventUpdateCallbacks = new Set();\n\n // Initialize socket client\n this.socketClient = new SocketClient();\n\n // Make socketClient globally available (for backward compatibility)\n window.socketClient = this.socketClient;\n\n this.setupSocketEventHandlers();\n\n // Force initial status update after a short delay to ensure DOM is ready\n setTimeout(() => {\n this.updateInitialConnectionStatus();\n }, 100);\n\n console.log('Socket manager initialized');\n }\n\n /**\n * Set up socket event handlers for connection status and events\n */\n setupSocketEventHandlers() {\n // Listen for connection status changes\n document.addEventListener('socketConnectionStatus', (e) => {\n console.log(`SocketManager: Processing connection status update: ${e.detail.status} (${e.detail.type})`);\n this.handleConnectionStatusChange(e.detail.status, e.detail.type);\n\n // Notify all registered callbacks\n this.connectionCallbacks.forEach(callback => {\n try {\n callback(e.detail.status, e.detail.type);\n } catch (error) {\n console.error('Error in connection callback:', error);\n }\n });\n });\n\n // Set up event update handling\n if (this.socketClient) {\n this.socketClient.onEventUpdate((events) => {\n // Notify all registered callbacks\n this.eventUpdateCallbacks.forEach(callback => {\n try {\n callback(events);\n } catch (error) {\n console.error('Error in event update callback:', error);\n }\n });\n });\n }\n }\n\n /**\n * Handle connection status changes\n * @param {string} status - Connection status text\n * @param {string} type - Connection type ('connected', 'disconnected', etc.)\n */\n handleConnectionStatusChange(status, type) {\n this.updateConnectionStatus(status, type);\n\n // Set up git branch listener when connected\n if (type === 'connected' && this.socketClient && this.socketClient.socket) {\n // Expose socket globally for components like CodeTree\n window.socket = this.socketClient.socket;\n console.log('SocketManager: Exposed socket globally as window.socket');\n \n this.setupGitBranchListener();\n }\n }\n\n /**\n * Update initial connection status on dashboard load\n */\n updateInitialConnectionStatus() {\n console.log('SocketManager: Updating initial connection status');\n\n // Force status check on socket client (uses fallback mechanism)\n if (this.socketClient && typeof this.socketClient.checkAndUpdateStatus === 'function') {\n console.log('SocketManager: Using socket client checkAndUpdateStatus method');\n this.socketClient.checkAndUpdateStatus();\n } else if (this.socketClient && this.socketClient.socket) {\n console.log('SocketManager: Checking socket state directly', {\n connected: this.socketClient.socket.connected,\n connecting: this.socketClient.socket.connecting,\n isConnecting: this.socketClient.isConnecting,\n isConnected: this.socketClient.isConnected\n });\n\n if (this.socketClient.socket.connected) {\n console.log('SocketManager: Socket is already connected, updating status');\n // Expose socket globally for components like CodeTree\n window.socket = this.socketClient.socket;\n console.log('SocketManager: Exposed socket globally as window.socket');\n this.updateConnectionStatus('Connected', 'connected');\n } else if (this.socketClient.isConnecting || this.socketClient.socket.connecting) {\n console.log('SocketManager: Socket is connecting, updating status');\n this.updateConnectionStatus('Connecting...', 'connecting');\n } else {\n console.log('SocketManager: Socket is disconnected, updating status');\n this.updateConnectionStatus('Disconnected', 'disconnected');\n }\n } else {\n console.log('SocketManager: No socket client or socket found, setting disconnected status');\n this.updateConnectionStatus('Disconnected', 'disconnected');\n }\n\n // Additional fallback - check again after a longer delay in case connection is still establishing\n setTimeout(() => {\n console.log('SocketManager: Secondary status check after 1 second');\n if (this.socketClient && this.socketClient.socket && this.socketClient.socket.connected) {\n console.log('SocketManager: Socket connected in secondary check, updating status');\n // Expose socket globally if not already done\n if (!window.socket) {\n window.socket = this.socketClient.socket;\n console.log('SocketManager: Exposed socket globally as window.socket (secondary check)');\n }\n this.updateConnectionStatus('Connected', 'connected');\n }\n }, 1000);\n }\n\n /**\n * Set up git branch response listener for connected socket\n */\n setupGitBranchListener() {\n // Remove any existing listener first\n this.socketClient.socket.off('git_branch_response');\n\n // Add the listener\n this.socketClient.socket.on('git_branch_response', (data) => {\n if (data.success) {\n const footerBranch = document.getElementById('footer-git-branch');\n if (footerBranch) {\n footerBranch.textContent = data.branch || 'unknown';\n }\n if (footerBranch) {\n footerBranch.style.display = 'inline';\n }\n } else {\n console.error('Git branch request failed:', data.error);\n }\n });\n }\n\n /**\n * Update connection status display\n * @param {string} status - Status text to display\n * @param {string} type - Status type for styling\n */\n updateConnectionStatus(status, type) {\n const statusElement = document.getElementById('connection-status');\n if (statusElement) {\n // Check if there's a span indicator first\n const indicator = statusElement.querySelector('span');\n if (indicator) {\n // If there's a span, update the text content after the span\n const statusIndicator = type === 'connected' ? '●' : '●';\n statusElement.innerHTML = `<span>${statusIndicator}</span> ${status}`;\n } else {\n // If no span, just update text content\n statusElement.textContent = status;\n }\n\n statusElement.className = `status-badge status-${type}`;\n console.log(`SocketManager: UI updated - status: '${status}' (${type})`);\n } else {\n console.error('SocketManager: Could not find connection-status element in DOM');\n }\n }\n\n /**\n * Connect to socket server\n * @param {number} port - Port number to connect to\n */\n connect(port) {\n if (this.socketClient) {\n this.socketClient.connect(port);\n }\n }\n\n /**\n * Disconnect from socket server\n */\n disconnect() {\n if (this.socketClient) {\n this.socketClient.disconnect();\n }\n }\n\n /**\n * Check if socket is connected\n * @returns {boolean} - True if connected\n */\n isConnected() {\n return this.socketClient && this.socketClient.isConnected;\n }\n\n /**\n * Check if socket is connecting\n * @returns {boolean} - True if connecting\n */\n isConnecting() {\n return this.socketClient && this.socketClient.isConnecting;\n }\n\n /**\n * Get the underlying socket client\n * @returns {SocketClient} - The socket client instance\n */\n getSocketClient() {\n return this.socketClient;\n }\n\n /**\n * Get the raw socket connection\n * @returns {Socket|null} - The raw socket or null\n */\n getSocket() {\n return this.socketClient ? this.socketClient.socket : null;\n }\n\n /**\n * Register a callback for connection status changes\n * @param {Function} callback - Callback function(status, type)\n */\n onConnectionStatusChange(callback) {\n this.connectionCallbacks.add(callback);\n }\n\n /**\n * Unregister a connection status callback\n * @param {Function} callback - Callback to remove\n */\n offConnectionStatusChange(callback) {\n this.connectionCallbacks.delete(callback);\n }\n\n /**\n * Register a callback for event updates\n * @param {Function} callback - Callback function(events)\n */\n onEventUpdate(callback) {\n this.eventUpdateCallbacks.add(callback);\n }\n\n /**\n * Unregister an event update callback\n * @param {Function} callback - Callback to remove\n */\n offEventUpdate(callback) {\n this.eventUpdateCallbacks.delete(callback);\n }\n\n /**\n * Toggle connection controls visibility\n */\n toggleConnectionControls() {\n const controlsRow = document.getElementById('connection-controls-row');\n const toggleBtn = document.getElementById('connection-toggle-btn');\n\n if (controlsRow && toggleBtn) {\n const isVisible = controlsRow.classList.contains('show');\n\n if (isVisible) {\n controlsRow.classList.remove('show');\n controlsRow.style.display = 'none';\n toggleBtn.textContent = 'Connection Settings';\n } else {\n controlsRow.classList.add('show');\n controlsRow.style.display = 'block';\n toggleBtn.textContent = 'Hide Settings';\n }\n }\n }\n\n /**\n * Setup connection control event handlers\n * Called during dashboard initialization\n */\n setupConnectionControls() {\n const connectBtn = document.getElementById('connect-btn');\n const disconnectBtn = document.getElementById('disconnect-btn');\n const connectionToggleBtn = document.getElementById('connection-toggle-btn');\n\n if (connectBtn) {\n connectBtn.addEventListener('click', () => {\n const port = document.getElementById('port-input').value || 8765;\n this.connect(port);\n });\n }\n\n if (disconnectBtn) {\n disconnectBtn.addEventListener('click', () => {\n this.disconnect();\n });\n }\n\n if (connectionToggleBtn) {\n connectionToggleBtn.addEventListener('click', () => {\n this.toggleConnectionControls();\n });\n }\n }\n\n /**\n * Initialize connection from URL parameters\n * @param {URLSearchParams} params - URL search parameters\n */\n initializeFromURL(params) {\n const port = params.get('port');\n const portInput = document.getElementById('port-input');\n\n // Determine the port to use:\n // 1. URL parameter 'port'\n // 2. Current page port (if served via HTTP)\n // 3. Default port value from input field\n // 4. Fallback to 8765\n let connectPort = port;\n if (!connectPort && window.location.protocol === 'http:') {\n connectPort = window.location.port || '8765';\n }\n if (!connectPort) {\n connectPort = portInput?.value || '8765';\n }\n\n // Update the port input field with the determined port\n if (portInput) {\n portInput.value = connectPort;\n }\n\n // Auto-connect by default unless explicitly disabled\n // Changed: Always auto-connect by default even without URL params\n const shouldAutoConnect = params.get('connect') !== 'false';\n if (shouldAutoConnect && !this.isConnected() && !this.isConnecting()) {\n console.log(`SocketManager: Auto-connecting to port ${connectPort}`);\n this.connect(connectPort);\n }\n }\n}\n\n// ES6 Module export\nexport { SocketManager };\nexport default SocketManager;\n\n// Make SocketManager globally available for the dist/dashboard.js\n// This ensures compatibility with the minified version\nwindow.SocketManager = SocketManager;\n","/**\n * UI State Manager Module\n *\n * Manages UI state including tab switching, card selection, keyboard navigation,\n * and visual feedback across the dashboard interface.\n *\n * WHY: Extracted from main dashboard to centralize UI state management and\n * provide better separation between business logic and UI state. This makes\n * the UI behavior more predictable and easier to test.\n *\n * DESIGN DECISION: Maintains centralized state for current tab, selected cards,\n * and navigation context while providing a clean API for other modules to\n * interact with UI state changes.\n */\nclass UIStateManager {\n constructor() {\n // Switching lock to prevent race conditions\n this._switching = false;\n\n // Hash to tab mapping\n this.hashToTab = {\n '#events': 'events',\n '#agents': 'agents',\n '#tools': 'tools',\n '#files': 'files',\n '#activity': 'activity',\n '#file_tree': 'claude-tree',\n '': 'events', // default\n };\n\n // Tab to hash mapping (reverse lookup)\n this.tabToHash = {\n 'events': '#events',\n 'agents': '#agents',\n 'tools': '#tools',\n 'files': '#files',\n 'activity': '#activity',\n 'claude-tree': '#file_tree'\n };\n\n // Current active tab - will be set based on URL hash\n this.currentTab = this.getTabFromHash();\n\n // Auto-scroll behavior\n this.autoScroll = true;\n\n // Selection state - tracks the currently selected card across all tabs\n this.selectedCard = {\n tab: null, // which tab the selection is in\n index: null, // index of selected item in that tab\n type: null, // 'event', 'agent', 'tool', 'file'\n data: null // the actual data object\n };\n\n // Navigation state for each tab\n this.tabNavigation = {\n events: { selectedIndex: -1, items: [] },\n agents: { selectedIndex: -1, items: [] },\n tools: { selectedIndex: -1, items: [] },\n files: { selectedIndex: -1, items: [] }\n };\n\n this.setupEventHandlers();\n console.log('UI state manager initialized with hash navigation');\n \n // Initialize with current hash\n this.handleHashChange();\n }\n\n /**\n * Get tab name from current URL hash\n * @returns {string} - Tab name based on hash\n */\n getTabFromHash() {\n const hash = window.location.hash || '';\n return this.hashToTab[hash] || 'events';\n }\n\n /**\n * Set up event handlers for UI interactions\n */\n setupEventHandlers() {\n this.setupHashNavigation();\n this.setupTabClickHandlers(); // Add explicit tab click handlers\n this.setupUnifiedKeyboardNavigation();\n }\n\n /**\n * Set up hash-based navigation\n */\n setupHashNavigation() {\n // Handle hash changes\n window.addEventListener('hashchange', (e) => {\n console.log('[Hash Navigation] Hash changed from', new URL(e.oldURL).hash, 'to', window.location.hash);\n this.handleHashChange();\n });\n\n // Handle initial page load\n document.addEventListener('DOMContentLoaded', () => {\n console.log('[Hash Navigation] Initial hash:', window.location.hash);\n this.handleHashChange();\n });\n }\n\n /**\n * Handle hash change events\n */\n handleHashChange() {\n const hash = window.location.hash || '';\n console.log('[Hash Navigation] DETAILED DEBUG:');\n console.log('[Hash Navigation] - Current hash:', hash);\n console.log('[Hash Navigation] - hashToTab mapping:', this.hashToTab);\n console.log('[Hash Navigation] - Direct lookup result:', this.hashToTab[hash]);\n console.log('[Hash Navigation] - Is hash in mapping?', hash in this.hashToTab);\n console.log('[Hash Navigation] - Hash length:', hash.length);\n console.log('[Hash Navigation] - Hash char codes:', hash.split('').map(c => c.charCodeAt(0)));\n \n const tabName = this.hashToTab[hash] || 'events';\n console.log('[Hash Navigation] Final resolved tab name:', tabName);\n \n // Special logging for File Tree tab\n if (tabName === 'claude-tree' || hash === '#file_tree') {\n console.log('[UIStateManager] FILE TREE TAB SELECTED via hash:', hash);\n console.log('[UIStateManager] Tab name resolved to:', tabName);\n }\n \n this.switchTab(tabName, false); // false = don't update hash (we're responding to hash change)\n }\n\n /**\n * DEPRECATED: Tab navigation is now handled by hash navigation\n * This method is kept for backward compatibility but does nothing\n */\n setupTabNavigation() {\n console.log('[Hash Navigation] setupTabNavigation is deprecated - using hash navigation instead');\n }\n\n /**\n * Set up explicit click handlers for tab buttons to ensure proper routing\n * This ensures tab clicks work even if other modules interfere\n */\n setupTabClickHandlers() {\n document.querySelectorAll('.tab-button').forEach(button => {\n button.addEventListener('click', (e) => {\n console.log('[UIStateManager] Tab button clicked:', e.target);\n \n // Prevent default only if we're going to handle it\n const tabName = this.getTabNameFromButton(e.target);\n console.log('[UIStateManager] Resolved tab name:', tabName);\n \n if (tabName) {\n // Let the href attribute update the hash naturally, which will trigger our hashchange handler\n // But also explicitly trigger the switch in case href doesn't work\n setTimeout(() => {\n const expectedHash = this.tabToHash[tabName];\n if (window.location.hash !== expectedHash && expectedHash) {\n console.log('[UIStateManager] Hash not updated, forcing update:', expectedHash);\n window.location.hash = expectedHash;\n }\n }, 10);\n }\n });\n });\n \n console.log('[UIStateManager] Tab click handlers set up for', document.querySelectorAll('.tab-button').length, 'buttons');\n }\n\n /**\n * Set up unified keyboard navigation across all tabs\n */\n setupUnifiedKeyboardNavigation() {\n document.addEventListener('keydown', (e) => {\n // Only handle if not in an input field\n if (document.activeElement &&\n ['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName)) {\n return;\n }\n\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n this.handleUnifiedArrowNavigation(e.key === 'ArrowDown' ? 1 : -1);\n } else if (e.key === 'Enter') {\n e.preventDefault();\n this.handleUnifiedEnterKey();\n } else if (e.key === 'Escape') {\n this.clearUnifiedSelection();\n }\n });\n }\n\n /**\n * Get tab name from button element\n * @param {HTMLElement} button - Tab button element\n * @returns {string} - Tab name\n */\n getTabNameFromButton(button) {\n console.log('[getTabNameFromButton] DEBUG: button object:', button);\n console.log('[getTabNameFromButton] DEBUG: button.nodeType:', button.nodeType);\n console.log('[getTabNameFromButton] DEBUG: button.tagName:', button.tagName);\n \n // CRITICAL FIX: Make sure we're dealing with the actual button element\n // Sometimes the click target might be a child element (like the emoji icon)\n let targetButton = button;\n if (button && button.closest && button.closest('.tab-button')) {\n targetButton = button.closest('.tab-button');\n console.log('[getTabNameFromButton] DEBUG: Used closest() to find actual button');\n }\n \n // First check for data-tab attribute\n const dataTab = targetButton ? targetButton.getAttribute('data-tab') : null;\n console.log('[getTabNameFromButton] DEBUG: data-tab attribute:', dataTab);\n console.log('[getTabNameFromButton] DEBUG: dataTab truthy:', !!dataTab);\n \n // CRITICAL: Specifically handle the File Tree case\n if (dataTab === 'claude-tree') {\n console.log('[getTabNameFromButton] DEBUG: Found claude-tree data-tab, returning it');\n return 'claude-tree';\n }\n \n if (dataTab) {\n console.log('[getTabNameFromButton] DEBUG: Returning dataTab:', dataTab);\n return dataTab;\n }\n \n // Fallback to text content matching\n const text = targetButton ? targetButton.textContent.toLowerCase() : '';\n console.log('[getTabNameFromButton] DEBUG: text content:', text);\n console.log('[getTabNameFromButton] DEBUG: text includes file tree:', text.includes('file tree'));\n console.log('[getTabNameFromButton] DEBUG: text includes events:', text.includes('events'));\n \n // CRITICAL: Check File Tree FIRST since it's the problematic one\n if (text.includes('file tree') || text.includes('📝')) {\n console.log('[getTabNameFromButton] DEBUG: Matched file tree, returning claude-tree');\n return 'claude-tree';\n }\n if (text.includes('activity') || text.includes('🌳')) return 'activity';\n if (text.includes('agents') || text.includes('🤖')) return 'agents';\n if (text.includes('tools') || text.includes('🔧')) return 'tools';\n if (text.includes('files') || text.includes('📁')) return 'files';\n if (text.includes('code')) return 'code';\n if (text.includes('sessions')) return 'sessions';\n if (text.includes('system')) return 'system';\n if (text.includes('events') || text.includes('📊')) return 'events';\n \n console.log('[getTabNameFromButton] DEBUG: No match, falling back to events');\n return 'events';\n }\n\n /**\n * Switch to specified tab - BULLETPROOF VERSION\n * @param {string} tabName - Name of tab to switch to\n * @param {boolean} updateHash - Whether to update URL hash (default: true)\n */\n switchTab(tabName, updateHash = true) {\n // CRITICAL: Prevent race conditions by using a switching lock\n if (this._switching) {\n console.log(`[UIStateManager] Tab switch already in progress, queuing: ${tabName}`);\n setTimeout(() => this.switchTab(tabName, updateHash), 50);\n return;\n }\n this._switching = true;\n\n console.log(`[UIStateManager] BULLETPROOF switchTab: ${tabName}, updateHash: ${updateHash}`);\n\n try {\n // Extra logging for File Tree debugging\n if (tabName === 'claude-tree') {\n console.log('[UIStateManager] SWITCHING TO FILE TREE TAB');\n console.log('[UIStateManager] Current tab before switch:', this.currentTab);\n }\n\n // Update URL hash if requested (when triggered by user action, not hash change)\n if (updateHash && this.tabToHash[tabName]) {\n const newHash = this.tabToHash[tabName];\n if (window.location.hash !== newHash) {\n console.log(`[UIStateManager] Updating hash to: ${newHash}`);\n this._switching = false; // Release lock before hash change\n window.location.hash = newHash;\n return; // The hashchange event will trigger switchTab again\n }\n }\n\n const previousTab = this.currentTab;\n this.currentTab = tabName;\n\n // STEP 1: NUCLEAR RESET - Remove ALL active states unconditionally\n this._removeAllActiveStates();\n\n // STEP 2: Set the ONE correct tab as active\n this._setActiveTab(tabName);\n\n // STEP 3: Show ONLY the correct content\n this._showTabContent(tabName);\n\n // STEP 4: Cleanup and validation\n this._validateTabState(tabName);\n\n // Clear previous selections when switching tabs\n this.clearUnifiedSelection();\n\n // Trigger tab change event for other modules\n document.dispatchEvent(new CustomEvent('tabChanged', {\n detail: {\n newTab: tabName,\n previousTab: previousTab\n }\n }));\n\n // Auto-scroll to bottom after a brief delay to ensure content is rendered\n setTimeout(() => {\n if (this.autoScroll) {\n this.scrollCurrentTabToBottom();\n }\n\n // Special handling for File Tree tab - trigger the tree render\n // But DON'T let it manipulate tabs itself\n if (tabName === 'claude-tree' && window.CodeViewer) {\n // Call a new method that only renders content, not tab switching\n if (window.CodeViewer.renderContent) {\n window.CodeViewer.renderContent();\n } else {\n // Fallback to show() but it should be fixed to not switch tabs\n window.CodeViewer.show();\n }\n }\n }, 100);\n\n } finally {\n // ALWAYS release the lock\n setTimeout(() => {\n this._switching = false;\n }, 200);\n }\n }\n\n /**\n * NUCLEAR RESET: Remove ALL active states from ALL elements\n * This ensures no stale states remain\n */\n _removeAllActiveStates() {\n // Remove active class from ALL tab buttons\n document.querySelectorAll('.tab-button').forEach(btn => {\n btn.classList.remove('active');\n // Also remove any inline styling that might interfere\n btn.style.removeProperty('border-bottom');\n btn.style.removeProperty('color');\n });\n\n // Remove active class from ALL tab content\n document.querySelectorAll('.tab-content').forEach(content => {\n content.classList.remove('active');\n // Clear any inline display styles\n content.style.removeProperty('display');\n\n // CRITICAL: Clean leaked content in non-events tabs\n if (content.id !== 'events-tab') {\n this._cleanLeakedEventContent(content);\n }\n });\n\n console.log('[UIStateManager] NUCLEAR: All active states removed');\n }\n\n /**\n * Set ONLY the specified tab as active\n */\n _setActiveTab(tabName) {\n const targetTab = document.querySelector(`[data-tab=\"${tabName}\"]`);\n if (targetTab) {\n targetTab.classList.add('active');\n console.log(`[UIStateManager] Set active: ${tabName}`);\n } else {\n console.error(`[UIStateManager] Could not find tab button for: ${tabName}`);\n }\n }\n\n /**\n * Show ONLY the specified tab content\n */\n _showTabContent(tabName) {\n const targetContent = document.getElementById(`${tabName}-tab`);\n if (targetContent) {\n targetContent.classList.add('active');\n console.log(`[UIStateManager] Showing content: ${tabName}-tab`);\n\n // Special handling for File Tree tab\n if (tabName === 'claude-tree') {\n this._prepareFileTreeContent(targetContent);\n }\n } else {\n console.error(`[UIStateManager] Could not find content for: ${tabName}`);\n }\n }\n\n /**\n * Clean any leaked event content from non-event tabs\n */\n _cleanLeakedEventContent(contentElement) {\n // Remove any event items that may have leaked\n const leakedEventItems = contentElement.querySelectorAll('.event-item');\n if (leakedEventItems.length > 0) {\n console.warn(`[UIStateManager] Found ${leakedEventItems.length} leaked event items in ${contentElement.id}, removing...`);\n leakedEventItems.forEach(item => item.remove());\n }\n\n // Remove any events-list elements\n const leakedEventsList = contentElement.querySelectorAll('#events-list, .events-list');\n if (leakedEventsList.length > 0) {\n console.warn(`[UIStateManager] Found leaked events-list in ${contentElement.id}, removing...`);\n leakedEventsList.forEach(list => list.remove());\n }\n }\n\n /**\n * Prepare File Tree content area\n */\n _prepareFileTreeContent(fileTreeContent) {\n const claudeTreeContainer = document.getElementById('claude-tree-container');\n if (claudeTreeContainer) {\n // Final cleanup check\n this._cleanLeakedEventContent(claudeTreeContainer);\n\n // Ensure container is properly marked for CodeViewer\n claudeTreeContainer.setAttribute('data-owner', 'code-viewer');\n claudeTreeContainer.setAttribute('data-component', 'CodeViewer');\n\n console.log('[UIStateManager] File Tree container prepared');\n }\n }\n\n /**\n * Validate that tab state is correct after switching\n */\n _validateTabState(expectedTab) {\n setTimeout(() => {\n const activeTabs = document.querySelectorAll('.tab-button.active');\n const activeContents = document.querySelectorAll('.tab-content.active');\n\n if (activeTabs.length !== 1) {\n console.error(`[UIStateManager] VALIDATION FAILED: Expected 1 active tab, found ${activeTabs.length}`);\n activeTabs.forEach((tab, idx) => {\n console.error(` - Active tab ${idx + 1}: ${tab.textContent.trim()} (${tab.getAttribute('data-tab')})`);\n });\n // Force fix\n this._removeAllActiveStates();\n this._setActiveTab(expectedTab);\n }\n\n if (activeContents.length !== 1) {\n console.error(`[UIStateManager] VALIDATION FAILED: Expected 1 active content, found ${activeContents.length}`);\n activeContents.forEach((content, idx) => {\n console.error(` - Active content ${idx + 1}: ${content.id}`);\n });\n // Force fix\n this._removeAllActiveStates();\n this._showTabContent(expectedTab);\n }\n\n console.log(`[UIStateManager] Tab state validated for: ${expectedTab}`);\n }, 50);\n }\n\n /**\n * Handle unified arrow navigation across tabs\n * @param {number} direction - Navigation direction (1 for down, -1 for up)\n */\n handleUnifiedArrowNavigation(direction) {\n const tabNav = this.tabNavigation[this.currentTab];\n if (!tabNav) return;\n\n let newIndex = tabNav.selectedIndex + direction;\n\n // Handle bounds\n if (tabNav.items.length === 0) return;\n\n if (newIndex < 0) {\n newIndex = tabNav.items.length - 1;\n } else if (newIndex >= tabNav.items.length) {\n newIndex = 0;\n }\n\n this.selectCardByIndex(this.currentTab, newIndex);\n }\n\n /**\n * Handle unified Enter key across all tabs\n */\n handleUnifiedEnterKey() {\n const tabNav = this.tabNavigation[this.currentTab];\n if (!tabNav || tabNav.selectedIndex === -1) return;\n\n const selectedElement = tabNav.items[tabNav.selectedIndex];\n if (selectedElement && selectedElement.onclick) {\n selectedElement.onclick();\n }\n }\n\n /**\n * Clear all unified selection states\n */\n clearUnifiedSelection() {\n // Clear all tab navigation states\n Object.keys(this.tabNavigation).forEach(tabName => {\n this.tabNavigation[tabName].selectedIndex = -1;\n });\n\n // Clear card selection\n this.clearCardSelection();\n }\n\n /**\n * Update tab navigation items for current tab\n * Should be called after tab content is rendered\n */\n updateTabNavigationItems() {\n const tabNav = this.tabNavigation[this.currentTab];\n if (!tabNav) return;\n\n let containerSelector;\n switch (this.currentTab) {\n case 'events':\n containerSelector = '#events-list .event-item';\n break;\n case 'agents':\n containerSelector = '#agents-list .event-item';\n break;\n case 'tools':\n containerSelector = '#tools-list .event-item';\n break;\n case 'files':\n containerSelector = '#files-list .event-item';\n break;\n }\n\n if (containerSelector) {\n tabNav.items = Array.from(document.querySelectorAll(containerSelector));\n }\n }\n\n /**\n * Select card by index for specified tab\n * @param {string} tabName - Tab name\n * @param {number} index - Index of item to select\n */\n selectCardByIndex(tabName, index) {\n const tabNav = this.tabNavigation[tabName];\n if (!tabNav || index < 0 || index >= tabNav.items.length) return;\n\n // Update navigation state\n tabNav.selectedIndex = index;\n\n // Update visual selection\n this.updateUnifiedSelectionUI();\n\n // If this is a different tab selection, record the card selection\n const selectedElement = tabNav.items[index];\n if (selectedElement) {\n // Extract data from the element to populate selectedCard\n this.selectCard(tabName, index, this.getCardType(tabName), index);\n }\n\n // Show details for the selected item\n this.showCardDetails(tabName, index);\n }\n\n /**\n * Update visual selection UI for unified navigation\n */\n updateUnifiedSelectionUI() {\n // Clear all existing selections\n document.querySelectorAll('.event-item.keyboard-selected').forEach(el => {\n el.classList.remove('keyboard-selected');\n });\n\n // Apply selection to current tab's selected item\n const tabNav = this.tabNavigation[this.currentTab];\n if (tabNav && tabNav.selectedIndex !== -1 && tabNav.items[tabNav.selectedIndex]) {\n tabNav.items[tabNav.selectedIndex].classList.add('keyboard-selected');\n }\n }\n\n /**\n * Show card details for specified tab and index\n * @param {string} tabName - Tab name\n * @param {number} index - Item index\n */\n showCardDetails(tabName, index) {\n // Dispatch event for other modules to handle\n document.dispatchEvent(new CustomEvent('showCardDetails', {\n detail: {\n tabName: tabName,\n index: index\n }\n }));\n }\n\n /**\n * Select a specific card\n * @param {string} tabName - Tab name\n * @param {number} index - Item index\n * @param {string} type - Item type\n * @param {*} data - Item data\n */\n selectCard(tabName, index, type, data) {\n // Clear previous selection\n this.clearCardSelection();\n\n // Update selection state\n this.selectedCard = {\n tab: tabName,\n index: index,\n type: type,\n data: data\n };\n\n this.updateCardSelectionUI();\n\n console.log('Card selected:', this.selectedCard);\n }\n\n /**\n * Clear card selection\n */\n clearCardSelection() {\n // Clear visual selection from all tabs\n document.querySelectorAll('.event-item.selected, .file-item.selected').forEach(el => {\n el.classList.remove('selected');\n });\n\n // Reset selection state\n this.selectedCard = {\n tab: null,\n index: null,\n type: null,\n data: null\n };\n }\n\n /**\n * Update card selection UI\n */\n updateCardSelectionUI() {\n if (!this.selectedCard.tab || this.selectedCard.index === null) return;\n\n // Get the list container for the selected tab\n let listContainer;\n switch (this.selectedCard.tab) {\n case 'events':\n listContainer = document.getElementById('events-list');\n break;\n case 'agents':\n listContainer = document.getElementById('agents-list');\n break;\n case 'tools':\n listContainer = document.getElementById('tools-list');\n break;\n case 'files':\n listContainer = document.getElementById('files-list');\n break;\n }\n\n if (listContainer) {\n const items = listContainer.querySelectorAll('.event-item, .file-item');\n if (items[this.selectedCard.index]) {\n items[this.selectedCard.index].classList.add('selected');\n }\n }\n }\n\n /**\n * Get card type based on tab name\n * @param {string} tabName - Tab name\n * @returns {string} - Card type\n */\n getCardType(tabName) {\n switch (tabName) {\n case 'events': return 'event';\n case 'agents': return 'agent';\n case 'tools': return 'tool';\n case 'files': return 'file';\n default: return 'unknown';\n }\n }\n\n /**\n * Scroll current tab to bottom\n */\n scrollCurrentTabToBottom() {\n const tabId = `${this.currentTab}-list`;\n const element = document.getElementById(tabId);\n if (element && this.autoScroll) {\n element.scrollTop = element.scrollHeight;\n }\n }\n\n /**\n * Clear selection for cleanup\n */\n clearSelection() {\n this.clearCardSelection();\n this.clearUnifiedSelection();\n }\n\n /**\n * Get current tab name\n * @returns {string} - Current tab name\n */\n getCurrentTab() {\n return this.currentTab;\n }\n\n /**\n * Get selected card info\n * @returns {Object} - Selected card state\n */\n getSelectedCard() {\n return { ...this.selectedCard };\n }\n\n /**\n * Get tab navigation state\n * @returns {Object} - Tab navigation state\n */\n getTabNavigation() {\n return { ...this.tabNavigation };\n }\n\n /**\n * Set auto-scroll behavior\n * @param {boolean} enabled - Whether to enable auto-scroll\n */\n setAutoScroll(enabled) {\n this.autoScroll = enabled;\n }\n\n /**\n * Get auto-scroll state\n * @returns {boolean} - Auto-scroll enabled state\n */\n getAutoScroll() {\n return this.autoScroll;\n }\n}\n// ES6 Module export\nexport { UIStateManager };\nexport default UIStateManager;\n\n// Make UIStateManager globally available for dist/dashboard.js\nwindow.UIStateManager = UIStateManager;\n"],"names":["io","window","SocketClient","constructor","this","socket","port","connectionCallbacks","connect","disconnect","error","event","eventSchema","required","optional","isConnected","isConnecting","lastConnectTime","disconnectTime","events","sessions","Map","currentSessionId","eventQueue","maxQueueSize","retryAttempts","maxRetryAttempts","retryDelays","pendingEmissions","lastPingTime","lastPongTime","pingTimeout","healthCheckInterval","startStatusCheckFallback","startHealthMonitoring","url","connected","connecting","console","log","setTimeout","doConnect","notifyConnectionStatus","autoConnect","reconnection","reconnectionDelay","reconnectionDelayMax","reconnectionAttempts","timeout","forceNew","transports","setupSocketHandlers","on","previouslyConnected","Date","now","downtime","toFixed","flushEventQueue","forEach","callback","id","requestStatus","reason","disconnectInfo","timestamp","toISOString","wasConnected","uptimeSeconds","lastPing","lastPong","includes","scheduleReconnect","errorMsg","message","description","addEvent","type","data","uri","retry_attempt","validatedEvent","validateEventSchema","warn","startsWith","transformedEvent","transformEvent","emit","client_time","subtype","heartbeat_number","server_uptime_formatted","connected_clients","Array","isArray","length","count","total_available","notifyEventUpdate","updateSessions","current_session","emitWithRetry","options","maxRetries","onSuccess","onFailure","emissionId","Math","random","attemptEmission","attemptNum","delete","delay","set","scheduledTime","queueEvent","removed","shift","push","item","index","requestHistory","params","limit","event_types","eventData","notify","session_id","sessionId","has","startTime","lastActivity","eventCount","working_directory","git_branch","session","get","possiblePaths","cwd","working_dir","workingDirectory","instance_info","path","trim","sessionsData","clearEvents","clear","refreshHistory","getEventsBySession","filter","onConnection","eventType","onEventUpdate","off","status","updateConnectionStatusDOM","document","dispatchEvent","CustomEvent","detail","statusElement","getElementById","innerHTML","className","getConnectionState","socketId","validated","source","value","originalEventName","eventName","toLowerCase","replace","substring","subtypePart","mainType","subtypeParts","split","join","parts","protectedFields","Object","keys","key","debug","JSON","parse","stringify","hook_event_name","tool_name","has_tool_parameters","tool_parameters","has_data","k","file_path","notebook_path","full_parameters","getState","setInterval","timeSinceLastPing","stopHealthMonitoring","clearInterval","checkAndUpdateStatus","readyState","addEventListener","actualStatus","actualType","currentText","textContent","currentClass","expectedClass","destroy","getConnectionMetrics","uptime","queuedEvents","size","SocketManager","socketClient","Set","eventUpdateCallbacks","setupSocketEventHandlers","updateInitialConnectionStatus","e","handleConnectionStatusChange","updateConnectionStatus","setupGitBranchListener","success","footerBranch","branch","style","display","querySelector","statusIndicator","getSocketClient","getSocket","onConnectionStatusChange","add","offConnectionStatusChange","offEventUpdate","toggleConnectionControls","controlsRow","toggleBtn","classList","contains","remove","setupConnectionControls","connectBtn","disconnectBtn","connectionToggleBtn","initializeFromURL","portInput","connectPort","location","protocol","UIStateManager","_switching","hashToTab","tabToHash","agents","tools","files","activity","currentTab","getTabFromHash","autoScroll","selectedCard","tab","tabNavigation","selectedIndex","items","setupEventHandlers","handleHashChange","hash","setupHashNavigation","setupTabClickHandlers","setupUnifiedKeyboardNavigation","URL","oldURL","map","c","charCodeAt","tabName","switchTab","setupTabNavigation","querySelectorAll","button","target","getTabNameFromButton","expectedHash","activeElement","tagName","preventDefault","handleUnifiedArrowNavigation","handleUnifiedEnterKey","clearUnifiedSelection","nodeType","targetButton","closest","dataTab","getAttribute","text","updateHash","newHash","previousTab","_removeAllActiveStates","_setActiveTab","_showTabContent","_validateTabState","newTab","scrollCurrentTabToBottom","CodeViewer","renderContent","show","btn","removeProperty","content","_cleanLeakedEventContent","targetTab","targetContent","_prepareFileTreeContent","contentElement","leakedEventItems","leakedEventsList","list","fileTreeContent","claudeTreeContainer","setAttribute","expectedTab","activeTabs","activeContents","idx","direction","tabNav","newIndex","selectCardByIndex","selectedElement","onclick","clearCardSelection","updateTabNavigationItems","containerSelector","from","updateUnifiedSelectionUI","selectCard","getCardType","showCardDetails","el","updateCardSelectionUI","listContainer","tabId","element","scrollTop","scrollHeight","clearSelection","getCurrentTab","getSelectedCard","getTabNavigation","setAutoScroll","enabled","getAutoScroll"],"mappings":"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"}
|