claude-mpm 4.3.12__py3-none-any.whl → 4.3.14__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/agents/PM_INSTRUCTIONS.md +414 -28
- claude_mpm/agents/templates/data_engineer.json +39 -14
- claude_mpm/agents/templates/engineer.json +11 -3
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +2 -2
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +5 -5
- claude_mpm/cli/commands/configure_tui.py +7 -7
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +5 -5
- claude_mpm/cli/commands/mcp.py +1 -1
- claude_mpm/cli/commands/mcp_command_router.py +1 -1
- claude_mpm/cli/commands/mcp_config.py +7 -10
- claude_mpm/cli/commands/mcp_external_commands.py +40 -32
- claude_mpm/cli/commands/mcp_install_commands.py +38 -10
- claude_mpm/cli/commands/mcp_setup_external.py +143 -102
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/commands/run.py +54 -2
- claude_mpm/cli/commands/search.py +41 -34
- claude_mpm/cli/interactive/agent_wizard.py +6 -2
- claude_mpm/cli/parsers/mcp_parser.py +1 -3
- claude_mpm/cli/parsers/search_parser.py +10 -4
- claude_mpm/cli/startup_logging.py +158 -5
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/core/agent_registry.py +2 -2
- claude_mpm/core/agent_session_manager.py +8 -8
- claude_mpm/core/api_validator.py +6 -4
- claude_mpm/core/base_service.py +10 -10
- claude_mpm/core/cache.py +5 -5
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/container.py +1 -1
- claude_mpm/core/error_handler.py +2 -2
- claude_mpm/core/file_utils.py +1 -1
- claude_mpm/core/framework_loader.py +3 -3
- claude_mpm/core/hook_manager.py +8 -6
- claude_mpm/core/instruction_reinforcement_hook.py +2 -2
- claude_mpm/core/interactive_session.py +3 -1
- claude_mpm/core/lazy.py +3 -3
- claude_mpm/core/log_manager.py +16 -12
- claude_mpm/core/logger.py +16 -11
- claude_mpm/core/optimized_agent_loader.py +6 -6
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/pm_hook_interceptor.py +3 -3
- claude_mpm/core/service_registry.py +1 -1
- claude_mpm/core/session_manager.py +11 -9
- claude_mpm/core/socketio_pool.py +13 -13
- claude_mpm/core/types.py +2 -2
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/core/unified_paths.py +1 -1
- claude_mpm/dashboard/analysis_runner.py +4 -4
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +4 -2
- claude_mpm/hooks/base_hook.py +2 -2
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
- claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
- claude_mpm/hooks/claude_hooks/installer.py +3 -3
- claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +8 -5
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
- claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/tool_call_interceptor.py +2 -2
- claude_mpm/models/agent_session.py +7 -5
- claude_mpm/scripts/mcp_server.py +0 -0
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/__init__.py +1 -1
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
- claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
- claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
- claude_mpm/services/agents/local_template_manager.py +6 -6
- claude_mpm/services/agents/management/agent_management_service.py +3 -3
- claude_mpm/services/agents/memory/content_manager.py +3 -3
- claude_mpm/services/agents/memory/memory_format_service.py +2 -2
- claude_mpm/services/agents/memory/template_generator.py +3 -3
- claude_mpm/services/agents/registry/modification_tracker.py +2 -2
- claude_mpm/services/async_session_logger.py +3 -3
- claude_mpm/services/claude_session_logger.py +4 -4
- claude_mpm/services/cli/agent_listing_service.py +3 -1
- claude_mpm/services/cli/agent_validation_service.py +2 -0
- claude_mpm/services/cli/memory_crud_service.py +11 -6
- claude_mpm/services/cli/memory_output_formatter.py +1 -1
- claude_mpm/services/cli/session_manager.py +15 -11
- claude_mpm/services/core/memory_manager.py +81 -23
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/event_bus/direct_relay.py +5 -3
- claude_mpm/services/event_bus/event_bus.py +3 -3
- claude_mpm/services/event_bus/relay.py +6 -4
- claude_mpm/services/events/consumers/dead_letter.py +5 -3
- claude_mpm/services/events/core.py +3 -3
- claude_mpm/services/events/producers/hook.py +6 -6
- claude_mpm/services/events/producers/system.py +8 -8
- claude_mpm/services/exceptions.py +5 -5
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
- claude_mpm/services/hook_installer_service.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +6 -4
- claude_mpm/services/infrastructure/daemon_manager.py +2 -2
- claude_mpm/services/infrastructure/logging.py +2 -2
- claude_mpm/services/mcp_config_manager.py +175 -30
- claude_mpm/services/mcp_gateway/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
- claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/core/base.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +21 -7
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/server/stdio_server.py +5 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
- claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +16 -16
- claude_mpm/services/memory/builder.py +7 -5
- claude_mpm/services/memory/indexed_memory.py +4 -4
- claude_mpm/services/memory/optimizer.py +6 -6
- claude_mpm/services/memory/router.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +6 -6
- claude_mpm/services/monitor/event_emitter.py +2 -2
- claude_mpm/services/monitor/management/lifecycle.py +3 -1
- claude_mpm/services/monitor/server.py +4 -4
- claude_mpm/services/monitor_build_service.py +2 -2
- claude_mpm/services/port_manager.py +3 -1
- claude_mpm/services/response_tracker.py +2 -2
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/socketio/client_proxy.py +2 -2
- claude_mpm/services/socketio/dashboard_server.py +4 -3
- claude_mpm/services/socketio/event_normalizer.py +11 -7
- claude_mpm/services/socketio/handlers/base.py +2 -2
- claude_mpm/services/socketio/handlers/connection.py +10 -10
- claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
- claude_mpm/services/socketio/handlers/hook.py +16 -15
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/monitor_client.py +5 -5
- claude_mpm/services/socketio/server/broadcaster.py +9 -7
- claude_mpm/services/socketio/server/connection_manager.py +2 -2
- claude_mpm/services/socketio/server/core.py +7 -5
- claude_mpm/services/socketio/server/eventbus_integration.py +18 -12
- claude_mpm/services/socketio/server/main.py +13 -13
- claude_mpm/services/socketio_client_manager.py +4 -4
- claude_mpm/services/system_instructions_service.py +2 -2
- claude_mpm/services/utility_service.py +5 -2
- claude_mpm/services/version_control/branch_strategy.py +2 -2
- claude_mpm/services/version_control/git_operations.py +22 -20
- claude_mpm/services/version_control/semantic_versioning.py +3 -3
- claude_mpm/services/version_control/version_parser.py +7 -5
- claude_mpm/services/visualization/mermaid_generator.py +3 -1
- claude_mpm/storage/state_storage.py +1 -1
- claude_mpm/tools/code_tree_analyzer.py +23 -18
- claude_mpm/tools/code_tree_builder.py +2 -2
- claude_mpm/tools/code_tree_events.py +10 -8
- claude_mpm/tools/socketio_debug.py +3 -3
- claude_mpm/utils/agent_dependency_loader.py +6 -2
- claude_mpm/utils/dependency_strategies.py +8 -3
- claude_mpm/utils/environment_context.py +1 -1
- claude_mpm/utils/error_handler.py +2 -2
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/log_cleanup.py +21 -7
- claude_mpm/validation/agent_validator.py +2 -2
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/METADATA +1 -1
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/RECORD +204 -191
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/top_level.txt +0 -0
|
@@ -16,7 +16,7 @@ DESIGN DECISIONS:
|
|
|
16
16
|
- Maintains backward compatibility with existing dashboard clients
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
from datetime import datetime
|
|
19
|
+
from datetime import datetime, timezone
|
|
20
20
|
from typing import Any, Dict, List, Optional
|
|
21
21
|
|
|
22
22
|
try:
|
|
@@ -125,7 +125,7 @@ class DashboardServer(SocketIOServiceInterface):
|
|
|
125
125
|
# Update state
|
|
126
126
|
self.running = self.dashboard_server.is_running()
|
|
127
127
|
if self.running:
|
|
128
|
-
self.stats["start_time"] = datetime.now().isoformat()
|
|
128
|
+
self.stats["start_time"] = datetime.now(timezone.utc).isoformat()
|
|
129
129
|
self.stats["monitor_connected"] = monitor_connected
|
|
130
130
|
|
|
131
131
|
self.logger.info(
|
|
@@ -224,7 +224,8 @@ class DashboardServer(SocketIOServiceInterface):
|
|
|
224
224
|
"monitor_stats": monitor_stats,
|
|
225
225
|
"uptime": (
|
|
226
226
|
(
|
|
227
|
-
datetime.now(
|
|
227
|
+
datetime.now(timezone.utc)
|
|
228
|
+
- datetime.fromisoformat(self.stats["start_time"])
|
|
228
229
|
).total_seconds()
|
|
229
230
|
if self.stats["start_time"]
|
|
230
231
|
else 0
|
|
@@ -15,7 +15,7 @@ DESIGN DECISION: Transform all events to a consistent schema:
|
|
|
15
15
|
|
|
16
16
|
import re
|
|
17
17
|
from dataclasses import dataclass, field
|
|
18
|
-
from datetime import datetime
|
|
18
|
+
from datetime import datetime, timezone
|
|
19
19
|
from enum import Enum
|
|
20
20
|
from typing import Any, Dict, Optional, Tuple
|
|
21
21
|
|
|
@@ -243,7 +243,7 @@ class EventNormalizer:
|
|
|
243
243
|
source="system",
|
|
244
244
|
type="unknown",
|
|
245
245
|
subtype="error",
|
|
246
|
-
timestamp=datetime.now().isoformat(),
|
|
246
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
247
247
|
data={"original": str(event_data), "error": str(e)},
|
|
248
248
|
)
|
|
249
249
|
|
|
@@ -277,7 +277,9 @@ class EventNormalizer:
|
|
|
277
277
|
source=source,
|
|
278
278
|
type=event_data.get("type", "unknown"),
|
|
279
279
|
subtype=event_data.get("subtype", "generic"),
|
|
280
|
-
timestamp=event_data.get(
|
|
280
|
+
timestamp=event_data.get(
|
|
281
|
+
"timestamp", datetime.now(timezone.utc).isoformat()
|
|
282
|
+
),
|
|
281
283
|
data=event_data.get("data", {}),
|
|
282
284
|
)
|
|
283
285
|
|
|
@@ -340,7 +342,7 @@ class EventNormalizer:
|
|
|
340
342
|
|
|
341
343
|
return "unknown"
|
|
342
344
|
|
|
343
|
-
def _map_event_name(self, event_name: str) -> Tuple[str, str]:
|
|
345
|
+
def _map_event_name(self, event_name: str) -> Tuple[str, str]: # noqa: PLR0911
|
|
344
346
|
"""Map event name to (type, subtype) tuple.
|
|
345
347
|
|
|
346
348
|
WHY: Consistent categorization helps clients filter and handle events.
|
|
@@ -553,12 +555,14 @@ class EventNormalizer:
|
|
|
553
555
|
# Convert other formats
|
|
554
556
|
try:
|
|
555
557
|
if isinstance(timestamp, (int, float)):
|
|
556
|
-
return datetime.fromtimestamp(
|
|
557
|
-
|
|
558
|
+
return datetime.fromtimestamp(
|
|
559
|
+
timestamp, tz=timezone.utc
|
|
560
|
+
).isoformat()
|
|
561
|
+
except Exception:
|
|
558
562
|
pass
|
|
559
563
|
|
|
560
564
|
# Generate new timestamp if not found
|
|
561
|
-
return datetime.now().isoformat()
|
|
565
|
+
return datetime.now(timezone.utc).isoformat()
|
|
562
566
|
|
|
563
567
|
def _determine_source(
|
|
564
568
|
self, event_data: Any, event_type: str, source_override: Optional[str] = None
|
|
@@ -5,7 +5,7 @@ logging, error handling, and access to the server instance. All handler
|
|
|
5
5
|
classes inherit from this to ensure consistent behavior.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from datetime import datetime
|
|
8
|
+
from datetime import datetime, timezone
|
|
9
9
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
10
10
|
|
|
11
11
|
from ....core.logger import get_logger
|
|
@@ -107,7 +107,7 @@ class BaseEventHandler:
|
|
|
107
107
|
"""
|
|
108
108
|
event = {
|
|
109
109
|
"type": event_type,
|
|
110
|
-
"timestamp": datetime.
|
|
110
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
111
111
|
"data": data,
|
|
112
112
|
}
|
|
113
113
|
self.event_history.append(event)
|
|
@@ -8,7 +8,7 @@ from other handlers makes connection management more maintainable.
|
|
|
8
8
|
import asyncio
|
|
9
9
|
import functools
|
|
10
10
|
import time
|
|
11
|
-
from datetime import datetime
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
12
|
from typing import Any, Callable, Dict, List, Optional
|
|
13
13
|
|
|
14
14
|
from .base import BaseEventHandler
|
|
@@ -48,7 +48,7 @@ def timeout_handler(timeout_seconds: float = 5.0):
|
|
|
48
48
|
f"⚠️ Handler {handler_name} took {elapsed:.2f}s "
|
|
49
49
|
f"(close to {timeout_seconds}s timeout)"
|
|
50
50
|
)
|
|
51
|
-
except:
|
|
51
|
+
except Exception:
|
|
52
52
|
print(
|
|
53
53
|
f"⚠️ Handler {handler_name} took {elapsed:.2f}s (close to {timeout_seconds}s timeout)"
|
|
54
54
|
)
|
|
@@ -65,7 +65,7 @@ def timeout_handler(timeout_seconds: float = 5.0):
|
|
|
65
65
|
logger.error(
|
|
66
66
|
f"❌ Handler {handler_name} timed out after {elapsed:.2f}s"
|
|
67
67
|
)
|
|
68
|
-
except:
|
|
68
|
+
except Exception:
|
|
69
69
|
print(f"❌ Handler {handler_name} timed out after {elapsed:.2f}s")
|
|
70
70
|
|
|
71
71
|
return None
|
|
@@ -80,7 +80,7 @@ def timeout_handler(timeout_seconds: float = 5.0):
|
|
|
80
80
|
logger.error(
|
|
81
81
|
f"❌ Handler {handler_name} failed after {elapsed:.2f}s: {e}"
|
|
82
82
|
)
|
|
83
|
-
except:
|
|
83
|
+
except Exception:
|
|
84
84
|
print(f"❌ Handler {handler_name} failed after {elapsed:.2f}s: {e}")
|
|
85
85
|
raise
|
|
86
86
|
|
|
@@ -274,7 +274,7 @@ class ConnectionEventHandler(BaseEventHandler):
|
|
|
274
274
|
# Force disconnect if still connected
|
|
275
275
|
try:
|
|
276
276
|
await self.sio.disconnect(sid)
|
|
277
|
-
except:
|
|
277
|
+
except Exception:
|
|
278
278
|
pass # Already disconnected
|
|
279
279
|
|
|
280
280
|
self.logger.info(f"🔌 Cleaned up stale connection: {sid}")
|
|
@@ -326,7 +326,7 @@ class ConnectionEventHandler(BaseEventHandler):
|
|
|
326
326
|
status_data = {
|
|
327
327
|
"type": "connection",
|
|
328
328
|
"subtype": "status",
|
|
329
|
-
"timestamp": datetime.
|
|
329
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
330
330
|
"source": "server",
|
|
331
331
|
"session_id": self.server.session_id,
|
|
332
332
|
"data": {
|
|
@@ -348,13 +348,13 @@ class ConnectionEventHandler(BaseEventHandler):
|
|
|
348
348
|
{
|
|
349
349
|
"type": "connection",
|
|
350
350
|
"subtype": "welcome",
|
|
351
|
-
"timestamp": datetime.
|
|
351
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
352
352
|
"source": "server",
|
|
353
353
|
"session_id": self.server.session_id,
|
|
354
354
|
"data": {
|
|
355
355
|
"message": "Connected to Claude MPM Socket.IO server",
|
|
356
356
|
"client_id": sid,
|
|
357
|
-
"server_time": datetime.
|
|
357
|
+
"server_time": datetime.now(timezone.utc).isoformat() + "Z",
|
|
358
358
|
"build_info": monitor_build_info,
|
|
359
359
|
},
|
|
360
360
|
},
|
|
@@ -401,7 +401,7 @@ class ConnectionEventHandler(BaseEventHandler):
|
|
|
401
401
|
status_data = {
|
|
402
402
|
"type": "connection",
|
|
403
403
|
"subtype": "status",
|
|
404
|
-
"timestamp": datetime.
|
|
404
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
405
405
|
"source": "server",
|
|
406
406
|
"session_id": self.server.session_id,
|
|
407
407
|
"data": {
|
|
@@ -456,7 +456,7 @@ class ConnectionEventHandler(BaseEventHandler):
|
|
|
456
456
|
{
|
|
457
457
|
"type": "connection",
|
|
458
458
|
"subtype": "subscribed",
|
|
459
|
-
"timestamp": datetime.
|
|
459
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
460
460
|
"source": "server",
|
|
461
461
|
"data": {"channels": channels},
|
|
462
462
|
},
|
|
@@ -8,7 +8,7 @@ DESIGN DECISION: Centralized connection event handling ensures consistent
|
|
|
8
8
|
state management and provides resilient event delivery across reconnections.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
from datetime import datetime
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
12
|
|
|
13
13
|
from .base import BaseEventHandler
|
|
14
14
|
|
|
@@ -50,7 +50,7 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
50
50
|
# Store client info
|
|
51
51
|
self.server.client_info[sid] = {
|
|
52
52
|
"client_id": conn.client_id,
|
|
53
|
-
"connected_at": datetime.now().isoformat(),
|
|
53
|
+
"connected_at": datetime.now(timezone.utc).isoformat(),
|
|
54
54
|
"user_agent": environ.get("HTTP_USER_AGENT", "unknown"),
|
|
55
55
|
"remote_addr": environ.get("REMOTE_ADDR", "unknown"),
|
|
56
56
|
}
|
|
@@ -61,7 +61,7 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
61
61
|
{
|
|
62
62
|
"client_id": conn.client_id,
|
|
63
63
|
"sid": sid,
|
|
64
|
-
"timestamp": datetime.now().isoformat(),
|
|
64
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
65
65
|
"server_version": self.get_server_version(),
|
|
66
66
|
},
|
|
67
67
|
room=sid,
|
|
@@ -120,7 +120,7 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
120
120
|
self.server.stats["connections_total"] += 1
|
|
121
121
|
|
|
122
122
|
self.server.client_info[sid] = {
|
|
123
|
-
"connected_at": datetime.now().isoformat(),
|
|
123
|
+
"connected_at": datetime.now(timezone.utc).isoformat(),
|
|
124
124
|
"user_agent": environ.get("HTTP_USER_AGENT", "unknown"),
|
|
125
125
|
"remote_addr": environ.get("REMOTE_ADDR", "unknown"),
|
|
126
126
|
}
|
|
@@ -185,8 +185,8 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
185
185
|
await sio.emit(
|
|
186
186
|
"pong",
|
|
187
187
|
{
|
|
188
|
-
"timestamp": datetime.now().isoformat(),
|
|
189
|
-
"server_time": datetime.now().timestamp(),
|
|
188
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
189
|
+
"server_time": datetime.now(timezone.utc).timestamp(),
|
|
190
190
|
},
|
|
191
191
|
room=sid,
|
|
192
192
|
)
|
|
@@ -210,7 +210,10 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
210
210
|
# Optional: Send confirmation
|
|
211
211
|
await sio.emit(
|
|
212
212
|
"ack_confirmed",
|
|
213
|
-
{
|
|
213
|
+
{
|
|
214
|
+
"sequence": sequence,
|
|
215
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
216
|
+
},
|
|
214
217
|
room=sid,
|
|
215
218
|
)
|
|
216
219
|
|
|
@@ -263,7 +266,7 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
263
266
|
"""Get connection statistics for debugging."""
|
|
264
267
|
try:
|
|
265
268
|
stats = {
|
|
266
|
-
"timestamp": datetime.now().isoformat(),
|
|
269
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
267
270
|
"total_connections": len(self.server.connected_clients),
|
|
268
271
|
"server_stats": self.server.stats,
|
|
269
272
|
}
|
|
@@ -312,7 +315,7 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
312
315
|
if self.server.stats.get("start_time")
|
|
313
316
|
else None
|
|
314
317
|
),
|
|
315
|
-
"timestamp": datetime.now().isoformat(),
|
|
318
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
316
319
|
}
|
|
317
320
|
|
|
318
321
|
await self.server.core.sio.emit("server_status", status_data, room=sid)
|
|
@@ -326,5 +329,5 @@ class EnhancedConnectionEventHandler(BaseEventHandler):
|
|
|
326
329
|
from claude_mpm.services.version_service import VersionService
|
|
327
330
|
|
|
328
331
|
return VersionService().get_version()
|
|
329
|
-
except:
|
|
332
|
+
except Exception:
|
|
330
333
|
return "unknown"
|
|
@@ -4,7 +4,7 @@ WHY: This module handles hook events from Claude to track session information,
|
|
|
4
4
|
agent delegations, and other hook-based activity for the system heartbeat.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from datetime import datetime
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
8
|
from typing import Any, Dict
|
|
9
9
|
|
|
10
10
|
from .base import BaseEventHandler
|
|
@@ -66,7 +66,8 @@ class HookEventHandler(BaseEventHandler):
|
|
|
66
66
|
"type": "hook",
|
|
67
67
|
"event": hook_event,
|
|
68
68
|
"data": hook_data,
|
|
69
|
-
"timestamp": data.get("timestamp")
|
|
69
|
+
"timestamp": data.get("timestamp")
|
|
70
|
+
or datetime.now(timezone.utc).isoformat(),
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
# Add the event to history for replay
|
|
@@ -105,11 +106,11 @@ class HookEventHandler(BaseEventHandler):
|
|
|
105
106
|
if hasattr(self.server, "active_sessions"):
|
|
106
107
|
self.server.active_sessions[session_id] = {
|
|
107
108
|
"session_id": session_id,
|
|
108
|
-
"start_time": datetime.now().isoformat(),
|
|
109
|
+
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
109
110
|
"agent": agent_type,
|
|
110
111
|
"status": "active",
|
|
111
112
|
"prompt": data.get("prompt", "")[:100], # First 100 chars
|
|
112
|
-
"last_activity": datetime.now().isoformat(),
|
|
113
|
+
"last_activity": datetime.now(timezone.utc).isoformat(),
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
self.logger.debug(
|
|
@@ -132,9 +133,9 @@ class HookEventHandler(BaseEventHandler):
|
|
|
132
133
|
if session_id in self.server.active_sessions:
|
|
133
134
|
# Mark as completed rather than removing immediately
|
|
134
135
|
self.server.active_sessions[session_id]["status"] = "completed"
|
|
135
|
-
self.server.active_sessions[session_id][
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
self.server.active_sessions[session_id]["last_activity"] = datetime.now(
|
|
137
|
+
timezone.utc
|
|
138
|
+
).isoformat()
|
|
138
139
|
|
|
139
140
|
self.logger.debug(
|
|
140
141
|
f"Marked session completed: session={session_id[:8]}..."
|
|
@@ -156,18 +157,18 @@ class HookEventHandler(BaseEventHandler):
|
|
|
156
157
|
if session_id not in self.server.active_sessions:
|
|
157
158
|
self.server.active_sessions[session_id] = {
|
|
158
159
|
"session_id": session_id,
|
|
159
|
-
"start_time": datetime.now().isoformat(),
|
|
160
|
+
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
160
161
|
"agent": "pm", # Default to PM
|
|
161
162
|
"status": "active",
|
|
162
163
|
"prompt": data.get("prompt_text", "")[:100],
|
|
163
164
|
"working_directory": data.get("working_directory", ""),
|
|
164
|
-
"last_activity": datetime.now().isoformat(),
|
|
165
|
+
"last_activity": datetime.now(timezone.utc).isoformat(),
|
|
165
166
|
}
|
|
166
167
|
else:
|
|
167
168
|
# Update last activity
|
|
168
|
-
self.server.active_sessions[session_id][
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
self.server.active_sessions[session_id]["last_activity"] = datetime.now(
|
|
170
|
+
timezone.utc
|
|
171
|
+
).isoformat()
|
|
171
172
|
|
|
172
173
|
async def _handle_pre_tool(self, data: Dict[str, Any]):
|
|
173
174
|
"""Handle pre-tool events.
|
|
@@ -190,9 +191,9 @@ class HookEventHandler(BaseEventHandler):
|
|
|
190
191
|
if session_id in self.server.active_sessions:
|
|
191
192
|
self.server.active_sessions[session_id]["agent"] = agent_type
|
|
192
193
|
self.server.active_sessions[session_id]["status"] = "delegated"
|
|
193
|
-
self.server.active_sessions[session_id][
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
self.server.active_sessions[session_id]["last_activity"] = datetime.now(
|
|
195
|
+
timezone.utc
|
|
196
|
+
).isoformat()
|
|
196
197
|
|
|
197
198
|
self.logger.debug(
|
|
198
199
|
f"Updated session delegation: session={session_id[:8]}..., agent={agent_type}"
|
|
@@ -223,7 +223,7 @@ class EventTypeMapper:
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
@classmethod
|
|
226
|
-
def map_event_type(cls, old_type: str) -> Tuple[str, str]:
|
|
226
|
+
def map_event_type(cls, old_type: str) -> Tuple[str, str]: # noqa: PLR0911
|
|
227
227
|
"""Map an old event type to new type/subtype.
|
|
228
228
|
|
|
229
229
|
WHY: Provides consistent categorization for all events.
|
|
@@ -16,7 +16,7 @@ DESIGN DECISIONS:
|
|
|
16
16
|
import asyncio
|
|
17
17
|
import threading
|
|
18
18
|
import time
|
|
19
|
-
from datetime import datetime
|
|
19
|
+
from datetime import datetime, timezone
|
|
20
20
|
from typing import Any, Callable, Dict
|
|
21
21
|
|
|
22
22
|
try:
|
|
@@ -119,7 +119,7 @@ class MonitorClient:
|
|
|
119
119
|
# Use the event loop from the client thread
|
|
120
120
|
if hasattr(self.client, "disconnect"):
|
|
121
121
|
asyncio.run(self.client.disconnect())
|
|
122
|
-
except:
|
|
122
|
+
except Exception:
|
|
123
123
|
pass
|
|
124
124
|
|
|
125
125
|
self.connected = False
|
|
@@ -152,7 +152,7 @@ class MonitorClient:
|
|
|
152
152
|
"monitor_url": self.monitor_url,
|
|
153
153
|
"uptime": (
|
|
154
154
|
(
|
|
155
|
-
datetime.now()
|
|
155
|
+
datetime.now(timezone.utc)
|
|
156
156
|
- datetime.fromisoformat(self.stats["last_connected"])
|
|
157
157
|
).total_seconds()
|
|
158
158
|
if self.stats["last_connected"] and self.connected
|
|
@@ -224,7 +224,7 @@ class MonitorClient:
|
|
|
224
224
|
self.connected = True
|
|
225
225
|
self.connecting = False
|
|
226
226
|
self.stats["successful_connections"] += 1
|
|
227
|
-
self.stats["last_connected"] = datetime.now().isoformat()
|
|
227
|
+
self.stats["last_connected"] = datetime.now(timezone.utc).isoformat()
|
|
228
228
|
self.reconnect_delay = 1.0 # Reset reconnect delay on successful connection
|
|
229
229
|
|
|
230
230
|
self.logger.info(f"Connected to monitor server at {self.monitor_url}")
|
|
@@ -255,7 +255,7 @@ class MonitorClient:
|
|
|
255
255
|
"""Handle disconnection."""
|
|
256
256
|
self.logger.info("Disconnected from monitor server")
|
|
257
257
|
self.connected = False
|
|
258
|
-
self.stats["last_disconnected"] = datetime.now().isoformat()
|
|
258
|
+
self.stats["last_disconnected"] = datetime.now(timezone.utc).isoformat()
|
|
259
259
|
|
|
260
260
|
@self.client.event
|
|
261
261
|
async def connect_error(data):
|
|
@@ -13,7 +13,7 @@ import asyncio
|
|
|
13
13
|
import time
|
|
14
14
|
from collections import deque
|
|
15
15
|
from dataclasses import dataclass
|
|
16
|
-
from datetime import datetime
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
17
|
from typing import Any, Deque, Dict, List, Optional, Set
|
|
18
18
|
|
|
19
19
|
from ..event_normalizer import EventNormalizer
|
|
@@ -284,7 +284,7 @@ class SocketIOEventBroadcaster:
|
|
|
284
284
|
# Reconstruct the raw event
|
|
285
285
|
raw_event = {
|
|
286
286
|
"type": event.event_type,
|
|
287
|
-
"timestamp": datetime.now().isoformat(),
|
|
287
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
288
288
|
"data": {**event.data, "retry_attempt": event.attempt_count + 1},
|
|
289
289
|
}
|
|
290
290
|
|
|
@@ -323,7 +323,7 @@ class SocketIOEventBroadcaster:
|
|
|
323
323
|
# Create raw event for normalization
|
|
324
324
|
raw_event = {
|
|
325
325
|
"type": event_type,
|
|
326
|
-
"timestamp": datetime.now().isoformat(),
|
|
326
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
327
327
|
"data": data,
|
|
328
328
|
}
|
|
329
329
|
|
|
@@ -388,11 +388,11 @@ class SocketIOEventBroadcaster:
|
|
|
388
388
|
asyncio.run_coroutine_threadsafe(
|
|
389
389
|
update_activities(), self.loop
|
|
390
390
|
)
|
|
391
|
-
except:
|
|
391
|
+
except Exception:
|
|
392
392
|
pass # Non-critical
|
|
393
393
|
|
|
394
394
|
self.logger.debug(f"Broadcasted event: {event_type}")
|
|
395
|
-
except:
|
|
395
|
+
except Exception:
|
|
396
396
|
# Will be added to retry queue below
|
|
397
397
|
pass
|
|
398
398
|
else:
|
|
@@ -426,13 +426,15 @@ class SocketIOEventBroadcaster:
|
|
|
426
426
|
"session_id": session_id,
|
|
427
427
|
"launch_method": launch_method,
|
|
428
428
|
"working_dir": working_dir,
|
|
429
|
-
"timestamp": datetime.now().isoformat(),
|
|
429
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
430
430
|
},
|
|
431
431
|
)
|
|
432
432
|
|
|
433
433
|
def session_ended(self):
|
|
434
434
|
"""Notify that a session has ended."""
|
|
435
|
-
self.broadcast_event(
|
|
435
|
+
self.broadcast_event(
|
|
436
|
+
"session_ended", {"timestamp": datetime.now(timezone.utc).isoformat()}
|
|
437
|
+
)
|
|
436
438
|
|
|
437
439
|
def claude_status_changed(
|
|
438
440
|
self, status: str, pid: Optional[int] = None, message: str = ""
|
|
@@ -14,7 +14,7 @@ import contextlib
|
|
|
14
14
|
import time
|
|
15
15
|
from collections import deque
|
|
16
16
|
from dataclasses import dataclass, field
|
|
17
|
-
from datetime import datetime
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
18
|
from enum import Enum
|
|
19
19
|
from typing import Any, Deque, Dict, List, Optional
|
|
20
20
|
from uuid import uuid4
|
|
@@ -464,7 +464,7 @@ class ConnectionManager:
|
|
|
464
464
|
async with self._lock:
|
|
465
465
|
now = time.time()
|
|
466
466
|
report = {
|
|
467
|
-
"timestamp": datetime.now().isoformat(),
|
|
467
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
468
468
|
"total_connections": len(self.connections),
|
|
469
469
|
"healthy": 0,
|
|
470
470
|
"stale": 0,
|
|
@@ -13,7 +13,7 @@ import asyncio
|
|
|
13
13
|
import threading
|
|
14
14
|
import time
|
|
15
15
|
from collections import deque
|
|
16
|
-
from datetime import datetime
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from typing import Any, Dict, Set
|
|
19
19
|
|
|
@@ -211,7 +211,7 @@ class SocketIOServerCore:
|
|
|
211
211
|
await self.site.start()
|
|
212
212
|
|
|
213
213
|
self.running = True
|
|
214
|
-
self.stats["start_time"] = datetime.now()
|
|
214
|
+
self.stats["start_time"] = datetime.now(timezone.utc)
|
|
215
215
|
|
|
216
216
|
self.logger.info(
|
|
217
217
|
f"Socket.IO server listening on http://{self.host}:{self.port}"
|
|
@@ -428,7 +428,7 @@ class SocketIOServerCore:
|
|
|
428
428
|
)
|
|
429
429
|
|
|
430
430
|
# Add file reading endpoint for source viewer
|
|
431
|
-
async def file_read_handler(request):
|
|
431
|
+
async def file_read_handler(request): # noqa: PLR0911
|
|
432
432
|
"""Handle GET /api/file/read for reading source files."""
|
|
433
433
|
import os
|
|
434
434
|
|
|
@@ -749,7 +749,9 @@ class SocketIOServerCore:
|
|
|
749
749
|
uptime_seconds = 0
|
|
750
750
|
if self.stats.get("start_time"):
|
|
751
751
|
uptime_seconds = int(
|
|
752
|
-
(
|
|
752
|
+
(
|
|
753
|
+
datetime.now(timezone.utc) - self.stats["start_time"]
|
|
754
|
+
).total_seconds()
|
|
753
755
|
)
|
|
754
756
|
|
|
755
757
|
# Get active sessions from main server if available
|
|
@@ -766,7 +768,7 @@ class SocketIOServerCore:
|
|
|
766
768
|
heartbeat_data = {
|
|
767
769
|
"type": "system",
|
|
768
770
|
"subtype": "heartbeat",
|
|
769
|
-
"timestamp": datetime.now().isoformat(),
|
|
771
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
770
772
|
"source": "server",
|
|
771
773
|
"data": {
|
|
772
774
|
"uptime_seconds": uptime_seconds,
|
|
@@ -8,6 +8,7 @@ WHY this integration module:
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
|
+
from datetime import datetime, timezone
|
|
11
12
|
from typing import Optional
|
|
12
13
|
|
|
13
14
|
from claude_mpm.services.event_bus import EventBus
|
|
@@ -48,17 +49,16 @@ class EventBusIntegration:
|
|
|
48
49
|
Returns:
|
|
49
50
|
bool: True if setup successful
|
|
50
51
|
"""
|
|
51
|
-
from datetime import datetime
|
|
52
52
|
|
|
53
53
|
print(
|
|
54
|
-
f"[{datetime.now().isoformat()}] EventBusIntegration.setup() called",
|
|
54
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBusIntegration.setup() called",
|
|
55
55
|
flush=True,
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
if not self.enabled:
|
|
59
59
|
logger.info("EventBus integration disabled by configuration")
|
|
60
60
|
print(
|
|
61
|
-
f"[{datetime.now().isoformat()}] EventBus integration disabled by configuration",
|
|
61
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBus integration disabled by configuration",
|
|
62
62
|
flush=True,
|
|
63
63
|
)
|
|
64
64
|
return False
|
|
@@ -66,12 +66,13 @@ class EventBusIntegration:
|
|
|
66
66
|
try:
|
|
67
67
|
# Get EventBus instance
|
|
68
68
|
print(
|
|
69
|
-
f"[{datetime.now().isoformat()}] Getting EventBus instance...",
|
|
69
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Getting EventBus instance...",
|
|
70
70
|
flush=True,
|
|
71
71
|
)
|
|
72
72
|
self.event_bus = EventBus.get_instance()
|
|
73
73
|
print(
|
|
74
|
-
f"[{datetime.now().isoformat()}] EventBus instance obtained",
|
|
74
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBus instance obtained",
|
|
75
|
+
flush=True,
|
|
75
76
|
)
|
|
76
77
|
|
|
77
78
|
# Apply configuration
|
|
@@ -79,31 +80,36 @@ class EventBusIntegration:
|
|
|
79
80
|
|
|
80
81
|
# Create direct relay that uses server's broadcaster
|
|
81
82
|
print(
|
|
82
|
-
f"[{datetime.now().isoformat()}] Creating DirectSocketIORelay...",
|
|
83
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Creating DirectSocketIORelay...",
|
|
83
84
|
flush=True,
|
|
84
85
|
)
|
|
85
86
|
if self.server:
|
|
86
87
|
self.relay = DirectSocketIORelay(self.server)
|
|
87
88
|
print(
|
|
88
|
-
f"[{datetime.now().isoformat()}] DirectSocketIORelay created with server instance",
|
|
89
|
+
f"[{datetime.now(timezone.utc).isoformat()}] DirectSocketIORelay created with server instance",
|
|
89
90
|
flush=True,
|
|
90
91
|
)
|
|
91
92
|
else:
|
|
92
93
|
logger.warning("No server instance provided, relay won't work")
|
|
93
94
|
print(
|
|
94
|
-
f"[{datetime.now().isoformat()}] WARNING: No server instance for relay",
|
|
95
|
+
f"[{datetime.now(timezone.utc).isoformat()}] WARNING: No server instance for relay",
|
|
95
96
|
flush=True,
|
|
96
97
|
)
|
|
97
98
|
return False
|
|
98
99
|
|
|
99
100
|
# Start the relay
|
|
100
|
-
print(
|
|
101
|
+
print(
|
|
102
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Starting relay...",
|
|
103
|
+
flush=True,
|
|
104
|
+
)
|
|
101
105
|
self.relay.start()
|
|
102
|
-
print(
|
|
106
|
+
print(
|
|
107
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Relay started", flush=True
|
|
108
|
+
)
|
|
103
109
|
|
|
104
110
|
logger.info("EventBus integration setup complete with DirectSocketIORelay")
|
|
105
111
|
print(
|
|
106
|
-
f"[{datetime.now().isoformat()}] EventBus integration setup complete with DirectSocketIORelay",
|
|
112
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBus integration setup complete with DirectSocketIORelay",
|
|
107
113
|
flush=True,
|
|
108
114
|
)
|
|
109
115
|
return True
|
|
@@ -111,7 +117,7 @@ class EventBusIntegration:
|
|
|
111
117
|
except Exception as e:
|
|
112
118
|
logger.error(f"Failed to setup EventBus integration: {e}")
|
|
113
119
|
print(
|
|
114
|
-
f"[{datetime.now().isoformat()}] Failed to setup EventBus integration: {e}",
|
|
120
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Failed to setup EventBus integration: {e}",
|
|
115
121
|
flush=True,
|
|
116
122
|
)
|
|
117
123
|
import traceback
|