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
|
@@ -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 typing import Any, Dict, List, Optional, Set
|
|
18
18
|
|
|
19
19
|
try:
|
|
@@ -107,7 +107,7 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
107
107
|
# Debug logging for EventBus initialization
|
|
108
108
|
self.logger.info("Starting Socket.IO server with EventBus integration...")
|
|
109
109
|
print(
|
|
110
|
-
f"[{datetime.now().isoformat()}] SocketIOServer.start_sync() called",
|
|
110
|
+
f"[{datetime.now(timezone.utc).isoformat()}] SocketIOServer.start_sync() called",
|
|
111
111
|
flush=True,
|
|
112
112
|
)
|
|
113
113
|
|
|
@@ -172,7 +172,7 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
172
172
|
# WHY: This connects the EventBus to the Socket.IO server, allowing
|
|
173
173
|
# events from other parts of the system to be broadcast to dashboard
|
|
174
174
|
print(
|
|
175
|
-
f"[{datetime.now().isoformat()}] Setting up EventBus integration...",
|
|
175
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Setting up EventBus integration...",
|
|
176
176
|
flush=True,
|
|
177
177
|
)
|
|
178
178
|
|
|
@@ -183,26 +183,26 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
183
183
|
"Broadcaster not initialized - cannot setup EventBus integration"
|
|
184
184
|
)
|
|
185
185
|
print(
|
|
186
|
-
f"[{datetime.now().isoformat()}] ERROR: Broadcaster not initialized",
|
|
186
|
+
f"[{datetime.now(timezone.utc).isoformat()}] ERROR: Broadcaster not initialized",
|
|
187
187
|
flush=True,
|
|
188
188
|
)
|
|
189
189
|
else:
|
|
190
190
|
print(
|
|
191
|
-
f"[{datetime.now().isoformat()}] Broadcaster ready, proceeding with EventBus setup",
|
|
191
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Broadcaster ready, proceeding with EventBus setup",
|
|
192
192
|
flush=True,
|
|
193
193
|
)
|
|
194
194
|
|
|
195
195
|
try:
|
|
196
196
|
self.eventbus_integration = EventBusIntegration(self)
|
|
197
197
|
print(
|
|
198
|
-
f"[{datetime.now().isoformat()}] EventBusIntegration instance created",
|
|
198
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBusIntegration instance created",
|
|
199
199
|
flush=True,
|
|
200
200
|
)
|
|
201
201
|
|
|
202
202
|
if self.eventbus_integration.setup(self.port):
|
|
203
203
|
self.logger.info("EventBus integration setup successful")
|
|
204
204
|
print(
|
|
205
|
-
f"[{datetime.now().isoformat()}] EventBus integration setup successful",
|
|
205
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBus integration setup successful",
|
|
206
206
|
flush=True,
|
|
207
207
|
)
|
|
208
208
|
|
|
@@ -214,19 +214,19 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
214
214
|
relay_stats = self.eventbus_integration.relay.get_stats()
|
|
215
215
|
self.logger.info(f"EventBus relay stats: {relay_stats}")
|
|
216
216
|
print(
|
|
217
|
-
f"[{datetime.now().isoformat()}] EventBus relay stats: {relay_stats}",
|
|
217
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBus relay stats: {relay_stats}",
|
|
218
218
|
flush=True,
|
|
219
219
|
)
|
|
220
220
|
else:
|
|
221
221
|
self.logger.warning("EventBus integration setup failed or disabled")
|
|
222
222
|
print(
|
|
223
|
-
f"[{datetime.now().isoformat()}] EventBus integration setup failed or disabled",
|
|
223
|
+
f"[{datetime.now(timezone.utc).isoformat()}] EventBus integration setup failed or disabled",
|
|
224
224
|
flush=True,
|
|
225
225
|
)
|
|
226
226
|
except Exception as e:
|
|
227
227
|
self.logger.error(f"Failed to setup EventBus integration: {e}")
|
|
228
228
|
print(
|
|
229
|
-
f"[{datetime.now().isoformat()}] Failed to setup EventBus integration: {e}",
|
|
229
|
+
f"[{datetime.now(timezone.utc).isoformat()}] Failed to setup EventBus integration: {e}",
|
|
230
230
|
flush=True,
|
|
231
231
|
)
|
|
232
232
|
import traceback
|
|
@@ -382,7 +382,7 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
382
382
|
# Track active session for heartbeat
|
|
383
383
|
self.active_sessions[session_id] = {
|
|
384
384
|
"session_id": session_id,
|
|
385
|
-
"start_time": datetime.now().isoformat(),
|
|
385
|
+
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
386
386
|
"agent": "pm", # Default to PM, will be updated if delegated
|
|
387
387
|
"status": "active",
|
|
388
388
|
"launch_method": launch_method,
|
|
@@ -472,7 +472,7 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
472
472
|
WHY: Provides session information for system heartbeat events.
|
|
473
473
|
"""
|
|
474
474
|
# Clean up old sessions (older than 1 hour)
|
|
475
|
-
cutoff_time = datetime.now().timestamp() - 3600
|
|
475
|
+
cutoff_time = datetime.now(timezone.utc).timestamp() - 3600
|
|
476
476
|
sessions_to_remove = []
|
|
477
477
|
|
|
478
478
|
for session_id, session_data in self.active_sessions.items():
|
|
@@ -480,7 +480,7 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
480
480
|
start_time = datetime.fromisoformat(session_data["start_time"])
|
|
481
481
|
if start_time.timestamp() < cutoff_time:
|
|
482
482
|
sessions_to_remove.append(session_id)
|
|
483
|
-
except:
|
|
483
|
+
except Exception:
|
|
484
484
|
pass
|
|
485
485
|
|
|
486
486
|
for session_id in sessions_to_remove:
|
|
@@ -18,7 +18,7 @@ import importlib.metadata
|
|
|
18
18
|
import socket
|
|
19
19
|
import threading
|
|
20
20
|
import time
|
|
21
|
-
from datetime import datetime
|
|
21
|
+
from datetime import datetime, timezone
|
|
22
22
|
from typing import Any, Dict, List, Optional, Tuple
|
|
23
23
|
|
|
24
24
|
from claude_mpm.core.constants import NetworkConfig, PerformanceConfig, TimeoutConfig
|
|
@@ -59,7 +59,7 @@ class ServerInfo:
|
|
|
59
59
|
"supported_client_versions", []
|
|
60
60
|
)
|
|
61
61
|
self.compatibility_matrix = response_data.get("compatibility_matrix", {})
|
|
62
|
-
self.detected_at = datetime.
|
|
62
|
+
self.detected_at = datetime.now(timezone.utc)
|
|
63
63
|
|
|
64
64
|
@property
|
|
65
65
|
def url(self) -> str:
|
|
@@ -161,7 +161,7 @@ class SocketIOClientManager:
|
|
|
161
161
|
self.logger.debug(f"Error checking {host}:{port}: {e}")
|
|
162
162
|
continue
|
|
163
163
|
|
|
164
|
-
self.last_discovery = datetime.
|
|
164
|
+
self.last_discovery = datetime.now(timezone.utc)
|
|
165
165
|
return discovered
|
|
166
166
|
|
|
167
167
|
def find_best_server(
|
|
@@ -323,7 +323,7 @@ class SocketIOClientManager:
|
|
|
323
323
|
try:
|
|
324
324
|
event_data = {
|
|
325
325
|
"type": event_type,
|
|
326
|
-
"timestamp": datetime.
|
|
326
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
327
327
|
"data": data,
|
|
328
328
|
"client_version": self.client_version,
|
|
329
329
|
}
|
|
@@ -10,7 +10,7 @@ Extracted from ClaudeRunner to follow Single Responsibility Principle.
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import re
|
|
13
|
-
from datetime import datetime
|
|
13
|
+
from datetime import datetime, timezone
|
|
14
14
|
from typing import List, Optional, Tuple
|
|
15
15
|
|
|
16
16
|
from claude_mpm.config.paths import paths
|
|
@@ -126,7 +126,7 @@ class SystemInstructionsService(BaseService, SystemInstructionsInterface):
|
|
|
126
126
|
|
|
127
127
|
# Replace current date
|
|
128
128
|
if "{{CURRENT_DATE}}" in base_pm_content:
|
|
129
|
-
current_date = datetime.now().strftime("%Y-%m-%d")
|
|
129
|
+
current_date = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
130
130
|
base_pm_content = base_pm_content.replace(
|
|
131
131
|
"{{CURRENT_DATE}}", current_date
|
|
132
132
|
)
|
|
@@ -14,7 +14,7 @@ Extracted from ClaudeRunner to follow Single Responsibility Principle.
|
|
|
14
14
|
import json
|
|
15
15
|
import re
|
|
16
16
|
import uuid
|
|
17
|
-
from datetime import datetime
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
18
|
from typing import Any, Dict, Optional, Tuple
|
|
19
19
|
|
|
20
20
|
from claude_mpm.core.base_service import BaseService
|
|
@@ -105,7 +105,10 @@ class UtilityService(BaseService, UtilityServiceInterface):
|
|
|
105
105
|
return
|
|
106
106
|
|
|
107
107
|
try:
|
|
108
|
-
log_entry = {
|
|
108
|
+
log_entry = {
|
|
109
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
110
|
+
**event_data,
|
|
111
|
+
}
|
|
109
112
|
|
|
110
113
|
with open(log_file, "a") as f:
|
|
111
114
|
f.write(json.dumps(log_entry) + "\n")
|
|
@@ -14,7 +14,7 @@ This module provides comprehensive branch strategy management including:
|
|
|
14
14
|
import logging
|
|
15
15
|
import re
|
|
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, Dict, List, Optional, Tuple
|
|
20
20
|
|
|
@@ -396,7 +396,7 @@ class BranchStrategyManager:
|
|
|
396
396
|
return f"{prefix}{ticket_id}"
|
|
397
397
|
if description:
|
|
398
398
|
return f"{prefix}{self._sanitize_branch_name(description)}"
|
|
399
|
-
return f"{prefix}{datetime.now().strftime('%Y%m%d')}"
|
|
399
|
+
return f"{prefix}{datetime.now(timezone.utc).strftime('%Y%m%d')}"
|
|
400
400
|
|
|
401
401
|
# Generate name based on rule
|
|
402
402
|
if strategy.strategy_type == BranchStrategyType.ISSUE_DRIVEN:
|
|
@@ -15,7 +15,7 @@ import logging
|
|
|
15
15
|
import os
|
|
16
16
|
import subprocess
|
|
17
17
|
from dataclasses import dataclass, field
|
|
18
|
-
from datetime import datetime
|
|
18
|
+
from datetime import datetime, timezone
|
|
19
19
|
from typing import Any, Dict, List, Optional
|
|
20
20
|
|
|
21
21
|
|
|
@@ -366,7 +366,7 @@ class GitOperationsManager:
|
|
|
366
366
|
Returns:
|
|
367
367
|
GitOperationResult with operation details
|
|
368
368
|
"""
|
|
369
|
-
start_time = datetime.now()
|
|
369
|
+
start_time = datetime.now(timezone.utc)
|
|
370
370
|
current_branch = self.get_current_branch()
|
|
371
371
|
|
|
372
372
|
# Generate full branch name with prefix
|
|
@@ -398,7 +398,7 @@ class GitOperationsManager:
|
|
|
398
398
|
# Remote push failed, continue without remote tracking
|
|
399
399
|
pass
|
|
400
400
|
|
|
401
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
401
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
402
402
|
|
|
403
403
|
return GitOperationResult(
|
|
404
404
|
success=True,
|
|
@@ -411,7 +411,7 @@ class GitOperationsManager:
|
|
|
411
411
|
)
|
|
412
412
|
|
|
413
413
|
except GitOperationError as e:
|
|
414
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
414
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
415
415
|
|
|
416
416
|
return GitOperationResult(
|
|
417
417
|
success=False,
|
|
@@ -433,7 +433,7 @@ class GitOperationsManager:
|
|
|
433
433
|
Returns:
|
|
434
434
|
GitOperationResult with operation details
|
|
435
435
|
"""
|
|
436
|
-
start_time = datetime.now()
|
|
436
|
+
start_time = datetime.now(timezone.utc)
|
|
437
437
|
current_branch = self.get_current_branch()
|
|
438
438
|
|
|
439
439
|
try:
|
|
@@ -448,13 +448,15 @@ class GitOperationsManager:
|
|
|
448
448
|
branch_before=current_branch,
|
|
449
449
|
branch_after=current_branch,
|
|
450
450
|
files_changed=modified_files,
|
|
451
|
-
execution_time=(
|
|
451
|
+
execution_time=(
|
|
452
|
+
datetime.now(timezone.utc) - start_time
|
|
453
|
+
).total_seconds(),
|
|
452
454
|
)
|
|
453
455
|
|
|
454
456
|
# Switch to the branch
|
|
455
457
|
result = self._run_git_command(["checkout", branch_name])
|
|
456
458
|
|
|
457
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
459
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
458
460
|
|
|
459
461
|
return GitOperationResult(
|
|
460
462
|
success=True,
|
|
@@ -467,7 +469,7 @@ class GitOperationsManager:
|
|
|
467
469
|
)
|
|
468
470
|
|
|
469
471
|
except GitOperationError as e:
|
|
470
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
472
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
471
473
|
|
|
472
474
|
return GitOperationResult(
|
|
473
475
|
success=False,
|
|
@@ -498,7 +500,7 @@ class GitOperationsManager:
|
|
|
498
500
|
Returns:
|
|
499
501
|
GitOperationResult with operation details
|
|
500
502
|
"""
|
|
501
|
-
start_time = datetime.now()
|
|
503
|
+
start_time = datetime.now(timezone.utc)
|
|
502
504
|
current_branch = self.get_current_branch()
|
|
503
505
|
|
|
504
506
|
try:
|
|
@@ -542,7 +544,7 @@ class GitOperationsManager:
|
|
|
542
544
|
# Branch deletion failed, but merge was successful
|
|
543
545
|
pass
|
|
544
546
|
|
|
545
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
547
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
546
548
|
|
|
547
549
|
return GitOperationResult(
|
|
548
550
|
success=True,
|
|
@@ -555,7 +557,7 @@ class GitOperationsManager:
|
|
|
555
557
|
)
|
|
556
558
|
|
|
557
559
|
except GitOperationError as e:
|
|
558
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
560
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
559
561
|
|
|
560
562
|
return GitOperationResult(
|
|
561
563
|
success=False,
|
|
@@ -651,7 +653,7 @@ class GitOperationsManager:
|
|
|
651
653
|
Returns:
|
|
652
654
|
GitOperationResult with operation details
|
|
653
655
|
"""
|
|
654
|
-
start_time = datetime.now()
|
|
656
|
+
start_time = datetime.now(timezone.utc)
|
|
655
657
|
current_branch = self.get_current_branch()
|
|
656
658
|
|
|
657
659
|
if not branch_name:
|
|
@@ -668,7 +670,7 @@ class GitOperationsManager:
|
|
|
668
670
|
|
|
669
671
|
result = self._run_git_command(push_args)
|
|
670
672
|
|
|
671
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
673
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
672
674
|
|
|
673
675
|
return GitOperationResult(
|
|
674
676
|
success=True,
|
|
@@ -681,7 +683,7 @@ class GitOperationsManager:
|
|
|
681
683
|
)
|
|
682
684
|
|
|
683
685
|
except GitOperationError as e:
|
|
684
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
686
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
685
687
|
|
|
686
688
|
return GitOperationResult(
|
|
687
689
|
success=False,
|
|
@@ -706,7 +708,7 @@ class GitOperationsManager:
|
|
|
706
708
|
Returns:
|
|
707
709
|
GitOperationResult with operation details
|
|
708
710
|
"""
|
|
709
|
-
start_time = datetime.now()
|
|
711
|
+
start_time = datetime.now(timezone.utc)
|
|
710
712
|
current_branch = self.get_current_branch()
|
|
711
713
|
|
|
712
714
|
if not branch_name:
|
|
@@ -725,7 +727,7 @@ class GitOperationsManager:
|
|
|
725
727
|
result = self._run_git_command(["pull", remote, branch_name])
|
|
726
728
|
self._run_git_command(["checkout", current_branch])
|
|
727
729
|
|
|
728
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
730
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
729
731
|
|
|
730
732
|
return GitOperationResult(
|
|
731
733
|
success=True,
|
|
@@ -738,7 +740,7 @@ class GitOperationsManager:
|
|
|
738
740
|
)
|
|
739
741
|
|
|
740
742
|
except GitOperationError as e:
|
|
741
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
743
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
742
744
|
|
|
743
745
|
return GitOperationResult(
|
|
744
746
|
success=False,
|
|
@@ -762,7 +764,7 @@ class GitOperationsManager:
|
|
|
762
764
|
Returns:
|
|
763
765
|
GitOperationResult with cleanup details
|
|
764
766
|
"""
|
|
765
|
-
start_time = datetime.now()
|
|
767
|
+
start_time = datetime.now(timezone.utc)
|
|
766
768
|
current_branch = self.get_current_branch()
|
|
767
769
|
|
|
768
770
|
try:
|
|
@@ -789,7 +791,7 @@ class GitOperationsManager:
|
|
|
789
791
|
# Clean up remote tracking branches
|
|
790
792
|
self._run_git_command(["remote", "prune", "origin"], check=False)
|
|
791
793
|
|
|
792
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
794
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
793
795
|
|
|
794
796
|
return GitOperationResult(
|
|
795
797
|
success=True,
|
|
@@ -802,7 +804,7 @@ class GitOperationsManager:
|
|
|
802
804
|
)
|
|
803
805
|
|
|
804
806
|
except GitOperationError as e:
|
|
805
|
-
execution_time = (datetime.now() - start_time).total_seconds()
|
|
807
|
+
execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
806
808
|
|
|
807
809
|
return GitOperationResult(
|
|
808
810
|
success=False,
|
|
@@ -42,7 +42,7 @@ Change Analysis:
|
|
|
42
42
|
import logging
|
|
43
43
|
import re
|
|
44
44
|
from dataclasses import dataclass, field
|
|
45
|
-
from datetime import datetime
|
|
45
|
+
from datetime import datetime, timezone
|
|
46
46
|
from enum import Enum
|
|
47
47
|
from typing import Dict, List, Optional, Tuple
|
|
48
48
|
|
|
@@ -100,7 +100,7 @@ class SemanticVersion:
|
|
|
100
100
|
version += f"+{self.build}"
|
|
101
101
|
return version
|
|
102
102
|
|
|
103
|
-
def __lt__(self, other: "SemanticVersion") -> bool:
|
|
103
|
+
def __lt__(self, other: "SemanticVersion") -> bool: # noqa: PLR0911
|
|
104
104
|
"""Compare versions for sorting according to semver precedence.
|
|
105
105
|
|
|
106
106
|
Comparison Rules:
|
|
@@ -748,7 +748,7 @@ class SemanticVersionManager:
|
|
|
748
748
|
Returns:
|
|
749
749
|
Formatted changelog entry
|
|
750
750
|
"""
|
|
751
|
-
date_str = datetime.now().strftime("%Y-%m-%d")
|
|
751
|
+
date_str = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
752
752
|
if metadata and metadata.release_date:
|
|
753
753
|
date_str = metadata.release_date.strftime("%Y-%m-%d")
|
|
754
754
|
|
|
@@ -20,7 +20,7 @@ import json
|
|
|
20
20
|
import logging
|
|
21
21
|
import re
|
|
22
22
|
import subprocess
|
|
23
|
-
from datetime import datetime, timedelta
|
|
23
|
+
from datetime import datetime, timedelta, timezone
|
|
24
24
|
from functools import lru_cache
|
|
25
25
|
from typing import Dict, List, Optional, Tuple
|
|
26
26
|
|
|
@@ -61,7 +61,7 @@ class VersionMetadata:
|
|
|
61
61
|
):
|
|
62
62
|
self.version = version
|
|
63
63
|
self.source = source
|
|
64
|
-
self.release_date = release_date or datetime.now()
|
|
64
|
+
self.release_date = release_date or datetime.now(timezone.utc)
|
|
65
65
|
self.commit_hash = commit_hash
|
|
66
66
|
self.author = author
|
|
67
67
|
self.message = message
|
|
@@ -119,14 +119,16 @@ class EnhancedVersionParser:
|
|
|
119
119
|
"""Get cached value if still valid."""
|
|
120
120
|
if key in self._cache:
|
|
121
121
|
timestamp, value = self._cache[key]
|
|
122
|
-
if datetime.now() - timestamp < timedelta(
|
|
122
|
+
if datetime.now(timezone.utc) - timestamp < timedelta(
|
|
123
|
+
seconds=self.cache_ttl
|
|
124
|
+
):
|
|
123
125
|
return value
|
|
124
126
|
del self._cache[key]
|
|
125
127
|
return None
|
|
126
128
|
|
|
127
129
|
def _set_cached(self, key: str, value: any) -> any:
|
|
128
130
|
"""Set cached value with timestamp."""
|
|
129
|
-
self._cache[key] = (datetime.now(), value)
|
|
131
|
+
self._cache[key] = (datetime.now(timezone.utc), value)
|
|
130
132
|
return value
|
|
131
133
|
|
|
132
134
|
def get_current_version(
|
|
@@ -332,7 +334,7 @@ class EnhancedVersionParser:
|
|
|
332
334
|
)
|
|
333
335
|
if result.returncode == 0:
|
|
334
336
|
commit_hash = result.stdout.strip()[:7]
|
|
335
|
-
except:
|
|
337
|
+
except Exception:
|
|
336
338
|
pass
|
|
337
339
|
|
|
338
340
|
return VersionMetadata(
|
|
@@ -801,7 +801,9 @@ class MermaidGeneratorService(SyncBaseService):
|
|
|
801
801
|
|
|
802
802
|
return False
|
|
803
803
|
|
|
804
|
-
def validate_mermaid_syntax(
|
|
804
|
+
def validate_mermaid_syntax(
|
|
805
|
+
self, diagram: str
|
|
806
|
+
) -> Tuple[bool, Optional[str]]:
|
|
805
807
|
"""
|
|
806
808
|
Validate that the generated Mermaid syntax is correct.
|
|
807
809
|
|
|
@@ -19,6 +19,7 @@ import hashlib
|
|
|
19
19
|
import json
|
|
20
20
|
import time
|
|
21
21
|
from dataclasses import dataclass
|
|
22
|
+
from datetime import timezone
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
from typing import Any, Dict, List, Optional
|
|
24
25
|
|
|
@@ -272,7 +273,9 @@ class GitignoreManager:
|
|
|
272
273
|
|
|
273
274
|
return patterns
|
|
274
275
|
|
|
275
|
-
def _basic_should_ignore(
|
|
276
|
+
def _basic_should_ignore(
|
|
277
|
+
self, path: Path, working_dir: Path
|
|
278
|
+
) -> bool:
|
|
276
279
|
"""Basic pattern matching fallback when pathspec is not available.
|
|
277
280
|
|
|
278
281
|
Args:
|
|
@@ -608,7 +611,9 @@ class PythonAnalyzer:
|
|
|
608
611
|
|
|
609
612
|
return nodes
|
|
610
613
|
|
|
611
|
-
def _get_assignment_signature(
|
|
614
|
+
def _get_assignment_signature(
|
|
615
|
+
self, node: ast.Assign, var_name: str
|
|
616
|
+
) -> str:
|
|
612
617
|
"""Get assignment signature string."""
|
|
613
618
|
try:
|
|
614
619
|
# Try to get a simple representation of the value
|
|
@@ -623,7 +628,7 @@ class PythonAnalyzer:
|
|
|
623
628
|
if isinstance(node.value, ast.Dict):
|
|
624
629
|
return f"{var_name} = {{...}}"
|
|
625
630
|
return f"{var_name} = ..."
|
|
626
|
-
except:
|
|
631
|
+
except Exception:
|
|
627
632
|
return f"{var_name} = ..."
|
|
628
633
|
|
|
629
634
|
|
|
@@ -1292,7 +1297,7 @@ class CodeTreeAnalyzer:
|
|
|
1292
1297
|
|
|
1293
1298
|
# Emit discovery start event
|
|
1294
1299
|
if self.emitter:
|
|
1295
|
-
from datetime import datetime
|
|
1300
|
+
from datetime import datetime, timezone
|
|
1296
1301
|
|
|
1297
1302
|
self.emitter.emit(
|
|
1298
1303
|
"info",
|
|
@@ -1301,7 +1306,7 @@ class CodeTreeAnalyzer:
|
|
|
1301
1306
|
"action": "scanning_directory",
|
|
1302
1307
|
"path": str(directory),
|
|
1303
1308
|
"message": f"Starting discovery of {directory.name}",
|
|
1304
|
-
"timestamp": datetime.now().isoformat(),
|
|
1309
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1305
1310
|
},
|
|
1306
1311
|
)
|
|
1307
1312
|
|
|
@@ -1336,7 +1341,7 @@ class CodeTreeAnalyzer:
|
|
|
1336
1341
|
"path": str(item),
|
|
1337
1342
|
"reason": "gitignore pattern",
|
|
1338
1343
|
"message": f"Ignored by gitignore: {item.name}",
|
|
1339
|
-
"timestamp": datetime.now().isoformat(),
|
|
1344
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1340
1345
|
},
|
|
1341
1346
|
)
|
|
1342
1347
|
ignored_count += 1
|
|
@@ -1354,7 +1359,7 @@ class CodeTreeAnalyzer:
|
|
|
1354
1359
|
"path": str(item),
|
|
1355
1360
|
"reason": "custom pattern",
|
|
1356
1361
|
"message": f"Ignored by pattern: {item.name}",
|
|
1357
|
-
"timestamp": datetime.now().isoformat(),
|
|
1362
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1358
1363
|
},
|
|
1359
1364
|
)
|
|
1360
1365
|
ignored_count += 1
|
|
@@ -1375,7 +1380,7 @@ class CodeTreeAnalyzer:
|
|
|
1375
1380
|
"path": str(item.name),
|
|
1376
1381
|
"reason": "no code files",
|
|
1377
1382
|
"message": f"Skipped directory without code: {item.name}",
|
|
1378
|
-
"timestamp": datetime.now().isoformat(),
|
|
1383
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1379
1384
|
},
|
|
1380
1385
|
)
|
|
1381
1386
|
ignored_count += 1
|
|
@@ -1395,7 +1400,7 @@ class CodeTreeAnalyzer:
|
|
|
1395
1400
|
"type": "discovery.directory",
|
|
1396
1401
|
"path": str(item),
|
|
1397
1402
|
"message": f"Found directory: {item.name}",
|
|
1398
|
-
"timestamp": datetime.now().isoformat(),
|
|
1403
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1399
1404
|
},
|
|
1400
1405
|
)
|
|
1401
1406
|
dirs_count += 1
|
|
@@ -1441,7 +1446,7 @@ class CodeTreeAnalyzer:
|
|
|
1441
1446
|
"language": language,
|
|
1442
1447
|
"size": item.stat().st_size,
|
|
1443
1448
|
"message": f"Found file: {item.name} ({language})",
|
|
1444
|
-
"timestamp": datetime.now().isoformat(),
|
|
1449
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1445
1450
|
},
|
|
1446
1451
|
)
|
|
1447
1452
|
files_count += 1
|
|
@@ -1481,7 +1486,7 @@ class CodeTreeAnalyzer:
|
|
|
1481
1486
|
"ignored": ignored_count,
|
|
1482
1487
|
},
|
|
1483
1488
|
"message": f"Discovery complete: {files_count} files, {dirs_count} directories, {ignored_count} ignored",
|
|
1484
|
-
"timestamp": datetime.now().isoformat(),
|
|
1489
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1485
1490
|
},
|
|
1486
1491
|
)
|
|
1487
1492
|
|
|
@@ -1538,7 +1543,7 @@ class CodeTreeAnalyzer:
|
|
|
1538
1543
|
"file": str(path),
|
|
1539
1544
|
"language": language,
|
|
1540
1545
|
"message": f"Analyzing: {path.name}",
|
|
1541
|
-
"timestamp": datetime.now().isoformat(),
|
|
1546
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1542
1547
|
},
|
|
1543
1548
|
)
|
|
1544
1549
|
|
|
@@ -1557,7 +1562,7 @@ class CodeTreeAnalyzer:
|
|
|
1557
1562
|
"type": "cache.hit",
|
|
1558
1563
|
"file": str(path),
|
|
1559
1564
|
"message": f"Using cached analysis for {path.name}",
|
|
1560
|
-
"timestamp": datetime.now().isoformat(),
|
|
1565
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1561
1566
|
},
|
|
1562
1567
|
)
|
|
1563
1568
|
else:
|
|
@@ -1571,7 +1576,7 @@ class CodeTreeAnalyzer:
|
|
|
1571
1576
|
"type": "cache.miss",
|
|
1572
1577
|
"file": str(path),
|
|
1573
1578
|
"message": f"Cache miss, analyzing fresh: {path.name}",
|
|
1574
|
-
"timestamp": datetime.now().isoformat(),
|
|
1579
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1575
1580
|
},
|
|
1576
1581
|
)
|
|
1577
1582
|
|
|
@@ -1594,7 +1599,7 @@ class CodeTreeAnalyzer:
|
|
|
1594
1599
|
"type": "analysis.parse",
|
|
1595
1600
|
"file": str(path),
|
|
1596
1601
|
"message": f"Parsing file content: {path.name}",
|
|
1597
|
-
"timestamp": datetime.now().isoformat(),
|
|
1602
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1598
1603
|
},
|
|
1599
1604
|
)
|
|
1600
1605
|
|
|
@@ -1626,7 +1631,7 @@ class CodeTreeAnalyzer:
|
|
|
1626
1631
|
"line_start": node.line_start,
|
|
1627
1632
|
"complexity": node.complexity,
|
|
1628
1633
|
"message": f"Found {node.node_type}: {node.name}",
|
|
1629
|
-
"timestamp": datetime.now().isoformat(),
|
|
1634
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1630
1635
|
},
|
|
1631
1636
|
)
|
|
1632
1637
|
|
|
@@ -1667,7 +1672,7 @@ class CodeTreeAnalyzer:
|
|
|
1667
1672
|
},
|
|
1668
1673
|
"duration": duration,
|
|
1669
1674
|
"message": f"Analysis complete: {classes_count} classes, {functions_count} functions, {methods_count} methods",
|
|
1670
|
-
"timestamp": datetime.now().isoformat(),
|
|
1675
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1671
1676
|
},
|
|
1672
1677
|
)
|
|
1673
1678
|
|
|
@@ -1725,7 +1730,7 @@ class CodeTreeAnalyzer:
|
|
|
1725
1730
|
},
|
|
1726
1731
|
}
|
|
1727
1732
|
|
|
1728
|
-
def _is_internal_node(self, node: CodeNode) -> bool:
|
|
1733
|
+
def _is_internal_node(self, node: CodeNode) -> bool: # noqa: PLR0911
|
|
1729
1734
|
"""Check if node is an internal function that should be filtered."""
|
|
1730
1735
|
# Don't filter classes - always show them
|
|
1731
1736
|
if node.node_type == "class":
|
|
@@ -17,7 +17,7 @@ import fnmatch
|
|
|
17
17
|
import hashlib
|
|
18
18
|
import json
|
|
19
19
|
from dataclasses import dataclass, field
|
|
20
|
-
from datetime import datetime
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
21
|
from pathlib import Path
|
|
22
22
|
from typing import Any, Dict, List, Optional, Set
|
|
23
23
|
|
|
@@ -505,7 +505,7 @@ class CodeTreeBuilder:
|
|
|
505
505
|
"files_ignored": self.stats["files_ignored"],
|
|
506
506
|
"total_size": self.stats["total_size"],
|
|
507
507
|
"languages": list(self.stats["languages"]),
|
|
508
|
-
"generated_at": datetime.
|
|
508
|
+
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
509
509
|
}
|
|
510
510
|
|
|
511
511
|
with open(output_path, "w") as f:
|