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
|
@@ -4,7 +4,7 @@ import gzip
|
|
|
4
4
|
import json
|
|
5
5
|
import shutil
|
|
6
6
|
import uuid
|
|
7
|
-
from datetime import datetime, timedelta
|
|
7
|
+
from datetime import datetime, timedelta, timezone
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Any, Dict, List, Optional
|
|
10
10
|
|
|
@@ -41,8 +41,8 @@ class SessionManager:
|
|
|
41
41
|
self.active_sessions[session_id] = {
|
|
42
42
|
"id": session_id,
|
|
43
43
|
"context": context,
|
|
44
|
-
"created_at": datetime.now().isoformat(),
|
|
45
|
-
"last_used": datetime.now().isoformat(),
|
|
44
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
45
|
+
"last_used": datetime.now(timezone.utc).isoformat(),
|
|
46
46
|
"use_count": 0,
|
|
47
47
|
"agents_run": [],
|
|
48
48
|
}
|
|
@@ -65,7 +65,7 @@ class SessionManager:
|
|
|
65
65
|
Session ID
|
|
66
66
|
"""
|
|
67
67
|
# Look for existing session in context
|
|
68
|
-
now = datetime.now()
|
|
68
|
+
now = datetime.now(timezone.utc)
|
|
69
69
|
max_age = timedelta(minutes=max_age_minutes)
|
|
70
70
|
|
|
71
71
|
for session_id, session_data in self.active_sessions.items():
|
|
@@ -95,10 +95,12 @@ class SessionManager:
|
|
|
95
95
|
{
|
|
96
96
|
"agent": agent,
|
|
97
97
|
"task": task[:100], # Truncate long tasks
|
|
98
|
-
"timestamp": datetime.now().isoformat(),
|
|
98
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
99
99
|
}
|
|
100
100
|
)
|
|
101
|
-
self.active_sessions[session_id]["last_used"] = datetime.now(
|
|
101
|
+
self.active_sessions[session_id]["last_used"] = datetime.now(
|
|
102
|
+
timezone.utc
|
|
103
|
+
).isoformat()
|
|
102
104
|
self._save_sessions()
|
|
103
105
|
|
|
104
106
|
def cleanup_old_sessions(self, max_age_hours: int = 24, archive: bool = True):
|
|
@@ -111,7 +113,7 @@ class SessionManager:
|
|
|
111
113
|
max_age_hours: Maximum age in hours
|
|
112
114
|
archive: Whether to archive sessions before removing
|
|
113
115
|
"""
|
|
114
|
-
now = datetime.now()
|
|
116
|
+
now = datetime.now(timezone.utc)
|
|
115
117
|
max_age = timedelta(hours=max_age_hours)
|
|
116
118
|
|
|
117
119
|
expired = []
|
|
@@ -223,7 +225,7 @@ class SessionManager:
|
|
|
223
225
|
archive_dir.mkdir(parents=True, exist_ok=True)
|
|
224
226
|
|
|
225
227
|
# Create timestamped archive file
|
|
226
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
228
|
+
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
227
229
|
archive_name = f"sessions_archive_{timestamp}.json.gz"
|
|
228
230
|
archive_path = archive_dir / archive_name
|
|
229
231
|
|
|
@@ -279,7 +281,7 @@ class SessionManager:
|
|
|
279
281
|
archive_dir = Path.home() / ".claude-mpm" / "archives"
|
|
280
282
|
archive_dir.mkdir(parents=True, exist_ok=True)
|
|
281
283
|
|
|
282
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
284
|
+
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
283
285
|
backup_name = f"claude_json_backup_{timestamp}.json.gz"
|
|
284
286
|
backup_path = archive_dir / backup_name
|
|
285
287
|
|
claude_mpm/core/socketio_pool.py
CHANGED
|
@@ -17,7 +17,7 @@ import threading
|
|
|
17
17
|
import time
|
|
18
18
|
from collections import defaultdict, deque
|
|
19
19
|
from dataclasses import dataclass, field
|
|
20
|
-
from datetime import datetime, timedelta
|
|
20
|
+
from datetime import datetime, timedelta, timezone
|
|
21
21
|
from enum import Enum
|
|
22
22
|
from typing import Any, Deque, Dict, List, Optional
|
|
23
23
|
|
|
@@ -97,11 +97,9 @@ class CircuitBreaker:
|
|
|
97
97
|
return True
|
|
98
98
|
if self.state == CircuitState.OPEN:
|
|
99
99
|
# Check if recovery timeout has passed
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
> timedelta(seconds=self.recovery_timeout)
|
|
104
|
-
):
|
|
100
|
+
if self.last_failure_time and datetime.now(
|
|
101
|
+
timezone.utc
|
|
102
|
+
) - self.last_failure_time > timedelta(seconds=self.recovery_timeout):
|
|
105
103
|
self.state = CircuitState.HALF_OPEN
|
|
106
104
|
self.logger.info(
|
|
107
105
|
"Circuit breaker transitioning to HALF_OPEN for testing"
|
|
@@ -127,7 +125,7 @@ class CircuitBreaker:
|
|
|
127
125
|
def record_failure(self):
|
|
128
126
|
"""Record failed execution."""
|
|
129
127
|
self.failure_count += 1
|
|
130
|
-
self.last_failure_time = datetime.now()
|
|
128
|
+
self.last_failure_time = datetime.now(timezone.utc)
|
|
131
129
|
|
|
132
130
|
if self.state == CircuitState.HALF_OPEN:
|
|
133
131
|
# Test failed, go back to OPEN
|
|
@@ -184,7 +182,7 @@ class SocketIOConnectionPool:
|
|
|
184
182
|
# Health monitoring
|
|
185
183
|
self.health_thread = None
|
|
186
184
|
self.health_running = False
|
|
187
|
-
self.last_health_check = datetime.now()
|
|
185
|
+
self.last_health_check = datetime.now(timezone.utc)
|
|
188
186
|
|
|
189
187
|
# Server configuration
|
|
190
188
|
self.server_url = None
|
|
@@ -311,7 +309,7 @@ class SocketIOConnectionPool:
|
|
|
311
309
|
self.server_url = f"http://localhost:{port}"
|
|
312
310
|
self.logger.debug(f"Detected Socket.IO server on port {port}")
|
|
313
311
|
return
|
|
314
|
-
except:
|
|
312
|
+
except Exception:
|
|
315
313
|
continue
|
|
316
314
|
|
|
317
315
|
# Fall back to default
|
|
@@ -375,7 +373,7 @@ class SocketIOConnectionPool:
|
|
|
375
373
|
# Check if connection is still valid
|
|
376
374
|
for conn_id, stats in self.connection_stats.items():
|
|
377
375
|
if stats.is_connected:
|
|
378
|
-
stats.last_used = datetime.now()
|
|
376
|
+
stats.last_used = datetime.now(timezone.utc)
|
|
379
377
|
return client
|
|
380
378
|
|
|
381
379
|
# Create new connection if under limit
|
|
@@ -581,7 +579,7 @@ class SocketIOConnectionPool:
|
|
|
581
579
|
loop.stop()
|
|
582
580
|
loop.run_until_complete(loop.shutdown_asyncgens())
|
|
583
581
|
loop.close()
|
|
584
|
-
except:
|
|
582
|
+
except Exception:
|
|
585
583
|
pass
|
|
586
584
|
|
|
587
585
|
async def _connect_client(self, client: socketio.AsyncClient):
|
|
@@ -623,7 +621,7 @@ class SocketIOConnectionPool:
|
|
|
623
621
|
self._check_connections_health()
|
|
624
622
|
|
|
625
623
|
# Update last health check time
|
|
626
|
-
self.last_health_check = datetime.now()
|
|
624
|
+
self.last_health_check = datetime.now(timezone.utc)
|
|
627
625
|
|
|
628
626
|
except Exception as e:
|
|
629
627
|
self.logger.error(f"Health monitor error: {e}")
|
|
@@ -655,7 +653,9 @@ class SocketIOConnectionPool:
|
|
|
655
653
|
continue
|
|
656
654
|
|
|
657
655
|
# 3. Connection idle for too long (>5 minutes)
|
|
658
|
-
idle_time = (
|
|
656
|
+
idle_time = (
|
|
657
|
+
datetime.now(timezone.utc) - stats.last_used
|
|
658
|
+
).total_seconds()
|
|
659
659
|
if idle_time > 300 and conn_id not in [
|
|
660
660
|
id for id, _ in enumerate(self.available_connections)
|
|
661
661
|
]:
|
claude_mpm/core/types.py
CHANGED
|
@@ -16,7 +16,7 @@ Module-specific types should remain in their respective modules.
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
from dataclasses import dataclass
|
|
19
|
-
from datetime import datetime
|
|
19
|
+
from datetime import datetime, timezone
|
|
20
20
|
from enum import Enum
|
|
21
21
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
22
22
|
|
|
@@ -206,7 +206,7 @@ class TaskInfo:
|
|
|
206
206
|
if self.metadata is None:
|
|
207
207
|
self.metadata = {}
|
|
208
208
|
if self.created_at is None:
|
|
209
|
-
self.created_at = datetime.now()
|
|
209
|
+
self.created_at = datetime.now(timezone.utc)
|
|
210
210
|
if self.updated_at is None:
|
|
211
211
|
self.updated_at = self.created_at
|
|
212
212
|
|
|
@@ -30,7 +30,7 @@ import json
|
|
|
30
30
|
import logging
|
|
31
31
|
import time
|
|
32
32
|
from dataclasses import asdict, dataclass
|
|
33
|
-
from datetime import datetime
|
|
33
|
+
from datetime import datetime, timezone
|
|
34
34
|
from enum import Enum
|
|
35
35
|
from pathlib import Path
|
|
36
36
|
from typing import Any, Dict, List, Optional, Set, Union
|
|
@@ -718,7 +718,7 @@ class UnifiedAgentRegistry:
|
|
|
718
718
|
|
|
719
719
|
export_data = {
|
|
720
720
|
"metadata": {
|
|
721
|
-
"export_time": datetime.now().isoformat(),
|
|
721
|
+
"export_time": datetime.now(timezone.utc).isoformat(),
|
|
722
722
|
"total_agents": len(self.registry),
|
|
723
723
|
"discovery_paths": [str(p) for p in self.discovery_paths],
|
|
724
724
|
},
|
claude_mpm/core/unified_paths.py
CHANGED
|
@@ -166,7 +166,7 @@ class PathContext:
|
|
|
166
166
|
|
|
167
167
|
@staticmethod
|
|
168
168
|
@lru_cache(maxsize=1)
|
|
169
|
-
def detect_deployment_context() -> DeploymentContext:
|
|
169
|
+
def detect_deployment_context() -> DeploymentContext: # noqa: PLR0911
|
|
170
170
|
"""Detect the current deployment context.
|
|
171
171
|
|
|
172
172
|
Priority order:
|
|
@@ -20,7 +20,7 @@ import subprocess
|
|
|
20
20
|
import sys
|
|
21
21
|
import threading
|
|
22
22
|
from dataclasses import asdict, dataclass
|
|
23
|
-
from datetime import datetime
|
|
23
|
+
from datetime import datetime, timezone
|
|
24
24
|
from pathlib import Path
|
|
25
25
|
from queue import Queue
|
|
26
26
|
from typing import Any, Dict, List, Optional
|
|
@@ -41,7 +41,7 @@ class AnalysisRequest:
|
|
|
41
41
|
|
|
42
42
|
def __post_init__(self):
|
|
43
43
|
if self.timestamp is None:
|
|
44
|
-
self.timestamp = datetime.
|
|
44
|
+
self.timestamp = datetime.now(timezone.utc)
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
class CodeAnalysisRunner:
|
|
@@ -433,7 +433,7 @@ class CodeAnalysisRunner:
|
|
|
433
433
|
if self.server:
|
|
434
434
|
# Add timestamp if not present
|
|
435
435
|
if "timestamp" not in data:
|
|
436
|
-
data["timestamp"] = datetime.
|
|
436
|
+
data["timestamp"] = datetime.now(timezone.utc).isoformat()
|
|
437
437
|
|
|
438
438
|
# Broadcast to all clients
|
|
439
439
|
self.server.broadcast_event(event_type, data)
|
|
@@ -450,6 +450,6 @@ class CodeAnalysisRunner:
|
|
|
450
450
|
{
|
|
451
451
|
"request_id": request_id,
|
|
452
452
|
"message": message,
|
|
453
|
-
"timestamp": datetime.
|
|
453
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
454
454
|
},
|
|
455
455
|
)
|
|
@@ -129,7 +129,7 @@ def has_code_files(directory_path, max_depth=5, current_depth=0):
|
|
|
129
129
|
return False
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
def should_show_item(item_name, item_path, is_directory):
|
|
132
|
+
def should_show_item(item_name, item_path, is_directory): # noqa: PLR0911
|
|
133
133
|
"""Determine if an item should be shown based on filtering rules"""
|
|
134
134
|
# Always hide system files
|
|
135
135
|
if item_name in {".DS_Store", "Thumbs.db", "desktop.ini"}:
|
|
@@ -7,7 +7,7 @@ Inspired by awesome-claude-code's template generation approach.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import re
|
|
10
|
-
from datetime import datetime
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
11
|
from typing import Any, Dict, Optional
|
|
12
12
|
|
|
13
13
|
import yaml
|
|
@@ -36,7 +36,9 @@ class AgentProfileGenerator:
|
|
|
36
36
|
"""Generate an agent profile from configuration."""
|
|
37
37
|
# Set default values
|
|
38
38
|
config.setdefault("VERSION", "1.0.0")
|
|
39
|
-
config.setdefault(
|
|
39
|
+
config.setdefault(
|
|
40
|
+
"CREATED_DATE", datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
41
|
+
)
|
|
40
42
|
config.setdefault("AUTHOR", "claude-mpm")
|
|
41
43
|
|
|
42
44
|
# Convert template to string
|
claude_mpm/hooks/base_hook.py
CHANGED
|
@@ -4,7 +4,7 @@ import asyncio
|
|
|
4
4
|
import logging
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
-
from datetime import datetime
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
8
|
from enum import Enum
|
|
9
9
|
from typing import Any, Dict, Optional
|
|
10
10
|
|
|
@@ -35,7 +35,7 @@ class HookContext:
|
|
|
35
35
|
def __post_init__(self):
|
|
36
36
|
"""Ensure timestamp is set."""
|
|
37
37
|
if not hasattr(self, "timestamp") or self.timestamp is None:
|
|
38
|
-
self.timestamp = datetime.now()
|
|
38
|
+
self.timestamp = datetime.now(timezone.utc)
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
@dataclass
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -131,7 +131,7 @@ class SocketIOConnectionPool:
|
|
|
131
131
|
"source": "connection_pool",
|
|
132
132
|
},
|
|
133
133
|
)
|
|
134
|
-
except:
|
|
134
|
+
except Exception:
|
|
135
135
|
pass # Ignore ping errors
|
|
136
136
|
return client
|
|
137
137
|
except Exception:
|
|
@@ -168,10 +168,10 @@ class SocketIOConnectionPool:
|
|
|
168
168
|
},
|
|
169
169
|
)
|
|
170
170
|
return True
|
|
171
|
-
except:
|
|
171
|
+
except Exception:
|
|
172
172
|
# If ping fails, connection might be dead
|
|
173
173
|
return client.connected # Fall back to basic check
|
|
174
|
-
except:
|
|
174
|
+
except Exception:
|
|
175
175
|
return False
|
|
176
176
|
|
|
177
177
|
def _close_connection(self, client: Any) -> None:
|
|
@@ -179,7 +179,7 @@ class SocketIOConnectionPool:
|
|
|
179
179
|
try:
|
|
180
180
|
if client:
|
|
181
181
|
client.disconnect()
|
|
182
|
-
except:
|
|
182
|
+
except Exception:
|
|
183
183
|
pass
|
|
184
184
|
|
|
185
185
|
def _cleanup_dead_connections(self) -> None:
|
|
@@ -9,7 +9,7 @@ import os
|
|
|
9
9
|
import re
|
|
10
10
|
import subprocess
|
|
11
11
|
import sys
|
|
12
|
-
from datetime import datetime
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
13
|
from typing import Optional
|
|
14
14
|
|
|
15
15
|
# Import tool analysis with fallback for direct execution
|
|
@@ -77,7 +77,7 @@ class EventHandlers:
|
|
|
77
77
|
"session_id": event.get("session_id", ""),
|
|
78
78
|
"working_directory": working_dir,
|
|
79
79
|
"git_branch": git_branch,
|
|
80
|
-
"timestamp": datetime.now().isoformat(),
|
|
80
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
81
81
|
"is_command": prompt.startswith("/"),
|
|
82
82
|
"contains_code": "```" in prompt
|
|
83
83
|
or "python" in prompt.lower()
|
|
@@ -101,7 +101,7 @@ class EventHandlers:
|
|
|
101
101
|
if session_id:
|
|
102
102
|
self.hook_handler.pending_prompts[session_id] = {
|
|
103
103
|
"prompt": prompt,
|
|
104
|
-
"timestamp": datetime.now().isoformat(),
|
|
104
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
105
105
|
"working_directory": working_dir,
|
|
106
106
|
}
|
|
107
107
|
if DEBUG:
|
|
@@ -150,7 +150,7 @@ class EventHandlers:
|
|
|
150
150
|
"session_id": event.get("session_id", ""),
|
|
151
151
|
"working_directory": working_dir,
|
|
152
152
|
"git_branch": git_branch,
|
|
153
|
-
"timestamp": datetime.now().isoformat(),
|
|
153
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
154
154
|
"parameter_count": len(tool_input) if isinstance(tool_input, dict) else 0,
|
|
155
155
|
"is_file_operation": tool_name
|
|
156
156
|
in ["Write", "Edit", "MultiEdit", "Read", "LS", "Glob"],
|
|
@@ -249,7 +249,7 @@ class EventHandlers:
|
|
|
249
249
|
"session_id": session_id,
|
|
250
250
|
"prompt": tool_input.get("prompt", ""),
|
|
251
251
|
"description": tool_input.get("description", ""),
|
|
252
|
-
"timestamp": datetime.now().isoformat(),
|
|
252
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
253
253
|
"hook_event_name": "SubagentStart", # For dashboard compatibility
|
|
254
254
|
}
|
|
255
255
|
self.hook_handler._emit_socketio_event(
|
|
@@ -277,7 +277,7 @@ class EventHandlers:
|
|
|
277
277
|
"session_id": session_id,
|
|
278
278
|
"delegation_context": {
|
|
279
279
|
"description": tool_input.get("description", ""),
|
|
280
|
-
"timestamp": datetime.now().isoformat(),
|
|
280
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
281
281
|
},
|
|
282
282
|
}
|
|
283
283
|
|
|
@@ -312,7 +312,7 @@ class EventHandlers:
|
|
|
312
312
|
working_dir = os.getcwd()
|
|
313
313
|
|
|
314
314
|
# Check cache first (cache for 30 seconds)
|
|
315
|
-
current_time = datetime.now().timestamp()
|
|
315
|
+
current_time = datetime.now(timezone.utc).timestamp()
|
|
316
316
|
cache_key = working_dir
|
|
317
317
|
|
|
318
318
|
if (
|
|
@@ -397,7 +397,7 @@ class EventHandlers:
|
|
|
397
397
|
"session_id": event.get("session_id", ""),
|
|
398
398
|
"working_directory": working_dir,
|
|
399
399
|
"git_branch": git_branch,
|
|
400
|
-
"timestamp": datetime.now().isoformat(),
|
|
400
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
401
401
|
"has_output": bool(result_data.get("output")),
|
|
402
402
|
"has_error": bool(result_data.get("error")),
|
|
403
403
|
"output_size": (
|
|
@@ -448,7 +448,7 @@ class EventHandlers:
|
|
|
448
448
|
"session_id": event.get("session_id", ""),
|
|
449
449
|
"working_directory": working_dir,
|
|
450
450
|
"git_branch": git_branch,
|
|
451
|
-
"timestamp": datetime.now().isoformat(),
|
|
451
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
452
452
|
"is_user_input_request": "input" in message.lower()
|
|
453
453
|
or "waiting" in message.lower(),
|
|
454
454
|
"is_error_notification": "error" in message.lower()
|
|
@@ -492,7 +492,7 @@ class EventHandlers:
|
|
|
492
492
|
"""Extract metadata from stop event."""
|
|
493
493
|
working_dir = event.get("cwd", "")
|
|
494
494
|
return {
|
|
495
|
-
"timestamp": datetime.now().isoformat(),
|
|
495
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
496
496
|
"working_directory": working_dir,
|
|
497
497
|
"git_branch": (
|
|
498
498
|
self._get_git_branch(working_dir) if working_dir else "Unknown"
|
|
@@ -639,7 +639,7 @@ class EventHandlers:
|
|
|
639
639
|
"has_error": reason in ["error", "timeout", "failed", "blocked"],
|
|
640
640
|
"working_directory": working_dir,
|
|
641
641
|
"git_branch": git_branch,
|
|
642
|
-
"timestamp": datetime.now().isoformat(),
|
|
642
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
643
643
|
"event_type": "subagent_stop",
|
|
644
644
|
"reason": reason,
|
|
645
645
|
"original_request_timestamp": request_info.get("timestamp"),
|
|
@@ -715,7 +715,7 @@ class EventHandlers:
|
|
|
715
715
|
"session_id": session_id,
|
|
716
716
|
"working_directory": working_dir,
|
|
717
717
|
"git_branch": git_branch,
|
|
718
|
-
"timestamp": datetime.now().isoformat(),
|
|
718
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
719
719
|
"contains_code": "```" in response_text,
|
|
720
720
|
"contains_json": "```json" in response_text,
|
|
721
721
|
"hook_event_name": "AssistantResponse", # Explicitly set for dashboard
|
|
@@ -25,7 +25,7 @@ import signal
|
|
|
25
25
|
import subprocess
|
|
26
26
|
import sys
|
|
27
27
|
import threading
|
|
28
|
-
from datetime import datetime
|
|
28
|
+
from datetime import datetime, timezone
|
|
29
29
|
from typing import Optional, Tuple
|
|
30
30
|
|
|
31
31
|
# Import extracted modules with fallback for direct execution
|
|
@@ -284,7 +284,7 @@ class ClaudeHookHandler:
|
|
|
284
284
|
if self.duplicate_detector.is_duplicate(event):
|
|
285
285
|
if DEBUG:
|
|
286
286
|
print(
|
|
287
|
-
f"[{datetime.now().isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
|
|
287
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
|
|
288
288
|
file=sys.stderr,
|
|
289
289
|
)
|
|
290
290
|
# Still need to output continue for this invocation
|
|
@@ -297,7 +297,7 @@ class ClaudeHookHandler:
|
|
|
297
297
|
if DEBUG:
|
|
298
298
|
hook_type = event.get("hook_event_name", "unknown")
|
|
299
299
|
print(
|
|
300
|
-
f"\n[{datetime.now().isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
|
|
300
|
+
f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
|
|
301
301
|
file=sys.stderr,
|
|
302
302
|
)
|
|
303
303
|
|
|
@@ -461,7 +461,7 @@ class ClaudeHookHandler:
|
|
|
461
461
|
if hasattr(self, "connection_manager") and self.connection_manager:
|
|
462
462
|
try:
|
|
463
463
|
self.connection_manager.cleanup()
|
|
464
|
-
except:
|
|
464
|
+
except Exception:
|
|
465
465
|
pass # Ignore cleanup errors during destruction
|
|
466
466
|
|
|
467
467
|
|
|
@@ -22,7 +22,7 @@ import sys
|
|
|
22
22
|
import threading
|
|
23
23
|
import time
|
|
24
24
|
from collections import deque
|
|
25
|
-
from datetime import datetime
|
|
25
|
+
from datetime import datetime, timezone
|
|
26
26
|
from pathlib import Path
|
|
27
27
|
from typing import Optional
|
|
28
28
|
|
|
@@ -55,7 +55,7 @@ except ImportError:
|
|
|
55
55
|
"type": event_data.get("type", "unknown"),
|
|
56
56
|
"subtype": event_data.get("subtype", "generic"),
|
|
57
57
|
"timestamp": event_data.get(
|
|
58
|
-
"timestamp", datetime.now().isoformat()
|
|
58
|
+
"timestamp", datetime.now(timezone.utc).isoformat()
|
|
59
59
|
),
|
|
60
60
|
"data": event_data.get("data", event_data),
|
|
61
61
|
"source": source,
|
|
@@ -174,7 +174,7 @@ class HookHandler:
|
|
|
174
174
|
raw_event = {
|
|
175
175
|
"type": "hook",
|
|
176
176
|
"subtype": event_type,
|
|
177
|
-
"timestamp": datetime.now().isoformat(),
|
|
177
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
178
178
|
"data": data,
|
|
179
179
|
"source": "claude_hooks",
|
|
180
180
|
"session_id": data.get("sessionId", self.current_session_id),
|
|
@@ -21,7 +21,7 @@ import sys
|
|
|
21
21
|
import threading
|
|
22
22
|
import time
|
|
23
23
|
from collections import deque
|
|
24
|
-
from datetime import datetime
|
|
24
|
+
from datetime import datetime, timezone
|
|
25
25
|
from typing import Optional
|
|
26
26
|
|
|
27
27
|
# Import extracted modules with fallback for direct execution
|
|
@@ -71,7 +71,7 @@ except ImportError:
|
|
|
71
71
|
"type": event_data.get("type", "unknown"),
|
|
72
72
|
"subtype": event_data.get("subtype", "generic"),
|
|
73
73
|
"timestamp": event_data.get(
|
|
74
|
-
"timestamp", datetime.now().isoformat()
|
|
74
|
+
"timestamp", datetime.now(timezone.utc).isoformat()
|
|
75
75
|
),
|
|
76
76
|
"data": event_data.get("data", event_data),
|
|
77
77
|
}
|
|
@@ -216,7 +216,7 @@ class ClaudeHookHandler:
|
|
|
216
216
|
|
|
217
217
|
if session_id and agent_type and agent_type != "unknown":
|
|
218
218
|
self.active_delegations[session_id] = agent_type
|
|
219
|
-
key = f"{session_id}:{datetime.now().timestamp()}"
|
|
219
|
+
key = f"{session_id}:{datetime.now(timezone.utc).timestamp()}"
|
|
220
220
|
self.delegation_history.append((key, agent_type))
|
|
221
221
|
|
|
222
222
|
# Store request data for response tracking correlation
|
|
@@ -224,7 +224,7 @@ class ClaudeHookHandler:
|
|
|
224
224
|
self.delegation_requests[session_id] = {
|
|
225
225
|
"agent_type": agent_type,
|
|
226
226
|
"request": request_data,
|
|
227
|
-
"timestamp": datetime.now().isoformat(),
|
|
227
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
228
228
|
}
|
|
229
229
|
if DEBUG:
|
|
230
230
|
print(
|
|
@@ -237,7 +237,7 @@ class ClaudeHookHandler:
|
|
|
237
237
|
)
|
|
238
238
|
|
|
239
239
|
# Clean up old delegations (older than 5 minutes)
|
|
240
|
-
cutoff_time = datetime.now().timestamp() - 300
|
|
240
|
+
cutoff_time = datetime.now(timezone.utc).timestamp() - 300
|
|
241
241
|
keys_to_remove = []
|
|
242
242
|
for sid in list(self.active_delegations.keys()):
|
|
243
243
|
# Check if this is an old entry by looking in history
|
|
@@ -259,7 +259,7 @@ class ClaudeHookHandler:
|
|
|
259
259
|
|
|
260
260
|
def _cleanup_old_entries(self):
|
|
261
261
|
"""Clean up old entries to prevent memory growth."""
|
|
262
|
-
datetime.now().timestamp() - self.MAX_CACHE_AGE_SECONDS
|
|
262
|
+
datetime.now(timezone.utc).timestamp() - self.MAX_CACHE_AGE_SECONDS
|
|
263
263
|
|
|
264
264
|
# Clean up delegation tracking dictionaries
|
|
265
265
|
for storage in [self.active_delegations, self.delegation_requests]:
|
|
@@ -281,7 +281,8 @@ class ClaudeHookHandler:
|
|
|
281
281
|
expired_keys = [
|
|
282
282
|
key
|
|
283
283
|
for key, cache_time in self._git_branch_cache_time.items()
|
|
284
|
-
if datetime.now().timestamp() - cache_time
|
|
284
|
+
if datetime.now(timezone.utc).timestamp() - cache_time
|
|
285
|
+
> self.MAX_CACHE_AGE_SECONDS
|
|
285
286
|
]
|
|
286
287
|
for key in expired_keys:
|
|
287
288
|
self._git_branch_cache.pop(key, None)
|
|
@@ -315,7 +316,7 @@ class ClaudeHookHandler:
|
|
|
315
316
|
working_dir = os.getcwd()
|
|
316
317
|
|
|
317
318
|
# Check cache first (cache for 30 seconds)
|
|
318
|
-
current_time = datetime.now().timestamp()
|
|
319
|
+
current_time = datetime.now(timezone.utc).timestamp()
|
|
319
320
|
cache_key = working_dir
|
|
320
321
|
|
|
321
322
|
if (
|
|
@@ -413,7 +414,7 @@ class ClaudeHookHandler:
|
|
|
413
414
|
if recent_key == event_key and (current_time - recent_time) < 0.1:
|
|
414
415
|
if DEBUG:
|
|
415
416
|
print(
|
|
416
|
-
f"[{datetime.now().isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
|
|
417
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
|
|
417
418
|
file=sys.stderr,
|
|
418
419
|
)
|
|
419
420
|
# Still need to output continue for this invocation
|
|
@@ -429,7 +430,7 @@ class ClaudeHookHandler:
|
|
|
429
430
|
if DEBUG:
|
|
430
431
|
hook_type = event.get("hook_event_name", "unknown")
|
|
431
432
|
print(
|
|
432
|
-
f"\n[{datetime.now().isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
|
|
433
|
+
f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
|
|
433
434
|
file=sys.stderr,
|
|
434
435
|
)
|
|
435
436
|
|
|
@@ -582,7 +583,7 @@ class ClaudeHookHandler:
|
|
|
582
583
|
raw_event = {
|
|
583
584
|
"type": "hook",
|
|
584
585
|
"subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
|
|
585
|
-
"timestamp": datetime.now().isoformat(),
|
|
586
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
586
587
|
"data": data,
|
|
587
588
|
"source": "claude_hooks", # Identify the source
|
|
588
589
|
"session_id": data.get("sessionId"), # Include session if available
|
|
@@ -857,7 +858,7 @@ class ClaudeHookHandler:
|
|
|
857
858
|
"duration_ms": event.get("duration_ms"),
|
|
858
859
|
"working_directory": working_dir,
|
|
859
860
|
"git_branch": git_branch,
|
|
860
|
-
"timestamp": datetime.now().isoformat(),
|
|
861
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
861
862
|
"event_type": "subagent_stop",
|
|
862
863
|
"reason": reason,
|
|
863
864
|
"original_request_timestamp": request_info.get("timestamp"),
|
|
@@ -922,7 +923,7 @@ class ClaudeHookHandler:
|
|
|
922
923
|
"session_id": session_id,
|
|
923
924
|
"working_directory": working_dir,
|
|
924
925
|
"git_branch": git_branch,
|
|
925
|
-
"timestamp": datetime.now().isoformat(),
|
|
926
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
926
927
|
"is_successful_completion": reason in ["completed", "finished", "done"],
|
|
927
928
|
"is_error_termination": reason in ["error", "timeout", "failed", "blocked"],
|
|
928
929
|
"is_delegation_related": agent_type
|
|
@@ -971,7 +972,7 @@ class ClaudeHookHandler:
|
|
|
971
972
|
if hasattr(self, "connection_pool") and self.connection_pool:
|
|
972
973
|
try:
|
|
973
974
|
self.connection_pool.cleanup()
|
|
974
|
-
except:
|
|
975
|
+
except Exception:
|
|
975
976
|
pass # Ignore cleanup errors during destruction
|
|
976
977
|
|
|
977
978
|
|
|
@@ -20,7 +20,7 @@ import select
|
|
|
20
20
|
import signal
|
|
21
21
|
import sys
|
|
22
22
|
import threading
|
|
23
|
-
from datetime import datetime
|
|
23
|
+
from datetime import datetime, timezone
|
|
24
24
|
|
|
25
25
|
# Import extracted modules with fallback for direct execution
|
|
26
26
|
try:
|
|
@@ -127,7 +127,7 @@ class ClaudeHookHandler:
|
|
|
127
127
|
if self.duplicate_detector.is_duplicate(event):
|
|
128
128
|
if DEBUG:
|
|
129
129
|
print(
|
|
130
|
-
f"[{datetime.now().isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
|
|
130
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
|
|
131
131
|
file=sys.stderr,
|
|
132
132
|
)
|
|
133
133
|
# Still need to output continue for this invocation
|
|
@@ -140,7 +140,7 @@ class ClaudeHookHandler:
|
|
|
140
140
|
if DEBUG:
|
|
141
141
|
hook_type = event.get("hook_event_name", "unknown")
|
|
142
142
|
print(
|
|
143
|
-
f"\n[{datetime.now().isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
|
|
143
|
+
f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
|
|
144
144
|
file=sys.stderr,
|
|
145
145
|
)
|
|
146
146
|
|
|
@@ -278,7 +278,7 @@ class ClaudeHookHandler:
|
|
|
278
278
|
if hasattr(self, "connection_manager") and self.connection_manager:
|
|
279
279
|
try:
|
|
280
280
|
self.connection_manager.cleanup()
|
|
281
|
-
except:
|
|
281
|
+
except Exception:
|
|
282
282
|
pass # Ignore cleanup errors during destruction
|
|
283
283
|
|
|
284
284
|
|