claude-mpm 4.25.10__py3-none-any.whl → 5.1.8__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.

Files changed (507) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +12 -0
  3. claude_mpm/agents/PM_INSTRUCTIONS.md +1055 -2230
  4. claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +1322 -0
  5. claude_mpm/agents/WORKFLOW.md +4 -4
  6. claude_mpm/agents/__init__.py +6 -0
  7. claude_mpm/agents/agent_loader.py +1 -4
  8. claude_mpm/agents/base_agent_loader.py +10 -35
  9. claude_mpm/agents/templates/{circuit_breakers.md → circuit-breakers.md} +576 -66
  10. claude_mpm/agents/templates/context-management-examples.md +544 -0
  11. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  12. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  13. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  14. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  15. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  16. claude_mpm/cli/__init__.py +28 -3
  17. claude_mpm/cli/commands/__init__.py +2 -0
  18. claude_mpm/cli/commands/agent_source.py +774 -0
  19. claude_mpm/cli/commands/agent_state_manager.py +188 -30
  20. claude_mpm/cli/commands/agents.py +959 -36
  21. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  22. claude_mpm/cli/commands/agents_discover.py +338 -0
  23. claude_mpm/cli/commands/auto_configure.py +537 -239
  24. claude_mpm/cli/commands/config.py +7 -4
  25. claude_mpm/cli/commands/configure.py +924 -45
  26. claude_mpm/cli/commands/configure_navigation.py +63 -46
  27. claude_mpm/cli/commands/doctor.py +10 -2
  28. claude_mpm/cli/commands/local_deploy.py +1 -4
  29. claude_mpm/cli/commands/postmortem.py +401 -0
  30. claude_mpm/cli/commands/run.py +1 -39
  31. claude_mpm/cli/commands/skill_source.py +694 -0
  32. claude_mpm/cli/commands/skills.py +322 -19
  33. claude_mpm/cli/executor.py +22 -3
  34. claude_mpm/cli/interactive/agent_wizard.py +1028 -43
  35. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  36. claude_mpm/cli/parsers/agents_parser.py +256 -4
  37. claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
  38. claude_mpm/cli/parsers/base_parser.py +25 -0
  39. claude_mpm/cli/parsers/config_parser.py +96 -43
  40. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  41. claude_mpm/cli/parsers/skills_parser.py +7 -0
  42. claude_mpm/cli/parsers/source_parser.py +138 -0
  43. claude_mpm/cli/startup.py +456 -103
  44. claude_mpm/cli/startup_display.py +4 -4
  45. claude_mpm/commands/{mpm-auto-configure.md → mpm-agents-auto-configure.md} +9 -0
  46. claude_mpm/commands/mpm-agents-detect.md +9 -0
  47. claude_mpm/commands/{mpm-agents.md → mpm-agents-list.md} +9 -0
  48. claude_mpm/commands/mpm-agents-recommend.md +9 -0
  49. claude_mpm/commands/{mpm-config.md → mpm-config-view.md} +9 -0
  50. claude_mpm/commands/mpm-doctor.md +9 -0
  51. claude_mpm/commands/mpm-help.md +14 -2
  52. claude_mpm/commands/mpm-init.md +9 -0
  53. claude_mpm/commands/mpm-monitor.md +9 -0
  54. claude_mpm/commands/mpm-postmortem.md +123 -0
  55. claude_mpm/commands/{mpm-resume.md → mpm-session-resume.md} +9 -0
  56. claude_mpm/commands/mpm-status.md +9 -0
  57. claude_mpm/commands/{mpm-organize.md → mpm-ticket-organize.md} +9 -0
  58. claude_mpm/commands/mpm-ticket-view.md +552 -0
  59. claude_mpm/commands/mpm-version.md +9 -0
  60. claude_mpm/commands/mpm.md +10 -0
  61. claude_mpm/config/agent_presets.py +488 -0
  62. claude_mpm/config/agent_sources.py +325 -0
  63. claude_mpm/config/skill_presets.py +392 -0
  64. claude_mpm/config/skill_sources.py +590 -0
  65. claude_mpm/constants.py +1 -0
  66. claude_mpm/core/claude_runner.py +5 -34
  67. claude_mpm/core/config.py +16 -0
  68. claude_mpm/core/framework/__init__.py +3 -16
  69. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  70. claude_mpm/core/framework/loaders/instruction_loader.py +25 -5
  71. claude_mpm/core/interactive_session.py +83 -7
  72. claude_mpm/core/oneshot_session.py +71 -8
  73. claude_mpm/core/protocols/__init__.py +23 -0
  74. claude_mpm/core/protocols/runner_protocol.py +103 -0
  75. claude_mpm/core/protocols/session_protocol.py +131 -0
  76. claude_mpm/core/shared/singleton_manager.py +11 -4
  77. claude_mpm/core/system_context.py +38 -0
  78. claude_mpm/core/unified_config.py +22 -0
  79. claude_mpm/experimental/cli_enhancements.py +1 -5
  80. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  81. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  82. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  83. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  84. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  85. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  86. claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
  87. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  88. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  89. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  90. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  91. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  92. claude_mpm/hooks/failure_learning/__init__.py +2 -8
  93. claude_mpm/hooks/failure_learning/failure_detection_hook.py +1 -6
  94. claude_mpm/hooks/failure_learning/fix_detection_hook.py +1 -6
  95. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +1 -6
  96. claude_mpm/hooks/kuzu_response_hook.py +1 -5
  97. claude_mpm/models/git_repository.py +198 -0
  98. claude_mpm/services/agents/agent_builder.py +45 -9
  99. claude_mpm/services/agents/agent_preset_service.py +238 -0
  100. claude_mpm/services/agents/agent_selection_service.py +484 -0
  101. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  102. claude_mpm/services/agents/cache_git_manager.py +621 -0
  103. claude_mpm/services/agents/deployment/agent_deployment.py +126 -2
  104. claude_mpm/services/agents/deployment/agent_discovery_service.py +105 -73
  105. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -5
  106. claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
  107. claude_mpm/services/agents/deployment/agent_template_builder.py +236 -15
  108. claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
  109. claude_mpm/services/agents/deployment/async_agent_deployment.py +2 -1
  110. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +115 -15
  111. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +1 -4
  112. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
  113. claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
  114. claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -46
  115. claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
  116. claude_mpm/services/agents/git_source_manager.py +629 -0
  117. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -4
  118. claude_mpm/services/agents/local_template_manager.py +47 -9
  119. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  120. claude_mpm/services/agents/sources/__init__.py +13 -0
  121. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  122. claude_mpm/services/agents/sources/git_source_sync_service.py +1087 -0
  123. claude_mpm/services/agents/startup_sync.py +239 -0
  124. claude_mpm/services/agents/toolchain_detector.py +474 -0
  125. claude_mpm/services/analysis/__init__.py +25 -0
  126. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  127. claude_mpm/services/analysis/postmortem_service.py +765 -0
  128. claude_mpm/services/command_deployment_service.py +200 -6
  129. claude_mpm/services/core/base.py +7 -2
  130. claude_mpm/services/core/interfaces/__init__.py +1 -3
  131. claude_mpm/services/core/interfaces/health.py +1 -4
  132. claude_mpm/services/core/models/__init__.py +2 -11
  133. claude_mpm/services/diagnostics/checks/__init__.py +4 -0
  134. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  135. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  136. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  137. claude_mpm/services/diagnostics/diagnostic_runner.py +9 -0
  138. claude_mpm/services/diagnostics/doctor_reporter.py +34 -6
  139. claude_mpm/services/git/__init__.py +21 -0
  140. claude_mpm/services/git/git_operations_service.py +494 -0
  141. claude_mpm/services/github/__init__.py +21 -0
  142. claude_mpm/services/github/github_cli_service.py +397 -0
  143. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -5
  144. claude_mpm/services/infrastructure/monitoring/aggregator.py +1 -6
  145. claude_mpm/services/instructions/__init__.py +9 -0
  146. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  147. claude_mpm/services/local_ops/__init__.py +3 -13
  148. claude_mpm/services/local_ops/health_checks/__init__.py +1 -3
  149. claude_mpm/services/local_ops/health_manager.py +1 -4
  150. claude_mpm/services/mcp_config_manager.py +75 -145
  151. claude_mpm/services/mcp_gateway/core/process_pool.py +22 -16
  152. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +1 -6
  153. claude_mpm/services/mcp_service_verifier.py +6 -3
  154. claude_mpm/services/monitor/daemon.py +28 -8
  155. claude_mpm/services/monitor/daemon_manager.py +96 -19
  156. claude_mpm/services/pr/__init__.py +14 -0
  157. claude_mpm/services/pr/pr_template_service.py +329 -0
  158. claude_mpm/services/project/project_organizer.py +4 -0
  159. claude_mpm/services/runner_configuration_service.py +16 -3
  160. claude_mpm/services/session_management_service.py +16 -4
  161. claude_mpm/services/skills/__init__.py +18 -0
  162. claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
  163. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  164. claude_mpm/services/socketio/server/core.py +1 -4
  165. claude_mpm/services/socketio/server/main.py +1 -3
  166. claude_mpm/services/unified/deployment_strategies/vercel.py +1 -5
  167. claude_mpm/services/unified/unified_deployment.py +1 -5
  168. claude_mpm/services/visualization/__init__.py +1 -5
  169. claude_mpm/templates/questions/__init__.py +2 -7
  170. claude_mpm/templates/questions/pr_strategy.py +1 -4
  171. claude_mpm/templates/questions/project_init.py +1 -4
  172. claude_mpm/templates/questions/ticket_mgmt.py +1 -4
  173. claude_mpm/utils/agent_dependency_loader.py +77 -10
  174. claude_mpm/utils/agent_filters.py +288 -0
  175. claude_mpm/utils/gitignore.py +3 -0
  176. claude_mpm/utils/migration.py +372 -0
  177. claude_mpm/utils/progress.py +387 -0
  178. {claude_mpm-4.25.10.dist-info → claude_mpm-5.1.8.dist-info}/METADATA +356 -112
  179. {claude_mpm-4.25.10.dist-info → claude_mpm-5.1.8.dist-info}/RECORD +188 -439
  180. claude_mpm/agents/templates/agent-manager.json +0 -273
  181. claude_mpm/agents/templates/agentic-coder-optimizer.json +0 -248
  182. claude_mpm/agents/templates/api_qa.json +0 -183
  183. claude_mpm/agents/templates/clerk-ops.json +0 -235
  184. claude_mpm/agents/templates/code_analyzer.json +0 -101
  185. claude_mpm/agents/templates/content-agent.json +0 -358
  186. claude_mpm/agents/templates/dart_engineer.json +0 -307
  187. claude_mpm/agents/templates/data_engineer.json +0 -225
  188. claude_mpm/agents/templates/documentation.json +0 -238
  189. claude_mpm/agents/templates/engineer.json +0 -210
  190. claude_mpm/agents/templates/gcp_ops_agent.json +0 -253
  191. claude_mpm/agents/templates/golang_engineer.json +0 -270
  192. claude_mpm/agents/templates/imagemagick.json +0 -264
  193. claude_mpm/agents/templates/java_engineer.json +0 -346
  194. claude_mpm/agents/templates/javascript_engineer_agent.json +0 -380
  195. claude_mpm/agents/templates/local_ops_agent.json +0 -1840
  196. claude_mpm/agents/templates/memory_manager.json +0 -158
  197. claude_mpm/agents/templates/nextjs_engineer.json +0 -285
  198. claude_mpm/agents/templates/ops.json +0 -185
  199. claude_mpm/agents/templates/php-engineer.json +0 -287
  200. claude_mpm/agents/templates/product_owner.json +0 -338
  201. claude_mpm/agents/templates/project_organizer.json +0 -144
  202. claude_mpm/agents/templates/prompt-engineer.json +0 -737
  203. claude_mpm/agents/templates/python_engineer.json +0 -387
  204. claude_mpm/agents/templates/qa.json +0 -243
  205. claude_mpm/agents/templates/react_engineer.json +0 -239
  206. claude_mpm/agents/templates/refactoring_engineer.json +0 -276
  207. claude_mpm/agents/templates/research.json +0 -258
  208. claude_mpm/agents/templates/ruby-engineer.json +0 -280
  209. claude_mpm/agents/templates/rust_engineer.json +0 -275
  210. claude_mpm/agents/templates/security.json +0 -202
  211. claude_mpm/agents/templates/svelte-engineer.json +0 -225
  212. claude_mpm/agents/templates/tauri_engineer.json +0 -274
  213. claude_mpm/agents/templates/ticketing.json +0 -181
  214. claude_mpm/agents/templates/typescript_engineer.json +0 -285
  215. claude_mpm/agents/templates/vercel_ops_agent.json +0 -412
  216. claude_mpm/agents/templates/version_control.json +0 -159
  217. claude_mpm/agents/templates/web_qa.json +0 -400
  218. claude_mpm/agents/templates/web_ui.json +0 -189
  219. claude_mpm/cli/README.md +0 -253
  220. claude_mpm/cli/commands/mcp_install_commands.py.backup +0 -284
  221. claude_mpm/cli/commands/mpm_init/README.md +0 -365
  222. claude_mpm/cli_module/refactoring_guide.md +0 -253
  223. claude_mpm/commands/mpm-tickets.md +0 -151
  224. claude_mpm/config/agent_capabilities.yaml +0 -658
  225. claude_mpm/config/async_logging_config.yaml +0 -145
  226. claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +0 -34
  227. claude_mpm/d2/.gitignore +0 -22
  228. claude_mpm/d2/ARCHITECTURE_COMPARISON.md +0 -273
  229. claude_mpm/d2/FLASK_INTEGRATION.md +0 -156
  230. claude_mpm/d2/IMPLEMENTATION_SUMMARY.md +0 -452
  231. claude_mpm/d2/QUICKSTART.md +0 -186
  232. claude_mpm/d2/README.md +0 -232
  233. claude_mpm/d2/STORE_FIX_SUMMARY.md +0 -167
  234. claude_mpm/d2/SVELTE5_STORES_GUIDE.md +0 -180
  235. claude_mpm/d2/TESTING.md +0 -288
  236. claude_mpm/d2/index.html +0 -118
  237. claude_mpm/d2/package.json +0 -19
  238. claude_mpm/d2/src/App.svelte +0 -110
  239. claude_mpm/d2/src/components/Header.svelte +0 -153
  240. claude_mpm/d2/src/components/MainContent.svelte +0 -74
  241. claude_mpm/d2/src/components/Sidebar.svelte +0 -85
  242. claude_mpm/d2/src/components/tabs/EventsTab.svelte +0 -326
  243. claude_mpm/d2/src/lib/socketio.js +0 -144
  244. claude_mpm/d2/src/main.js +0 -7
  245. claude_mpm/d2/src/stores/events.js +0 -114
  246. claude_mpm/d2/src/stores/socket.js +0 -108
  247. claude_mpm/d2/src/stores/theme.js +0 -65
  248. claude_mpm/d2/svelte.config.js +0 -12
  249. claude_mpm/d2/vite.config.js +0 -15
  250. claude_mpm/dashboard/.claude-mpm/memories/README.md +0 -36
  251. claude_mpm/dashboard/BUILD_NUMBER +0 -1
  252. claude_mpm/dashboard/README.md +0 -121
  253. claude_mpm/dashboard/VERSION +0 -1
  254. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +0 -188
  255. claude_mpm/dashboard/react/components/DataInspector/DataInspector.tsx +0 -273
  256. claude_mpm/dashboard/react/components/ErrorBoundary.tsx +0 -75
  257. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +0 -156
  258. claude_mpm/dashboard/react/components/EventViewer/EventViewer.tsx +0 -141
  259. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +0 -38
  260. claude_mpm/dashboard/react/components/shared/ConnectionStatus.tsx +0 -36
  261. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +0 -92
  262. claude_mpm/dashboard/react/components/shared/FilterBar.tsx +0 -89
  263. claude_mpm/dashboard/react/contexts/DashboardContext.tsx +0 -215
  264. claude_mpm/dashboard/react/entries/events.tsx +0 -165
  265. claude_mpm/dashboard/react/hooks/useEvents.ts +0 -191
  266. claude_mpm/dashboard/react/hooks/useSocket.ts +0 -225
  267. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +0 -248
  268. claude_mpm/dashboard/static/built/REFACTORING_SUMMARY.md +0 -170
  269. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +0 -1
  270. claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
  271. claude_mpm/dashboard/static/built/components/activity-tree.js.map +0 -1
  272. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +0 -777
  273. claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
  274. claude_mpm/dashboard/static/built/components/agent-inference.js.map +0 -1
  275. claude_mpm/dashboard/static/built/components/build-tracker.js +0 -333
  276. claude_mpm/dashboard/static/built/components/code-simple.js +0 -857
  277. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +0 -353
  278. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +0 -235
  279. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +0 -409
  280. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +0 -435
  281. claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
  282. claude_mpm/dashboard/static/built/components/code-tree.js.map +0 -1
  283. claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
  284. claude_mpm/dashboard/static/built/components/code-viewer.js.map +0 -1
  285. claude_mpm/dashboard/static/built/components/connection-debug.js +0 -654
  286. claude_mpm/dashboard/static/built/components/diff-viewer.js +0 -891
  287. claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
  288. claude_mpm/dashboard/static/built/components/event-processor.js.map +0 -1
  289. claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
  290. claude_mpm/dashboard/static/built/components/event-viewer.js.map +0 -1
  291. claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
  292. claude_mpm/dashboard/static/built/components/export-manager.js.map +0 -1
  293. claude_mpm/dashboard/static/built/components/file-change-tracker.js +0 -443
  294. claude_mpm/dashboard/static/built/components/file-change-viewer.js +0 -690
  295. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
  296. claude_mpm/dashboard/static/built/components/file-tool-tracker.js.map +0 -1
  297. claude_mpm/dashboard/static/built/components/file-viewer.js +0 -2
  298. claude_mpm/dashboard/static/built/components/file-viewer.js.map +0 -1
  299. claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
  300. claude_mpm/dashboard/static/built/components/hud-library-loader.js.map +0 -1
  301. claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
  302. claude_mpm/dashboard/static/built/components/hud-manager.js.map +0 -1
  303. claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
  304. claude_mpm/dashboard/static/built/components/hud-visualizer.js.map +0 -1
  305. claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
  306. claude_mpm/dashboard/static/built/components/module-viewer.js.map +0 -1
  307. claude_mpm/dashboard/static/built/components/nav-bar.js +0 -145
  308. claude_mpm/dashboard/static/built/components/page-structure.js +0 -429
  309. claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
  310. claude_mpm/dashboard/static/built/components/session-manager.js.map +0 -1
  311. claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
  312. claude_mpm/dashboard/static/built/components/socket-manager.js.map +0 -1
  313. claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
  314. claude_mpm/dashboard/static/built/components/ui-state-manager.js.map +0 -1
  315. claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
  316. claude_mpm/dashboard/static/built/components/unified-data-viewer.js.map +0 -1
  317. claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
  318. claude_mpm/dashboard/static/built/components/working-directory.js.map +0 -1
  319. claude_mpm/dashboard/static/built/connection-manager.js +0 -536
  320. claude_mpm/dashboard/static/built/dashboard.js +0 -2
  321. claude_mpm/dashboard/static/built/dashboard.js.map +0 -1
  322. claude_mpm/dashboard/static/built/extension-error-handler.js +0 -164
  323. claude_mpm/dashboard/static/built/react/events.js +0 -30
  324. claude_mpm/dashboard/static/built/react/events.js.map +0 -1
  325. claude_mpm/dashboard/static/built/shared/dom-helpers.js +0 -396
  326. claude_mpm/dashboard/static/built/shared/event-bus.js +0 -330
  327. claude_mpm/dashboard/static/built/shared/event-filter-service.js +0 -540
  328. claude_mpm/dashboard/static/built/shared/logger.js +0 -385
  329. claude_mpm/dashboard/static/built/shared/page-structure.js +0 -249
  330. claude_mpm/dashboard/static/built/shared/tooltip-service.js +0 -253
  331. claude_mpm/dashboard/static/built/socket-client.js +0 -2
  332. claude_mpm/dashboard/static/built/socket-client.js.map +0 -1
  333. claude_mpm/dashboard/static/built/tab-isolation-fix.js +0 -185
  334. claude_mpm/dashboard/static/events.html +0 -607
  335. claude_mpm/dashboard/static/index.html +0 -635
  336. claude_mpm/dashboard/static/js/REFACTORING_SUMMARY.md +0 -170
  337. claude_mpm/dashboard/static/js/shared/dom-helpers.js +0 -396
  338. claude_mpm/dashboard/static/js/shared/event-bus.js +0 -330
  339. claude_mpm/dashboard/static/js/shared/logger.js +0 -385
  340. claude_mpm/dashboard/static/js/shared/tooltip-service.js +0 -253
  341. claude_mpm/dashboard/static/js/stores/dashboard-store.js +0 -562
  342. claude_mpm/dashboard/static/legacy/activity.html +0 -736
  343. claude_mpm/dashboard/static/legacy/agents.html +0 -786
  344. claude_mpm/dashboard/static/legacy/files.html +0 -747
  345. claude_mpm/dashboard/static/legacy/tools.html +0 -831
  346. claude_mpm/dashboard/static/monitors.html +0 -431
  347. claude_mpm/dashboard/static/navigation-test-results.md +0 -118
  348. claude_mpm/dashboard/static/production/events.html +0 -659
  349. claude_mpm/dashboard/static/production/main.html +0 -698
  350. claude_mpm/dashboard/static/production/monitors.html +0 -483
  351. claude_mpm/dashboard/static/test-archive/dashboard.html +0 -635
  352. claude_mpm/dashboard/static/test-archive/debug-events.html +0 -147
  353. claude_mpm/dashboard/static/test-archive/test-navigation.html +0 -256
  354. claude_mpm/dashboard/static/test-archive/test-react-exports.html +0 -180
  355. claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +0 -36
  356. claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +0 -39
  357. claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +0 -38
  358. claude_mpm/hooks/README.md +0 -143
  359. claude_mpm/hooks/templates/README.md +0 -180
  360. claude_mpm/hooks/templates/settings.json.example +0 -147
  361. claude_mpm/schemas/agent_schema.json +0 -596
  362. claude_mpm/schemas/frontmatter_schema.json +0 -165
  363. claude_mpm/services/event_bus/README.md +0 -244
  364. claude_mpm/services/events/README.md +0 -303
  365. claude_mpm/services/framework_claude_md_generator/README.md +0 -119
  366. claude_mpm/services/mcp_gateway/README.md +0 -185
  367. claude_mpm/services/socketio/handlers/connection.py.backup +0 -217
  368. claude_mpm/services/socketio/handlers/hook.py.backup +0 -154
  369. claude_mpm/services/static/.gitkeep +0 -2
  370. claude_mpm/services/version_control/VERSION +0 -1
  371. claude_mpm/skills/bundled/.gitkeep +0 -2
  372. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +0 -79
  373. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -178
  374. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +0 -577
  375. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +0 -467
  376. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +0 -537
  377. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +0 -730
  378. claude_mpm/skills/bundled/collaboration/git-worktrees.md +0 -317
  379. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -112
  380. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +0 -146
  381. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +0 -412
  382. claude_mpm/skills/bundled/collaboration/stacked-prs.md +0 -251
  383. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -81
  384. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +0 -362
  385. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +0 -312
  386. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -152
  387. claude_mpm/skills/bundled/debugging/root-cause-tracing/find-polluter.sh +0 -63
  388. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +0 -668
  389. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +0 -587
  390. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +0 -438
  391. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +0 -391
  392. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +0 -119
  393. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +0 -148
  394. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +0 -483
  395. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +0 -452
  396. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +0 -449
  397. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +0 -411
  398. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +0 -14
  399. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +0 -58
  400. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +0 -68
  401. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +0 -69
  402. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +0 -131
  403. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -325
  404. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +0 -490
  405. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +0 -425
  406. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -499
  407. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +0 -611
  408. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +0 -596
  409. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +0 -260
  410. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +0 -315
  411. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +0 -436
  412. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +0 -433
  413. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +0 -452
  414. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +0 -404
  415. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +0 -420
  416. claude_mpm/skills/bundled/main/artifacts-builder/LICENSE.txt +0 -202
  417. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -86
  418. claude_mpm/skills/bundled/main/artifacts-builder/scripts/bundle-artifact.sh +0 -54
  419. claude_mpm/skills/bundled/main/artifacts-builder/scripts/init-artifact.sh +0 -322
  420. claude_mpm/skills/bundled/main/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  421. claude_mpm/skills/bundled/main/internal-comms/LICENSE.txt +0 -202
  422. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -43
  423. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +0 -47
  424. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +0 -65
  425. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +0 -30
  426. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +0 -16
  427. claude_mpm/skills/bundled/main/mcp-builder/LICENSE.txt +0 -202
  428. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +0 -160
  429. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +0 -412
  430. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +0 -602
  431. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +0 -915
  432. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +0 -916
  433. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +0 -752
  434. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +0 -1237
  435. claude_mpm/skills/bundled/main/mcp-builder/scripts/example_evaluation.xml +0 -22
  436. claude_mpm/skills/bundled/main/mcp-builder/scripts/requirements.txt +0 -2
  437. claude_mpm/skills/bundled/main/skill-creator/LICENSE.txt +0 -202
  438. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +0 -189
  439. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +0 -500
  440. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +0 -464
  441. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +0 -619
  442. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +0 -437
  443. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +0 -231
  444. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +0 -170
  445. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +0 -602
  446. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +0 -821
  447. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +0 -742
  448. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +0 -726
  449. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +0 -764
  450. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +0 -831
  451. claude_mpm/skills/bundled/react/flexlayout-react.md +0 -742
  452. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +0 -226
  453. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +0 -901
  454. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +0 -901
  455. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +0 -775
  456. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +0 -937
  457. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +0 -770
  458. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +0 -961
  459. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +0 -495
  460. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +0 -599
  461. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +0 -535
  462. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +0 -613
  463. claude_mpm/skills/bundled/tauri/tauri-event-system.md +0 -648
  464. claude_mpm/skills/bundled/tauri/tauri-file-system.md +0 -673
  465. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +0 -767
  466. claude_mpm/skills/bundled/tauri/tauri-performance.md +0 -669
  467. claude_mpm/skills/bundled/tauri/tauri-state-management.md +0 -573
  468. claude_mpm/skills/bundled/tauri/tauri-testing.md +0 -384
  469. claude_mpm/skills/bundled/tauri/tauri-window-management.md +0 -628
  470. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -119
  471. claude_mpm/skills/bundled/testing/condition-based-waiting/example.ts +0 -158
  472. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +0 -253
  473. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +0 -145
  474. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +0 -543
  475. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +0 -741
  476. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +0 -470
  477. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +0 -458
  478. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +0 -639
  479. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +0 -458
  480. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +0 -411
  481. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +0 -317
  482. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +0 -270
  483. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +0 -436
  484. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +0 -140
  485. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +0 -572
  486. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +0 -411
  487. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +0 -569
  488. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +0 -695
  489. claude_mpm/skills/bundled/testing/webapp-testing/LICENSE.txt +0 -202
  490. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -184
  491. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +0 -459
  492. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +0 -479
  493. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +0 -687
  494. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +0 -758
  495. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +0 -868
  496. claude_mpm/templates/questions/EXAMPLES.md +0 -501
  497. claude_mpm/tools/README_SOCKETIO_DEBUG.md +0 -224
  498. claude_mpm/tools/code_tree_analyzer/README.md +0 -64
  499. /claude_mpm/agents/templates/{git_file_tracking.md → git-file-tracking.md} +0 -0
  500. /claude_mpm/agents/templates/{pm_examples.md → pm-examples.md} +0 -0
  501. /claude_mpm/agents/templates/{pm_red_flags.md → pm-red-flags.md} +0 -0
  502. /claude_mpm/agents/templates/{response_format.md → response-format.md} +0 -0
  503. /claude_mpm/agents/templates/{validation_templates.md → validation-templates.md} +0 -0
  504. {claude_mpm-4.25.10.dist-info → claude_mpm-5.1.8.dist-info}/WHEEL +0 -0
  505. {claude_mpm-4.25.10.dist-info → claude_mpm-5.1.8.dist-info}/entry_points.txt +0 -0
  506. {claude_mpm-4.25.10.dist-info → claude_mpm-5.1.8.dist-info}/licenses/LICENSE +0 -0
  507. {claude_mpm-4.25.10.dist-info → claude_mpm-5.1.8.dist-info}/top_level.txt +0 -0
@@ -1 +0,0 @@
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":"AA0CA,MAAMA,EAAKC,OAAOD,GA2BlB,MAAME,EAeF,WAAAC,GAMIC,KAAKC,OAAS,KAOdD,KAAKE,KAAO,KAQZF,KAAKG,oBAAsB,CACvBC,QAAS,GACTC,WAAY,GACZC,MAAO,GACPC,MAAO,IASXP,KAAKQ,YAAc,CACfC,SAAU,CAAC,SAAU,OAAQ,UAAW,YAAa,QACrDC,SAAU,CAAC,QAAS,eAQxBV,KAAKW,aAAc,EAQnBX,KAAKY,cAAe,EAOpBZ,KAAKa,gBAAkB,KAQvBb,KAAKc,eAAiB,KAQtBd,KAAKe,OAAS,GAQdf,KAAKgB,aAAeC,IAOpBjB,KAAKkB,iBAAmB,KAQxBlB,KAAKmB,WAAa,GASlBnB,KAAKoB,aAAe,IAQpBpB,KAAKqB,cAAgB,EASrBrB,KAAKsB,iBAAmB,EASxBtB,KAAKuB,YAAc,CAAC,IAAM,IAAM,IAAM,IAAM,KAQ5CvB,KAAKwB,qBAAuBP,IAQ5BjB,KAAKyB,aAAe,KAQpBzB,KAAK0B,aAAe,KASpB1B,KAAK2B,YAAc,KAOnB3B,KAAK4B,oBAAsB,KAG3B5B,KAAK6B,2BACL7B,KAAK8B,uBACT,CA4BA,OAAA1B,CAAQF,EAAO,QAEXF,KAAKE,KAAOA,EACZ,MAAM6B,EAAM,oBAAoB7B,IAGhC,GAAIF,KAAKC,SAAWD,KAAKC,OAAO+B,WAAahC,KAAKC,OAAOgC,YAKrD,OAJAC,QAAQC,IAAI,2DACZnC,KAAKC,OAAOI,kBAEZ+B,WAAW,IAAMpC,KAAKqC,UAAUN,GAAM,KAI1C/B,KAAKqC,UAAUN,EACnB,CA0BA,SAAAM,CAAUN,GAIN,GAHAG,QAAQC,IAAI,qCAAqCJ,UAG/B,IAAPnC,EAGP,OAFAsC,QAAQ5B,MAAM,+FACdN,KAAKsC,uBAAuB,+BAAgC,SAIhEtC,KAAKY,cAAe,EACpBZ,KAAKsC,uBAAuB,gBAAiB,cAE7CtC,KAAKC,OAASL,EAAGmC,EAAK,CAClBQ,aAAa,EACbC,cAAc,EACdC,kBAAmB,IACnBC,qBAAsB,IACtBC,qBAAsB,GACtBC,QAAS,IACTC,UAAU,EACVC,WAAY,CAAC,YAAa,aAK9B9C,KAAK+C,qBACT,CAKA,mBAAAA,GACI/C,KAAKC,OAAO+C,GAAG,UAAW,KACtBd,QAAQC,IAAI,iCACZ,MAAMc,EAAsBjD,KAAKW,YAOjC,GANAX,KAAKW,aAAc,EACnBX,KAAKY,cAAe,EACpBZ,KAAKa,gBAAkBqC,KAAKC,MAC5BnD,KAAKqB,cAAgB,EAGjBrB,KAAKc,iBAA0C,IAAxBmC,EAA+B,CACtD,MAAMG,GAAYF,KAAKC,MAAQnD,KAAKc,gBAAkB,IACtDoB,QAAQC,IAAI,qBAAqBiB,EAASC,QAAQ,gBAGlDrD,KAAKsD,iBACT,CAEAtD,KAAKsC,uBAAuB,YAAa,aAGzCzC,OAAOI,OAASD,KAAKC,OACrBiC,QAAQC,IAAI,0DAGZnC,KAAKG,oBAAoBC,QAAQmD,QAAQC,GACrCA,EAASxD,KAAKC,OAAOwD,KAGzBzD,KAAK0D,kBAKT1D,KAAKC,OAAO+C,GAAG,aAAeW,IAE1B,MAAMC,EAAiB,CACnBD,SACAE,WAAA,IAAeX,MAAOY,cACtBC,aAAc/D,KAAKW,YACnBqD,cAAehE,KAAKa,kBAAoBqC,KAAKC,MAAQnD,KAAKa,iBAAmB,KAAMwC,QAAQ,GAAK,EAChGY,SAAUjE,KAAKyB,eAAiByB,KAAKC,MAAQnD,KAAKyB,cAAgB,KAAM4B,QAAQ,GAAK,QAAU,QAC/Fa,SAAUlE,KAAK0B,eAAiBwB,KAAKC,MAAQnD,KAAK0B,cAAgB,KAAM2B,QAAQ,GAAK,QAAU,SAGnGnB,QAAQC,IAAI,4BAA6ByB,GAEzC5D,KAAKW,aAAc,EACnBX,KAAKY,cAAe,EACpBZ,KAAKc,eAAiBoC,KAAKC,MAE3BnD,KAAKsC,uBAAuB,iBAAiBqB,IAAU,gBAGvD3D,KAAKG,oBAAoBE,WAAWkD,QAAQC,GACxCA,EAASG,IAIY,CACrB,kBACA,eACA,kBACA,wBAGiBQ,SAASR,IAC1BzB,QAAQC,IAAI,wCAAwCwB,KACpD3D,KAAKoE,qBACa,yBAAXT,EACPzB,QAAQC,IAAI,uDAEZD,QAAQC,IAAI,8BAA8BwB,kCAC1C3D,KAAKoE,uBAIbpE,KAAKC,OAAO+C,GAAG,gBAAkB1C,IAC7B4B,QAAQ5B,MAAM,oBAAqBA,GACnCN,KAAKY,cAAe,EACpB,MAAMyD,EAAW/D,EAAMgE,SAAWhE,EAAMiE,aAAe,gBACvDvE,KAAKsC,uBAAuB,qBAAqB+B,IAAY,gBAG7DrE,KAAKwE,SAAS,CACVC,KAAM,mBACNZ,WAAA,IAAeX,MAAOY,cACtBY,KAAM,CACFpE,MAAO+D,EACPtC,IAAK/B,KAAKC,OAAOL,GAAG+E,IACpBC,cAAe5E,KAAKqB,iBAK5BrB,KAAKG,oBAAoBG,MAAMiD,QAAQC,GACnCA,EAASa,IAIbrE,KAAKoE,sBAITpE,KAAKC,OAAO+C,GAAG,eAAiB0B,IAC5BxC,QAAQC,IAAI,yBAA0BuC,GAGtC,MAAMG,EAAiB7E,KAAK8E,oBAAoBJ,GAChD,IAAKG,EAED,YADA3C,QAAQ6C,KAAK,iCAAkCL,GAM/CG,EAAeJ,MAAQI,EAAeJ,KAAKO,WAAW,UACtD9C,QAAQC,IAAI,4FAA6F0C,EAAeJ,MAI5H,MAAMQ,EAAmBjF,KAAKkF,eAAeL,GAC7C3C,QAAQC,IAAI,qBAAsB8C,GAClCjF,KAAKwE,SAASS,KAIlBjF,KAAKC,OAAO+C,GAAG,OAAS0B,IAEpB1E,KAAKyB,aAAeyB,KAAKC,MAGzBnD,KAAKC,OAAOkF,KAAK,OAAQ,CACrBtB,UAAWa,EAAKb,UAChBuB,YAAalC,KAAKC,UAK1BnD,KAAKC,OAAO+C,GAAG,OAAS0B,IACpB1E,KAAK0B,aAAewB,KAAKC,QAK7BnD,KAAKC,OAAO+C,GAAG,YAAc0B,IACzBxC,QAAQC,IAAI,gCAAiCuC,GAE7C1E,KAAKwE,SAAS,CACVC,KAAM,SACNY,QAAS,YACTxB,UAAWa,EAAKb,YAAA,IAAiBX,MAAOY,cACxCY,SAIJ1E,KAAKyB,aAAeyB,KAAKC,MAGzBjB,QAAQC,IAAI,qBAAqBuC,EAAKY,qBAAqBZ,EAAKa,mCAAmCb,EAAKc,yCAI5GxF,KAAKC,OAAO+C,GAAG,kBAAoB0B,IAC/B1E,KAAKwE,SAAS,CAAEC,KAAM,UAAWY,QAAS,UAAWxB,WAAA,IAAeX,MAAOY,cAAeY,WAG9F1E,KAAKC,OAAO+C,GAAG,gBAAkB0B,IAC7B1E,KAAKwE,SAAS,CAAEC,KAAM,UAAWY,QAAS,QAASxB,WAAA,IAAeX,MAAOY,cAAeY,WAG5F1E,KAAKC,OAAO+C,GAAG,iBAAmB0B,IAC9B1E,KAAKwE,SAAS,CAAEC,KAAM,SAAUY,QAAS,UAAWxB,WAAA,IAAeX,MAAOY,cAAeY,WAG7F1E,KAAKC,OAAO+C,GAAG,kBAAoB0B,IAC/B1E,KAAKwE,SAAS,CAAEC,KAAM,SAAUY,QAAS,WAAYxB,WAAA,IAAeX,MAAOY,cAAeY,WAG9F1E,KAAKC,OAAO+C,GAAG,eAAiB0B,IAC5B1E,KAAKwE,SAAS,CAAEC,KAAM,QAASY,QAAS,SAAUxB,WAAA,IAAeX,MAAOY,cAAeY,WAG3F1E,KAAKC,OAAO+C,GAAG,iBAAmB0B,IAC9B1E,KAAKwE,SAAS,CAAEC,KAAM,QAASY,QAAS,WAAYxB,WAAA,IAAeX,MAAOY,cAAeY,WAa7F1E,KAAKC,OAAO+C,GAAG,eAAiB0B,IAC5B1E,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,UAAWxB,WAAA,IAAeX,MAAOY,cAAeY,WAG3F1E,KAAKC,OAAO+C,GAAG,mBAAqB0B,IAChC1E,KAAKwE,SAAS,CAAEC,KAAM,SAAUY,QAAS,YAAaxB,WAAA,IAAeX,MAAOY,cAAeY,WAG/F1E,KAAKC,OAAO+C,GAAG,YAAc0B,IACzB1E,KAAKwE,SAAS,CAAEC,KAAM,MAAOY,QAAS,QAASxB,WAAA,IAAeX,MAAOY,cAAeY,WAMxF1E,KAAKC,OAAO+C,GAAG,uBAAyB0B,IAEpCxC,QAAQC,IAAI,kFACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,kBAAmBxB,WAAA,IAAeX,MAAOY,cAAeY,WAGnG1E,KAAKC,OAAO+C,GAAG,yBAA2B0B,IAEtCxC,QAAQC,IAAI,oFACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,oBAAqBxB,WAAA,IAAeX,MAAOY,cAAeY,WAGrG1E,KAAKC,OAAO+C,GAAG,sBAAwB0B,IAEnCxC,QAAQC,IAAI,iFACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,iBAAkBxB,WAAA,IAAeX,MAAOY,cAAeY,WAGlG1E,KAAKC,OAAO+C,GAAG,yBAA2B0B,IAEtCxC,QAAQC,IAAI,oFACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,oBAAqBxB,WAAA,IAAeX,MAAOY,cAAeY,WAGrG1E,KAAKC,OAAO+C,GAAG,sBAAwB0B,IAEnCxC,QAAQC,IAAI,iFACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,iBAAkBxB,WAAA,IAAeX,MAAOY,cAAeY,WAGlG1E,KAAKC,OAAO+C,GAAG,kBAAoB0B,IAE/BxC,QAAQC,IAAI,6EACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,aAAcxB,WAAA,IAAeX,MAAOY,cAAeY,WAG9F1E,KAAKC,OAAO+C,GAAG,kBAAoB0B,IAE/BxC,QAAQC,IAAI,6EACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,aAAcxB,WAAA,IAAeX,MAAOY,cAAeY,WAG9F1E,KAAKC,OAAO+C,GAAG,yBAA2B0B,IAEtCxC,QAAQC,IAAI,oFACZnC,KAAKwE,SAAS,CAAEC,KAAM,OAAQY,QAAS,oBAAqBxB,WAAA,IAAeX,MAAOY,cAAeY,WAGrG1E,KAAKC,OAAO+C,GAAG,UAAY0B,IACvBxC,QAAQC,IAAI,0BAA2BuC,GACnCA,GAAQe,MAAMC,QAAQhB,EAAK3D,SAC3BmB,QAAQC,IAAI,cAAcuC,EAAK3D,OAAO4E,6BAA6BjB,EAAKkB,eAAelB,EAAKmB,oCAG5FnB,EAAK3D,OAAOwC,QAAQhD,IAChB,MAAM0E,EAAmBjF,KAAKkF,eAAe3E,GAC7CP,KAAKwE,SAASS,GAAkB,KAEpCjF,KAAK8F,oBACL5D,QAAQC,IAAI,yBAAyBuC,EAAK3D,OAAO4E,qCAC1CF,MAAMC,QAAQhB,KAErBxC,QAAQC,IAAI,wCAAyCuC,EAAKiB,OAAQ,UAClEjB,EAAKnB,QAAQhD,IACT,MAAM0E,EAAmBjF,KAAKkF,eAAe3E,GAC7CP,KAAKwE,SAASS,GAAkB,KAEpCjF,KAAK8F,uBAIb9F,KAAKC,OAAO+C,GAAG,gBAAkB0B,IAC7BxC,QAAQC,IAAI,0BAA2BuC,GACnCA,EAAK1D,UACLhB,KAAK+F,eAAerB,EAAK1D,UAEzB0D,EAAKsB,kBACLhG,KAAKkB,iBAAmBwD,EAAKsB,kBAGzC,CAKA,UAAA3F,GACQL,KAAKC,SACLD,KAAKC,OAAOI,aACZL,KAAKC,OAAS,MAElBD,KAAKE,KAAO,KACZF,KAAKW,aAAc,EACnBX,KAAKY,cAAe,CACxB,CAQA,aAAAqF,CAAc1F,EAAOmE,EAAO,KAAMwB,EAAU,CAAA,GACxC,MAAMC,WACFA,EAAa,EAAA5E,YACbA,EAAc,CAAC,IAAM,IAAM,KAAI6E,UAC/BA,EAAY,KAAAC,UACZA,EAAY,MACZH,EAEEI,EAAa,GAAG/F,KAAS2C,KAAKC,SAASoD,KAAKC,WAE5CC,EAAkB,CAACC,EAAa,KAClC,GAAK1G,KAAKC,QAAWD,KAAKC,OAAO+B,UAUjC,IAEIhC,KAAKC,OAAOkF,KAAK5E,EAAOmE,GACxBxC,QAAQC,IAAI,WAAW5B,kBAGvBP,KAAKwB,iBAAiBmF,OAAOL,GAEzBF,GAAWA,GAEnB,OAAS9F,GAGL,GAFA4B,QAAQ5B,MAAM,kBAAkBC,cAAkBmG,EAAa,MAAOpG,GAElEoG,EAAaP,EAAa,EAAG,CAC7B,MAAMS,EAAQrF,EAAYmF,IAAenF,EAAYA,EAAYoE,OAAS,GAC1EzD,QAAQC,IAAI,YAAY5B,QAAYqG,UAGpC5G,KAAKwB,iBAAiBqF,IAAIP,EAAY,CAClC/F,QACAmE,OACAgC,WAAYA,EAAa,EACzBI,cAAe5D,KAAKC,MAAQyD,IAGhCxE,WAAW,IAAMqE,EAAgBC,EAAa,GAAIE,EACtD,MACI1E,QAAQ5B,MAAM,kBAAkBC,WAAe4F,cAC/CnG,KAAKwB,iBAAiBmF,OAAOL,GACzBD,KAAqB,uBAEjC,MAvCuB,IAAfK,IACA1G,KAAK+G,WAAWxG,EAAOmE,GACvBxC,QAAQC,IAAI,UAAU5B,uCAClB8F,KAAqB,kBAuCrCI,GACJ,CAOA,UAAAM,CAAWxG,EAAOmE,GACd,GAAI1E,KAAKmB,WAAWwE,QAAU3F,KAAKoB,aAAc,CAE7C,MAAM4F,EAAUhH,KAAKmB,WAAW8F,QAChC/E,QAAQ6C,KAAK,2CAA2CiC,EAAQzG,QACpE,CAEAP,KAAKmB,WAAW+F,KAAK,CACjB3G,QACAmE,OACAb,UAAWX,KAAKC,OAExB,CAKA,eAAAG,GACI,GAA+B,IAA3BtD,KAAKmB,WAAWwE,OAAc,OAElCzD,QAAQC,IAAI,YAAYnC,KAAKmB,WAAWwE,2BACxC,MAAM5E,EAAS,IAAIf,KAAKmB,YACxBnB,KAAKmB,WAAa,GAGlBJ,EAAOwC,QAAQ,CAAC4D,EAAMC,KAClBhF,WAAW,KACHpC,KAAKC,QAAUD,KAAKC,OAAO+B,YAC3BhC,KAAKC,OAAOkF,KAAKgC,EAAK5G,MAAO4G,EAAKzC,MAClCxC,QAAQC,IAAI,yBAAyBgF,EAAK5G,WAEvC,IAAR6G,IAEX,CAKA,iBAAAhD,GACI,GAAIpE,KAAKqB,eAAiBrB,KAAKsB,iBAG3B,OAFAY,QAAQC,IAAI,mEACZnC,KAAKsC,uBAAuB,sBAAuB,gBAIvD,MAAMsE,EAAQ5G,KAAKuB,YAAYvB,KAAKqB,gBAAkBrB,KAAKuB,YAAYvB,KAAKuB,YAAYoE,OAAS,GACjG3F,KAAKqB,gBAELa,QAAQC,IAAI,gCAAgCnC,KAAKqB,iBAAiBrB,KAAKsB,uBAAuBsF,UAC9F5G,KAAKsC,uBAAuB,mBAAmBsE,EAAM,UAAY,cAEjExE,WAAW,MACFpC,KAAKW,aAAeX,KAAKE,OAC1BgC,QAAQC,IAAI,2BAA2BnC,KAAKqB,iBAAiBrB,KAAKsB,uBAClEtB,KAAKI,QAAQJ,KAAKE,QAEvB0G,EACP,CAKA,aAAAlD,GACQ1D,KAAKC,QAAUD,KAAKC,OAAO+B,YAC3BE,QAAQC,IAAI,+BACZnC,KAAKiG,cAAc,iBAAkB,KAAM,CACvCE,WAAY,EACZ5E,YAAa,CAAC,IAAK,OAG/B,CAQA,cAAA8F,CAAenB,EAAU,IACrB,GAAIlG,KAAKC,QAAUD,KAAKC,OAAO+B,UAAW,CACtC,MAAMsF,EAAS,CACXC,MAAOrB,EAAQqB,OAAS,GACxBC,YAAatB,EAAQsB,aAAe,IAExCtF,QAAQC,IAAI,8BAA+BmF,GAC3CtH,KAAKiG,cAAc,cAAeqB,EAAQ,CACtCnB,WAAY,EACZ5E,YAAa,CAAC,IAAM,IAAM,KAC1B8E,UAAY1C,IACRzB,QAAQ5B,MAAM,8BAA8BqD,OAGxD,MACIzB,QAAQ6C,KAAK,kDAErB,CAOA,QAAAP,CAASiD,EAAWC,GAAS,GAYzB,GAVKD,EAAU5D,YACX4D,EAAU5D,WAAA,IAAgBX,MAAOY,eAEhC2D,EAAUhE,KACXgE,EAAUhE,GAAKP,KAAKC,MAAQoD,KAAKC,UAGrCxG,KAAKe,OAAOmG,KAAKO,GAGbA,EAAU/C,MAAQ+C,EAAU/C,KAAKiD,WAAY,CAC7C,MAAMC,EAAYH,EAAU/C,KAAKiD,WAC5B3H,KAAKgB,SAAS6G,IAAID,IACnB5H,KAAKgB,SAAS6F,IAAIe,EAAW,CACzBnE,GAAImE,EACJE,UAAWL,EAAU5D,UACrBkE,aAAcN,EAAU5D,UACxBmE,WAAY,EACZC,kBAAmB,KACnBC,WAAY,OAGpB,MAAMC,EAAUnI,KAAKgB,SAASoH,IAAIR,GAClCO,EAAQJ,aAAeN,EAAU5D,UACjCsE,EAAQH,aAIR,MAAMK,EAAgB,CAClBZ,EAAU/C,KAAK4D,IACfb,EAAU/C,KAAKuD,kBACfR,EAAU/C,KAAK6D,YACfd,EAAU/C,KAAK8D,iBACff,EAAU/C,KAAK+D,eAAeF,YAC9Bd,EAAU/C,KAAK+D,eAAeR,kBAC9BR,EAAU/C,KAAK+D,eAAeH,IAC9Bb,EAAUa,IACVb,EAAUQ,kBACVR,EAAUc,aAGd,IAAA,MAAWG,KAAQL,EACf,GAAIK,GAAwB,iBAATA,GAAqBA,EAAKC,OAAQ,CACjDR,EAAQF,kBAAoBS,EAC5BxG,QAAQC,IAAI,uDAAuDyF,KAAcc,GACjF,KACJ,CAIAjB,EAAU/C,KAAKwD,WACfC,EAAQD,WAAaT,EAAU/C,KAAKwD,WAC7BT,EAAU/C,KAAK+D,eAAiBhB,EAAU/C,KAAK+D,cAAcP,aACpEC,EAAQD,WAAaT,EAAU/C,KAAK+D,cAAcP,WAE1D,CAEIR,GACA1H,KAAK8F,mBAEb,CAMA,cAAAC,CAAe6C,GACPnD,MAAMC,QAAQkD,IACdA,EAAarF,QAAQ4E,IACjBnI,KAAKgB,SAAS6F,IAAIsB,EAAQ1E,GAAI0E,IAG1C,CAKA,WAAAU,GACI7I,KAAKe,OAAS,GACdf,KAAKgB,SAAS8H,QACd9I,KAAK8F,mBACT,CAMA,cAAAiD,CAAe7C,EAAU,IACrBlG,KAAK6I,cACL7I,KAAKqH,eAAenB,EACxB,CAOA,kBAAA8C,CAAmBpB,EAAY,MAC3B,OAAKA,EAGE5H,KAAKe,OAAOkI,OAAO1I,GACtBA,EAAMmE,MAAQnE,EAAMmE,KAAKiD,aAAeC,GAHjC5H,KAAKe,MAKpB,CAOA,YAAAmI,CAAaC,EAAW3F,GAChBxD,KAAKG,oBAAoBgJ,IACzBnJ,KAAKG,oBAAoBgJ,GAAWjC,KAAK1D,EAEjD,CAMA,aAAA4F,CAAc5F,GACVxD,KAAKG,oBAAoBI,MAAM2G,KAAK1D,EACxC,CAOA,EAAAR,CAAGzC,EAAOiD,GACN,GAAIxD,KAAKC,OACL,OAAOD,KAAKC,OAAO+C,GAAGzC,EAAOiD,GAE7BtB,QAAQ6C,KAAK,wBAAwBxE,6BAE7C,CAOA,GAAA8I,CAAI9I,EAAOiD,GACP,GAAIxD,KAAKC,OACL,OAAOD,KAAKC,OAAOoJ,IAAI9I,EAAOiD,GAE9BtB,QAAQ6C,KAAK,4BAA4BxE,6BAEjD,CAOA,sBAAA+B,CAAuBgH,EAAQ7E,GAC3BvC,QAAQC,IAAI,+CAA+CmH,OAAY7E,MAGvEzE,KAAKuJ,0BAA0BD,EAAQ7E,GAGvC+E,SAASC,cAAc,IAAIC,YAAY,yBAA0B,CAC7DC,OAAQ,CAAEL,SAAQ7E,UAE1B,CAOA,yBAAA8E,CAA0BD,EAAQ7E,GAC9B,MAAMmF,EAAgBJ,SAASK,eAAe,qBAC1CD,GAEAA,EAAcE,UAAY,kBAAkBR,IAG5CM,EAAcG,UAAY,uBAAuBtF,IAEjDvC,QAAQC,IAAI,8CAA8CmH,OAAY7E,OAEtEvC,QAAQ6C,KAAK,gEAErB,CAKA,iBAAAe,GACI9F,KAAKG,oBAAoBI,MAAMgD,QAAQC,GACnCA,EAASxD,KAAKe,OAAQf,KAAKgB,WAI/BwI,SAASC,cAAc,IAAIC,YAAY,oBAAqB,CACxDC,OAAQ,CAAE5I,OAAQf,KAAKe,OAAQC,SAAUhB,KAAKgB,YAEtD,CAMA,kBAAAgJ,GACI,MAAO,CACHrJ,YAAaX,KAAKW,YAClBC,aAAcZ,KAAKY,aACnBqJ,SAAUjK,KAAKC,OAASD,KAAKC,OAAOwD,GAAK,KAEjD,CAOA,mBAAAqB,CAAoB2C,GAChB,IAAKA,GAAkC,iBAAdA,EAErB,OADAvF,QAAQ6C,KAAK,+BAAgC0C,GACtC,KAIX,MAAMyC,EAAY,IAAKzC,GA8BvB,OA3BKyC,EAAUC,SACXD,EAAUC,OAAS,UAElBD,EAAUzF,OAEPyF,EAAU3J,MACV2J,EAAUzF,KAAOyF,EAAU3J,MAE3B2J,EAAUzF,KAAO,WAGpByF,EAAU7E,UACX6E,EAAU7E,QAAU,WAEnB6E,EAAUrG,YACXqG,EAAUrG,WAAA,IAAgBX,MAAOY,eAEhCoG,EAAUxF,OACXwF,EAAUxF,KAAO,CAAA,GAIjBwF,EAAUxF,MAAkC,iBAAnBwF,EAAUxF,OACnCwF,EAAUxF,KAAO,CAAE0F,MAAOF,EAAUxF,OAGxCxC,QAAQC,IAAI,mBAAoB+H,GACzBA,CACX,CAOA,cAAAhF,CAAeuC,GAOX,IAAKA,EACD,OAAOA,EAGX,IAAIxC,EAAmB,IAAKwC,GAQ5B,GAJ4BA,EAAUhD,MAAQgD,EAAUpC,UAC5BoC,EAAUhD,KAAKN,SAAS,OACxBsD,EAAUhD,KAAKN,SAAS,KAK3Cc,EAAiBoF,oBACQ,YAAtB5C,EAAUpC,SAAyBoC,EAAUhD,OAASgD,EAAUpC,QAChEJ,EAAiBoF,kBAAoB5C,EAAUhD,KAE/CQ,EAAiBoF,kBAAoB,GAAG5C,EAAUhD,QAAQgD,EAAUpC,gBAIhF,IAEUoC,EAAUhD,MAAQgD,EAAUlH,MAAO,CAEzC,MAAM+J,EAAY7C,EAAUlH,MAGV,cAAd+J,GAA2C,YAAdA,GAC7BrF,EAAiBR,KAAO,OACxBQ,EAAiBI,QAAUiF,EAAUC,cAAcC,QAAQ,OAAQ,KAC9C,kBAAdF,GAA+C,iBAAdA,GACxCrF,EAAiBR,KAAO,WACxBQ,EAAiBI,QAAUiF,EAAUC,cAAcC,QAAQ,WAAY,KAClD,aAAdF,GACPrF,EAAiBR,KAAO,OACxBQ,EAAiBI,QAAU,QACN,eAAdiF,GACPrF,EAAiBR,KAAO,OACxBQ,EAAiBI,QAAU,gBAI3BJ,EAAiBR,KAAO,UACxBQ,EAAiBI,QAAUiF,EAAUC,cAGjCtF,EAAiBR,OAASQ,EAAiBI,UAC3CJ,EAAiBI,QAAU,iBAK5BJ,EAAiB1E,MAExB0E,EAAiBoF,kBAAoBC,CACzC,MAAA,GAES7C,EAAUhD,KAAM,CACrB,MAAMA,EAAOgD,EAAUhD,KAGvB,GAAIA,EAAKO,WAAW,SAAU,CAC1B,MAAMK,EAAUZ,EAAKgG,UAAU,GAC/BxF,EAAiBR,KAAO,OACxBQ,EAAiBI,QAAUA,EAC3BJ,EAAiBoF,kBAAoB5F,CACzC,MAAA,GAGSA,EAAKO,WAAW,SAAU,CAC/BC,EAAiBR,KAAO,OAExB,MAAMiG,EAAcjG,EAAKgG,UAAU,GACnCxF,EAAiBI,QAAUqF,EAAYF,QAAQ,KAAM,KACrDvF,EAAiBoF,kBAAoB5F,CACzC,MAAA,GAESA,EAAKN,SAAS,KAAM,CACzB,MAAOwG,KAAaC,GAAgBnG,EAAKoG,MAAM,KAC/C5F,EAAiBR,KAAOkG,EACxB1F,EAAiBI,QAAUuF,EAAaE,KAAK,KAC7C7F,EAAiBoF,kBAAoB5F,CACzC,MAAA,GAESA,EAAKN,SAAS,KAAM,CACzB,MAAM4G,EAAQtG,EAAKoG,MAAM,IAAK,GAC9B5F,EAAiBR,KAAOsG,EAAM,GAE9B9F,EAAiBI,QAAU0F,EAAMpF,OAAS,EAAIoF,EAAM,GAAGP,QAAQ,KAAM,KAAO,UAC5EvF,EAAiBoF,kBAAoB5F,CACzC,MAEUgD,EAAUpC,UAChBJ,EAAiBI,QAAU,UAC3BJ,EAAiBoF,kBAAoB5F,EAE7C,MAGIQ,EAAiBR,KAAO,UACxBQ,EAAiBI,QAAU,GAC3BJ,EAAiBoF,kBAAoB,UAKzC,GAAI5C,EAAU/C,MAAkC,iBAAnB+C,EAAU/C,KAAmB,CAEtD,MAAMsG,EAAkB,CAAC,OAAQ,UAAW,YAAa,KAAM,QAAS,aAAc,qBAGtFC,OAAOC,KAAKzD,EAAU/C,MAAMnB,QAAQ4H,IAE3BH,EAAgB7G,SAASgH,GAYd,cAARA,GACAjJ,QAAQkJ,MAAM,oBAAoBD,6EAV1B,oBAARA,GAA4D,iBAAxB1D,EAAU/C,KAAKyG,GAEnDlG,EAAiBkG,GAAOE,KAAKC,MAAMD,KAAKE,UAAU9D,EAAU/C,KAAKyG,KAEjElG,EAAiBkG,GAAO1D,EAAU/C,KAAKyG,KAYnDlG,EAAiBP,KAAO+C,EAAU/C,IACtC,CA+BA,GA3B8B,SAA1BO,EAAiBR,KACgB,aAA7BQ,EAAiBI,QACjBJ,EAAiBuG,gBAAkB,aACC,cAA7BvG,EAAiBI,QACxBJ,EAAiBuG,gBAAkB,cACC,mBAA7BvG,EAAiBI,QACxBJ,EAAiBuG,gBAAkB,gBACC,kBAA7BvG,EAAiBI,QACxBJ,EAAiBuG,gBAAkB,eACC,eAA7BvG,EAAiBI,QACxBJ,EAAiBuG,gBAAkB,YACC,UAA7BvG,EAAiBI,QACxBJ,EAAiBuG,gBAAkB,QACC,SAA7BvG,EAAiBI,UACxBJ,EAAiBuG,gBAAkB,QAEN,aAA1BvG,EAAiBR,KACS,UAA7BQ,EAAiBI,QACjBJ,EAAiBuG,gBAAkB,gBACC,SAA7BvG,EAAiBI,UACxBJ,EAAiBuG,gBAAkB,gBAEN,SAA1BvG,EAAiBR,MAAgD,YAA7BQ,EAAiBI,UAC5DJ,EAAiBuG,gBAAkB,aAIT,SAA1BvG,EAAiBR,OAAiD,aAA7BQ,EAAiBI,SAAuD,cAA7BJ,EAAiBI,SAA0B,CAC3HnD,QAAQC,IAAI,0BAA2B,CACnCsC,KAAMQ,EAAiBR,KACvBY,QAASJ,EAAiBI,QAC1BmG,gBAAiBvG,EAAiBuG,gBAClCC,UAAWxG,EAAiBwG,UAC5BC,sBAAuBzG,EAAiB0G,gBACxCA,gBAAiB1G,EAAiB0G,gBAClCC,WAAY3G,EAAiBP,KAC7BwG,KAAMD,OAAOC,KAAKjG,GAAkBgE,OAAO4C,GAAW,SAANA,KAIlC,CAAC,OAAQ,QAAS,OAAQ,YAAa,gBAC3C1H,SAASc,EAAiBwG,YACpCvJ,QAAQC,IAAI,2BAA4B,CACpCsJ,UAAWxG,EAAiBwG,UAC5BK,UAAW7G,EAAiB0G,iBAAiBG,UAC7CpD,KAAMzD,EAAiB0G,iBAAiBjD,KACxCqD,cAAe9G,EAAiB0G,iBAAiBI,cACjDC,gBAAiB/G,EAAiB0G,iBAG9C,CAEA,OAAO1G,CACX,CAMA,QAAAgH,GACI,MAAO,CACHlL,OAAQf,KAAKe,OACbC,SAAUhB,KAAKgB,SACfE,iBAAkBlB,KAAKkB,iBAE/B,CAMA,qBAAAY,GACI9B,KAAK4B,oBAAsBsK,YAAY,KACnC,GAAIlM,KAAKW,aAAeX,KAAKyB,aAAc,CACvC,MAAM0K,EAAoBjJ,KAAKC,MAAQnD,KAAKyB,aAExC0K,EAAoBnM,KAAK2B,cACzBO,QAAQ6C,KAAK,2BAA2BoH,EAAkB,iCAGtDnM,KAAKC,SACLiC,QAAQC,IAAI,mDACZnC,KAAKC,OAAOI,aACZ+B,WAAW,KACHpC,KAAKE,MACLF,KAAKI,QAAQJ,KAAKE,OAEvB,MAGf,GACD,IACP,CAKA,oBAAAkM,GACQpM,KAAK4B,sBACLyK,cAAcrM,KAAK4B,qBACnB5B,KAAK4B,oBAAsB,KAEnC,CAMA,wBAAAC,GAEIqK,YAAY,KACRlM,KAAKsM,wBACN,KAGyB,YAAxB9C,SAAS+C,WACT/C,SAASgD,iBAAiB,mBAAoB,KAC1CpK,WAAW,IAAMpC,KAAKsM,uBAAwB,OAGlDlK,WAAW,IAAMpC,KAAKsM,uBAAwB,IAEtD,CAKA,oBAAAA,GACI,IAAIG,EAAe,eACfC,EAAa,eAEb1M,KAAKC,SACDD,KAAKC,OAAO+B,WACZyK,EAAe,YACfC,EAAa,YACb1M,KAAKW,aAAc,EACnBX,KAAKY,cAAe,GACbZ,KAAKC,OAAOgC,YAAcjC,KAAKY,cACtC6L,EAAe,gBACfC,EAAa,aACb1M,KAAKW,aAAc,IAEnB8L,EAAe,eACfC,EAAa,eACb1M,KAAKW,aAAc,EACnBX,KAAKY,cAAe,IAK5B,MAAMgJ,EAAgBJ,SAASK,eAAe,qBAC9C,GAAID,EAAe,CACf,MAAM+C,EAAc/C,EAAcgD,YAAYpC,QAAQ,IAAK,IAAI7B,OACzDkE,EAAejD,EAAcG,UAC7B+C,EAAgB,uBAAuBJ,IAGzCC,IAAgBF,GAAgBI,IAAiBC,IACjD5K,QAAQC,IAAI,wCAAwCwK,OAAiBE,YAAuBJ,OAAkBK,MAC9G9M,KAAKuJ,0BAA0BkD,EAAcC,GAErD,CACJ,CAKA,OAAAK,GACI/M,KAAKoM,uBACDpM,KAAKC,SACLD,KAAKC,OAAOI,aACZL,KAAKC,OAAS,MAElBD,KAAKmB,WAAa,GAClBnB,KAAKwB,iBAAiBsH,OAC1B,CAMA,oBAAAkE,GACI,MAAO,CACHrM,YAAaX,KAAKW,YAClBsM,OAAQjN,KAAKa,iBAAmBqC,KAAKC,MAAQnD,KAAKa,iBAAmB,IAAO,EAC5EoD,SAAUjE,KAAKyB,cAAgByB,KAAKC,MAAQnD,KAAKyB,cAAgB,IAAO,KACxEyL,aAAclN,KAAKmB,WAAWwE,OAC9BnE,iBAAkBxB,KAAKwB,iBAAiB2L,KACxC9L,cAAerB,KAAKqB,cAE5B,EAQJxB,OAAOC,aAAeA,EC35CtB,MAAMsN,EACF,WAAArN,GACIC,KAAKqN,aAAe,KACpBrN,KAAKG,wBAA0BmN,IAC/BtN,KAAKuN,yBAA2BD,IAGhCtN,KAAKqN,aAAe,IAAIvN,EAGxBD,OAAOwN,aAAerN,KAAKqN,aAE3BrN,KAAKwN,2BAGLpL,WAAW,KACPpC,KAAKyN,iCACN,KAEHvL,QAAQC,IAAI,6BAChB,CAKA,wBAAAqL,GAEIhE,SAASgD,iBAAiB,yBAA2BkB,IACjDxL,QAAQC,IAAI,uDAAuDuL,EAAE/D,OAAOL,WAAWoE,EAAE/D,OAAOlF,SAChGzE,KAAK2N,6BAA6BD,EAAE/D,OAAOL,OAAQoE,EAAE/D,OAAOlF,MAG5DzE,KAAKG,oBAAoBoD,QAAQC,IAC7B,IACIA,EAASkK,EAAE/D,OAAOL,OAAQoE,EAAE/D,OAAOlF,KACvC,OAASnE,GACL4B,QAAQ5B,MAAM,gCAAiCA,EACnD,MAKJN,KAAKqN,cACLrN,KAAKqN,aAAajE,cAAerI,IAE7Bf,KAAKuN,qBAAqBhK,QAAQC,IAC9B,IACIA,EAASzC,EACb,OAAST,GACL4B,QAAQ5B,MAAM,kCAAmCA,EACrD,KAIhB,CAOA,4BAAAqN,CAA6BrE,EAAQ7E,GACjCzE,KAAK4N,uBAAuBtE,EAAQ7E,GAGvB,cAATA,GAAwBzE,KAAKqN,cAAgBrN,KAAKqN,aAAapN,SAE/DJ,OAAOI,OAASD,KAAKqN,aAAapN,OAClCiC,QAAQC,IAAI,2DAEZnC,KAAK6N,yBAEb,CAKA,6BAAAJ,GACIvL,QAAQC,IAAI,qDAGRnC,KAAKqN,cAAkE,mBAA3CrN,KAAKqN,aAAaf,sBAC9CpK,QAAQC,IAAI,kEACZnC,KAAKqN,aAAaf,wBACXtM,KAAKqN,cAAgBrN,KAAKqN,aAAapN,QAC9CiC,QAAQC,IAAI,gDAAiD,CACzDH,UAAWhC,KAAKqN,aAAapN,OAAO+B,UACpCC,WAAYjC,KAAKqN,aAAapN,OAAOgC,WACrCrB,aAAcZ,KAAKqN,aAAazM,aAChCD,YAAaX,KAAKqN,aAAa1M,cAG/BX,KAAKqN,aAAapN,OAAO+B,WACzBE,QAAQC,IAAI,+DAEZtC,OAAOI,OAASD,KAAKqN,aAAapN,OAClCiC,QAAQC,IAAI,2DACZnC,KAAK4N,uBAAuB,YAAa,cAClC5N,KAAKqN,aAAazM,cAAgBZ,KAAKqN,aAAapN,OAAOgC,YAClEC,QAAQC,IAAI,wDACZnC,KAAK4N,uBAAuB,gBAAiB,gBAE7C1L,QAAQC,IAAI,0DACZnC,KAAK4N,uBAAuB,eAAgB,mBAGhD1L,QAAQC,IAAI,gFACZnC,KAAK4N,uBAAuB,eAAgB,iBAIhDxL,WAAW,KACPF,QAAQC,IAAI,wDACRnC,KAAKqN,cAAgBrN,KAAKqN,aAAapN,QAAUD,KAAKqN,aAAapN,OAAO+B,YAC1EE,QAAQC,IAAI,uEAEPtC,OAAOI,SACRJ,OAAOI,OAASD,KAAKqN,aAAapN,OAClCiC,QAAQC,IAAI,8EAEhBnC,KAAK4N,uBAAuB,YAAa,eAE9C,IACP,CAKA,sBAAAC,GAEI7N,KAAKqN,aAAapN,OAAOoJ,IAAI,uBAG7BrJ,KAAKqN,aAAapN,OAAO+C,GAAG,sBAAwB0B,IAChD,GAAIA,EAAKoJ,QAAS,CACd,MAAMC,EAAevE,SAASK,eAAe,qBACzCkE,IACAA,EAAanB,YAAclI,EAAKsJ,QAAU,WAE1CD,IACAA,EAAaE,MAAMC,QAAU,SAErC,MACIhM,QAAQ5B,MAAM,6BAA8BoE,EAAKpE,QAG7D,CAOA,sBAAAsN,CAAuBtE,EAAQ7E,GAC3B,MAAMmF,EAAgBJ,SAASK,eAAe,qBAC9C,GAAID,EAAe,CAGf,GADkBA,EAAcuE,cAAc,QAC/B,CAEX,MAAMC,EAAyC,IAC/CxE,EAAcE,UAAY,SAASsE,YAA0B9E,GACjE,MAEIM,EAAcgD,YAActD,EAGhCM,EAAcG,UAAY,uBAAuBtF,IACjDvC,QAAQC,IAAI,wCAAwCmH,OAAY7E,KACpE,MACIvC,QAAQ5B,MAAM,iEAEtB,CAMA,OAAAF,CAAQF,GACAF,KAAKqN,cACLrN,KAAKqN,aAAajN,QAAQF,EAElC,CAKA,UAAAG,GACQL,KAAKqN,cACLrN,KAAKqN,aAAahN,YAE1B,CAMA,WAAAM,GACI,OAAOX,KAAKqN,cAAgBrN,KAAKqN,aAAa1M,WAClD,CAMA,YAAAC,GACI,OAAOZ,KAAKqN,cAAgBrN,KAAKqN,aAAazM,YAClD,CAMA,eAAAyN,GACI,OAAOrO,KAAKqN,YAChB,CAMA,SAAAiB,GACI,OAAOtO,KAAKqN,aAAerN,KAAKqN,aAAapN,OAAS,IAC1D,CAMA,wBAAAsO,CAAyB/K,GACrBxD,KAAKG,oBAAoBqO,IAAIhL,EACjC,CAMA,yBAAAiL,CAA0BjL,GACtBxD,KAAKG,oBAAoBwG,OAAOnD,EACpC,CAMA,aAAA4F,CAAc5F,GACVxD,KAAKuN,qBAAqBiB,IAAIhL,EAClC,CAMA,cAAAkL,CAAelL,GACXxD,KAAKuN,qBAAqB5G,OAAOnD,EACrC,CAKA,wBAAAmL,GACI,MAAMC,EAAcpF,SAASK,eAAe,2BACtCgF,EAAYrF,SAASK,eAAe,yBAE1C,GAAI+E,GAAeC,EAAW,CACRD,EAAYE,UAAUC,SAAS,SAG7CH,EAAYE,UAAUE,OAAO,QAC7BJ,EAAYX,MAAMC,QAAU,OAC5BW,EAAUjC,YAAc,wBAExBgC,EAAYE,UAAUN,IAAI,QAC1BI,EAAYX,MAAMC,QAAU,QAC5BW,EAAUjC,YAAc,gBAEhC,CACJ,CAMA,uBAAAqC,GACI,MAAMC,EAAa1F,SAASK,eAAe,eACrCsF,EAAgB3F,SAASK,eAAe,kBACxCuF,EAAsB5F,SAASK,eAAe,yBAEhDqF,GACAA,EAAW1C,iBAAiB,QAAS,KACjC,MAAMtM,EAAOsJ,SAASK,eAAe,cAAcO,OAAS,KAC5DpK,KAAKI,QAAQF,KAIjBiP,GACAA,EAAc3C,iBAAiB,QAAS,KACpCxM,KAAKK,eAIT+O,GACAA,EAAoB5C,iBAAiB,QAAS,KAC1CxM,KAAK2O,4BAGjB,CAMA,iBAAAU,CAAkB/H,GACd,MAAMpH,EAAOoH,EAAOc,IAAI,QAClBkH,EAAY9F,SAASK,eAAe,cAO1C,IAAI0F,EAAcrP,EACbqP,GAA4C,UAA7B1P,OAAO2P,SAASC,WAChCF,EAAc1P,OAAO2P,SAAStP,MAAQ,QAErCqP,IACDA,EAAcD,GAAWlF,OAAS,QAIlCkF,IACAA,EAAUlF,MAAQmF,KAK8B,UAA1BjI,EAAOc,IAAI,aACXpI,KAAKW,eAAkBX,KAAKY,iBAClDsB,QAAQC,IAAI,0CAA0CoN,KACtDvP,KAAKI,QAAQmP,GAErB,EASJ1P,OAAOuN,cAAgBA,ECjWvB,MAAMsC,EACF,WAAA3P,GAEIC,KAAK2P,YAAa,EAGlB3P,KAAK4P,UAAY,CACb,UAAW,SACX,UAAW,SACX,SAAU,QACV,SAAU,QACV,YAAa,WACb,aAAc,cACd,GAAI,UAIR5P,KAAK6P,UAAY,CACb9O,OAAU,UACV+O,OAAU,UACVC,MAAS,SACTC,MAAS,SACTC,SAAY,YACZ,cAAe,cAInBjQ,KAAKkQ,WAAalQ,KAAKmQ,iBAGvBnQ,KAAKoQ,YAAa,EAGlBpQ,KAAKqQ,aAAe,CAChBC,IAAK,KACLlJ,MAAO,KACP3C,KAAM,KACNC,KAAM,MAIV1E,KAAKuQ,cAAgB,CACjBxP,OAAQ,CAAEyP,eAAe,EAAIC,MAAO,IACpCX,OAAQ,CAAEU,eAAe,EAAIC,MAAO,IACpCV,MAAO,CAAES,eAAe,EAAIC,MAAO,IACnCT,MAAO,CAAEQ,eAAe,EAAIC,MAAO,KAGvCzQ,KAAK0Q,qBACLxO,QAAQC,IAAI,qDAGZnC,KAAK2Q,kBACT,CAMA,cAAAR,GACI,MAAMS,EAAO/Q,OAAO2P,SAASoB,MAAQ,GACrC,OAAO5Q,KAAK4P,UAAUgB,IAAS,QACnC,CAKA,kBAAAF,GACI1Q,KAAK6Q,sBACL7Q,KAAK8Q,wBACL9Q,KAAK+Q,gCACT,CAKA,mBAAAF,GAEIhR,OAAO2M,iBAAiB,aAAekB,IACnCxL,QAAQC,IAAI,sCAAuC,IAAI6O,IAAItD,EAAEuD,QAAQL,KAAM,KAAM/Q,OAAO2P,SAASoB,MACjG5Q,KAAK2Q,qBAITnH,SAASgD,iBAAiB,mBAAoB,KAC1CtK,QAAQC,IAAI,kCAAmCtC,OAAO2P,SAASoB,MAC/D5Q,KAAK2Q,oBAEb,CAKA,gBAAAA,GACI,MAAMC,EAAO/Q,OAAO2P,SAASoB,MAAQ,GACrC1O,QAAQC,IAAI,qCACZD,QAAQC,IAAI,oCAAqCyO,GACjD1O,QAAQC,IAAI,yCAA0CnC,KAAK4P,WAC3D1N,QAAQC,IAAI,4CAA6CnC,KAAK4P,UAAUgB,IACxE1O,QAAQC,IAAI,0CAA2CyO,KAAQ5Q,KAAK4P,WACpE1N,QAAQC,IAAI,mCAAoCyO,EAAKjL,QACrDzD,QAAQC,IAAI,uCAAwCyO,EAAK/F,MAAM,IAAIqG,IAAIC,GAAKA,EAAEC,WAAW,KAEzF,MAAMC,EAAUrR,KAAK4P,UAAUgB,IAAS,SACxC1O,QAAQC,IAAI,6CAA8CkP,GAG1C,gBAAZA,GAAsC,eAATT,IAC7B1O,QAAQC,IAAI,oDAAqDyO,GACjE1O,QAAQC,IAAI,yCAA0CkP,IAG1DrR,KAAKsR,UAAUD,GAAS,EAC5B,CAMA,kBAAAE,GACIrP,QAAQC,IAAI,qFAChB,CAMA,qBAAA2O,GACItH,SAASgI,iBAAiB,eAAejO,QAAQkO,IAC7CA,EAAOjF,iBAAiB,QAAUkB,IAC9BxL,QAAQC,IAAI,uCAAwCuL,EAAEgE,QAGtD,MAAML,EAAUrR,KAAK2R,qBAAqBjE,EAAEgE,QAC5CxP,QAAQC,IAAI,sCAAuCkP,GAE/CA,GAGAjP,WAAW,KACP,MAAMwP,EAAe5R,KAAK6P,UAAUwB,GAChCxR,OAAO2P,SAASoB,OAASgB,GAAgBA,IACzC1P,QAAQC,IAAI,qDAAsDyP,GAClE/R,OAAO2P,SAASoB,KAAOgB,IAE5B,QAKf1P,QAAQC,IAAI,iDAAkDqH,SAASgI,iBAAiB,eAAe7L,OAAQ,UACnH,CAKA,8BAAAoL,GACIvH,SAASgD,iBAAiB,UAAYkB,IAE9BlE,SAASqI,eACT,CAAC,QAAS,WAAY,UAAU1N,SAASqF,SAASqI,cAAcC,WAItD,YAAVpE,EAAEvC,KAA+B,cAAVuC,EAAEvC,KACzBuC,EAAEqE,iBACF/R,KAAKgS,6BAAuC,cAAVtE,EAAEvC,IAAsB,GAAI,IAC7C,UAAVuC,EAAEvC,KACTuC,EAAEqE,iBACF/R,KAAKiS,yBACY,WAAVvE,EAAEvC,KACTnL,KAAKkS,0BAGjB,CAOA,oBAAAP,CAAqBF,GACjBvP,QAAQC,IAAI,+CAAgDsP,GAC5DvP,QAAQC,IAAI,iDAAkDsP,EAAOU,UACrEjQ,QAAQC,IAAI,gDAAiDsP,EAAOK,SAIpE,IAAIM,EAAeX,EACfA,GAAUA,EAAOY,SAAWZ,EAAOY,QAAQ,iBAC3CD,EAAeX,EAAOY,QAAQ,eAC9BnQ,QAAQC,IAAI,uEAIhB,MAAMmQ,EAAUF,EAAeA,EAAaG,aAAa,YAAc,KAKvE,GAJArQ,QAAQC,IAAI,oDAAqDmQ,GACjEpQ,QAAQC,IAAI,kDAAmDmQ,GAG/C,gBAAZA,EAEA,OADApQ,QAAQC,IAAI,0EACL,cAGX,GAAImQ,EAEA,OADApQ,QAAQC,IAAI,mDAAoDmQ,GACzDA,EAIX,MAAME,EAAOJ,EAAeA,EAAaxF,YAAYrC,cAAgB,GAMrE,OALArI,QAAQC,IAAI,8CAA+CqQ,GAC3DtQ,QAAQC,IAAI,yDAA0DqQ,EAAKrO,SAAS,cACpFjC,QAAQC,IAAI,sDAAuDqQ,EAAKrO,SAAS,WAG7EqO,EAAKrO,SAAS,cAAgBqO,EAAKrO,SAAS,OAC5CjC,QAAQC,IAAI,0EACL,eAEPqQ,EAAKrO,SAAS,aAAeqO,EAAKrO,SAAS,MAAc,WACzDqO,EAAKrO,SAAS,WAAaqO,EAAKrO,SAAS,MAAc,SACvDqO,EAAKrO,SAAS,UAAYqO,EAAKrO,SAAS,MAAc,QACtDqO,EAAKrO,SAAS,UAAYqO,EAAKrO,SAAS,MAAc,QACtDqO,EAAKrO,SAAS,QAAgB,OAC9BqO,EAAKrO,SAAS,YAAoB,WAClCqO,EAAKrO,SAAS,UAAkB,UAChCqO,EAAKrO,SAAS,WAAaqO,EAAKrO,SAAS,OAE7CjC,QAAQC,IAAI,kEAF+C,SAI/D,CAOA,SAAAmP,CAAUD,EAASoB,GAAa,GAE5B,GAAIzS,KAAK2P,WAGL,OAFAzN,QAAQC,IAAI,6DAA6DkP,UACzEjP,WAAW,IAAMpC,KAAKsR,UAAUD,EAASoB,GAAa,IAG1DzS,KAAK2P,YAAa,EAElBzN,QAAQC,IAAI,2CAA2CkP,kBAAwBoB,KAE/E,IAQI,GANgB,gBAAZpB,IACAnP,QAAQC,IAAI,+CACZD,QAAQC,IAAI,8CAA+CnC,KAAKkQ,aAIhEuC,GAAczS,KAAK6P,UAAUwB,GAAU,CACvC,MAAMqB,EAAU1S,KAAK6P,UAAUwB,GAC/B,GAAIxR,OAAO2P,SAASoB,OAAS8B,EAIzB,OAHAxQ,QAAQC,IAAI,sCAAsCuQ,KAClD1S,KAAK2P,YAAa,OAClB9P,OAAO2P,SAASoB,KAAO8B,EAG/B,CAEA,MAAMC,EAAc3S,KAAKkQ,WACzBlQ,KAAKkQ,WAAamB,EAGlBrR,KAAK4S,yBAGL5S,KAAK6S,cAAcxB,GAGnBrR,KAAK8S,gBAAgBzB,GAGrBrR,KAAK+S,kBAAkB1B,GAGvBrR,KAAKkS,wBAGL1I,SAASC,cAAc,IAAIC,YAAY,aAAc,CACjDC,OAAQ,CACJqJ,OAAQ3B,EACRsB,kBAKRvQ,WAAW,KACHpC,KAAKoQ,YACLpQ,KAAKiT,2BAKO,gBAAZ5B,GAA6BxR,OAAOqT,aAEhCrT,OAAOqT,WAAWC,cAClBtT,OAAOqT,WAAWC,gBAGlBtT,OAAOqT,WAAWE,SAG3B,IAEP,CAAA,QAEIhR,WAAW,KACPpC,KAAK2P,YAAa,GACnB,IACP,CACJ,CAMA,sBAAAiD,GAEIpJ,SAASgI,iBAAiB,eAAejO,QAAQ8P,IAC7CA,EAAIvE,UAAUE,OAAO,UAErBqE,EAAIpF,MAAMqF,eAAe,iBACzBD,EAAIpF,MAAMqF,eAAe,WAI7B9J,SAASgI,iBAAiB,gBAAgBjO,QAAQgQ,IAC9CA,EAAQzE,UAAUE,OAAO,UAEzBuE,EAAQtF,MAAMqF,eAAe,WAGV,eAAfC,EAAQ9P,IACRzD,KAAKwT,yBAAyBD,KAItCrR,QAAQC,IAAI,sDAChB,CAKA,aAAA0Q,CAAcxB,GACV,MAAMoC,EAAYjK,SAAS2E,cAAc,cAAckD,OACnDoC,GACAA,EAAU3E,UAAUN,IAAI,UACxBtM,QAAQC,IAAI,gCAAgCkP,MAE5CnP,QAAQ5B,MAAM,mDAAmD+Q,IAEzE,CAKA,eAAAyB,CAAgBzB,GACZ,MAAMqC,EAAgBlK,SAASK,eAAe,GAAGwH,SAC7CqC,GACAA,EAAc5E,UAAUN,IAAI,UAC5BtM,QAAQC,IAAI,qCAAqCkP,SAGjC,gBAAZA,GACArR,KAAK2T,wBAAwBD,IAGjCxR,QAAQ5B,MAAM,gDAAgD+Q,IAEtE,CAKA,wBAAAmC,CAAyBI,GAErB,MAAMC,EAAmBD,EAAepC,iBAAiB,eACrDqC,EAAiBlO,OAAS,IAC1BzD,QAAQ6C,KAAK,0BAA0B8O,EAAiBlO,gCAAgCiO,EAAenQ,mBACvGoQ,EAAiBtQ,QAAQ4D,GAAQA,EAAK6H,WAI1C,MAAM8E,EAAmBF,EAAepC,iBAAiB,8BACrDsC,EAAiBnO,OAAS,IAC1BzD,QAAQ6C,KAAK,gDAAgD6O,EAAenQ,mBAC5EqQ,EAAiBvQ,QAAQwQ,GAAQA,EAAK/E,UAE9C,CAKA,uBAAA2E,CAAwBK,GACpB,MAAMC,EAAsBzK,SAASK,eAAe,yBAChDoK,IAEAjU,KAAKwT,yBAAyBS,GAG9BA,EAAoBC,aAAa,aAAc,eAC/CD,EAAoBC,aAAa,iBAAkB,cAEnDhS,QAAQC,IAAI,iDAEpB,CAKA,iBAAA4Q,CAAkBoB,GACd/R,WAAW,KACP,MAAMgS,EAAa5K,SAASgI,iBAAiB,sBACvC6C,EAAiB7K,SAASgI,iBAAiB,uBAEvB,IAAtB4C,EAAWzO,SACXzD,QAAQ5B,MAAM,oEAAoE8T,EAAWzO,UAC7FyO,EAAW7Q,QAAQ,CAAC+M,EAAKgE,KACrBpS,QAAQ5B,MAAM,kBAAkBgU,EAAM,MAAMhE,EAAI1D,YAAYjE,WAAW2H,EAAIiC,aAAa,kBAG5FvS,KAAK4S,yBACL5S,KAAK6S,cAAcsB,IAGO,IAA1BE,EAAe1O,SACfzD,QAAQ5B,MAAM,wEAAwE+T,EAAe1O,UACrG0O,EAAe9Q,QAAQ,CAACgQ,EAASe,KAC7BpS,QAAQ5B,MAAM,sBAAsBgU,EAAM,MAAMf,EAAQ9P,QAG5DzD,KAAK4S,yBACL5S,KAAK8S,gBAAgBqB,IAGzBjS,QAAQC,IAAI,6CAA6CgS,MAC1D,GACP,CAMA,4BAAAnC,CAA6BuC,GACzB,MAAMC,EAASxU,KAAKuQ,cAAcvQ,KAAKkQ,YACvC,IAAKsE,EAAQ,OAEb,IAAIC,EAAWD,EAAOhE,cAAgB+D,EAGV,IAAxBC,EAAO/D,MAAM9K,SAEb8O,EAAW,EACXA,EAAWD,EAAO/D,MAAM9K,OAAS,EAC1B8O,GAAYD,EAAO/D,MAAM9K,SAChC8O,EAAW,GAGfzU,KAAK0U,kBAAkB1U,KAAKkQ,WAAYuE,GAC5C,CAKA,qBAAAxC,GACI,MAAMuC,EAASxU,KAAKuQ,cAAcvQ,KAAKkQ,YACvC,IAAKsE,IAAmC,IAAzBA,EAAOhE,cAAsB,OAE5C,MAAMmE,EAAkBH,EAAO/D,MAAM+D,EAAOhE,eACxCmE,GAAmBA,EAAgBC,SACnCD,EAAgBC,SAExB,CAKA,qBAAA1C,GAEIjH,OAAOC,KAAKlL,KAAKuQ,eAAehN,QAAQ8N,IACpCrR,KAAKuQ,cAAcc,GAASb,eAAgB,IAIhDxQ,KAAK6U,oBACT,CAMA,wBAAAC,GACI,MAAMN,EAASxU,KAAKuQ,cAAcvQ,KAAKkQ,YACvC,IAAKsE,EAAQ,OAEb,IAAIO,EACJ,OAAQ/U,KAAKkQ,YACT,IAAK,SACD6E,EAAoB,2BACpB,MACJ,IAAK,SACDA,EAAoB,2BACpB,MACJ,IAAK,QACDA,EAAoB,0BACpB,MACJ,IAAK,QACDA,EAAoB,0BAIxBA,IACAP,EAAO/D,MAAQhL,MAAMuP,KAAKxL,SAASgI,iBAAiBuD,IAE5D,CAOA,iBAAAL,CAAkBrD,EAASjK,GACvB,MAAMoN,EAASxU,KAAKuQ,cAAcc,GAClC,IAAKmD,GAAUpN,EAAQ,GAAKA,GAASoN,EAAO/D,MAAM9K,OAAQ,OAG1D6O,EAAOhE,cAAgBpJ,EAGvBpH,KAAKiV,2BAGmBT,EAAO/D,MAAMrJ,IAGjCpH,KAAKkV,WAAW7D,EAASjK,EAAOpH,KAAKmV,YAAY9D,GAAUjK,GAI/DpH,KAAKoV,gBAAgB/D,EAASjK,EAClC,CAKA,wBAAA6N,GAEIzL,SAASgI,iBAAiB,iCAAiCjO,QAAQ8R,IAC/DA,EAAGvG,UAAUE,OAAO,uBAIxB,MAAMwF,EAASxU,KAAKuQ,cAAcvQ,KAAKkQ,YACnCsE,IAAmC,IAAzBA,EAAOhE,eAAwBgE,EAAO/D,MAAM+D,EAAOhE,gBAC7DgE,EAAO/D,MAAM+D,EAAOhE,eAAe1B,UAAUN,IAAI,oBAEzD,CAOA,eAAA4G,CAAgB/D,EAASjK,GAErBoC,SAASC,cAAc,IAAIC,YAAY,kBAAmB,CACtDC,OAAQ,CACJ0H,UACAjK,WAGZ,CASA,UAAA8N,CAAW7D,EAASjK,EAAO3C,EAAMC,GAE7B1E,KAAK6U,qBAGL7U,KAAKqQ,aAAe,CAChBC,IAAKe,EACLjK,QACA3C,OACAC,QAGJ1E,KAAKsV,wBAELpT,QAAQC,IAAI,iBAAkBnC,KAAKqQ,aACvC,CAKA,kBAAAwE,GAEIrL,SAASgI,iBAAiB,6CAA6CjO,QAAQ8R,IAC3EA,EAAGvG,UAAUE,OAAO,cAIxBhP,KAAKqQ,aAAe,CAChBC,IAAK,KACLlJ,MAAO,KACP3C,KAAM,KACNC,KAAM,KAEd,CAKA,qBAAA4Q,GACI,IAAKtV,KAAKqQ,aAAaC,KAAmC,OAA5BtQ,KAAKqQ,aAAajJ,MAAgB,OAGhE,IAAImO,EACJ,OAAQvV,KAAKqQ,aAAaC,KACtB,IAAK,SACDiF,EAAgB/L,SAASK,eAAe,eACxC,MACJ,IAAK,SACD0L,EAAgB/L,SAASK,eAAe,eACxC,MACJ,IAAK,QACD0L,EAAgB/L,SAASK,eAAe,cACxC,MACJ,IAAK,QACD0L,EAAgB/L,SAASK,eAAe,cAIhD,GAAI0L,EAAe,CACf,MAAM9E,EAAQ8E,EAAc/D,iBAAiB,2BACzCf,EAAMzQ,KAAKqQ,aAAajJ,QACxBqJ,EAAMzQ,KAAKqQ,aAAajJ,OAAO0H,UAAUN,IAAI,WAErD,CACJ,CAOA,WAAA2G,CAAY9D,GACR,OAAQA,GACJ,IAAK,SAAU,MAAO,QACtB,IAAK,SAAU,MAAO,QACtB,IAAK,QAAS,MAAO,OACrB,IAAK,QAAS,MAAO,OACrB,QAAS,MAAO,UAExB,CAKA,wBAAA4B,GACI,MAAMuC,EAAQ,GAAGxV,KAAKkQ,kBAChBuF,EAAUjM,SAASK,eAAe2L,GACpCC,GAAWzV,KAAKoQ,aAChBqF,EAAQC,UAAYD,EAAQE,aAEpC,CAKA,cAAAC,GACI5V,KAAK6U,qBACL7U,KAAKkS,uBACT,CAMA,aAAA2D,GACI,OAAO7V,KAAKkQ,UAChB,CAMA,eAAA4F,GACI,MAAO,IAAK9V,KAAKqQ,aACrB,CAMA,gBAAA0F,GACI,MAAO,IAAK/V,KAAKuQ,cACrB,CAMA,aAAAyF,CAAcC,GACVjW,KAAKoQ,WAAa6F,CACtB,CAMA,aAAAC,GACI,OAAOlW,KAAKoQ,UAChB,EAOJvQ,OAAO6P,eAAiBA"}
@@ -1,185 +0,0 @@
1
- /**
2
- * BULLETPROOF FILE TREE TAB ISOLATION FIX
3
- *
4
- * This is a surgical fix to resolve the File Tree tab isolation issue
5
- * without requiring changes to the complex build system or existing dashboard.
6
- *
7
- * This script can be loaded independently and will override any existing
8
- * problematic tab switching behavior.
9
- */
10
-
11
- console.log('[TAB-FIX] Bulletproof File Tree tab isolation fix loaded');
12
-
13
- // Wait for DOM to be ready
14
- function whenReady(callback) {
15
- if (document.readyState === 'loading') {
16
- document.addEventListener('DOMContentLoaded', callback);
17
- } else {
18
- callback();
19
- }
20
- }
21
-
22
- function implementTabFix() {
23
- console.log('[TAB-FIX] Implementing bulletproof tab switching...');
24
-
25
- let tabSwitchingInProgress = false;
26
-
27
- function switchToTab(tabName) {
28
- if (tabSwitchingInProgress) {
29
- console.log('[TAB-FIX] Tab switching already in progress, queuing...');
30
- setTimeout(() => switchToTab(tabName), 100);
31
- return;
32
- }
33
-
34
- tabSwitchingInProgress = true;
35
- console.log(`[TAB-FIX] Switching to tab: ${tabName}`);
36
-
37
- try {
38
- // STEP 1: Remove ALL active states
39
- document.querySelectorAll('.tab-button').forEach(btn => {
40
- btn.classList.remove('active');
41
- });
42
-
43
- document.querySelectorAll('.tab-content').forEach(content => {
44
- content.classList.remove('active');
45
- });
46
-
47
- // STEP 2: Add active to the correct tab button
48
- const targetButton = document.querySelector(`[data-tab="${tabName}"]`);
49
- if (targetButton) {
50
- targetButton.classList.add('active');
51
- console.log(`[TAB-FIX] Activated tab button: ${tabName}`);
52
- } else {
53
- console.warn(`[TAB-FIX] Tab button not found: ${tabName}`);
54
- }
55
-
56
- // STEP 3: Add active to the correct content
57
- const targetContent = document.getElementById(`${tabName}-tab`);
58
- if (targetContent) {
59
- targetContent.classList.add('active');
60
- console.log(`[TAB-FIX] Activated tab content: ${tabName}-tab`);
61
-
62
- // STEP 4: Special handling for File Tree
63
- if (tabName === 'claude-tree') {
64
- // Ensure File Tree content is clean
65
- const eventsInFileTree = targetContent.querySelectorAll('.event-item');
66
- if (eventsInFileTree.length > 0) {
67
- console.warn(`[TAB-FIX] Found ${eventsInFileTree.length} event items in File Tree, removing...`);
68
- eventsInFileTree.forEach(item => item.remove());
69
- }
70
-
71
- // Trigger CodeViewer if available
72
- if (window.CodeViewer && typeof window.CodeViewer.show === 'function') {
73
- setTimeout(() => {
74
- window.CodeViewer.show();
75
- }, 100);
76
- }
77
- }
78
- } else {
79
- console.warn(`[TAB-FIX] Tab content not found: ${tabName}-tab`);
80
- }
81
-
82
- } finally {
83
- setTimeout(() => {
84
- tabSwitchingInProgress = false;
85
- }, 200);
86
- }
87
- }
88
-
89
- // Override any existing tab switching
90
- function setupTabClickHandlers() {
91
- console.log('[TAB-FIX] Setting up click handlers...');
92
-
93
- document.querySelectorAll('.tab-button').forEach(button => {
94
- // Remove any existing listeners by cloning the element
95
- const newButton = button.cloneNode(true);
96
- button.parentNode.replaceChild(newButton, button);
97
-
98
- // Add our handler
99
- newButton.addEventListener('click', function(e) {
100
- e.preventDefault();
101
- e.stopPropagation();
102
-
103
- const tabName = this.getAttribute('data-tab');
104
- if (tabName) {
105
- console.log(`[TAB-FIX] Tab clicked: ${tabName}`);
106
- switchToTab(tabName);
107
-
108
- // Update hash
109
- const hashMap = {
110
- 'events': '#events',
111
- 'agents': '#agents',
112
- 'tools': '#tools',
113
- 'files': '#files',
114
- 'activity': '#activity',
115
- 'claude-tree': '#file_tree'
116
- };
117
- if (hashMap[tabName]) {
118
- history.replaceState(null, null, hashMap[tabName]);
119
- }
120
- } else {
121
- console.warn('[TAB-FIX] No data-tab attribute found on button');
122
- }
123
- });
124
- });
125
-
126
- console.log(`[TAB-FIX] Set up handlers for ${document.querySelectorAll('.tab-button').length} tab buttons`);
127
- }
128
-
129
- // Handle hash navigation
130
- function handleHashNavigation() {
131
- const hash = window.location.hash;
132
- const hashToTab = {
133
- '#events': 'events',
134
- '#agents': 'agents',
135
- '#tools': 'tools',
136
- '#files': 'files',
137
- '#activity': 'activity',
138
- '#file_tree': 'claude-tree',
139
- '': 'events'
140
- };
141
-
142
- const tabName = hashToTab[hash] || 'events';
143
- console.log(`[TAB-FIX] Hash navigation: ${hash} -> ${tabName}`);
144
- switchToTab(tabName);
145
- }
146
-
147
- // Wait for tabs to be available
148
- function waitForTabsAndSetup() {
149
- const tabs = document.querySelectorAll('.tab-button');
150
- if (tabs.length > 0) {
151
- console.log(`[TAB-FIX] Found ${tabs.length} tabs, setting up handlers...`);
152
- setupTabClickHandlers();
153
-
154
- // Set up hash navigation
155
- window.addEventListener('hashchange', handleHashNavigation);
156
-
157
- // Handle initial hash
158
- setTimeout(handleHashNavigation, 100);
159
-
160
- console.log('[TAB-FIX] Bulletproof tab fix fully activated!');
161
- } else {
162
- console.log('[TAB-FIX] Tabs not ready yet, retrying in 500ms...');
163
- setTimeout(waitForTabsAndSetup, 500);
164
- }
165
- }
166
-
167
- // Start the setup process
168
- waitForTabsAndSetup();
169
- }
170
-
171
- // Export functions for global access
172
- window.TabFix = {
173
- implement: implementTabFix,
174
- switchToTab: function(tabName) {
175
- // This will be available after implementTabFix is called
176
- const event = new CustomEvent('tabfix-switch', { detail: { tabName } });
177
- document.dispatchEvent(event);
178
- }
179
- };
180
-
181
- // Auto-implement when ready
182
- whenReady(() => {
183
- console.log('[TAB-FIX] DOM ready, waiting 3 seconds for other scripts to load...');
184
- setTimeout(implementTabFix, 3000);
185
- });