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
@@ -18,7 +18,7 @@ DESIGN DECISIONS:
18
18
 
19
19
  import asyncio
20
20
  import json
21
- from datetime import datetime
21
+ from datetime import datetime, timezone
22
22
 
23
23
  from claude_mpm.services.mcp_gateway.core.interfaces import (
24
24
  MCPToolDefinition,
@@ -89,7 +89,7 @@ class TicketCreateTool(BaseToolAdapter):
89
89
  Returns:
90
90
  Tool execution result with created ticket ID
91
91
  """
92
- start_time = datetime.now()
92
+ start_time = datetime.now(timezone.utc)
93
93
 
94
94
  try:
95
95
  params = invocation.parameters
@@ -120,7 +120,7 @@ class TicketCreateTool(BaseToolAdapter):
120
120
 
121
121
  stdout, stderr = await process.communicate()
122
122
 
123
- execution_time = (datetime.now() - start_time).total_seconds()
123
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
124
124
 
125
125
  if process.returncode == 0:
126
126
  # Parse ticket ID from output
@@ -160,7 +160,7 @@ class TicketCreateTool(BaseToolAdapter):
160
160
  )
161
161
 
162
162
  except Exception as e:
163
- execution_time = (datetime.now() - start_time).total_seconds()
163
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
164
164
  self._update_metrics(False, execution_time)
165
165
 
166
166
  return MCPToolResult(
@@ -232,7 +232,7 @@ class TicketListTool(BaseToolAdapter):
232
232
  Returns:
233
233
  Tool execution result with list of tickets
234
234
  """
235
- start_time = datetime.now()
235
+ start_time = datetime.now(timezone.utc)
236
236
 
237
237
  try:
238
238
  params = invocation.parameters
@@ -252,7 +252,7 @@ class TicketListTool(BaseToolAdapter):
252
252
 
253
253
  stdout, stderr = await process.communicate()
254
254
 
255
- execution_time = (datetime.now() - start_time).total_seconds()
255
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
256
256
 
257
257
  if process.returncode == 0:
258
258
  try:
@@ -285,7 +285,7 @@ class TicketListTool(BaseToolAdapter):
285
285
  )
286
286
 
287
287
  except Exception as e:
288
- execution_time = (datetime.now() - start_time).total_seconds()
288
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
289
289
  self._update_metrics(False, execution_time)
290
290
 
291
291
  return MCPToolResult(
@@ -352,7 +352,7 @@ class TicketUpdateTool(BaseToolAdapter):
352
352
  Returns:
353
353
  Tool execution result
354
354
  """
355
- start_time = datetime.now()
355
+ start_time = datetime.now(timezone.utc)
356
356
 
357
357
  try:
358
358
  params = invocation.parameters
@@ -387,7 +387,7 @@ class TicketUpdateTool(BaseToolAdapter):
387
387
 
388
388
  stdout, stderr = await process.communicate()
389
389
 
390
- execution_time = (datetime.now() - start_time).total_seconds()
390
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
391
391
 
392
392
  if process.returncode == 0:
393
393
  self._update_metrics(True, execution_time)
@@ -414,7 +414,7 @@ class TicketUpdateTool(BaseToolAdapter):
414
414
  )
415
415
 
416
416
  except Exception as e:
417
- execution_time = (datetime.now() - start_time).total_seconds()
417
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
418
418
  self._update_metrics(False, execution_time)
419
419
 
420
420
  return MCPToolResult(
@@ -466,7 +466,7 @@ class TicketViewTool(BaseToolAdapter):
466
466
  Returns:
467
467
  Tool execution result with ticket details
468
468
  """
469
- start_time = datetime.now()
469
+ start_time = datetime.now(timezone.utc)
470
470
 
471
471
  try:
472
472
  params = invocation.parameters
@@ -483,7 +483,7 @@ class TicketViewTool(BaseToolAdapter):
483
483
 
484
484
  stdout, stderr = await process.communicate()
485
485
 
486
- execution_time = (datetime.now() - start_time).total_seconds()
486
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
487
487
 
488
488
  if process.returncode == 0:
489
489
  output = stdout.decode().strip()
@@ -518,7 +518,7 @@ class TicketViewTool(BaseToolAdapter):
518
518
  )
519
519
 
520
520
  except Exception as e:
521
- execution_time = (datetime.now() - start_time).total_seconds()
521
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
522
522
  self._update_metrics(False, execution_time)
523
523
 
524
524
  return MCPToolResult(
@@ -572,7 +572,7 @@ class TicketSearchTool(BaseToolAdapter):
572
572
  Returns:
573
573
  Tool execution result with matching tickets
574
574
  """
575
- start_time = datetime.now()
575
+ start_time = datetime.now(timezone.utc)
576
576
 
577
577
  try:
578
578
  params = invocation.parameters
@@ -592,7 +592,7 @@ class TicketSearchTool(BaseToolAdapter):
592
592
 
593
593
  stdout, stderr = await process.communicate()
594
594
 
595
- execution_time = (datetime.now() - start_time).total_seconds()
595
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
596
596
 
597
597
  if process.returncode == 0:
598
598
  try:
@@ -625,7 +625,7 @@ class TicketSearchTool(BaseToolAdapter):
625
625
  )
626
626
 
627
627
  except Exception as e:
628
- execution_time = (datetime.now() - start_time).total_seconds()
628
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
629
629
  self._update_metrics(False, execution_time)
630
630
 
631
631
  return MCPToolResult(
@@ -21,7 +21,7 @@ DESIGN DECISIONS:
21
21
  import asyncio
22
22
  import json
23
23
  import re
24
- from datetime import datetime
24
+ from datetime import datetime, timezone
25
25
  from typing import Any, Dict, Optional
26
26
 
27
27
  from claude_mpm.services.mcp_gateway.core.interfaces import (
@@ -242,7 +242,7 @@ class UnifiedTicketTool(BaseToolAdapter):
242
242
  Returns:
243
243
  Tool execution result with created ticket ID
244
244
  """
245
- start_time = datetime.now()
245
+ start_time = datetime.now(timezone.utc)
246
246
 
247
247
  try:
248
248
  # Build aitrackdown command
@@ -269,7 +269,7 @@ class UnifiedTicketTool(BaseToolAdapter):
269
269
  )
270
270
 
271
271
  stdout, stderr = await process.communicate()
272
- execution_time = (datetime.now() - start_time).total_seconds()
272
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
273
273
 
274
274
  if process.returncode == 0:
275
275
  # Parse ticket ID from output
@@ -305,7 +305,7 @@ class UnifiedTicketTool(BaseToolAdapter):
305
305
  )
306
306
 
307
307
  except Exception as e:
308
- execution_time = (datetime.now() - start_time).total_seconds()
308
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
309
309
  self._update_metrics(False, execution_time)
310
310
 
311
311
  return MCPToolResult(
@@ -324,7 +324,7 @@ class UnifiedTicketTool(BaseToolAdapter):
324
324
  Returns:
325
325
  Tool execution result with list of tickets
326
326
  """
327
- start_time = datetime.now()
327
+ start_time = datetime.now(timezone.utc)
328
328
 
329
329
  try:
330
330
  limit = params.get("limit", 10)
@@ -342,7 +342,7 @@ class UnifiedTicketTool(BaseToolAdapter):
342
342
  )
343
343
 
344
344
  stdout, stderr = await process.communicate()
345
- execution_time = (datetime.now() - start_time).total_seconds()
345
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
346
346
 
347
347
  if process.returncode == 0:
348
348
  try:
@@ -375,7 +375,7 @@ class UnifiedTicketTool(BaseToolAdapter):
375
375
  )
376
376
 
377
377
  except Exception as e:
378
- execution_time = (datetime.now() - start_time).total_seconds()
378
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
379
379
  self._update_metrics(False, execution_time)
380
380
 
381
381
  return MCPToolResult(
@@ -394,7 +394,7 @@ class UnifiedTicketTool(BaseToolAdapter):
394
394
  Returns:
395
395
  Tool execution result
396
396
  """
397
- start_time = datetime.now()
397
+ start_time = datetime.now(timezone.utc)
398
398
 
399
399
  try:
400
400
  ticket_id = params["ticket_id"]
@@ -426,7 +426,7 @@ class UnifiedTicketTool(BaseToolAdapter):
426
426
  )
427
427
 
428
428
  stdout, stderr = await process.communicate()
429
- execution_time = (datetime.now() - start_time).total_seconds()
429
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
430
430
 
431
431
  if process.returncode == 0:
432
432
  self._update_metrics(True, execution_time)
@@ -453,7 +453,7 @@ class UnifiedTicketTool(BaseToolAdapter):
453
453
  )
454
454
 
455
455
  except Exception as e:
456
- execution_time = (datetime.now() - start_time).total_seconds()
456
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
457
457
  self._update_metrics(False, execution_time)
458
458
 
459
459
  return MCPToolResult(
@@ -472,7 +472,7 @@ class UnifiedTicketTool(BaseToolAdapter):
472
472
  Returns:
473
473
  Tool execution result with ticket details
474
474
  """
475
- start_time = datetime.now()
475
+ start_time = datetime.now(timezone.utc)
476
476
 
477
477
  try:
478
478
  ticket_id = params["ticket_id"]
@@ -487,7 +487,7 @@ class UnifiedTicketTool(BaseToolAdapter):
487
487
  )
488
488
 
489
489
  stdout, stderr = await process.communicate()
490
- execution_time = (datetime.now() - start_time).total_seconds()
490
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
491
491
 
492
492
  if process.returncode == 0:
493
493
  output = stdout.decode().strip()
@@ -522,7 +522,7 @@ class UnifiedTicketTool(BaseToolAdapter):
522
522
  )
523
523
 
524
524
  except Exception as e:
525
- execution_time = (datetime.now() - start_time).total_seconds()
525
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
526
526
  self._update_metrics(False, execution_time)
527
527
 
528
528
  return MCPToolResult(
@@ -541,7 +541,7 @@ class UnifiedTicketTool(BaseToolAdapter):
541
541
  Returns:
542
542
  Tool execution result with matching tickets
543
543
  """
544
- start_time = datetime.now()
544
+ start_time = datetime.now(timezone.utc)
545
545
 
546
546
  try:
547
547
  query = params["query"]
@@ -559,7 +559,7 @@ class UnifiedTicketTool(BaseToolAdapter):
559
559
  )
560
560
 
561
561
  stdout, stderr = await process.communicate()
562
- execution_time = (datetime.now() - start_time).total_seconds()
562
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
563
563
 
564
564
  if process.returncode == 0:
565
565
  try:
@@ -588,7 +588,7 @@ class UnifiedTicketTool(BaseToolAdapter):
588
588
  )
589
589
 
590
590
  except Exception as e:
591
- execution_time = (datetime.now() - start_time).total_seconds()
591
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
592
592
  self._update_metrics(False, execution_time)
593
593
 
594
594
  return MCPToolResult(
@@ -24,7 +24,7 @@ while preserving essential information.
24
24
 
25
25
  import os
26
26
  import re
27
- from datetime import datetime
27
+ from datetime import datetime, timezone
28
28
  from pathlib import Path
29
29
  from typing import Any, Dict, List, Optional
30
30
 
@@ -234,7 +234,7 @@ class MemoryBuilder(LoggerMixin):
234
234
  try:
235
235
  results = {
236
236
  "success": True,
237
- "timestamp": datetime.now().isoformat(),
237
+ "timestamp": datetime.now(timezone.utc).isoformat(),
238
238
  "files_processed": 0,
239
239
  "memories_created": 0,
240
240
  "memories_updated": 0,
@@ -293,7 +293,7 @@ class MemoryBuilder(LoggerMixin):
293
293
  return {
294
294
  "success": False,
295
295
  "error": str(e),
296
- "timestamp": datetime.now().isoformat(),
296
+ "timestamp": datetime.now(timezone.utc).isoformat(),
297
297
  }
298
298
 
299
299
  def extract_from_text(self, text: str, source: str) -> List[Dict[str, Any]]:
@@ -777,7 +777,9 @@ class MemoryBuilder(LoggerMixin):
777
777
  return True
778
778
 
779
779
  last_processed_time = datetime.fromisoformat(last_processed[file_key])
780
- file_modified_time = datetime.fromtimestamp(file_path.stat().st_mtime)
780
+ file_modified_time = datetime.fromtimestamp(
781
+ file_path.stat().st_mtime, tz=timezone.utc
782
+ )
781
783
 
782
784
  return file_modified_time > last_processed_time
783
785
 
@@ -805,7 +807,7 @@ class MemoryBuilder(LoggerMixin):
805
807
 
806
808
  # Update timestamp
807
809
  file_key = str(file_path.relative_to(self.project_root))
808
- last_processed[file_key] = datetime.now().isoformat()
810
+ last_processed[file_key] = datetime.now(timezone.utc).isoformat()
809
811
 
810
812
  # Save back
811
813
  import json
@@ -23,7 +23,7 @@ import re
23
23
  import time
24
24
  from collections import Counter, defaultdict
25
25
  from dataclasses import dataclass, field
26
- from datetime import datetime, timedelta
26
+ from datetime import datetime, timedelta, timezone
27
27
  from typing import Any, Dict, List, Optional, Set, Tuple
28
28
 
29
29
  from ...core.cache import get_file_cache
@@ -388,7 +388,7 @@ class IndexedMemoryService:
388
388
  agent_id=agent_id,
389
389
  content=content,
390
390
  category=category,
391
- timestamp=datetime.now(),
391
+ timestamp=datetime.now(timezone.utc),
392
392
  tags=tags or [],
393
393
  metadata=metadata or {},
394
394
  )
@@ -510,7 +510,7 @@ class IndexedMemoryService:
510
510
  start_time = time.time()
511
511
 
512
512
  # Calculate time range
513
- now = datetime.now()
513
+ now = datetime.now(timezone.utc)
514
514
  if hours:
515
515
  min_time = now - timedelta(hours=hours)
516
516
  elif days:
@@ -563,7 +563,7 @@ class IndexedMemoryService:
563
563
 
564
564
  def _generate_id(self, agent_id: str, content: str) -> str:
565
565
  """Generate unique ID for memory entry."""
566
- timestamp = datetime.now().isoformat()
566
+ timestamp = datetime.now(timezone.utc).isoformat()
567
567
  hash_input = f"{agent_id}:{content[:100]}:{timestamp}"
568
568
  return hashlib.md5(hash_input.encode()).hexdigest()[:12]
569
569
 
@@ -24,7 +24,7 @@ information than lose important insights.
24
24
 
25
25
  import os
26
26
  import re
27
- from datetime import datetime
27
+ from datetime import datetime, timezone
28
28
  from difflib import SequenceMatcher
29
29
  from pathlib import Path
30
30
  from typing import Any, Dict, List, Optional, Tuple
@@ -164,7 +164,7 @@ class MemoryOptimizer(LoggerMixin):
164
164
  else 0
165
165
  ),
166
166
  "backup_created": str(backup_path),
167
- "timestamp": datetime.now().isoformat(),
167
+ "timestamp": datetime.now(timezone.utc).isoformat(),
168
168
  **optimization_stats,
169
169
  }
170
170
 
@@ -230,7 +230,7 @@ class MemoryOptimizer(LoggerMixin):
230
230
 
231
231
  return {
232
232
  "success": True,
233
- "timestamp": datetime.now().isoformat(),
233
+ "timestamp": datetime.now(timezone.utc).isoformat(),
234
234
  "agents": results,
235
235
  "summary": {
236
236
  **total_stats,
@@ -545,7 +545,7 @@ class MemoryOptimizer(LoggerMixin):
545
545
 
546
546
  # Update timestamp
547
547
  content = "\n".join(content_lines)
548
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
548
+ timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
549
549
  return re.sub(
550
550
  r"<!-- Last Updated: .+ \| Auto-updated by: .+ -->",
551
551
  f"<!-- Last Updated: {timestamp} | Auto-updated by: optimizer -->",
@@ -561,7 +561,7 @@ class MemoryOptimizer(LoggerMixin):
561
561
  Returns:
562
562
  Path to backup file
563
563
  """
564
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
564
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
565
565
  backup_name = f"{memory_file.stem}_backup_{timestamp}{memory_file.suffix}"
566
566
  backup_path = memory_file.parent / backup_name
567
567
 
@@ -647,7 +647,7 @@ class MemoryOptimizer(LoggerMixin):
647
647
 
648
648
  return {
649
649
  "success": True,
650
- "timestamp": datetime.now().isoformat(),
650
+ "timestamp": datetime.now(timezone.utc).isoformat(),
651
651
  "agents_analyzed": len(agents_analysis),
652
652
  "agents": agents_analysis,
653
653
  }
@@ -21,7 +21,7 @@ users understand why content was assigned to specific agents.
21
21
  """
22
22
 
23
23
  import re
24
- from datetime import datetime
24
+ from datetime import datetime, timezone
25
25
  from typing import Any, Dict, List, Optional, Tuple
26
26
 
27
27
  from claude_mpm.core.config import Config
@@ -622,7 +622,7 @@ class MemoryRouter(LoggerMixin):
622
622
  "confidence": confidence,
623
623
  "reasoning": reasoning,
624
624
  "agent_scores": agent_scores,
625
- "timestamp": datetime.now().isoformat(),
625
+ "timestamp": datetime.now(timezone.utc).isoformat(),
626
626
  "content_length": len(content),
627
627
  }
628
628
 
@@ -639,7 +639,7 @@ class MemoryRouter(LoggerMixin):
639
639
  "confidence": 0.1,
640
640
  "reasoning": f"Error during analysis, defaulting to {self.DEFAULT_AGENT}",
641
641
  "error": str(e),
642
- "timestamp": datetime.now().isoformat(),
642
+ "timestamp": datetime.now(timezone.utc).isoformat(),
643
643
  "content_length": len(content) if content else 0,
644
644
  }
645
645
 
@@ -121,7 +121,7 @@ class UnifiedMonitorDaemon:
121
121
  """
122
122
  return self.daemon_manager.cleanup_port_conflicts()
123
123
 
124
- def _start_daemon(self, force_restart: bool = False) -> bool:
124
+ def _start_daemon(self, force_restart: bool = False) -> bool: # noqa: PLR0911
125
125
  """Start as background daemon process.
126
126
 
127
127
  Args:
@@ -163,7 +163,7 @@ class DaemonManager:
163
163
  test_sock.bind(("::1", self.port))
164
164
  test_sock.close()
165
165
  return True
166
- except:
166
+ except Exception:
167
167
  # Both IPv4 and IPv6 failed - port is in use
168
168
  return False
169
169
 
@@ -434,10 +434,10 @@ class DaemonManager:
434
434
  # It's likely our service, try to find PID
435
435
  pid = self._find_service_pid()
436
436
  return True, pid
437
- except:
437
+ except Exception:
438
438
  pass
439
439
 
440
- except:
440
+ except Exception:
441
441
  pass
442
442
 
443
443
  return False, None
@@ -465,7 +465,7 @@ class DaemonManager:
465
465
  if pids:
466
466
  return int(pids[0].strip())
467
467
 
468
- except:
468
+ except Exception:
469
469
  pass
470
470
 
471
471
  return None
@@ -615,7 +615,7 @@ class DaemonManager:
615
615
  f"Monitor daemon successfully started on port {self.port}"
616
616
  )
617
617
  return True
618
- except:
618
+ except Exception:
619
619
  pass # PID file not ready yet
620
620
 
621
621
  time.sleep(0.5)
@@ -958,5 +958,5 @@ class DaemonManager:
958
958
  with open("/tmp/daemon_debug_error.txt", "a") as debug:
959
959
  debug.write(f"Error reporting error: {e}\n")
960
960
  debug.write(f"Status file: {self.startup_status_file}\n")
961
- except:
961
+ except Exception:
962
962
  pass
@@ -10,7 +10,7 @@ WHY: Eliminates HTTP overhead for in-process events while maintaining external A
10
10
 
11
11
  import asyncio
12
12
  import weakref
13
- from datetime import datetime
13
+ from datetime import datetime, timezone
14
14
  from typing import Any, Dict, Optional, Set
15
15
 
16
16
  import aiohttp
@@ -203,7 +203,7 @@ class AsyncEventEmitter:
203
203
  "namespace": namespace,
204
204
  "event": event,
205
205
  "data": data,
206
- "timestamp": datetime.now().isoformat(),
206
+ "timestamp": datetime.now(timezone.utc).isoformat(),
207
207
  "source": "async_emitter",
208
208
  }
209
209
 
@@ -514,7 +514,9 @@ class DaemonLifecycle:
514
514
  error_msg = f"Port {self.port} is already in use or cannot be bound: {e}"
515
515
  return False, error_msg
516
516
 
517
- def is_our_service(self, host: str = "localhost") -> Tuple[bool, Optional[int]]:
517
+ def is_our_service(
518
+ self, host: str = "localhost"
519
+ ) -> Tuple[bool, Optional[int]]:
518
520
  """Check if the service on the port is our Socket.IO service.
519
521
 
520
522
  This uses multiple detection methods:
@@ -19,7 +19,7 @@ import contextlib
19
19
  import os
20
20
  import threading
21
21
  import time
22
- from datetime import datetime
22
+ from datetime import datetime, timezone
23
23
  from pathlib import Path
24
24
  from typing import Dict, Optional
25
25
 
@@ -365,7 +365,7 @@ class UnifiedMonitorServer:
365
365
  return web.Response(text=f"Error: {e!s}", status=500)
366
366
 
367
367
  # File content endpoint for file viewer
368
- async def api_file_handler(request):
368
+ async def api_file_handler(request): # noqa: PLR0911
369
369
  """Handle file content requests."""
370
370
  import json
371
371
  import os
@@ -481,7 +481,7 @@ class UnifiedMonitorServer:
481
481
  config = {
482
482
  "workingDirectory": os.getcwd(),
483
483
  "gitBranch": "Unknown",
484
- "serverTime": datetime.utcnow().isoformat() + "Z",
484
+ "serverTime": datetime.now(timezone.utc).isoformat() + "Z",
485
485
  "service": "unified-monitor",
486
486
  }
487
487
 
@@ -661,7 +661,7 @@ class UnifiedMonitorServer:
661
661
 
662
662
  # Create heartbeat data
663
663
  heartbeat_data = {
664
- "timestamp": datetime.utcnow().isoformat() + "Z",
664
+ "timestamp": datetime.now(timezone.utc).isoformat() + "Z",
665
665
  "type": "heartbeat",
666
666
  "server_uptime": uptime_seconds,
667
667
  "server_uptime_formatted": uptime_str,
@@ -156,9 +156,9 @@ class MonitorBuildService(BaseService):
156
156
  info: Build information dictionary
157
157
  """
158
158
  # Add timestamp
159
- from datetime import datetime
159
+ from datetime import datetime, timezone
160
160
 
161
- info["last_updated"] = datetime.utcnow().isoformat()
161
+ info["last_updated"] = datetime.now(timezone.utc).isoformat()
162
162
 
163
163
  # Write atomically using temp file and rename
164
164
  temp_fd, temp_path = tempfile.mkstemp(
@@ -243,7 +243,9 @@ class PortManager:
243
243
 
244
244
  return any(pattern in cmdline_lower for pattern in daemon_patterns)
245
245
 
246
- def kill_process_on_port(self, port: int, force: bool = False) -> bool:
246
+ def kill_process_on_port(
247
+ self, port: int, force: bool = False
248
+ ) -> bool:
247
249
  """Kill a process using a specific port if it's safe to do so.
248
250
 
249
251
  WHY: Automatically reclaim ports from our debug scripts while preserving
@@ -19,7 +19,7 @@ DESIGN DECISIONS:
19
19
  """
20
20
 
21
21
  import logging
22
- from datetime import datetime
22
+ from datetime import datetime, timezone
23
23
  from typing import Any, Dict, Optional
24
24
 
25
25
  from claude_mpm.core.config import Config
@@ -144,7 +144,7 @@ class ResponseTracker:
144
144
  {
145
145
  "agent": agent_name,
146
146
  "tracked_by": "ResponseTracker",
147
- "tracking_timestamp": datetime.now().isoformat(),
147
+ "tracking_timestamp": datetime.now(timezone.utc).isoformat(),
148
148
  }
149
149
  )
150
150
 
@@ -13,6 +13,7 @@ Extracted from ClaudeRunner to follow Single Responsibility Principle.
13
13
 
14
14
  import time
15
15
  import uuid
16
+ from datetime import timezone
16
17
  from typing import Any, Dict, List, Optional
17
18
 
18
19
  from claude_mpm.core.base_service import BaseService
@@ -153,7 +154,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
153
154
  session_logs_dir.mkdir(parents=True, exist_ok=True)
154
155
 
155
156
  # Generate unique session log filename
156
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
157
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
157
158
  session_id = str(uuid.uuid4())[:8]
158
159
  log_filename = f"session_{timestamp}_{session_id}.jsonl"
159
160
  log_file = session_logs_dir / log_filename
@@ -183,7 +184,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
183
184
  from datetime import datetime
184
185
 
185
186
  # Add timestamp to event data
186
- event_data["timestamp"] = datetime.now().isoformat()
187
+ event_data["timestamp"] = datetime.now(timezone.utc).isoformat()
187
188
 
188
189
  # Append to log file as JSONL
189
190
  with open(log_file, "a") as f:
@@ -13,7 +13,7 @@ organization and to reduce the complexity of the main server file.
13
13
  import asyncio
14
14
  import threading
15
15
  import time
16
- from datetime import datetime
16
+ from datetime import datetime, timezone
17
17
  from typing import Any, Dict, List, Optional
18
18
 
19
19
  try:
@@ -172,7 +172,7 @@ class SocketIOClientProxy:
172
172
  try:
173
173
  event = {
174
174
  "type": event_type,
175
- "timestamp": datetime.now().isoformat(),
175
+ "timestamp": datetime.now(timezone.utc).isoformat(),
176
176
  "data": data,
177
177
  }
178
178