claude-mpm 4.3.12__py3-none-any.whl → 4.3.13__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 (199) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +390 -28
  3. claude_mpm/agents/templates/data_engineer.json +39 -14
  4. claude_mpm/cli/commands/agent_manager.py +3 -3
  5. claude_mpm/cli/commands/agents.py +2 -2
  6. claude_mpm/cli/commands/aggregate.py +1 -1
  7. claude_mpm/cli/commands/config.py +2 -2
  8. claude_mpm/cli/commands/configure.py +5 -5
  9. claude_mpm/cli/commands/configure_tui.py +7 -7
  10. claude_mpm/cli/commands/dashboard.py +1 -1
  11. claude_mpm/cli/commands/debug.py +5 -5
  12. claude_mpm/cli/commands/mcp.py +1 -1
  13. claude_mpm/cli/commands/mcp_command_router.py +1 -1
  14. claude_mpm/cli/commands/mcp_config.py +7 -10
  15. claude_mpm/cli/commands/mcp_external_commands.py +40 -32
  16. claude_mpm/cli/commands/mcp_install_commands.py +38 -10
  17. claude_mpm/cli/commands/mcp_setup_external.py +143 -102
  18. claude_mpm/cli/commands/monitor.py +2 -2
  19. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  20. claude_mpm/cli/commands/run.py +46 -2
  21. claude_mpm/cli/commands/search.py +41 -34
  22. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  23. claude_mpm/cli/parsers/mcp_parser.py +1 -3
  24. claude_mpm/cli/parsers/search_parser.py +10 -4
  25. claude_mpm/cli/startup_logging.py +3 -5
  26. claude_mpm/cli/utils.py +1 -1
  27. claude_mpm/core/agent_registry.py +12 -8
  28. claude_mpm/core/agent_session_manager.py +8 -8
  29. claude_mpm/core/api_validator.py +4 -4
  30. claude_mpm/core/base_service.py +10 -10
  31. claude_mpm/core/cache.py +5 -5
  32. claude_mpm/core/config_constants.py +1 -1
  33. claude_mpm/core/container.py +1 -1
  34. claude_mpm/core/error_handler.py +2 -2
  35. claude_mpm/core/file_utils.py +1 -1
  36. claude_mpm/core/framework_loader.py +3 -3
  37. claude_mpm/core/hook_manager.py +8 -6
  38. claude_mpm/core/instruction_reinforcement_hook.py +2 -2
  39. claude_mpm/core/interactive_session.py +1 -1
  40. claude_mpm/core/lazy.py +3 -3
  41. claude_mpm/core/log_manager.py +16 -12
  42. claude_mpm/core/logger.py +16 -11
  43. claude_mpm/core/logging_config.py +4 -2
  44. claude_mpm/core/oneshot_session.py +1 -1
  45. claude_mpm/core/optimized_agent_loader.py +6 -6
  46. claude_mpm/core/output_style_manager.py +1 -1
  47. claude_mpm/core/pm_hook_interceptor.py +3 -3
  48. claude_mpm/core/service_registry.py +1 -1
  49. claude_mpm/core/session_manager.py +11 -9
  50. claude_mpm/core/socketio_pool.py +13 -13
  51. claude_mpm/core/types.py +2 -2
  52. claude_mpm/core/unified_agent_registry.py +2 -2
  53. claude_mpm/core/unified_paths.py +1 -1
  54. claude_mpm/dashboard/analysis_runner.py +4 -4
  55. claude_mpm/dashboard/api/simple_directory.py +1 -1
  56. claude_mpm/generators/agent_profile_generator.py +4 -2
  57. claude_mpm/hooks/base_hook.py +2 -2
  58. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  59. claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
  60. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
  61. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
  62. claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
  63. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
  64. claude_mpm/hooks/claude_hooks/installer.py +3 -3
  65. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  66. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
  67. claude_mpm/hooks/claude_hooks/services/connection_manager.py +5 -5
  68. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
  69. claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
  70. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  71. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  72. claude_mpm/hooks/memory_integration_hook.py +1 -1
  73. claude_mpm/hooks/tool_call_interceptor.py +2 -2
  74. claude_mpm/models/agent_session.py +5 -5
  75. claude_mpm/services/__init__.py +1 -1
  76. claude_mpm/services/agent_capabilities_service.py +1 -1
  77. claude_mpm/services/agents/agent_builder.py +3 -3
  78. claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
  79. claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
  80. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +7 -5
  81. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
  82. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  83. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  84. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  85. claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
  86. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  87. claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
  88. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
  89. claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
  90. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  91. claude_mpm/services/agents/local_template_manager.py +6 -6
  92. claude_mpm/services/agents/management/agent_management_service.py +3 -3
  93. claude_mpm/services/agents/memory/content_manager.py +3 -3
  94. claude_mpm/services/agents/memory/memory_format_service.py +2 -2
  95. claude_mpm/services/agents/memory/template_generator.py +3 -3
  96. claude_mpm/services/agents/registry/__init__.py +1 -1
  97. claude_mpm/services/agents/registry/modification_tracker.py +2 -2
  98. claude_mpm/services/async_session_logger.py +3 -3
  99. claude_mpm/services/claude_session_logger.py +4 -4
  100. claude_mpm/services/cli/agent_listing_service.py +1 -1
  101. claude_mpm/services/cli/agent_validation_service.py +1 -0
  102. claude_mpm/services/cli/memory_crud_service.py +11 -6
  103. claude_mpm/services/cli/memory_output_formatter.py +1 -1
  104. claude_mpm/services/cli/session_manager.py +15 -11
  105. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  106. claude_mpm/services/core/memory_manager.py +81 -23
  107. claude_mpm/services/core/path_resolver.py +2 -2
  108. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  109. claude_mpm/services/event_aggregator.py +4 -2
  110. claude_mpm/services/event_bus/direct_relay.py +5 -3
  111. claude_mpm/services/event_bus/event_bus.py +3 -3
  112. claude_mpm/services/event_bus/relay.py +6 -4
  113. claude_mpm/services/events/consumers/dead_letter.py +5 -3
  114. claude_mpm/services/events/core.py +3 -3
  115. claude_mpm/services/events/producers/hook.py +6 -6
  116. claude_mpm/services/events/producers/system.py +8 -8
  117. claude_mpm/services/exceptions.py +5 -5
  118. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
  119. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  120. claude_mpm/services/hook_installer_service.py +1 -1
  121. claude_mpm/services/infrastructure/context_preservation.py +6 -4
  122. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  123. claude_mpm/services/infrastructure/logging.py +2 -2
  124. claude_mpm/services/mcp_config_manager.py +175 -30
  125. claude_mpm/services/mcp_gateway/__init__.py +1 -1
  126. claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
  127. claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
  128. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  129. claude_mpm/services/mcp_gateway/core/base.py +2 -2
  130. claude_mpm/services/mcp_gateway/main.py +21 -7
  131. claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
  132. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  133. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  134. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -3
  135. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  136. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
  137. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
  138. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
  139. claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
  140. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
  141. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +17 -17
  142. claude_mpm/services/memory/builder.py +7 -5
  143. claude_mpm/services/memory/indexed_memory.py +4 -4
  144. claude_mpm/services/memory/optimizer.py +6 -6
  145. claude_mpm/services/memory/router.py +3 -3
  146. claude_mpm/services/monitor/daemon.py +1 -1
  147. claude_mpm/services/monitor/daemon_manager.py +6 -6
  148. claude_mpm/services/monitor/event_emitter.py +2 -2
  149. claude_mpm/services/monitor/handlers/file.py +1 -1
  150. claude_mpm/services/monitor/management/lifecycle.py +1 -1
  151. claude_mpm/services/monitor/server.py +4 -4
  152. claude_mpm/services/monitor_build_service.py +2 -2
  153. claude_mpm/services/port_manager.py +2 -2
  154. claude_mpm/services/response_tracker.py +2 -2
  155. claude_mpm/services/session_management_service.py +3 -2
  156. claude_mpm/services/socketio/client_proxy.py +2 -2
  157. claude_mpm/services/socketio/dashboard_server.py +4 -3
  158. claude_mpm/services/socketio/event_normalizer.py +12 -8
  159. claude_mpm/services/socketio/handlers/base.py +2 -2
  160. claude_mpm/services/socketio/handlers/connection.py +10 -10
  161. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  162. claude_mpm/services/socketio/handlers/file.py +1 -1
  163. claude_mpm/services/socketio/handlers/git.py +1 -1
  164. claude_mpm/services/socketio/handlers/hook.py +16 -15
  165. claude_mpm/services/socketio/migration_utils.py +1 -1
  166. claude_mpm/services/socketio/monitor_client.py +5 -5
  167. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  168. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  169. claude_mpm/services/socketio/server/core.py +7 -5
  170. claude_mpm/services/socketio/server/eventbus_integration.py +18 -11
  171. claude_mpm/services/socketio/server/main.py +13 -13
  172. claude_mpm/services/socketio_client_manager.py +4 -4
  173. claude_mpm/services/system_instructions_service.py +2 -2
  174. claude_mpm/services/ticket_services/validation_service.py +1 -1
  175. claude_mpm/services/utility_service.py +5 -2
  176. claude_mpm/services/version_control/branch_strategy.py +2 -2
  177. claude_mpm/services/version_control/git_operations.py +22 -20
  178. claude_mpm/services/version_control/semantic_versioning.py +3 -3
  179. claude_mpm/services/version_control/version_parser.py +7 -5
  180. claude_mpm/services/visualization/mermaid_generator.py +1 -1
  181. claude_mpm/storage/state_storage.py +1 -1
  182. claude_mpm/tools/code_tree_analyzer.py +19 -18
  183. claude_mpm/tools/code_tree_builder.py +2 -2
  184. claude_mpm/tools/code_tree_events.py +10 -8
  185. claude_mpm/tools/socketio_debug.py +3 -3
  186. claude_mpm/utils/agent_dependency_loader.py +2 -2
  187. claude_mpm/utils/dependency_strategies.py +8 -3
  188. claude_mpm/utils/environment_context.py +2 -2
  189. claude_mpm/utils/error_handler.py +2 -2
  190. claude_mpm/utils/file_utils.py +1 -1
  191. claude_mpm/utils/imports.py +1 -1
  192. claude_mpm/utils/log_cleanup.py +21 -7
  193. claude_mpm/validation/agent_validator.py +2 -2
  194. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +1 -1
  195. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +199 -199
  196. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
  197. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
  198. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
  199. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/top_level.txt +0 -0
@@ -129,7 +129,7 @@ def has_code_files(directory_path, max_depth=5, current_depth=0):
129
129
  return False
130
130
 
131
131
 
132
- def should_show_item(item_name, item_path, is_directory):
132
+ def should_show_item(item_name, item_path, is_directory): # noqa: PLR0911
133
133
  """Determine if an item should be shown based on filtering rules"""
134
134
  # Always hide system files
135
135
  if item_name in {".DS_Store", "Thumbs.db", "desktop.ini"}:
@@ -7,7 +7,7 @@ Inspired by awesome-claude-code's template generation approach.
7
7
  """
8
8
 
9
9
  import re
10
- from datetime import datetime
10
+ from datetime import datetime, timezone
11
11
  from typing import Any, Dict, Optional
12
12
 
13
13
  import yaml
@@ -36,7 +36,9 @@ class AgentProfileGenerator:
36
36
  """Generate an agent profile from configuration."""
37
37
  # Set default values
38
38
  config.setdefault("VERSION", "1.0.0")
39
- config.setdefault("CREATED_DATE", datetime.now().strftime("%Y-%m-%d"))
39
+ config.setdefault(
40
+ "CREATED_DATE", datetime.now(timezone.utc).strftime("%Y-%m-%d")
41
+ )
40
42
  config.setdefault("AUTHOR", "claude-mpm")
41
43
 
42
44
  # Convert template to string
@@ -4,7 +4,7 @@ import asyncio
4
4
  import logging
5
5
  from abc import ABC, abstractmethod
6
6
  from dataclasses import dataclass
7
- from datetime import datetime
7
+ from datetime import datetime, timezone
8
8
  from enum import Enum
9
9
  from typing import Any, Dict, Optional
10
10
 
@@ -35,7 +35,7 @@ class HookContext:
35
35
  def __post_init__(self):
36
36
  """Ensure timestamp is set."""
37
37
  if not hasattr(self, "timestamp") or self.timestamp is None:
38
- self.timestamp = datetime.now()
38
+ self.timestamp = datetime.now(timezone.utc)
39
39
 
40
40
 
41
41
  @dataclass
@@ -131,7 +131,7 @@ class SocketIOConnectionPool:
131
131
  "source": "connection_pool",
132
132
  },
133
133
  )
134
- except:
134
+ except Exception:
135
135
  pass # Ignore ping errors
136
136
  return client
137
137
  except Exception:
@@ -168,10 +168,10 @@ class SocketIOConnectionPool:
168
168
  },
169
169
  )
170
170
  return True
171
- except:
171
+ except Exception:
172
172
  # If ping fails, connection might be dead
173
173
  return client.connected # Fall back to basic check
174
- except:
174
+ except Exception:
175
175
  return False
176
176
 
177
177
  def _close_connection(self, client: Any) -> None:
@@ -179,7 +179,7 @@ class SocketIOConnectionPool:
179
179
  try:
180
180
  if client:
181
181
  client.disconnect()
182
- except:
182
+ except Exception:
183
183
  pass
184
184
 
185
185
  def _cleanup_dead_connections(self) -> None:
@@ -9,7 +9,7 @@ import os
9
9
  import re
10
10
  import subprocess
11
11
  import sys
12
- from datetime import datetime
12
+ from datetime import datetime, timezone
13
13
  from typing import Optional
14
14
 
15
15
  # Import tool analysis with fallback for direct execution
@@ -77,7 +77,7 @@ class EventHandlers:
77
77
  "session_id": event.get("session_id", ""),
78
78
  "working_directory": working_dir,
79
79
  "git_branch": git_branch,
80
- "timestamp": datetime.now().isoformat(),
80
+ "timestamp": datetime.now(timezone.utc).isoformat(),
81
81
  "is_command": prompt.startswith("/"),
82
82
  "contains_code": "```" in prompt
83
83
  or "python" in prompt.lower()
@@ -101,7 +101,7 @@ class EventHandlers:
101
101
  if session_id:
102
102
  self.hook_handler.pending_prompts[session_id] = {
103
103
  "prompt": prompt,
104
- "timestamp": datetime.now().isoformat(),
104
+ "timestamp": datetime.now(timezone.utc).isoformat(),
105
105
  "working_directory": working_dir,
106
106
  }
107
107
  if DEBUG:
@@ -150,7 +150,7 @@ class EventHandlers:
150
150
  "session_id": event.get("session_id", ""),
151
151
  "working_directory": working_dir,
152
152
  "git_branch": git_branch,
153
- "timestamp": datetime.now().isoformat(),
153
+ "timestamp": datetime.now(timezone.utc).isoformat(),
154
154
  "parameter_count": len(tool_input) if isinstance(tool_input, dict) else 0,
155
155
  "is_file_operation": tool_name
156
156
  in ["Write", "Edit", "MultiEdit", "Read", "LS", "Glob"],
@@ -249,7 +249,7 @@ class EventHandlers:
249
249
  "session_id": session_id,
250
250
  "prompt": tool_input.get("prompt", ""),
251
251
  "description": tool_input.get("description", ""),
252
- "timestamp": datetime.now().isoformat(),
252
+ "timestamp": datetime.now(timezone.utc).isoformat(),
253
253
  "hook_event_name": "SubagentStart", # For dashboard compatibility
254
254
  }
255
255
  self.hook_handler._emit_socketio_event(
@@ -277,7 +277,7 @@ class EventHandlers:
277
277
  "session_id": session_id,
278
278
  "delegation_context": {
279
279
  "description": tool_input.get("description", ""),
280
- "timestamp": datetime.now().isoformat(),
280
+ "timestamp": datetime.now(timezone.utc).isoformat(),
281
281
  },
282
282
  }
283
283
 
@@ -312,7 +312,7 @@ class EventHandlers:
312
312
  working_dir = os.getcwd()
313
313
 
314
314
  # Check cache first (cache for 30 seconds)
315
- current_time = datetime.now().timestamp()
315
+ current_time = datetime.now(timezone.utc).timestamp()
316
316
  cache_key = working_dir
317
317
 
318
318
  if (
@@ -397,7 +397,7 @@ class EventHandlers:
397
397
  "session_id": event.get("session_id", ""),
398
398
  "working_directory": working_dir,
399
399
  "git_branch": git_branch,
400
- "timestamp": datetime.now().isoformat(),
400
+ "timestamp": datetime.now(timezone.utc).isoformat(),
401
401
  "has_output": bool(result_data.get("output")),
402
402
  "has_error": bool(result_data.get("error")),
403
403
  "output_size": (
@@ -448,7 +448,7 @@ class EventHandlers:
448
448
  "session_id": event.get("session_id", ""),
449
449
  "working_directory": working_dir,
450
450
  "git_branch": git_branch,
451
- "timestamp": datetime.now().isoformat(),
451
+ "timestamp": datetime.now(timezone.utc).isoformat(),
452
452
  "is_user_input_request": "input" in message.lower()
453
453
  or "waiting" in message.lower(),
454
454
  "is_error_notification": "error" in message.lower()
@@ -492,7 +492,7 @@ class EventHandlers:
492
492
  """Extract metadata from stop event."""
493
493
  working_dir = event.get("cwd", "")
494
494
  return {
495
- "timestamp": datetime.now().isoformat(),
495
+ "timestamp": datetime.now(timezone.utc).isoformat(),
496
496
  "working_directory": working_dir,
497
497
  "git_branch": (
498
498
  self._get_git_branch(working_dir) if working_dir else "Unknown"
@@ -639,7 +639,7 @@ class EventHandlers:
639
639
  "has_error": reason in ["error", "timeout", "failed", "blocked"],
640
640
  "working_directory": working_dir,
641
641
  "git_branch": git_branch,
642
- "timestamp": datetime.now().isoformat(),
642
+ "timestamp": datetime.now(timezone.utc).isoformat(),
643
643
  "event_type": "subagent_stop",
644
644
  "reason": reason,
645
645
  "original_request_timestamp": request_info.get("timestamp"),
@@ -715,7 +715,7 @@ class EventHandlers:
715
715
  "session_id": session_id,
716
716
  "working_directory": working_dir,
717
717
  "git_branch": git_branch,
718
- "timestamp": datetime.now().isoformat(),
718
+ "timestamp": datetime.now(timezone.utc).isoformat(),
719
719
  "contains_code": "```" in response_text,
720
720
  "contains_json": "```json" in response_text,
721
721
  "hook_event_name": "AssistantResponse", # Explicitly set for dashboard
@@ -25,7 +25,7 @@ import signal
25
25
  import subprocess
26
26
  import sys
27
27
  import threading
28
- from datetime import datetime
28
+ from datetime import datetime, timezone
29
29
  from typing import Optional, Tuple
30
30
 
31
31
  # Import extracted modules with fallback for direct execution
@@ -284,7 +284,7 @@ class ClaudeHookHandler:
284
284
  if self.duplicate_detector.is_duplicate(event):
285
285
  if DEBUG:
286
286
  print(
287
- f"[{datetime.now().isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
287
+ f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
288
288
  file=sys.stderr,
289
289
  )
290
290
  # Still need to output continue for this invocation
@@ -297,7 +297,7 @@ class ClaudeHookHandler:
297
297
  if DEBUG:
298
298
  hook_type = event.get("hook_event_name", "unknown")
299
299
  print(
300
- f"\n[{datetime.now().isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
300
+ f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
301
301
  file=sys.stderr,
302
302
  )
303
303
 
@@ -461,7 +461,7 @@ class ClaudeHookHandler:
461
461
  if hasattr(self, "connection_manager") and self.connection_manager:
462
462
  try:
463
463
  self.connection_manager.cleanup()
464
- except:
464
+ except Exception:
465
465
  pass # Ignore cleanup errors during destruction
466
466
 
467
467
 
@@ -22,7 +22,7 @@ import sys
22
22
  import threading
23
23
  import time
24
24
  from collections import deque
25
- from datetime import datetime
25
+ from datetime import datetime, timezone
26
26
  from pathlib import Path
27
27
  from typing import Optional
28
28
 
@@ -55,7 +55,7 @@ except ImportError:
55
55
  "type": event_data.get("type", "unknown"),
56
56
  "subtype": event_data.get("subtype", "generic"),
57
57
  "timestamp": event_data.get(
58
- "timestamp", datetime.now().isoformat()
58
+ "timestamp", datetime.now(timezone.utc).isoformat()
59
59
  ),
60
60
  "data": event_data.get("data", event_data),
61
61
  "source": source,
@@ -174,7 +174,7 @@ class HookHandler:
174
174
  raw_event = {
175
175
  "type": "hook",
176
176
  "subtype": event_type,
177
- "timestamp": datetime.now().isoformat(),
177
+ "timestamp": datetime.now(timezone.utc).isoformat(),
178
178
  "data": data,
179
179
  "source": "claude_hooks",
180
180
  "session_id": data.get("sessionId", self.current_session_id),
@@ -21,7 +21,7 @@ import sys
21
21
  import threading
22
22
  import time
23
23
  from collections import deque
24
- from datetime import datetime
24
+ from datetime import datetime, timezone
25
25
  from typing import Optional
26
26
 
27
27
  # Import extracted modules with fallback for direct execution
@@ -71,7 +71,7 @@ except ImportError:
71
71
  "type": event_data.get("type", "unknown"),
72
72
  "subtype": event_data.get("subtype", "generic"),
73
73
  "timestamp": event_data.get(
74
- "timestamp", datetime.now().isoformat()
74
+ "timestamp", datetime.now(timezone.utc).isoformat()
75
75
  ),
76
76
  "data": event_data.get("data", event_data),
77
77
  }
@@ -216,7 +216,7 @@ class ClaudeHookHandler:
216
216
 
217
217
  if session_id and agent_type and agent_type != "unknown":
218
218
  self.active_delegations[session_id] = agent_type
219
- key = f"{session_id}:{datetime.now().timestamp()}"
219
+ key = f"{session_id}:{datetime.now(timezone.utc).timestamp()}"
220
220
  self.delegation_history.append((key, agent_type))
221
221
 
222
222
  # Store request data for response tracking correlation
@@ -224,7 +224,7 @@ class ClaudeHookHandler:
224
224
  self.delegation_requests[session_id] = {
225
225
  "agent_type": agent_type,
226
226
  "request": request_data,
227
- "timestamp": datetime.now().isoformat(),
227
+ "timestamp": datetime.now(timezone.utc).isoformat(),
228
228
  }
229
229
  if DEBUG:
230
230
  print(
@@ -237,7 +237,7 @@ class ClaudeHookHandler:
237
237
  )
238
238
 
239
239
  # Clean up old delegations (older than 5 minutes)
240
- cutoff_time = datetime.now().timestamp() - 300
240
+ cutoff_time = datetime.now(timezone.utc).timestamp() - 300
241
241
  keys_to_remove = []
242
242
  for sid in list(self.active_delegations.keys()):
243
243
  # Check if this is an old entry by looking in history
@@ -259,7 +259,7 @@ class ClaudeHookHandler:
259
259
 
260
260
  def _cleanup_old_entries(self):
261
261
  """Clean up old entries to prevent memory growth."""
262
- datetime.now().timestamp() - self.MAX_CACHE_AGE_SECONDS
262
+ datetime.now(timezone.utc).timestamp() - self.MAX_CACHE_AGE_SECONDS
263
263
 
264
264
  # Clean up delegation tracking dictionaries
265
265
  for storage in [self.active_delegations, self.delegation_requests]:
@@ -281,7 +281,8 @@ class ClaudeHookHandler:
281
281
  expired_keys = [
282
282
  key
283
283
  for key, cache_time in self._git_branch_cache_time.items()
284
- if datetime.now().timestamp() - cache_time > self.MAX_CACHE_AGE_SECONDS
284
+ if datetime.now(timezone.utc).timestamp() - cache_time
285
+ > self.MAX_CACHE_AGE_SECONDS
285
286
  ]
286
287
  for key in expired_keys:
287
288
  self._git_branch_cache.pop(key, None)
@@ -315,7 +316,7 @@ class ClaudeHookHandler:
315
316
  working_dir = os.getcwd()
316
317
 
317
318
  # Check cache first (cache for 30 seconds)
318
- current_time = datetime.now().timestamp()
319
+ current_time = datetime.now(timezone.utc).timestamp()
319
320
  cache_key = working_dir
320
321
 
321
322
  if (
@@ -413,7 +414,7 @@ class ClaudeHookHandler:
413
414
  if recent_key == event_key and (current_time - recent_time) < 0.1:
414
415
  if DEBUG:
415
416
  print(
416
- f"[{datetime.now().isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
417
+ f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
417
418
  file=sys.stderr,
418
419
  )
419
420
  # Still need to output continue for this invocation
@@ -429,7 +430,7 @@ class ClaudeHookHandler:
429
430
  if DEBUG:
430
431
  hook_type = event.get("hook_event_name", "unknown")
431
432
  print(
432
- f"\n[{datetime.now().isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
433
+ f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
433
434
  file=sys.stderr,
434
435
  )
435
436
 
@@ -582,7 +583,7 @@ class ClaudeHookHandler:
582
583
  raw_event = {
583
584
  "type": "hook",
584
585
  "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
585
- "timestamp": datetime.now().isoformat(),
586
+ "timestamp": datetime.now(timezone.utc).isoformat(),
586
587
  "data": data,
587
588
  "source": "claude_hooks", # Identify the source
588
589
  "session_id": data.get("sessionId"), # Include session if available
@@ -857,7 +858,7 @@ class ClaudeHookHandler:
857
858
  "duration_ms": event.get("duration_ms"),
858
859
  "working_directory": working_dir,
859
860
  "git_branch": git_branch,
860
- "timestamp": datetime.now().isoformat(),
861
+ "timestamp": datetime.now(timezone.utc).isoformat(),
861
862
  "event_type": "subagent_stop",
862
863
  "reason": reason,
863
864
  "original_request_timestamp": request_info.get("timestamp"),
@@ -922,7 +923,7 @@ class ClaudeHookHandler:
922
923
  "session_id": session_id,
923
924
  "working_directory": working_dir,
924
925
  "git_branch": git_branch,
925
- "timestamp": datetime.now().isoformat(),
926
+ "timestamp": datetime.now(timezone.utc).isoformat(),
926
927
  "is_successful_completion": reason in ["completed", "finished", "done"],
927
928
  "is_error_termination": reason in ["error", "timeout", "failed", "blocked"],
928
929
  "is_delegation_related": agent_type
@@ -971,7 +972,7 @@ class ClaudeHookHandler:
971
972
  if hasattr(self, "connection_pool") and self.connection_pool:
972
973
  try:
973
974
  self.connection_pool.cleanup()
974
- except:
975
+ except Exception:
975
976
  pass # Ignore cleanup errors during destruction
976
977
 
977
978
 
@@ -20,7 +20,7 @@ import select
20
20
  import signal
21
21
  import sys
22
22
  import threading
23
- from datetime import datetime
23
+ from datetime import datetime, timezone
24
24
 
25
25
  # Import extracted modules with fallback for direct execution
26
26
  try:
@@ -127,7 +127,7 @@ class ClaudeHookHandler:
127
127
  if self.duplicate_detector.is_duplicate(event):
128
128
  if DEBUG:
129
129
  print(
130
- f"[{datetime.now().isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
130
+ f"[{datetime.now(timezone.utc).isoformat()}] Skipping duplicate event: {event.get('hook_event_name', 'unknown')} (PID: {os.getpid()})",
131
131
  file=sys.stderr,
132
132
  )
133
133
  # Still need to output continue for this invocation
@@ -140,7 +140,7 @@ class ClaudeHookHandler:
140
140
  if DEBUG:
141
141
  hook_type = event.get("hook_event_name", "unknown")
142
142
  print(
143
- f"\n[{datetime.now().isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
143
+ f"\n[{datetime.now(timezone.utc).isoformat()}] Processing hook event: {hook_type} (PID: {os.getpid()})",
144
144
  file=sys.stderr,
145
145
  )
146
146
 
@@ -278,7 +278,7 @@ class ClaudeHookHandler:
278
278
  if hasattr(self, "connection_manager") and self.connection_manager:
279
279
  try:
280
280
  self.connection_manager.cleanup()
281
- except:
281
+ except Exception:
282
282
  pass # Ignore cleanup errors during destruction
283
283
 
284
284
 
@@ -85,7 +85,7 @@ try:
85
85
  else:
86
86
  # Installed package - just return the package location
87
87
  print(os.path.dirname(pkg_dir))
88
- except:
88
+ except Exception:
89
89
  pass
90
90
  " 2>/dev/null)
91
91
 
@@ -714,7 +714,7 @@ main "$@"
714
714
  if "hooks" in settings:
715
715
  status["configured_events"] = list(settings["hooks"].keys())
716
716
  configured_in_local = True
717
- except:
717
+ except Exception:
718
718
  pass
719
719
 
720
720
  # Also check old settings file
@@ -728,7 +728,7 @@ main "$@"
728
728
  status["warning"] = (
729
729
  "Hooks found in settings.local.json but Claude Code reads from settings.json"
730
730
  )
731
- except:
731
+ except Exception:
732
732
  pass
733
733
 
734
734
  status["settings_location"] = (
@@ -7,7 +7,7 @@ including pre and post delegation hooks.
7
7
 
8
8
  import os
9
9
  import sys
10
- from datetime import datetime
10
+ from datetime import datetime, timezone
11
11
  from typing import Optional
12
12
 
13
13
  # Debug mode
@@ -122,7 +122,7 @@ class MemoryHookManager:
122
122
  "session_id": session_id,
123
123
  },
124
124
  metadata={"source": "claude_hook_handler", "tool_name": "Task"},
125
- timestamp=datetime.now().isoformat(),
125
+ timestamp=datetime.now(timezone.utc).isoformat(),
126
126
  session_id=session_id,
127
127
  )
128
128
 
@@ -200,7 +200,7 @@ class MemoryHookManager:
200
200
  "tool_name": "Task",
201
201
  "duration_ms": event.get("duration_ms", 0),
202
202
  },
203
- timestamp=datetime.now().isoformat(),
203
+ timestamp=datetime.now(timezone.utc).isoformat(),
204
204
  session_id=session_id,
205
205
  )
206
206
 
@@ -9,7 +9,7 @@ import json
9
9
  import os
10
10
  import re
11
11
  import sys
12
- from datetime import datetime
12
+ from datetime import datetime, timezone
13
13
  from typing import Optional
14
14
 
15
15
  # Debug mode
@@ -192,7 +192,7 @@ class ResponseTrackingManager:
192
192
  "has_error": bool(event.get("error")),
193
193
  "duration_ms": event.get("duration_ms"),
194
194
  "working_directory": event.get("cwd", ""),
195
- "timestamp": datetime.now().isoformat(),
195
+ "timestamp": datetime.now(timezone.utc).isoformat(),
196
196
  "tool_name": "Task",
197
197
  "original_request_timestamp": request_info.get("timestamp"),
198
198
  }
@@ -344,7 +344,7 @@ class ResponseTrackingManager:
344
344
 
345
345
  # Track the response
346
346
  metadata = {
347
- "timestamp": datetime.now().isoformat(),
347
+ "timestamp": datetime.now(timezone.utc).isoformat(),
348
348
  "prompt_timestamp": prompt_data.get("timestamp"),
349
349
  "working_directory": prompt_data.get("working_directory", ""),
350
350
  "event_type": "assistant_response",
@@ -18,7 +18,7 @@ This service manages:
18
18
 
19
19
  import os
20
20
  import sys
21
- from datetime import datetime
21
+ from datetime import datetime, timezone
22
22
 
23
23
  # Debug mode is enabled by default for better visibility into hook processing
24
24
  DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
@@ -62,7 +62,7 @@ except ImportError:
62
62
  "type": event_data.get("type", "unknown"),
63
63
  "subtype": event_data.get("subtype", "generic"),
64
64
  "timestamp": event_data.get(
65
- "timestamp", datetime.now().isoformat()
65
+ "timestamp", datetime.now(timezone.utc).isoformat()
66
66
  ),
67
67
  "data": event_data.get("data", event_data),
68
68
  }
@@ -119,7 +119,7 @@ class ConnectionManagerService:
119
119
  raw_event = {
120
120
  "type": "hook",
121
121
  "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
122
- "timestamp": datetime.now().isoformat(),
122
+ "timestamp": datetime.now(timezone.utc).isoformat(),
123
123
  "data": data,
124
124
  "source": "claude_hooks", # Identify the source
125
125
  "session_id": data.get("sessionId"), # Include session if available
@@ -190,7 +190,7 @@ class ConnectionManagerService:
190
190
 
191
191
  # Warn if no emission method is available
192
192
  if not self.connection_pool and DEBUG:
193
- print(f"⚠️ No event emission method available for: {event}", file=sys.stderr)
193
+ print(f"⚠️ No event emission method available for: {claude_event_data.get('event', 'unknown')}", file=sys.stderr)
194
194
 
195
195
  def cleanup(self):
196
196
  """Cleanup connections on service destruction."""
@@ -198,5 +198,5 @@ class ConnectionManagerService:
198
198
  if self.connection_pool:
199
199
  try:
200
200
  self.connection_pool.cleanup()
201
- except:
201
+ except Exception:
202
202
  pass # Ignore cleanup errors during destruction
@@ -12,7 +12,7 @@ This eliminates disconnection issues and matches the process lifecycle.
12
12
  import asyncio
13
13
  import os
14
14
  import sys
15
- from datetime import datetime
15
+ from datetime import datetime, timezone
16
16
 
17
17
  # Debug mode is enabled by default for better visibility into hook processing
18
18
  DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
@@ -52,7 +52,7 @@ except ImportError:
52
52
  "type": event_data.get("type", "unknown"),
53
53
  "subtype": event_data.get("subtype", "generic"),
54
54
  "timestamp": event_data.get(
55
- "timestamp", datetime.now().isoformat()
55
+ "timestamp", datetime.now(timezone.utc).isoformat()
56
56
  ),
57
57
  "data": event_data.get("data", event_data),
58
58
  }
@@ -101,7 +101,7 @@ class ConnectionManagerService:
101
101
  raw_event = {
102
102
  "type": "hook",
103
103
  "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
104
- "timestamp": datetime.now().isoformat(),
104
+ "timestamp": datetime.now(timezone.utc).isoformat(),
105
105
  "data": data,
106
106
  "source": "claude_hooks", # Identify the source
107
107
  "session_id": data.get("sessionId"), # Include session if available
@@ -11,7 +11,7 @@ import os
11
11
  import subprocess
12
12
  import time
13
13
  from collections import deque
14
- from datetime import datetime
14
+ from datetime import datetime, timezone
15
15
  from typing import Optional
16
16
 
17
17
  # Import constants for configuration
@@ -77,7 +77,7 @@ class StateManagerService:
77
77
 
78
78
  if session_id and agent_type and agent_type != "unknown":
79
79
  self.active_delegations[session_id] = agent_type
80
- key = f"{session_id}:{datetime.now().timestamp()}"
80
+ key = f"{session_id}:{datetime.now(timezone.utc).timestamp()}"
81
81
  self.delegation_history.append((key, agent_type))
82
82
 
83
83
  # Store request data for response tracking correlation
@@ -85,7 +85,7 @@ class StateManagerService:
85
85
  self.delegation_requests[session_id] = {
86
86
  "agent_type": agent_type,
87
87
  "request": request_data,
88
- "timestamp": datetime.now().isoformat(),
88
+ "timestamp": datetime.now(timezone.utc).isoformat(),
89
89
  }
90
90
  if DEBUG:
91
91
  import sys
@@ -100,7 +100,7 @@ class StateManagerService:
100
100
  )
101
101
 
102
102
  # Clean up old delegations (older than 5 minutes)
103
- cutoff_time = datetime.now().timestamp() - 300
103
+ cutoff_time = datetime.now(timezone.utc).timestamp() - 300
104
104
  keys_to_remove = []
105
105
  for sid in list(self.active_delegations.keys()):
106
106
  # Check if this is an old entry by looking in history
@@ -136,7 +136,7 @@ class StateManagerService:
136
136
 
137
137
  def cleanup_old_entries(self):
138
138
  """Clean up old entries to prevent memory growth."""
139
- datetime.now().timestamp() - self.MAX_CACHE_AGE_SECONDS
139
+ datetime.now(timezone.utc).timestamp() - self.MAX_CACHE_AGE_SECONDS
140
140
 
141
141
  # Clean up delegation tracking dictionaries
142
142
  for storage in [self.active_delegations, self.delegation_requests]:
@@ -158,7 +158,8 @@ class StateManagerService:
158
158
  expired_keys = [
159
159
  key
160
160
  for key, cache_time in self._git_branch_cache_time.items()
161
- if datetime.now().timestamp() - cache_time > self.MAX_CACHE_AGE_SECONDS
161
+ if datetime.now(timezone.utc).timestamp() - cache_time
162
+ > self.MAX_CACHE_AGE_SECONDS
162
163
  ]
163
164
  for key in expired_keys:
164
165
  self._git_branch_cache.pop(key, None)
@@ -178,7 +179,7 @@ class StateManagerService:
178
179
  working_dir = os.getcwd()
179
180
 
180
181
  # Check cache first (cache for 30 seconds)
181
- current_time = datetime.now().timestamp()
182
+ current_time = datetime.now(timezone.utc).timestamp()
182
183
  cache_key = working_dir
183
184
 
184
185
  if (
@@ -11,7 +11,7 @@ import json
11
11
  import os
12
12
  import re
13
13
  import sys
14
- from datetime import datetime
14
+ from datetime import datetime, timezone
15
15
  from typing import Optional, Tuple
16
16
 
17
17
  # Debug mode is enabled by default for better visibility into hook processing
@@ -272,7 +272,7 @@ class SubagentResponseProcessor:
272
272
  "duration_ms": event.get("duration_ms"),
273
273
  "working_directory": working_dir,
274
274
  "git_branch": git_branch,
275
- "timestamp": datetime.now().isoformat(),
275
+ "timestamp": datetime.now(timezone.utc).isoformat(),
276
276
  "event_type": "subagent_stop",
277
277
  "reason": reason,
278
278
  "original_request_timestamp": request_info.get("timestamp"),
@@ -347,7 +347,7 @@ class SubagentResponseProcessor:
347
347
  "session_id": session_id,
348
348
  "working_directory": working_dir,
349
349
  "git_branch": git_branch,
350
- "timestamp": datetime.now().isoformat(),
350
+ "timestamp": datetime.now(timezone.utc).isoformat(),
351
351
  "is_successful_completion": reason in ["completed", "finished", "done"],
352
352
  "is_error_termination": reason in ["error", "timeout", "failed", "blocked"],
353
353
  "is_delegation_related": agent_type