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.
Files changed (206) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +414 -28
  3. claude_mpm/agents/templates/data_engineer.json +39 -14
  4. claude_mpm/agents/templates/engineer.json +11 -3
  5. claude_mpm/cli/commands/agent_manager.py +3 -3
  6. claude_mpm/cli/commands/agents.py +2 -2
  7. claude_mpm/cli/commands/aggregate.py +1 -1
  8. claude_mpm/cli/commands/config.py +2 -2
  9. claude_mpm/cli/commands/configure.py +5 -5
  10. claude_mpm/cli/commands/configure_tui.py +7 -7
  11. claude_mpm/cli/commands/dashboard.py +1 -1
  12. claude_mpm/cli/commands/debug.py +5 -5
  13. claude_mpm/cli/commands/mcp.py +1 -1
  14. claude_mpm/cli/commands/mcp_command_router.py +1 -1
  15. claude_mpm/cli/commands/mcp_config.py +7 -10
  16. claude_mpm/cli/commands/mcp_external_commands.py +40 -32
  17. claude_mpm/cli/commands/mcp_install_commands.py +38 -10
  18. claude_mpm/cli/commands/mcp_setup_external.py +143 -102
  19. claude_mpm/cli/commands/monitor.py +2 -2
  20. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  21. claude_mpm/cli/commands/run.py +54 -2
  22. claude_mpm/cli/commands/search.py +41 -34
  23. claude_mpm/cli/interactive/agent_wizard.py +6 -2
  24. claude_mpm/cli/parsers/mcp_parser.py +1 -3
  25. claude_mpm/cli/parsers/search_parser.py +10 -4
  26. claude_mpm/cli/startup_logging.py +158 -5
  27. claude_mpm/cli/utils.py +1 -1
  28. claude_mpm/core/agent_registry.py +2 -2
  29. claude_mpm/core/agent_session_manager.py +8 -8
  30. claude_mpm/core/api_validator.py +6 -4
  31. claude_mpm/core/base_service.py +10 -10
  32. claude_mpm/core/cache.py +5 -5
  33. claude_mpm/core/config_constants.py +1 -1
  34. claude_mpm/core/container.py +1 -1
  35. claude_mpm/core/error_handler.py +2 -2
  36. claude_mpm/core/file_utils.py +1 -1
  37. claude_mpm/core/framework_loader.py +3 -3
  38. claude_mpm/core/hook_manager.py +8 -6
  39. claude_mpm/core/instruction_reinforcement_hook.py +2 -2
  40. claude_mpm/core/interactive_session.py +3 -1
  41. claude_mpm/core/lazy.py +3 -3
  42. claude_mpm/core/log_manager.py +16 -12
  43. claude_mpm/core/logger.py +16 -11
  44. claude_mpm/core/optimized_agent_loader.py +6 -6
  45. claude_mpm/core/output_style_manager.py +1 -1
  46. claude_mpm/core/pm_hook_interceptor.py +3 -3
  47. claude_mpm/core/service_registry.py +1 -1
  48. claude_mpm/core/session_manager.py +11 -9
  49. claude_mpm/core/socketio_pool.py +13 -13
  50. claude_mpm/core/types.py +2 -2
  51. claude_mpm/core/unified_agent_registry.py +2 -2
  52. claude_mpm/core/unified_paths.py +1 -1
  53. claude_mpm/dashboard/analysis_runner.py +4 -4
  54. claude_mpm/dashboard/api/simple_directory.py +1 -1
  55. claude_mpm/generators/agent_profile_generator.py +4 -2
  56. claude_mpm/hooks/base_hook.py +2 -2
  57. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  58. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  59. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  60. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
  61. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  62. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  63. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  64. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  65. claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
  66. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
  67. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
  68. claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
  69. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
  70. claude_mpm/hooks/claude_hooks/installer.py +3 -3
  71. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  72. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
  73. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  74. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
  75. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  76. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  77. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  78. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  79. claude_mpm/hooks/claude_hooks/services/connection_manager.py +8 -5
  80. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
  81. claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
  82. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  83. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  84. claude_mpm/hooks/memory_integration_hook.py +1 -1
  85. claude_mpm/hooks/tool_call_interceptor.py +2 -2
  86. claude_mpm/models/agent_session.py +7 -5
  87. claude_mpm/scripts/mcp_server.py +0 -0
  88. claude_mpm/scripts/start_activity_logging.py +0 -0
  89. claude_mpm/services/__init__.py +1 -1
  90. claude_mpm/services/agent_capabilities_service.py +1 -1
  91. claude_mpm/services/agents/agent_builder.py +3 -3
  92. claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
  93. claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
  94. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
  95. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
  96. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  97. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  98. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  99. claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
  100. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  101. claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
  102. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
  103. claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
  104. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  105. claude_mpm/services/agents/local_template_manager.py +6 -6
  106. claude_mpm/services/agents/management/agent_management_service.py +3 -3
  107. claude_mpm/services/agents/memory/content_manager.py +3 -3
  108. claude_mpm/services/agents/memory/memory_format_service.py +2 -2
  109. claude_mpm/services/agents/memory/template_generator.py +3 -3
  110. claude_mpm/services/agents/registry/modification_tracker.py +2 -2
  111. claude_mpm/services/async_session_logger.py +3 -3
  112. claude_mpm/services/claude_session_logger.py +4 -4
  113. claude_mpm/services/cli/agent_listing_service.py +3 -1
  114. claude_mpm/services/cli/agent_validation_service.py +2 -0
  115. claude_mpm/services/cli/memory_crud_service.py +11 -6
  116. claude_mpm/services/cli/memory_output_formatter.py +1 -1
  117. claude_mpm/services/cli/session_manager.py +15 -11
  118. claude_mpm/services/core/memory_manager.py +81 -23
  119. claude_mpm/services/core/path_resolver.py +1 -1
  120. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  121. claude_mpm/services/event_aggregator.py +4 -2
  122. claude_mpm/services/event_bus/direct_relay.py +5 -3
  123. claude_mpm/services/event_bus/event_bus.py +3 -3
  124. claude_mpm/services/event_bus/relay.py +6 -4
  125. claude_mpm/services/events/consumers/dead_letter.py +5 -3
  126. claude_mpm/services/events/core.py +3 -3
  127. claude_mpm/services/events/producers/hook.py +6 -6
  128. claude_mpm/services/events/producers/system.py +8 -8
  129. claude_mpm/services/exceptions.py +5 -5
  130. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
  131. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  132. claude_mpm/services/hook_installer_service.py +1 -1
  133. claude_mpm/services/infrastructure/context_preservation.py +6 -4
  134. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  135. claude_mpm/services/infrastructure/logging.py +2 -2
  136. claude_mpm/services/mcp_config_manager.py +175 -30
  137. claude_mpm/services/mcp_gateway/__init__.py +1 -1
  138. claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
  139. claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
  140. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  141. claude_mpm/services/mcp_gateway/core/base.py +2 -2
  142. claude_mpm/services/mcp_gateway/main.py +21 -7
  143. claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
  144. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  145. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  146. claude_mpm/services/mcp_gateway/server/stdio_server.py +5 -2
  147. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  148. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
  149. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
  150. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
  151. claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
  152. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
  153. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +16 -16
  154. claude_mpm/services/memory/builder.py +7 -5
  155. claude_mpm/services/memory/indexed_memory.py +4 -4
  156. claude_mpm/services/memory/optimizer.py +6 -6
  157. claude_mpm/services/memory/router.py +3 -3
  158. claude_mpm/services/monitor/daemon.py +1 -1
  159. claude_mpm/services/monitor/daemon_manager.py +6 -6
  160. claude_mpm/services/monitor/event_emitter.py +2 -2
  161. claude_mpm/services/monitor/management/lifecycle.py +3 -1
  162. claude_mpm/services/monitor/server.py +4 -4
  163. claude_mpm/services/monitor_build_service.py +2 -2
  164. claude_mpm/services/port_manager.py +3 -1
  165. claude_mpm/services/response_tracker.py +2 -2
  166. claude_mpm/services/session_management_service.py +3 -2
  167. claude_mpm/services/socketio/client_proxy.py +2 -2
  168. claude_mpm/services/socketio/dashboard_server.py +4 -3
  169. claude_mpm/services/socketio/event_normalizer.py +11 -7
  170. claude_mpm/services/socketio/handlers/base.py +2 -2
  171. claude_mpm/services/socketio/handlers/connection.py +10 -10
  172. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  173. claude_mpm/services/socketio/handlers/hook.py +16 -15
  174. claude_mpm/services/socketio/migration_utils.py +1 -1
  175. claude_mpm/services/socketio/monitor_client.py +5 -5
  176. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  177. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  178. claude_mpm/services/socketio/server/core.py +7 -5
  179. claude_mpm/services/socketio/server/eventbus_integration.py +18 -12
  180. claude_mpm/services/socketio/server/main.py +13 -13
  181. claude_mpm/services/socketio_client_manager.py +4 -4
  182. claude_mpm/services/system_instructions_service.py +2 -2
  183. claude_mpm/services/utility_service.py +5 -2
  184. claude_mpm/services/version_control/branch_strategy.py +2 -2
  185. claude_mpm/services/version_control/git_operations.py +22 -20
  186. claude_mpm/services/version_control/semantic_versioning.py +3 -3
  187. claude_mpm/services/version_control/version_parser.py +7 -5
  188. claude_mpm/services/visualization/mermaid_generator.py +3 -1
  189. claude_mpm/storage/state_storage.py +1 -1
  190. claude_mpm/tools/code_tree_analyzer.py +23 -18
  191. claude_mpm/tools/code_tree_builder.py +2 -2
  192. claude_mpm/tools/code_tree_events.py +10 -8
  193. claude_mpm/tools/socketio_debug.py +3 -3
  194. claude_mpm/utils/agent_dependency_loader.py +6 -2
  195. claude_mpm/utils/dependency_strategies.py +8 -3
  196. claude_mpm/utils/environment_context.py +1 -1
  197. claude_mpm/utils/error_handler.py +2 -2
  198. claude_mpm/utils/file_utils.py +1 -1
  199. claude_mpm/utils/log_cleanup.py +21 -7
  200. claude_mpm/validation/agent_validator.py +2 -2
  201. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/METADATA +1 -1
  202. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/RECORD +204 -191
  203. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/WHEEL +0 -0
  204. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/entry_points.txt +0 -0
  205. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/licenses/LICENSE +0 -0
  206. {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.utcnow()
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.utcnow()
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.utcnow().isoformat() + "Z",
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 = {"timestamp": datetime.now().isoformat(), **event_data}
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=(datetime.now() - start_time).total_seconds(),
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(seconds=self.cache_ttl):
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(self, diagram: str) -> Tuple[bool, Optional[str]]:
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
 
@@ -397,7 +397,7 @@ class StateStorage:
397
397
  temp_file.unlink()
398
398
  cleaned += 1
399
399
  self.logger.debug(f"Cleaned up temp file: {temp_file}")
400
- except:
400
+ except Exception:
401
401
  pass
402
402
 
403
403
  # Clean up orphaned checksum files
@@ -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(self, path: Path, working_dir: Path) -> bool:
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(self, node: ast.Assign, var_name: str) -> str:
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.utcnow().isoformat(),
508
+ "generated_at": datetime.now(timezone.utc).isoformat(),
509
509
  }
510
510
 
511
511
  with open(output_path, "w") as f: