claude-mpm 3.9.11__py3-none-any.whl → 4.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +1 -1
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +79 -51
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +20 -20
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +140 -905
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +203 -81
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +305 -197
- claude_mpm/cli/parser.py +24 -1156
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +104 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +71 -73
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +35 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +120 -54
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +233 -199
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +30 -13
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
- claude_mpm/services/mcp_gateway/main.py +287 -137
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +223 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +145 -65
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +170 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +19 -533
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +2 -2
- claude_mpm/storage/state_storage.py +177 -181
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +27 -1
- claude_mpm-4.0.3.dist-info/RECORD +402 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/cli/commands/run_guarded.py +0 -511
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/config/memory_guardian_yaml.py +0 -335
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/core/memory_aware_runner.py +0 -353
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
- claude_mpm/services/infrastructure/health_monitor.py +0 -775
- claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
- claude_mpm/services/infrastructure/memory_guardian.py +0 -944
- claude_mpm/services/infrastructure/restart_protection.py +0 -642
- claude_mpm/services/infrastructure/state_manager.py +0 -774
- claude_mpm/services/mcp_gateway/manager.py +0 -334
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.11.dist-info/RECORD +0 -306
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
| @@ -7,26 +7,26 @@ class EventViewer { | |
| 7 7 | 
             
                constructor(containerId, socketClient) {
         | 
| 8 8 | 
             
                    this.container = document.getElementById(containerId);
         | 
| 9 9 | 
             
                    this.socketClient = socketClient;
         | 
| 10 | 
            -
             | 
| 10 | 
            +
             | 
| 11 11 | 
             
                    // State
         | 
| 12 12 | 
             
                    this.events = [];
         | 
| 13 13 | 
             
                    this.filteredEvents = [];
         | 
| 14 14 | 
             
                    this.selectedEventIndex = -1;
         | 
| 15 15 | 
             
                    this.filteredEventElements = [];
         | 
| 16 16 | 
             
                    this.autoScroll = true;
         | 
| 17 | 
            -
             | 
| 17 | 
            +
             | 
| 18 18 | 
             
                    // Filters
         | 
| 19 19 | 
             
                    this.searchFilter = '';
         | 
| 20 20 | 
             
                    this.typeFilter = '';
         | 
| 21 21 | 
             
                    this.sessionFilter = '';
         | 
| 22 | 
            -
             | 
| 22 | 
            +
             | 
| 23 23 | 
             
                    // Event type tracking
         | 
| 24 24 | 
             
                    this.eventTypeCount = {};
         | 
| 25 25 | 
             
                    this.availableEventTypes = new Set();
         | 
| 26 26 | 
             
                    this.errorCount = 0;
         | 
| 27 27 | 
             
                    this.eventsThisMinute = 0;
         | 
| 28 28 | 
             
                    this.lastMinute = new Date().getMinutes();
         | 
| 29 | 
            -
             | 
| 29 | 
            +
             | 
| 30 30 | 
             
                    this.init();
         | 
| 31 31 | 
             
                }
         | 
| 32 32 |  | 
| @@ -36,7 +36,7 @@ class EventViewer { | |
| 36 36 | 
             
                init() {
         | 
| 37 37 | 
             
                    this.setupEventHandlers();
         | 
| 38 38 | 
             
                    this.setupKeyboardNavigation();
         | 
| 39 | 
            -
             | 
| 39 | 
            +
             | 
| 40 40 | 
             
                    // Subscribe to socket events
         | 
| 41 41 | 
             
                    this.socketClient.onEventUpdate((events, sessions) => {
         | 
| 42 42 | 
             
                        // Ensure we always have a valid events array
         | 
| @@ -87,7 +87,7 @@ class EventViewer { | |
| 87 87 |  | 
| 88 88 | 
             
                    // Calculate new index
         | 
| 89 89 | 
             
                    let newIndex = this.selectedEventIndex + direction;
         | 
| 90 | 
            -
             | 
| 90 | 
            +
             | 
| 91 91 | 
             
                    // Wrap around
         | 
| 92 92 | 
             
                    if (newIndex >= this.filteredEventElements.length) {
         | 
| 93 93 | 
             
                        newIndex = 0;
         | 
| @@ -107,7 +107,7 @@ class EventViewer { | |
| 107 107 | 
             
                        console.warn('EventViewer: events array is not initialized, using empty array');
         | 
| 108 108 | 
             
                        this.events = [];
         | 
| 109 109 | 
             
                    }
         | 
| 110 | 
            -
             | 
| 110 | 
            +
             | 
| 111 111 | 
             
                    this.filteredEvents = this.events.filter(event => {
         | 
| 112 112 | 
             
                        // Search filter
         | 
| 113 113 | 
             
                        if (this.searchFilter) {
         | 
| @@ -116,7 +116,7 @@ class EventViewer { | |
| 116 116 | 
             
                                event.subtype || '',
         | 
| 117 117 | 
             
                                JSON.stringify(event.data || {})
         | 
| 118 118 | 
             
                            ].join(' ').toLowerCase();
         | 
| 119 | 
            -
             | 
| 119 | 
            +
             | 
| 120 120 | 
             
                            if (!searchableText.includes(this.searchFilter)) {
         | 
| 121 121 | 
             
                                return false;
         | 
| 122 122 | 
             
                            }
         | 
| @@ -161,7 +161,7 @@ class EventViewer { | |
| 161 161 | 
             
                        console.warn('EventViewer: events array is not initialized in updateEventTypeDropdown');
         | 
| 162 162 | 
             
                        this.events = [];
         | 
| 163 163 | 
             
                    }
         | 
| 164 | 
            -
             | 
| 164 | 
            +
             | 
| 165 165 | 
             
                    this.events.forEach(event => {
         | 
| 166 166 | 
             
                        if (event.type && event.type.trim() !== '') {
         | 
| 167 167 | 
             
                            // Combine type and subtype if subtype exists, otherwise just use type
         | 
| @@ -173,7 +173,7 @@ class EventViewer { | |
| 173 173 | 
             
                    // Check if event types have changed
         | 
| 174 174 | 
             
                    const currentTypes = Array.from(eventTypes).sort();
         | 
| 175 175 | 
             
                    const previousTypes = Array.from(this.availableEventTypes).sort();
         | 
| 176 | 
            -
             | 
| 176 | 
            +
             | 
| 177 177 | 
             
                    if (JSON.stringify(currentTypes) === JSON.stringify(previousTypes)) {
         | 
| 178 178 | 
             
                        return; // No change needed
         | 
| 179 179 | 
             
                    }
         | 
| @@ -224,8 +224,8 @@ class EventViewer { | |
| 224 224 | 
             
                    if (this.filteredEvents.length === 0) {
         | 
| 225 225 | 
             
                        eventsList.innerHTML = `
         | 
| 226 226 | 
             
                            <div class="no-events">
         | 
| 227 | 
            -
                                ${this.events.length === 0 ? | 
| 228 | 
            -
                                    'Connect to Socket.IO server to see events...' : | 
| 227 | 
            +
                                ${this.events.length === 0 ?
         | 
| 228 | 
            +
                                    'Connect to Socket.IO server to see events...' :
         | 
| 229 229 | 
             
                                    'No events match current filters...'}
         | 
| 230 230 | 
             
                            </div>
         | 
| 231 231 | 
             
                        `;
         | 
| @@ -237,16 +237,16 @@ class EventViewer { | |
| 237 237 | 
             
                        const timestamp = new Date(event.timestamp).toLocaleTimeString();
         | 
| 238 238 | 
             
                        const eventClass = event.type ? `event-${event.type}` : 'event-default';
         | 
| 239 239 | 
             
                        const isSelected = index === this.selectedEventIndex;
         | 
| 240 | 
            -
             | 
| 240 | 
            +
             | 
| 241 241 | 
             
                        // Get main content and timestamp separately
         | 
| 242 242 | 
             
                        const mainContent = this.formatSingleRowEventContent(event);
         | 
| 243 | 
            -
             | 
| 243 | 
            +
             | 
| 244 244 | 
             
                        // Check if this is an Edit/MultiEdit tool event and add diff viewer
         | 
| 245 245 | 
             
                        const diffViewer = this.createInlineEditDiffViewer(event, index);
         | 
| 246 | 
            -
             | 
| 246 | 
            +
             | 
| 247 247 | 
             
                        return `
         | 
| 248 | 
            -
                            <div class="event-item single-row ${eventClass} ${isSelected ? 'selected' : ''}" | 
| 249 | 
            -
                                 onclick="eventViewer.showEventDetails(${index})" | 
| 248 | 
            +
                            <div class="event-item single-row ${eventClass} ${isSelected ? 'selected' : ''}"
         | 
| 249 | 
            +
                                 onclick="eventViewer.showEventDetails(${index})"
         | 
| 250 250 | 
             
                                 data-index="${index}">
         | 
| 251 251 | 
             
                                <span class="event-single-row-content">
         | 
| 252 252 | 
             
                                    <span class="event-content-main">${mainContent}</span>
         | 
| @@ -258,12 +258,12 @@ class EventViewer { | |
| 258 258 | 
             
                    }).join('');
         | 
| 259 259 |  | 
| 260 260 | 
             
                    eventsList.innerHTML = html;
         | 
| 261 | 
            -
             | 
| 261 | 
            +
             | 
| 262 262 | 
             
                    // Update filtered elements reference
         | 
| 263 263 | 
             
                    this.filteredEventElements = Array.from(eventsList.querySelectorAll('.event-item'));
         | 
| 264 264 |  | 
| 265 265 | 
             
                    // Update Dashboard navigation items if we're in the events tab
         | 
| 266 | 
            -
                    if (window.dashboard && window.dashboard.currentTab === 'events' && | 
| 266 | 
            +
                    if (window.dashboard && window.dashboard.currentTab === 'events' &&
         | 
| 267 267 | 
             
                        window.dashboard.tabNavigation && window.dashboard.tabNavigation.events) {
         | 
| 268 268 | 
             
                        window.dashboard.tabNavigation.events.items = this.filteredEventElements;
         | 
| 269 269 | 
             
                    }
         | 
| @@ -364,40 +364,40 @@ class EventViewer { | |
| 364 364 | 
             
                formatHookEvent(event) {
         | 
| 365 365 | 
             
                    const data = event.data;
         | 
| 366 366 | 
             
                    const eventType = data.event_type || event.subtype || 'unknown';
         | 
| 367 | 
            -
             | 
| 367 | 
            +
             | 
| 368 368 | 
             
                    // Format based on specific hook event type
         | 
| 369 369 | 
             
                    switch (eventType) {
         | 
| 370 370 | 
             
                        case 'user_prompt':
         | 
| 371 371 | 
             
                            const prompt = data.prompt_text || data.prompt_preview || '';
         | 
| 372 372 | 
             
                            const truncated = prompt.length > 80 ? prompt.substring(0, 80) + '...' : prompt;
         | 
| 373 373 | 
             
                            return `<strong>User Prompt:</strong> ${truncated || 'No prompt text'}`;
         | 
| 374 | 
            -
             | 
| 374 | 
            +
             | 
| 375 375 | 
             
                        case 'pre_tool':
         | 
| 376 376 | 
             
                            const toolName = data.tool_name || 'Unknown tool';
         | 
| 377 377 | 
             
                            const operation = data.operation_type || 'operation';
         | 
| 378 378 | 
             
                            return `<strong>Pre-Tool (${operation}):</strong> ${toolName}`;
         | 
| 379 | 
            -
             | 
| 379 | 
            +
             | 
| 380 380 | 
             
                        case 'post_tool':
         | 
| 381 381 | 
             
                            const postToolName = data.tool_name || 'Unknown tool';
         | 
| 382 382 | 
             
                            const status = data.success ? 'success' : data.status || 'failed';
         | 
| 383 383 | 
             
                            const duration = data.duration_ms ? ` (${data.duration_ms}ms)` : '';
         | 
| 384 384 | 
             
                            return `<strong>Post-Tool (${status}):</strong> ${postToolName}${duration}`;
         | 
| 385 | 
            -
             | 
| 385 | 
            +
             | 
| 386 386 | 
             
                        case 'notification':
         | 
| 387 387 | 
             
                            const notifType = data.notification_type || 'notification';
         | 
| 388 388 | 
             
                            const message = data.message_preview || data.message || 'No message';
         | 
| 389 389 | 
             
                            return `<strong>Notification (${notifType}):</strong> ${message}`;
         | 
| 390 | 
            -
             | 
| 390 | 
            +
             | 
| 391 391 | 
             
                        case 'stop':
         | 
| 392 392 | 
             
                            const reason = data.reason || 'unknown';
         | 
| 393 393 | 
             
                            const stopType = data.stop_type || 'normal';
         | 
| 394 394 | 
             
                            return `<strong>Stop (${stopType}):</strong> ${reason}`;
         | 
| 395 | 
            -
             | 
| 395 | 
            +
             | 
| 396 396 | 
             
                        case 'subagent_stop':
         | 
| 397 397 | 
             
                            const agentType = data.agent_type || 'unknown agent';
         | 
| 398 398 | 
             
                            const stopReason = data.reason || 'unknown';
         | 
| 399 399 | 
             
                            return `<strong>Subagent Stop (${agentType}):</strong> ${stopReason}`;
         | 
| 400 | 
            -
             | 
| 400 | 
            +
             | 
| 401 401 | 
             
                        default:
         | 
| 402 402 | 
             
                            // Fallback to original logic for unknown hook types
         | 
| 403 403 | 
             
                            const hookName = data.hook_name || data.name || data.event_type || 'Unknown';
         | 
| @@ -458,12 +458,12 @@ class EventViewer { | |
| 458 458 | 
             
                formatSingleRowEventContent(event) {
         | 
| 459 459 | 
             
                    const eventType = this.formatEventType(event);
         | 
| 460 460 | 
             
                    const data = event.data || {};
         | 
| 461 | 
            -
             | 
| 461 | 
            +
             | 
| 462 462 | 
             
                    // Extract event details for different event types
         | 
| 463 463 | 
             
                    let eventDetails = '';
         | 
| 464 464 | 
             
                    let category = '';
         | 
| 465 465 | 
             
                    let action = '';
         | 
| 466 | 
            -
             | 
| 466 | 
            +
             | 
| 467 467 | 
             
                    switch (event.type) {
         | 
| 468 468 | 
             
                        case 'hook':
         | 
| 469 469 | 
             
                            // Hook events: extract tool name and hook type
         | 
| @@ -473,7 +473,7 @@ class EventViewer { | |
| 473 473 | 
             
                            category = this.getEventCategory(event);
         | 
| 474 474 | 
             
                            eventDetails = `${hookDisplayName} (${category}): ${toolName}`;
         | 
| 475 475 | 
             
                            break;
         | 
| 476 | 
            -
             | 
| 476 | 
            +
             | 
| 477 477 | 
             
                        case 'agent':
         | 
| 478 478 | 
             
                            // Agent events
         | 
| 479 479 | 
             
                            const agentName = event.subagent_type || data.subagent_type || 'PM';
         | 
| @@ -481,14 +481,14 @@ class EventViewer { | |
| 481 481 | 
             
                            category = 'agent_operations';
         | 
| 482 482 | 
             
                            eventDetails = `${agentName} ${agentAction}`;
         | 
| 483 483 | 
             
                            break;
         | 
| 484 | 
            -
             | 
| 484 | 
            +
             | 
| 485 485 | 
             
                        case 'todo':
         | 
| 486 486 | 
             
                            // Todo events
         | 
| 487 487 | 
             
                            const todoCount = data.todos ? data.todos.length : 0;
         | 
| 488 488 | 
             
                            category = 'task_management';
         | 
| 489 489 | 
             
                            eventDetails = `TodoWrite (${todoCount} items)`;
         | 
| 490 490 | 
             
                            break;
         | 
| 491 | 
            -
             | 
| 491 | 
            +
             | 
| 492 492 | 
             
                        case 'memory':
         | 
| 493 493 | 
             
                            // Memory events
         | 
| 494 494 | 
             
                            const operation = data.operation || 'unknown';
         | 
| @@ -496,28 +496,28 @@ class EventViewer { | |
| 496 496 | 
             
                            category = 'memory_operations';
         | 
| 497 497 | 
             
                            eventDetails = `${operation} ${key}`;
         | 
| 498 498 | 
             
                            break;
         | 
| 499 | 
            -
             | 
| 499 | 
            +
             | 
| 500 500 | 
             
                        case 'session':
         | 
| 501 501 | 
             
                            // Session events
         | 
| 502 502 | 
             
                            const sessionAction = event.subtype || 'unknown';
         | 
| 503 503 | 
             
                            category = 'session_management';
         | 
| 504 504 | 
             
                            eventDetails = `Session ${sessionAction}`;
         | 
| 505 505 | 
             
                            break;
         | 
| 506 | 
            -
             | 
| 506 | 
            +
             | 
| 507 507 | 
             
                        case 'claude':
         | 
| 508 508 | 
             
                            // Claude events
         | 
| 509 509 | 
             
                            const claudeAction = event.subtype || 'interaction';
         | 
| 510 510 | 
             
                            category = 'claude_interactions';
         | 
| 511 511 | 
             
                            eventDetails = `Claude ${claudeAction}`;
         | 
| 512 512 | 
             
                            break;
         | 
| 513 | 
            -
             | 
| 513 | 
            +
             | 
| 514 514 | 
             
                        default:
         | 
| 515 515 | 
             
                            // Generic events
         | 
| 516 516 | 
             
                            category = 'general';
         | 
| 517 517 | 
             
                            eventDetails = event.type || 'Unknown Event';
         | 
| 518 518 | 
             
                            break;
         | 
| 519 519 | 
             
                    }
         | 
| 520 | 
            -
             | 
| 520 | 
            +
             | 
| 521 521 | 
             
                    // Return formatted string: "type.subtype DisplayName (category): Details"
         | 
| 522 522 | 
             
                    return `${eventType} ${eventDetails}`;
         | 
| 523 523 | 
             
                }
         | 
| @@ -537,7 +537,7 @@ class EventViewer { | |
| 537 537 | 
             
                        'subagent_stop': 'Subagent-Stop',
         | 
| 538 538 | 
             
                        'notification': 'Notification'
         | 
| 539 539 | 
             
                    };
         | 
| 540 | 
            -
             | 
| 540 | 
            +
             | 
| 541 541 | 
             
                    return hookNames[hookType] || hookType.replace('_', '-');
         | 
| 542 542 | 
             
                }
         | 
| 543 543 |  | 
| @@ -549,7 +549,7 @@ class EventViewer { | |
| 549 549 | 
             
                getEventCategory(event) {
         | 
| 550 550 | 
             
                    const data = event.data || {};
         | 
| 551 551 | 
             
                    const toolName = event.tool_name || data.tool_name || '';
         | 
| 552 | 
            -
             | 
| 552 | 
            +
             | 
| 553 553 | 
             
                    // Categorize based on tool type
         | 
| 554 554 | 
             
                    if (['Read', 'Write', 'Edit', 'MultiEdit'].includes(toolName)) {
         | 
| 555 555 | 
             
                        return 'file_operations';
         | 
| @@ -562,7 +562,7 @@ class EventViewer { | |
| 562 562 | 
             
                    } else if (event.subtype === 'stop' || event.subtype === 'subagent_stop') {
         | 
| 563 563 | 
             
                        return 'session_control';
         | 
| 564 564 | 
             
                    }
         | 
| 565 | 
            -
             | 
| 565 | 
            +
             | 
| 566 566 | 
             
                    return 'general';
         | 
| 567 567 | 
             
                }
         | 
| 568 568 |  | 
| @@ -580,10 +580,10 @@ class EventViewer { | |
| 580 580 |  | 
| 581 581 | 
             
                    // Update selection
         | 
| 582 582 | 
             
                    this.selectedEventIndex = index;
         | 
| 583 | 
            -
             | 
| 583 | 
            +
             | 
| 584 584 | 
             
                    // Get the selected event
         | 
| 585 585 | 
             
                    const event = this.filteredEvents[index];
         | 
| 586 | 
            -
             | 
| 586 | 
            +
             | 
| 587 587 | 
             
                    // Coordinate with Dashboard unified navigation system
         | 
| 588 588 | 
             
                    if (window.dashboard) {
         | 
| 589 589 | 
             
                        // Update the dashboard's navigation state for events tab
         | 
| @@ -594,12 +594,12 @@ class EventViewer { | |
| 594 594 | 
             
                            window.dashboard.selectCard('events', index, 'event', event);
         | 
| 595 595 | 
             
                        }
         | 
| 596 596 | 
             
                    }
         | 
| 597 | 
            -
             | 
| 597 | 
            +
             | 
| 598 598 | 
             
                    // Update visual selection (this will be handled by Dashboard.updateCardSelectionUI())
         | 
| 599 599 | 
             
                    this.filteredEventElements.forEach((el, i) => {
         | 
| 600 600 | 
             
                        el.classList.toggle('selected', i === index);
         | 
| 601 601 | 
             
                    });
         | 
| 602 | 
            -
             | 
| 602 | 
            +
             | 
| 603 603 | 
             
                    // Notify other components about selection
         | 
| 604 604 | 
             
                    document.dispatchEvent(new CustomEvent('eventSelected', {
         | 
| 605 605 | 
             
                        detail: { event, index }
         | 
| @@ -608,9 +608,9 @@ class EventViewer { | |
| 608 608 | 
             
                    // Scroll to selected event if not visible
         | 
| 609 609 | 
             
                    const selectedElement = this.filteredEventElements[index];
         | 
| 610 610 | 
             
                    if (selectedElement) {
         | 
| 611 | 
            -
                        selectedElement.scrollIntoView({ | 
| 612 | 
            -
                            behavior: 'smooth', | 
| 613 | 
            -
                            block: 'nearest' | 
| 611 | 
            +
                        selectedElement.scrollIntoView({
         | 
| 612 | 
            +
                            behavior: 'smooth',
         | 
| 613 | 
            +
                            block: 'nearest'
         | 
| 614 614 | 
             
                        });
         | 
| 615 615 | 
             
                    }
         | 
| 616 616 | 
             
                }
         | 
| @@ -623,7 +623,7 @@ class EventViewer { | |
| 623 623 | 
             
                    this.filteredEventElements.forEach(el => {
         | 
| 624 624 | 
             
                        el.classList.remove('selected');
         | 
| 625 625 | 
             
                    });
         | 
| 626 | 
            -
             | 
| 626 | 
            +
             | 
| 627 627 | 
             
                    // Coordinate with Dashboard unified navigation system
         | 
| 628 628 | 
             
                    if (window.dashboard) {
         | 
| 629 629 | 
             
                        if (window.dashboard.tabNavigation && window.dashboard.tabNavigation.events) {
         | 
| @@ -633,7 +633,7 @@ class EventViewer { | |
| 633 633 | 
             
                            window.dashboard.clearCardSelection();
         | 
| 634 634 | 
             
                        }
         | 
| 635 635 | 
             
                    }
         | 
| 636 | 
            -
             | 
| 636 | 
            +
             | 
| 637 637 | 
             
                    // Notify other components
         | 
| 638 638 | 
             
                    document.dispatchEvent(new CustomEvent('eventSelectionCleared'));
         | 
| 639 639 | 
             
                }
         | 
| @@ -645,19 +645,19 @@ class EventViewer { | |
| 645 645 | 
             
                    // Update event type counts
         | 
| 646 646 | 
             
                    this.eventTypeCount = {};
         | 
| 647 647 | 
             
                    this.errorCount = 0;
         | 
| 648 | 
            -
             | 
| 648 | 
            +
             | 
| 649 649 | 
             
                    // Defensive check to ensure events array exists
         | 
| 650 650 | 
             
                    if (!this.events || !Array.isArray(this.events)) {
         | 
| 651 651 | 
             
                        console.warn('EventViewer: events array is not initialized in updateMetrics');
         | 
| 652 652 | 
             
                        this.events = [];
         | 
| 653 653 | 
             
                    }
         | 
| 654 | 
            -
             | 
| 654 | 
            +
             | 
| 655 655 | 
             
                    this.events.forEach(event => {
         | 
| 656 656 | 
             
                        const type = event.type || 'unknown';
         | 
| 657 657 | 
             
                        this.eventTypeCount[type] = (this.eventTypeCount[type] || 0) + 1;
         | 
| 658 | 
            -
             | 
| 659 | 
            -
                        if (event.type === 'log' && | 
| 660 | 
            -
                            event.data && | 
| 658 | 
            +
             | 
| 659 | 
            +
                        if (event.type === 'log' &&
         | 
| 660 | 
            +
                            event.data &&
         | 
| 661 661 | 
             
                            ['error', 'critical'].includes(event.data.level)) {
         | 
| 662 662 | 
             
                            this.errorCount++;
         | 
| 663 663 | 
             
                        }
         | 
| @@ -672,7 +672,7 @@ class EventViewer { | |
| 672 672 |  | 
| 673 673 | 
             
                    // Count events in the last minute
         | 
| 674 674 | 
             
                    const oneMinuteAgo = new Date(Date.now() - 60000);
         | 
| 675 | 
            -
                    this.eventsThisMinute = this.events.filter(event => | 
| 675 | 
            +
                    this.eventsThisMinute = this.events.filter(event =>
         | 
| 676 676 | 
             
                        new Date(event.timestamp) > oneMinuteAgo
         | 
| 677 677 | 
             
                    ).length;
         | 
| 678 678 |  | 
| @@ -702,12 +702,12 @@ class EventViewer { | |
| 702 702 | 
             
                    const dataStr = JSON.stringify(this.filteredEvents, null, 2);
         | 
| 703 703 | 
             
                    const dataBlob = new Blob([dataStr], { type: 'application/json' });
         | 
| 704 704 | 
             
                    const url = URL.createObjectURL(dataBlob);
         | 
| 705 | 
            -
             | 
| 705 | 
            +
             | 
| 706 706 | 
             
                    const link = document.createElement('a');
         | 
| 707 707 | 
             
                    link.href = url;
         | 
| 708 708 | 
             
                    link.download = `claude-mpm-events-${new Date().toISOString().split('T')[0]}.json`;
         | 
| 709 709 | 
             
                    link.click();
         | 
| 710 | 
            -
             | 
| 710 | 
            +
             | 
| 711 711 | 
             
                    URL.revokeObjectURL(url);
         | 
| 712 712 | 
             
                }
         | 
| 713 713 |  | 
| @@ -768,12 +768,12 @@ class EventViewer { | |
| 768 768 | 
             
                createInlineEditDiffViewer(event, index) {
         | 
| 769 769 | 
             
                    const data = event.data || {};
         | 
| 770 770 | 
             
                    const toolName = event.tool_name || data.tool_name || '';
         | 
| 771 | 
            -
             | 
| 771 | 
            +
             | 
| 772 772 | 
             
                    // Only show for Edit and MultiEdit tools
         | 
| 773 773 | 
             
                    if (!['Edit', 'MultiEdit'].includes(toolName)) {
         | 
| 774 774 | 
             
                        return '';
         | 
| 775 775 | 
             
                    }
         | 
| 776 | 
            -
             | 
| 776 | 
            +
             | 
| 777 777 | 
             
                    // Extract edit parameters based on tool type
         | 
| 778 778 | 
             
                    let edits = [];
         | 
| 779 779 | 
             
                    if (toolName === 'Edit') {
         | 
| @@ -796,20 +796,20 @@ class EventViewer { | |
| 796 796 | 
             
                            }));
         | 
| 797 797 | 
             
                        }
         | 
| 798 798 | 
             
                    }
         | 
| 799 | 
            -
             | 
| 799 | 
            +
             | 
| 800 800 | 
             
                    if (edits.length === 0) {
         | 
| 801 801 | 
             
                        return '';
         | 
| 802 802 | 
             
                    }
         | 
| 803 | 
            -
             | 
| 803 | 
            +
             | 
| 804 804 | 
             
                    // Create collapsible diff section
         | 
| 805 805 | 
             
                    const diffId = `edit-diff-${index}`;
         | 
| 806 806 | 
             
                    const isMultiEdit = edits.length > 1;
         | 
| 807 | 
            -
             | 
| 807 | 
            +
             | 
| 808 808 | 
             
                    let diffContent = '';
         | 
| 809 809 | 
             
                    edits.forEach((edit, editIndex) => {
         | 
| 810 810 | 
             
                        const editId = `${diffId}-${editIndex}`;
         | 
| 811 811 | 
             
                        const diffHtml = this.createDiffHtml(edit.old_string, edit.new_string);
         | 
| 812 | 
            -
             | 
| 812 | 
            +
             | 
| 813 813 | 
             
                        diffContent += `
         | 
| 814 814 | 
             
                            <div class="edit-diff-section">
         | 
| 815 815 | 
             
                                ${isMultiEdit ? `<div class="edit-diff-header">Edit ${editIndex + 1}</div>` : ''}
         | 
| @@ -817,7 +817,7 @@ class EventViewer { | |
| 817 817 | 
             
                            </div>
         | 
| 818 818 | 
             
                        `;
         | 
| 819 819 | 
             
                    });
         | 
| 820 | 
            -
             | 
| 820 | 
            +
             | 
| 821 821 | 
             
                    return `
         | 
| 822 822 | 
             
                        <div class="inline-edit-diff-viewer">
         | 
| 823 823 | 
             
                            <div class="diff-toggle-header" onclick="eventViewer.toggleEditDiff('${diffId}', event)">
         | 
| @@ -843,15 +843,15 @@ class EventViewer { | |
| 843 843 | 
             
                    // Simple line-by-line diff implementation
         | 
| 844 844 | 
             
                    const oldLines = oldText.split('\n');
         | 
| 845 845 | 
             
                    const newLines = newText.split('\n');
         | 
| 846 | 
            -
             | 
| 846 | 
            +
             | 
| 847 847 | 
             
                    let diffHtml = '';
         | 
| 848 848 | 
             
                    let i = 0, j = 0;
         | 
| 849 | 
            -
             | 
| 849 | 
            +
             | 
| 850 850 | 
             
                    // Simple diff algorithm - can be enhanced with proper diff library if needed
         | 
| 851 851 | 
             
                    while (i < oldLines.length || j < newLines.length) {
         | 
| 852 852 | 
             
                        const oldLine = i < oldLines.length ? oldLines[i] : null;
         | 
| 853 853 | 
             
                        const newLine = j < newLines.length ? newLines[j] : null;
         | 
| 854 | 
            -
             | 
| 854 | 
            +
             | 
| 855 855 | 
             
                        if (oldLine === null) {
         | 
| 856 856 | 
             
                            // New line added
         | 
| 857 857 | 
             
                            diffHtml += `<div class="diff-line diff-added">+ ${this.escapeHtml(newLine)}</div>`;
         | 
| @@ -873,7 +873,7 @@ class EventViewer { | |
| 873 873 | 
             
                            j++;
         | 
| 874 874 | 
             
                        }
         | 
| 875 875 | 
             
                    }
         | 
| 876 | 
            -
             | 
| 876 | 
            +
             | 
| 877 877 | 
             
                    return `<div class="diff-container">${diffHtml}</div>`;
         | 
| 878 878 | 
             
                }
         | 
| 879 879 |  | 
| @@ -885,10 +885,10 @@ class EventViewer { | |
| 885 885 | 
             
                toggleEditDiff(diffId, event) {
         | 
| 886 886 | 
             
                    // Prevent event bubbling to parent event item
         | 
| 887 887 | 
             
                    event.stopPropagation();
         | 
| 888 | 
            -
             | 
| 888 | 
            +
             | 
| 889 889 | 
             
                    const diffContainer = document.getElementById(diffId);
         | 
| 890 890 | 
             
                    const arrow = event.currentTarget.querySelector('.diff-toggle-arrow');
         | 
| 891 | 
            -
             | 
| 891 | 
            +
             | 
| 892 892 | 
             
                    if (diffContainer) {
         | 
| 893 893 | 
             
                        const isVisible = diffContainer.style.display !== 'none';
         | 
| 894 894 | 
             
                        diffContainer.style.display = isVisible ? 'none' : 'block';
         | 
| @@ -910,5 +910,9 @@ class EventViewer { | |
| 910 910 | 
             
                }
         | 
| 911 911 | 
             
            }
         | 
| 912 912 |  | 
| 913 | 
            -
            //  | 
| 914 | 
            -
             | 
| 913 | 
            +
            // ES6 Module export
         | 
| 914 | 
            +
            export { EventViewer };
         | 
| 915 | 
            +
            export default EventViewer;
         | 
| 916 | 
            +
             | 
| 917 | 
            +
            // Backward compatibility - keep window export for non-module usage
         | 
| 918 | 
            +
            window.EventViewer = EventViewer;
         | 
| @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            /**
         | 
| 2 2 | 
             
             * Export Manager Module
         | 
| 3 | 
            -
             * | 
| 3 | 
            +
             *
         | 
| 4 4 | 
             
             * Handles export functionality and utility functions for the dashboard.
         | 
| 5 5 | 
             
             * Provides data export capabilities and common utility functions used across modules.
         | 
| 6 | 
            -
             * | 
| 6 | 
            +
             *
         | 
| 7 7 | 
             
             * WHY: Extracted from main dashboard to centralize export logic and utility functions
         | 
| 8 8 | 
             
             * that don't belong to specific functional areas. This provides a clean place for
         | 
| 9 9 | 
             
             * shared utilities while keeping export logic organized and testable.
         | 
| 10 | 
            -
             * | 
| 10 | 
            +
             *
         | 
| 11 11 | 
             
             * DESIGN DECISION: Combines export functionality with general utilities to avoid
         | 
| 12 12 | 
             
             * creating too many small modules while keeping related functionality together.
         | 
| 13 13 | 
             
             * Provides both data export and UI utility functions.
         | 
| @@ -16,7 +16,7 @@ class ExportManager { | |
| 16 16 | 
             
                constructor(eventViewer) {
         | 
| 17 17 | 
             
                    this.eventViewer = eventViewer;
         | 
| 18 18 | 
             
                    this.setupEventHandlers();
         | 
| 19 | 
            -
             | 
| 19 | 
            +
             | 
| 20 20 | 
             
                    console.log('Export manager initialized');
         | 
| 21 21 | 
             
                }
         | 
| 22 22 |  | 
| @@ -26,13 +26,13 @@ class ExportManager { | |
| 26 26 | 
             
                setupEventHandlers() {
         | 
| 27 27 | 
             
                    const clearBtn = document.querySelector('button[onclick="clearEvents()"]');
         | 
| 28 28 | 
             
                    const exportBtn = document.getElementById('export-btn');
         | 
| 29 | 
            -
             | 
| 29 | 
            +
             | 
| 30 30 | 
             
                    if (clearBtn) {
         | 
| 31 31 | 
             
                        clearBtn.addEventListener('click', () => {
         | 
| 32 32 | 
             
                            this.clearEvents();
         | 
| 33 33 | 
             
                        });
         | 
| 34 34 | 
             
                    }
         | 
| 35 | 
            -
             | 
| 35 | 
            +
             | 
| 36 36 | 
             
                    if (exportBtn) {
         | 
| 37 37 | 
             
                        exportBtn.addEventListener('click', () => {
         | 
| 38 38 | 
             
                            this.exportEvents();
         | 
| @@ -59,15 +59,15 @@ class ExportManager { | |
| 59 59 | 
             
                clearEvents() {
         | 
| 60 60 | 
             
                    // Dispatch event to notify other modules
         | 
| 61 61 | 
             
                    document.dispatchEvent(new CustomEvent('eventsClearing'));
         | 
| 62 | 
            -
             | 
| 62 | 
            +
             | 
| 63 63 | 
             
                    // Clear events from event viewer
         | 
| 64 64 | 
             
                    if (this.eventViewer) {
         | 
| 65 65 | 
             
                        this.eventViewer.clearEvents();
         | 
| 66 66 | 
             
                    }
         | 
| 67 | 
            -
             | 
| 67 | 
            +
             | 
| 68 68 | 
             
                    // Dispatch event to notify clearing is complete
         | 
| 69 69 | 
             
                    document.dispatchEvent(new CustomEvent('eventsCleared'));
         | 
| 70 | 
            -
             | 
| 70 | 
            +
             | 
| 71 71 | 
             
                    console.log('Events cleared');
         | 
| 72 72 | 
             
                }
         | 
| 73 73 |  | 
| @@ -86,7 +86,7 @@ class ExportManager { | |
| 86 86 | 
             
                    } = options;
         | 
| 87 87 |  | 
| 88 88 | 
             
                    const eventsToExport = events || (this.eventViewer ? this.eventViewer.events : []);
         | 
| 89 | 
            -
             | 
| 89 | 
            +
             | 
| 90 90 | 
             
                    if (eventsToExport.length === 0) {
         | 
| 91 91 | 
             
                        console.warn('No events to export');
         | 
| 92 92 | 
             
                        return;
         | 
| @@ -106,19 +106,19 @@ class ExportManager { | |
| 106 106 | 
             
                            mimeType = 'application/json';
         | 
| 107 107 | 
             
                            fileExtension = '.json';
         | 
| 108 108 | 
             
                            break;
         | 
| 109 | 
            -
             | 
| 109 | 
            +
             | 
| 110 110 | 
             
                        case 'csv':
         | 
| 111 111 | 
             
                            content = this.convertEventsToCSV(eventsToExport);
         | 
| 112 112 | 
             
                            mimeType = 'text/csv';
         | 
| 113 113 | 
             
                            fileExtension = '.csv';
         | 
| 114 114 | 
             
                            break;
         | 
| 115 | 
            -
             | 
| 115 | 
            +
             | 
| 116 116 | 
             
                        case 'txt':
         | 
| 117 117 | 
             
                            content = this.convertEventsToText(eventsToExport);
         | 
| 118 118 | 
             
                            mimeType = 'text/plain';
         | 
| 119 119 | 
             
                            fileExtension = '.txt';
         | 
| 120 120 | 
             
                            break;
         | 
| 121 | 
            -
             | 
| 121 | 
            +
             | 
| 122 122 | 
             
                        default:
         | 
| 123 123 | 
             
                            console.error('Unsupported export format:', format);
         | 
| 124 124 | 
             
                            return;
         | 
| @@ -137,7 +137,7 @@ class ExportManager { | |
| 137 137 |  | 
| 138 138 | 
             
                    // Define CSV headers
         | 
| 139 139 | 
             
                    const headers = ['timestamp', 'type', 'subtype', 'tool_name', 'agent_type', 'session_id', 'data'];
         | 
| 140 | 
            -
             | 
| 140 | 
            +
             | 
| 141 141 | 
             
                    // Convert events to CSV rows
         | 
| 142 142 | 
             
                    const rows = events.map(event => {
         | 
| 143 143 | 
             
                        return [
         | 
| @@ -173,15 +173,15 @@ class ExportManager { | |
| 173 173 | 
             
                        const subtype = event.subtype ? ` (${event.subtype})` : '';
         | 
| 174 174 | 
             
                        const toolName = event.tool_name ? ` - Tool: ${event.tool_name}` : '';
         | 
| 175 175 | 
             
                        const agentType = event.agent_type ? ` - Agent: ${event.agent_type}` : '';
         | 
| 176 | 
            -
             | 
| 176 | 
            +
             | 
| 177 177 | 
             
                        let content = `Event ${index + 1}: ${type}${subtype}${toolName}${agentType}\n`;
         | 
| 178 178 | 
             
                        content += `  Time: ${timestamp}\n`;
         | 
| 179 179 | 
             
                        content += `  Session: ${event.session_id || 'Unknown'}\n`;
         | 
| 180 | 
            -
             | 
| 180 | 
            +
             | 
| 181 181 | 
             
                        if (event.data && Object.keys(event.data).length > 0) {
         | 
| 182 182 | 
             
                            content += `  Data: ${JSON.stringify(event.data, null, 2)}\n`;
         | 
| 183 183 | 
             
                        }
         | 
| 184 | 
            -
             | 
| 184 | 
            +
             | 
| 185 185 | 
             
                        return content;
         | 
| 186 186 | 
             
                    }).join('\n' + '='.repeat(80) + '\n');
         | 
| 187 187 | 
             
                }
         | 
| @@ -196,19 +196,19 @@ class ExportManager { | |
| 196 196 | 
             
                    try {
         | 
| 197 197 | 
             
                        const blob = new Blob([content], { type: mimeType });
         | 
| 198 198 | 
             
                        const url = window.URL.createObjectURL(blob);
         | 
| 199 | 
            -
             | 
| 199 | 
            +
             | 
| 200 200 | 
             
                        const link = document.createElement('a');
         | 
| 201 201 | 
             
                        link.href = url;
         | 
| 202 202 | 
             
                        link.download = filename;
         | 
| 203 203 | 
             
                        link.style.display = 'none';
         | 
| 204 | 
            -
             | 
| 204 | 
            +
             | 
| 205 205 | 
             
                        document.body.appendChild(link);
         | 
| 206 206 | 
             
                        link.click();
         | 
| 207 207 | 
             
                        document.body.removeChild(link);
         | 
| 208 | 
            -
             | 
| 208 | 
            +
             | 
| 209 209 | 
             
                        // Clean up the URL object
         | 
| 210 210 | 
             
                        window.URL.revokeObjectURL(url);
         | 
| 211 | 
            -
             | 
| 211 | 
            +
             | 
| 212 212 | 
             
                        console.log(`File exported: ${filename}`);
         | 
| 213 213 | 
             
                    } catch (error) {
         | 
| 214 214 | 
             
                        console.error('Failed to export file:', error);
         | 
| @@ -226,13 +226,13 @@ class ExportManager { | |
| 226 226 | 
             
                 */
         | 
| 227 227 | 
             
                formatTimestamp(timestamp) {
         | 
| 228 228 | 
             
                    if (!timestamp) return 'Unknown time';
         | 
| 229 | 
            -
             | 
| 229 | 
            +
             | 
| 230 230 | 
             
                    try {
         | 
| 231 231 | 
             
                        const date = new Date(timestamp);
         | 
| 232 232 | 
             
                        if (isNaN(date.getTime())) {
         | 
| 233 233 | 
             
                            return 'Invalid time';
         | 
| 234 234 | 
             
                        }
         | 
| 235 | 
            -
             | 
| 235 | 
            +
             | 
| 236 236 | 
             
                        return date.toLocaleTimeString('en-US', {
         | 
| 237 237 | 
             
                            hour12: false,
         | 
| 238 238 | 
             
                            hour: '2-digit',
         | 
| @@ -252,13 +252,13 @@ class ExportManager { | |
| 252 252 | 
             
                 */
         | 
| 253 253 | 
             
                formatFullTimestamp(timestamp) {
         | 
| 254 254 | 
             
                    if (!timestamp) return 'Unknown time';
         | 
| 255 | 
            -
             | 
| 255 | 
            +
             | 
| 256 256 | 
             
                    try {
         | 
| 257 257 | 
             
                        const date = new Date(timestamp);
         | 
| 258 258 | 
             
                        if (isNaN(date.getTime())) {
         | 
| 259 259 | 
             
                            return 'Invalid time';
         | 
| 260 260 | 
             
                        }
         | 
| 261 | 
            -
             | 
| 261 | 
            +
             | 
| 262 262 | 
             
                        return date.toLocaleString('en-US', {
         | 
| 263 263 | 
             
                            year: 'numeric',
         | 
| 264 264 | 
             
                            month: '2-digit',
         | 
| @@ -280,12 +280,12 @@ class ExportManager { | |
| 280 280 | 
             
                 */
         | 
| 281 281 | 
             
                scrollListToBottom(listId) {
         | 
| 282 282 | 
             
                    console.log(`[DEBUG] scrollListToBottom called with listId: ${listId}`);
         | 
| 283 | 
            -
             | 
| 283 | 
            +
             | 
| 284 284 | 
             
                    // Use setTimeout to ensure DOM updates are completed
         | 
| 285 285 | 
             
                    setTimeout(() => {
         | 
| 286 286 | 
             
                        const listElement = document.getElementById(listId);
         | 
| 287 287 | 
             
                        console.log(`[DEBUG] Element found for ${listId}:`, listElement);
         | 
| 288 | 
            -
             | 
| 288 | 
            +
             | 
| 289 289 | 
             
                        if (listElement) {
         | 
| 290 290 | 
             
                            console.log(`[DEBUG] Scrolling ${listId} - scrollHeight: ${listElement.scrollHeight}, scrollTop before: ${listElement.scrollTop}`);
         | 
| 291 291 | 
             
                            listElement.scrollTop = listElement.scrollHeight;
         | 
| @@ -359,4 +359,7 @@ class ExportManager { | |
| 359 359 | 
             
                    }
         | 
| 360 360 | 
             
                    return obj;
         | 
| 361 361 | 
             
                }
         | 
| 362 | 
            -
            }
         | 
| 362 | 
            +
            }
         | 
| 363 | 
            +
            // ES6 Module export
         | 
| 364 | 
            +
            export { ExportManager };
         | 
| 365 | 
            +
            export default ExportManager;
         |