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
@@ -26,7 +26,7 @@ import traceback
26
26
  from abc import ABC, abstractmethod
27
27
  from contextlib import asynccontextmanager
28
28
  from dataclasses import dataclass, field
29
- from datetime import datetime, timedelta
29
+ from datetime import datetime, timedelta, timezone
30
30
  from pathlib import Path
31
31
  from typing import Any, Dict, List, Optional
32
32
 
@@ -144,7 +144,7 @@ class BaseService(LoggerMixin, ABC):
144
144
  self._health = ServiceHealth(
145
145
  status="unknown",
146
146
  message="Service not started",
147
- timestamp=datetime.now().isoformat(),
147
+ timestamp=datetime.now(timezone.utc).isoformat(),
148
148
  )
149
149
  self._metrics = ServiceMetrics()
150
150
  self._last_health_check: Optional[float] = None
@@ -199,7 +199,7 @@ class BaseService(LoggerMixin, ABC):
199
199
  def uptime(self) -> Optional[float]:
200
200
  """Get service uptime in seconds."""
201
201
  if self._start_time and self._running:
202
- return (datetime.now() - self._start_time).total_seconds()
202
+ return (datetime.now(timezone.utc) - self._start_time).total_seconds()
203
203
  return None
204
204
 
205
205
  @property
@@ -237,7 +237,7 @@ class BaseService(LoggerMixin, ABC):
237
237
  self._health = ServiceHealth(
238
238
  status="unhealthy",
239
239
  message=f"Startup failed: {e!s}",
240
- timestamp=datetime.now().isoformat(),
240
+ timestamp=datetime.now(timezone.utc).isoformat(),
241
241
  checks={"startup": False},
242
242
  )
243
243
 
@@ -268,13 +268,13 @@ class BaseService(LoggerMixin, ABC):
268
268
 
269
269
  # Mark as running
270
270
  self._running = True
271
- self._start_time = datetime.now()
271
+ self._start_time = datetime.now(timezone.utc)
272
272
 
273
273
  # Update health status
274
274
  self._health = ServiceHealth(
275
275
  status="healthy",
276
276
  message="Service started successfully",
277
- timestamp=datetime.now().isoformat(),
277
+ timestamp=datetime.now(timezone.utc).isoformat(),
278
278
  checks={"startup": True},
279
279
  metrics=self._get_health_metrics() if self._enable_enhanced else {},
280
280
  )
@@ -338,7 +338,7 @@ class BaseService(LoggerMixin, ABC):
338
338
  self._health = ServiceHealth(
339
339
  status="unknown",
340
340
  message="Service stopped",
341
- timestamp=datetime.now().isoformat(),
341
+ timestamp=datetime.now(timezone.utc).isoformat(),
342
342
  checks={"running": False},
343
343
  )
344
344
 
@@ -388,7 +388,7 @@ class BaseService(LoggerMixin, ABC):
388
388
  self._health = ServiceHealth(
389
389
  status=status,
390
390
  message=message,
391
- timestamp=datetime.now().isoformat(),
391
+ timestamp=datetime.now(timezone.utc).isoformat(),
392
392
  checks=checks,
393
393
  metrics={
394
394
  "uptime": self.uptime,
@@ -404,7 +404,7 @@ class BaseService(LoggerMixin, ABC):
404
404
  self._health = ServiceHealth(
405
405
  status="unhealthy",
406
406
  message=f"Health check error: {e!s}",
407
- timestamp=datetime.now().isoformat(),
407
+ timestamp=datetime.now(timezone.utc).isoformat(),
408
408
  checks={"health_check_error": True},
409
409
  )
410
410
  return self._health
@@ -586,7 +586,7 @@ class BaseService(LoggerMixin, ABC):
586
586
  return ServiceHealth(
587
587
  status="degraded",
588
588
  message="Service circuit breaker is open",
589
- timestamp=datetime.now().isoformat(),
589
+ timestamp=datetime.now(timezone.utc).isoformat(),
590
590
  checks={"circuit_breaker": False},
591
591
  metrics=self._get_health_metrics(),
592
592
  )
claude_mpm/core/cache.py CHANGED
@@ -19,7 +19,7 @@ import pickle
19
19
  import threading
20
20
  from collections import OrderedDict
21
21
  from dataclasses import dataclass, field
22
- from datetime import datetime
22
+ from datetime import datetime, timezone
23
23
  from typing import Any, Callable, Dict, Optional, TypeVar, Union
24
24
 
25
25
  from ..core.logger import get_logger
@@ -43,12 +43,12 @@ class CacheEntry:
43
43
  """Check if entry has expired based on TTL."""
44
44
  if self.ttl is None:
45
45
  return False
46
- age = (datetime.now() - self.created_at).total_seconds()
46
+ age = (datetime.now(timezone.utc) - self.created_at).total_seconds()
47
47
  return age > self.ttl
48
48
 
49
49
  def touch(self):
50
50
  """Update last access time and increment counter."""
51
- self.last_accessed = datetime.now()
51
+ self.last_accessed = datetime.now(timezone.utc)
52
52
  self.access_count += 1
53
53
 
54
54
 
@@ -129,13 +129,13 @@ class FileSystemCache:
129
129
  # Rough estimate using JSON serialization
130
130
  try:
131
131
  return len(json.dumps(value))
132
- except:
132
+ except Exception:
133
133
  return 1000 # Default estimate
134
134
  else:
135
135
  # Use pickle for size estimation
136
136
  try:
137
137
  return len(pickle.dumps(value))
138
- except:
138
+ except Exception:
139
139
  return 100 # Default small size
140
140
 
141
141
  def _evict_lru(self):
@@ -99,7 +99,7 @@ class ConfigConstants:
99
99
  cls._config_service = config_service
100
100
 
101
101
  @classmethod
102
- def get_timeout(cls, timeout_type: str) -> int:
102
+ def get_timeout(cls, timeout_type: str) -> int: # noqa: PLR0911
103
103
  """
104
104
  Get timeout value by type.
105
105
 
@@ -636,7 +636,7 @@ class DIContainer(IServiceContainer):
636
636
  if reg_type.__name__ == param_type:
637
637
  param_type = reg_type
638
638
  break
639
- except:
639
+ except Exception:
640
640
  # If we can't resolve, skip this parameter
641
641
  if param.default != param.empty:
642
642
  kwargs[param_name] = param.default
@@ -384,7 +384,7 @@ def with_error_handling(
384
384
  if callable(fallback_value):
385
385
  try:
386
386
  fb_value = fallback_value(*args, **kwargs)
387
- except:
387
+ except Exception:
388
388
  fb_value = None
389
389
 
390
390
  return handle_error(
@@ -428,7 +428,7 @@ def safe_operation(
428
428
  if callable(fallback_value):
429
429
  try:
430
430
  return fallback_value(*args, **kwargs)
431
- except:
431
+ except Exception:
432
432
  return None
433
433
  return fallback_value
434
434
 
@@ -652,7 +652,7 @@ def file_lock(filepath: Union[str, Path], timeout: float = 5.0):
652
652
  fcntl.flock(lock_handle, fcntl.LOCK_UN)
653
653
  lock_handle.close()
654
654
  lock_file.unlink(missing_ok=True)
655
- except:
655
+ except Exception:
656
656
  pass
657
657
 
658
658
 
@@ -6,7 +6,7 @@ import logging
6
6
  import os
7
7
  import platform
8
8
  import time
9
- from datetime import datetime
9
+ from datetime import datetime, timezone
10
10
  from pathlib import Path
11
11
  from typing import Any, Dict, Optional
12
12
 
@@ -1432,7 +1432,7 @@ Extract tickets from these patterns:
1432
1432
 
1433
1433
  try:
1434
1434
  # Get current datetime with timezone awareness
1435
- now = datetime.now()
1435
+ now = datetime.now(timezone.utc)
1436
1436
 
1437
1437
  # Try to get timezone info - fallback to UTC offset if timezone name not available
1438
1438
  try:
@@ -1470,7 +1470,7 @@ Extract tickets from these patterns:
1470
1470
  # Fallback to basic date if enhanced datetime fails
1471
1471
  self.logger.debug(f"Error generating enhanced datetime context: {e}")
1472
1472
  context_lines.append(
1473
- f"**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
1473
+ f"**Today's Date**: {datetime.now(timezone.utc).strftime('%Y-%m-%d')}\n"
1474
1474
  )
1475
1475
 
1476
1476
  try:
@@ -19,7 +19,7 @@ import queue
19
19
  import subprocess
20
20
  import threading
21
21
  import uuid
22
- from datetime import datetime
22
+ from datetime import datetime, timezone
23
23
  from typing import Any, Dict, Optional
24
24
 
25
25
  from ..core.logger import get_logger
@@ -106,7 +106,9 @@ class HookManager:
106
106
  hook_event = {
107
107
  "hook_event_name": hook_type,
108
108
  "session_id": self.session_id,
109
- "timestamp": hook_data.get("timestamp", datetime.utcnow().isoformat()),
109
+ "timestamp": hook_data.get(
110
+ "timestamp", datetime.now(timezone.utc).isoformat()
111
+ ),
110
112
  **event_data,
111
113
  }
112
114
 
@@ -182,7 +184,7 @@ class HookManager:
182
184
  {
183
185
  "tool_name": tool_name,
184
186
  "tool_args": tool_args or {},
185
- "timestamp": datetime.utcnow().isoformat(),
187
+ "timestamp": datetime.now(timezone.utc).isoformat(),
186
188
  },
187
189
  )
188
190
 
@@ -205,7 +207,7 @@ class HookManager:
205
207
  "tool_name": tool_name,
206
208
  "exit_code": exit_code,
207
209
  "result": str(result) if result is not None else None,
208
- "timestamp": datetime.utcnow().isoformat(),
210
+ "timestamp": datetime.now(timezone.utc).isoformat(),
209
211
  },
210
212
  )
211
213
 
@@ -220,7 +222,7 @@ class HookManager:
220
222
  """
221
223
  return self._trigger_hook_event(
222
224
  "UserPromptSubmit",
223
- {"prompt": prompt, "timestamp": datetime.utcnow().isoformat()},
225
+ {"prompt": prompt, "timestamp": datetime.now(timezone.utc).isoformat()},
224
226
  )
225
227
 
226
228
  def _trigger_hook_event(self, hook_type: str, event_data: Dict[str, Any]) -> bool:
@@ -250,7 +252,7 @@ class HookManager:
250
252
  hook_data = {
251
253
  "hook_type": hook_type,
252
254
  "event_data": event_data,
253
- "timestamp": datetime.utcnow().isoformat(),
255
+ "timestamp": datetime.now(timezone.utc).isoformat(),
254
256
  }
255
257
 
256
258
  # Try to queue without blocking
@@ -18,7 +18,7 @@ The hook works by:
18
18
  """
19
19
 
20
20
  import threading
21
- from datetime import datetime
21
+ from datetime import datetime, timezone
22
22
  from typing import Any, Dict, List, Optional
23
23
 
24
24
  from ..core.logger import get_logger
@@ -197,7 +197,7 @@ class InstructionReinforcementHook:
197
197
  "enabled": self.enabled,
198
198
  "test_mode": self.test_mode,
199
199
  "injection_interval": self.injection_interval,
200
- "timestamp": datetime.utcnow().isoformat(),
200
+ "timestamp": datetime.now(timezone.utc).isoformat(),
201
201
  }
202
202
 
203
203
  def reset_counters(self):
@@ -154,7 +154,9 @@ class InteractiveSession:
154
154
  self.logger.error(error_msg)
155
155
  return False, {}
156
156
 
157
- def handle_interactive_input(self, environment: Dict[str, Any]) -> bool:
157
+ def handle_interactive_input(
158
+ self, environment: Dict[str, Any]
159
+ ) -> bool:
158
160
  """Handle the interactive input/output loop.
159
161
 
160
162
  Launches Claude and manages the interactive session using either
claude_mpm/core/lazy.py CHANGED
@@ -16,7 +16,7 @@ import functools
16
16
  import threading
17
17
  import time
18
18
  from dataclasses import dataclass, field
19
- from datetime import datetime
19
+ from datetime import datetime, timezone
20
20
  from typing import Any, Callable, Dict, Generic, Optional, Type, TypeVar
21
21
 
22
22
  from ..core.logger import get_logger
@@ -121,7 +121,7 @@ class LazyService(Generic[T]):
121
121
  # Track initialization
122
122
  start_time = time.time()
123
123
  if self._metrics.first_access is None:
124
- self._metrics.first_access = datetime.now()
124
+ self._metrics.first_access = datetime.now(timezone.utc)
125
125
 
126
126
  try:
127
127
  self._logger.debug(f"Initializing lazy service: {self._name}")
@@ -417,7 +417,7 @@ class AsyncLazyService(Generic[T]):
417
417
 
418
418
  start_time = time.time()
419
419
  if self._metrics.first_access is None:
420
- self._metrics.first_access = datetime.now()
420
+ self._metrics.first_access = datetime.now(timezone.utc)
421
421
 
422
422
  try:
423
423
  self._logger.debug(f"Async initializing: {self._name}")
@@ -18,7 +18,7 @@ import asyncio
18
18
  import json
19
19
  import logging
20
20
  import os
21
- from datetime import datetime, timedelta
21
+ from datetime import datetime, timedelta, timezone
22
22
  from pathlib import Path
23
23
  from queue import Full, Queue
24
24
  from threading import Lock, Thread
@@ -191,7 +191,7 @@ class LogManager:
191
191
  finally:
192
192
  self.write_queue.task_done()
193
193
 
194
- except:
194
+ except Exception:
195
195
  continue # Timeout or other error, continue loop
196
196
 
197
197
  def _process_cleanup_queue(self):
@@ -211,7 +211,7 @@ class LogManager:
211
211
  finally:
212
212
  self.cleanup_queue.task_done()
213
213
 
214
- except:
214
+ except Exception:
215
215
  continue # Timeout or other error, continue loop
216
216
 
217
217
  async def setup_logging(self, log_type: str) -> Path:
@@ -296,7 +296,7 @@ class LogManager:
296
296
  return 0
297
297
 
298
298
  # Calculate cutoff time
299
- cutoff_time = datetime.now() - timedelta(hours=retention_hours)
299
+ cutoff_time = datetime.now(timezone.utc) - timedelta(hours=retention_hours)
300
300
 
301
301
  # Schedule async cleanup
302
302
  deleted_count = await self._async_cleanup(directory, pattern, cutoff_time)
@@ -337,7 +337,9 @@ class LogManager:
337
337
 
338
338
  try:
339
339
  # Check file modification time
340
- mtime = datetime.fromtimestamp(file_path.stat().st_mtime)
340
+ mtime = datetime.fromtimestamp(
341
+ file_path.stat().st_mtime, tz=timezone.utc
342
+ )
341
343
  if mtime < cutoff_time:
342
344
  file_path.unlink()
343
345
  deleted_count += 1
@@ -370,7 +372,7 @@ class LogManager:
370
372
  return 0
371
373
 
372
374
  # Calculate cutoff time
373
- cutoff_time = datetime.now() - timedelta(hours=retention_hours)
375
+ cutoff_time = datetime.now(timezone.utc) - timedelta(hours=retention_hours)
374
376
  deleted_count = 0
375
377
 
376
378
  try:
@@ -386,7 +388,9 @@ class LogManager:
386
388
 
387
389
  try:
388
390
  # Check file modification time
389
- mtime = datetime.fromtimestamp(file_path.stat().st_mtime)
391
+ mtime = datetime.fromtimestamp(
392
+ file_path.stat().st_mtime, tz=timezone.utc
393
+ )
390
394
  if mtime < cutoff_time:
391
395
  file_path.unlink()
392
396
  deleted_count += 1
@@ -468,7 +472,7 @@ class LogManager:
468
472
  prompts_dir = await self.setup_logging("prompts")
469
473
 
470
474
  # Generate filename with timestamp
471
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[
475
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S_%f")[
472
476
  :-3
473
477
  ] # Microseconds to milliseconds
474
478
 
@@ -494,7 +498,7 @@ class LogManager:
494
498
 
495
499
  # Prepare prompt data
496
500
  prompt_data = {
497
- "timestamp": datetime.now().isoformat(),
501
+ "timestamp": datetime.now(timezone.utc).isoformat(),
498
502
  "type": prompt_type,
499
503
  "content": content,
500
504
  "metadata": metadata or {},
@@ -567,12 +571,12 @@ class LogManager:
567
571
  message: Log message to write
568
572
  level: Log level (INFO, WARNING, ERROR, DEBUG)
569
573
  """
570
- timestamp = datetime.now().isoformat()
574
+ timestamp = datetime.now(timezone.utc).isoformat()
571
575
  log_entry = f"[{timestamp}] [{level}] {message}\n"
572
576
 
573
577
  # Get appropriate log file based on context
574
578
  log_dir = self._get_log_directory("mpm")
575
- log_file = log_dir / f"mpm_{datetime.now().strftime('%Y%m%d')}.log"
579
+ log_file = log_dir / f"mpm_{datetime.now(timezone.utc).strftime('%Y%m%d')}.log"
576
580
 
577
581
  def write_task():
578
582
  try:
@@ -652,7 +656,7 @@ class LogManager:
652
656
  try:
653
657
  self.write_queue.put_nowait(None)
654
658
  self.cleanup_queue.put_nowait(None)
655
- except:
659
+ except Exception:
656
660
  pass
657
661
 
658
662
  # Wait for threads to finish
claude_mpm/core/logger.py CHANGED
@@ -14,7 +14,7 @@ import sys
14
14
  import threading
15
15
  import time
16
16
  from collections import defaultdict
17
- from datetime import datetime
17
+ from datetime import datetime, timezone
18
18
  from enum import Enum
19
19
  from pathlib import Path
20
20
  from typing import Any, Dict, Optional
@@ -84,7 +84,7 @@ class StreamingHandler(logging.StreamHandler):
84
84
 
85
85
  except (KeyboardInterrupt, SystemExit):
86
86
  raise
87
- except:
87
+ except Exception:
88
88
  self.handleError(record)
89
89
 
90
90
  def finalize_info_line(self):
@@ -237,7 +237,7 @@ def setup_logging(
237
237
  log_dir.mkdir(parents=True, exist_ok=True)
238
238
 
239
239
  # Create timestamped log file
240
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
240
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
241
241
  log_file = log_dir / f"mpm_{timestamp}.log"
242
242
 
243
243
  file_handler = logging.FileHandler(log_file)
@@ -485,8 +485,8 @@ class ProjectLogger:
485
485
  path.mkdir(parents=True, exist_ok=True)
486
486
 
487
487
  # Create session directory
488
- self.session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
489
- self.session_start_time = datetime.now()
488
+ self.session_id = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
489
+ self.session_start_time = datetime.now(timezone.utc)
490
490
  self.session_dir = self.dirs["logs_sessions"] / self.session_id
491
491
  self.session_dir.mkdir(parents=True, exist_ok=True)
492
492
 
@@ -513,7 +513,7 @@ class ProjectLogger:
513
513
  if self.log_level == LogLevel.OFF:
514
514
  return
515
515
 
516
- timestamp = datetime.now().isoformat()
516
+ timestamp = datetime.now(timezone.utc).isoformat()
517
517
  log_entry = {
518
518
  "timestamp": timestamp,
519
519
  "level": level,
@@ -523,7 +523,8 @@ class ProjectLogger:
523
523
 
524
524
  # Write to daily log file
525
525
  log_file = (
526
- self.dirs["logs_system"] / f"{datetime.now().strftime('%Y%m%d')}.jsonl"
526
+ self.dirs["logs_system"]
527
+ / f"{datetime.now(timezone.utc).strftime('%Y%m%d')}.jsonl"
527
528
  )
528
529
  with open(log_file, "a") as f:
529
530
  f.write(json.dumps(log_entry) + "\n")
@@ -543,10 +544,10 @@ class ProjectLogger:
543
544
  if self.log_level == LogLevel.OFF:
544
545
  return
545
546
 
546
- timestamp = datetime.now().isoformat()
547
+ timestamp = datetime.now(timezone.utc).isoformat()
547
548
 
548
549
  # Update statistics
549
- today = datetime.now().strftime("%Y-%m-%d")
550
+ today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
550
551
  self.stats[today]["total_calls"] += 1
551
552
  self.stats[today]["total_tokens"] += tokens
552
553
  self.stats[today]["total_time_seconds"] += execution_time
@@ -576,7 +577,9 @@ class ProjectLogger:
576
577
  agent_log_dir = self.dirs["logs_agents"] / agent.lower()
577
578
  agent_log_dir.mkdir(exist_ok=True)
578
579
 
579
- daily_log = agent_log_dir / f"{datetime.now().strftime('%Y%m%d')}.jsonl"
580
+ daily_log = (
581
+ agent_log_dir / f"{datetime.now(timezone.utc).strftime('%Y%m%d')}.jsonl"
582
+ )
580
583
  with open(daily_log, "a") as f:
581
584
  f.write(json.dumps(log_entry) + "\n")
582
585
 
@@ -586,7 +589,9 @@ class ProjectLogger:
586
589
  "session_id": self.session_id,
587
590
  "session_dir": str(self.session_dir),
588
591
  "start_time": self.session_id,
589
- "stats": self.stats.get(datetime.now().strftime("%Y-%m-%d"), {}),
592
+ "stats": self.stats.get(
593
+ datetime.now(timezone.utc).strftime("%Y-%m-%d"), {}
594
+ ),
590
595
  }
591
596
 
592
597
 
@@ -22,7 +22,7 @@ import threading
22
22
  import time
23
23
  from concurrent.futures import ThreadPoolExecutor, as_completed
24
24
  from dataclasses import dataclass
25
- from datetime import datetime
25
+ from datetime import datetime, timezone
26
26
  from typing import Any, Dict, List, Optional
27
27
 
28
28
  try:
@@ -111,7 +111,7 @@ class OptimizedAgentLoader:
111
111
  try:
112
112
  mtime = file_path.stat().st_mtime
113
113
  return f"agent:{file_path}:{mtime}"
114
- except:
114
+ except Exception:
115
115
  return f"agent:{file_path}"
116
116
 
117
117
  def _load_agent_file(self, file_path: Path) -> Optional[Dict[str, Any]]:
@@ -154,7 +154,7 @@ class OptimizedAgentLoader:
154
154
 
155
155
  # Add metadata
156
156
  agent_data["_file_path"] = str(file_path)
157
- agent_data["_loaded_at"] = datetime.now().isoformat()
157
+ agent_data["_loaded_at"] = datetime.now(timezone.utc).isoformat()
158
158
 
159
159
  # Cache the result
160
160
  self.cache.put(cache_key, agent_data, ttl=self.cache_ttl)
@@ -188,7 +188,7 @@ class OptimizedAgentLoader:
188
188
  data = yaml.safe_load(frontmatter) or {}
189
189
  data["instructions"] = body
190
190
  return data
191
- except:
191
+ except Exception:
192
192
  pass
193
193
 
194
194
  # No frontmatter, treat as pure instructions
@@ -322,7 +322,7 @@ class OptimizedAgentLoader:
322
322
 
323
323
  # Add metadata
324
324
  agent_data["_file_path"] = str(file_path)
325
- agent_data["_loaded_at"] = datetime.now().isoformat()
325
+ agent_data["_loaded_at"] = datetime.now(timezone.utc).isoformat()
326
326
 
327
327
  # Cache the result
328
328
  self.cache.put(cache_key, agent_data, ttl=self.cache_ttl)
@@ -366,7 +366,7 @@ class OptimizedAgentLoader:
366
366
  "template": template,
367
367
  "variables": self._extract_variables(template),
368
368
  "sections": self._extract_sections(template),
369
- "compiled_at": datetime.now().isoformat(),
369
+ "compiled_at": datetime.now(timezone.utc).isoformat(),
370
370
  }
371
371
 
372
372
  # Cache compiled template
@@ -42,7 +42,7 @@ class OutputStyleManager:
42
42
  Path(__file__).parent.parent / "agents" / "OUTPUT_STYLE.md"
43
43
  )
44
44
 
45
- def _detect_claude_version(self) -> Optional[str]:
45
+ def _detect_claude_version(self) -> Optional[str]: # noqa: PLR0911
46
46
  """
47
47
  Detect Claude Code version by running 'claude --version'.
48
48
  Uses global cache to avoid duplicate detection and logging.
@@ -14,7 +14,7 @@ WHY this is needed:
14
14
  import functools
15
15
  import threading
16
16
  import time
17
- from datetime import datetime
17
+ from datetime import datetime, timezone
18
18
  from typing import Any, Dict, List, Optional
19
19
 
20
20
  from ..core.hook_manager import get_hook_manager
@@ -195,7 +195,7 @@ class PMHookInterceptor:
195
195
  {
196
196
  "todos": todos,
197
197
  "source": "PM_Manual",
198
- "timestamp": datetime.utcnow().isoformat(),
198
+ "timestamp": datetime.now(timezone.utc).isoformat(),
199
199
  },
200
200
  )
201
201
 
@@ -210,7 +210,7 @@ class PMHookInterceptor:
210
210
  "todos_count": len(todos),
211
211
  "source": "PM_Manual",
212
212
  "success": True,
213
- "timestamp": datetime.utcnow().isoformat(),
213
+ "timestamp": datetime.now(timezone.utc).isoformat(),
214
214
  },
215
215
  )
216
216
 
@@ -160,7 +160,7 @@ class ServiceRegistry:
160
160
  try:
161
161
  # Use the enhanced container's named resolution
162
162
  return self.container.get(BaseService, name=service_type)
163
- except:
163
+ except Exception:
164
164
  # Fall back to looking up class and resolving
165
165
  if service_type not in self._services:
166
166
  raise KeyError(f"Service '{service_type}' not registered")