claude-mpm 4.5.8__py3-none-any.whl → 4.5.12__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 (226) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +20 -5
  3. claude_mpm/agents/agent_loader.py +19 -2
  4. claude_mpm/agents/base_agent_loader.py +5 -5
  5. claude_mpm/agents/frontmatter_validator.py +4 -4
  6. claude_mpm/agents/templates/agent-manager.json +3 -3
  7. claude_mpm/agents/templates/agentic-coder-optimizer.json +3 -3
  8. claude_mpm/agents/templates/api_qa.json +1 -1
  9. claude_mpm/agents/templates/clerk-ops.json +3 -3
  10. claude_mpm/agents/templates/code_analyzer.json +3 -3
  11. claude_mpm/agents/templates/dart_engineer.json +294 -0
  12. claude_mpm/agents/templates/data_engineer.json +3 -3
  13. claude_mpm/agents/templates/documentation.json +2 -2
  14. claude_mpm/agents/templates/engineer.json +2 -2
  15. claude_mpm/agents/templates/gcp_ops_agent.json +2 -2
  16. claude_mpm/agents/templates/imagemagick.json +1 -1
  17. claude_mpm/agents/templates/local_ops_agent.json +319 -41
  18. claude_mpm/agents/templates/memory_manager.json +2 -2
  19. claude_mpm/agents/templates/nextjs_engineer.json +2 -2
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/php-engineer.json +1 -1
  22. claude_mpm/agents/templates/project_organizer.json +1 -1
  23. claude_mpm/agents/templates/prompt-engineer.json +6 -4
  24. claude_mpm/agents/templates/python_engineer.json +2 -2
  25. claude_mpm/agents/templates/qa.json +1 -1
  26. claude_mpm/agents/templates/react_engineer.json +3 -3
  27. claude_mpm/agents/templates/refactoring_engineer.json +3 -3
  28. claude_mpm/agents/templates/research.json +2 -2
  29. claude_mpm/agents/templates/security.json +2 -2
  30. claude_mpm/agents/templates/ticketing.json +2 -2
  31. claude_mpm/agents/templates/typescript_engineer.json +2 -2
  32. claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
  33. claude_mpm/agents/templates/version_control.json +2 -2
  34. claude_mpm/agents/templates/web_qa.json +6 -6
  35. claude_mpm/agents/templates/web_ui.json +3 -3
  36. claude_mpm/cli/__init__.py +49 -19
  37. claude_mpm/cli/commands/agent_manager.py +3 -3
  38. claude_mpm/cli/commands/agents.py +6 -6
  39. claude_mpm/cli/commands/aggregate.py +4 -4
  40. claude_mpm/cli/commands/analyze.py +2 -2
  41. claude_mpm/cli/commands/analyze_code.py +1 -1
  42. claude_mpm/cli/commands/cleanup.py +3 -3
  43. claude_mpm/cli/commands/config.py +2 -2
  44. claude_mpm/cli/commands/configure.py +605 -21
  45. claude_mpm/cli/commands/dashboard.py +1 -1
  46. claude_mpm/cli/commands/debug.py +3 -3
  47. claude_mpm/cli/commands/doctor.py +1 -1
  48. claude_mpm/cli/commands/mcp.py +7 -7
  49. claude_mpm/cli/commands/mcp_command_router.py +1 -1
  50. claude_mpm/cli/commands/mcp_config.py +2 -2
  51. claude_mpm/cli/commands/mcp_external_commands.py +2 -2
  52. claude_mpm/cli/commands/mcp_install_commands.py +3 -3
  53. claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
  54. claude_mpm/cli/commands/mcp_setup_external.py +3 -3
  55. claude_mpm/cli/commands/monitor.py +1 -1
  56. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  57. claude_mpm/cli/interactive/agent_wizard.py +1 -1
  58. claude_mpm/cli/parsers/configure_parser.py +5 -0
  59. claude_mpm/cli/parsers/search_parser.py +1 -1
  60. claude_mpm/cli/shared/argument_patterns.py +2 -2
  61. claude_mpm/cli/shared/base_command.py +1 -1
  62. claude_mpm/cli/startup_logging.py +4 -4
  63. claude_mpm/config/experimental_features.py +4 -4
  64. claude_mpm/config/socketio_config.py +2 -2
  65. claude_mpm/core/__init__.py +53 -17
  66. claude_mpm/core/agent_session_manager.py +2 -2
  67. claude_mpm/core/api_validator.py +3 -3
  68. claude_mpm/core/base_service.py +10 -1
  69. claude_mpm/core/cache.py +2 -2
  70. claude_mpm/core/config.py +5 -5
  71. claude_mpm/core/config_aliases.py +4 -4
  72. claude_mpm/core/config_constants.py +1 -1
  73. claude_mpm/core/error_handler.py +1 -1
  74. claude_mpm/core/file_utils.py +5 -5
  75. claude_mpm/core/framework/formatters/capability_generator.py +5 -5
  76. claude_mpm/core/framework/loaders/agent_loader.py +1 -1
  77. claude_mpm/core/framework/processors/metadata_processor.py +1 -1
  78. claude_mpm/core/framework/processors/template_processor.py +3 -3
  79. claude_mpm/core/framework_loader.py +2 -2
  80. claude_mpm/core/log_manager.py +11 -4
  81. claude_mpm/core/logger.py +2 -2
  82. claude_mpm/core/optimized_startup.py +1 -1
  83. claude_mpm/core/output_style_manager.py +1 -1
  84. claude_mpm/core/service_registry.py +2 -2
  85. claude_mpm/core/session_manager.py +3 -3
  86. claude_mpm/core/shared/config_loader.py +1 -1
  87. claude_mpm/core/socketio_pool.py +2 -2
  88. claude_mpm/core/unified_agent_registry.py +2 -2
  89. claude_mpm/core/unified_config.py +6 -6
  90. claude_mpm/core/unified_paths.py +2 -2
  91. claude_mpm/dashboard/api/simple_directory.py +1 -1
  92. claude_mpm/generators/agent_profile_generator.py +1 -1
  93. claude_mpm/hooks/claude_hooks/event_handlers.py +2 -2
  94. claude_mpm/hooks/claude_hooks/installer.py +9 -9
  95. claude_mpm/hooks/claude_hooks/response_tracking.py +16 -11
  96. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +16 -13
  97. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  98. claude_mpm/hooks/memory_integration_hook.py +1 -1
  99. claude_mpm/hooks/validation_hooks.py +1 -1
  100. claude_mpm/init.py +4 -4
  101. claude_mpm/models/agent_session.py +1 -1
  102. claude_mpm/scripts/socketio_daemon.py +5 -5
  103. claude_mpm/services/__init__.py +145 -161
  104. claude_mpm/services/agent_capabilities_service.py +1 -1
  105. claude_mpm/services/agents/agent_builder.py +4 -4
  106. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -1
  107. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  108. claude_mpm/services/agents/deployment/agent_record_service.py +3 -3
  109. claude_mpm/services/agents/deployment/deployment_config_loader.py +21 -0
  110. claude_mpm/services/agents/deployment/deployment_wrapper.py +1 -1
  111. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +2 -2
  112. claude_mpm/services/agents/loading/agent_profile_loader.py +2 -2
  113. claude_mpm/services/agents/loading/base_agent_manager.py +12 -2
  114. claude_mpm/services/agents/local_template_manager.py +5 -5
  115. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  116. claude_mpm/services/agents/registry/modification_tracker.py +19 -11
  117. claude_mpm/services/async_session_logger.py +3 -3
  118. claude_mpm/services/claude_session_logger.py +4 -4
  119. claude_mpm/services/cli/agent_listing_service.py +3 -3
  120. claude_mpm/services/cli/agent_validation_service.py +1 -1
  121. claude_mpm/services/cli/session_manager.py +2 -2
  122. claude_mpm/services/core/path_resolver.py +1 -1
  123. claude_mpm/services/diagnostics/checks/agent_check.py +1 -1
  124. claude_mpm/services/diagnostics/checks/claude_code_check.py +2 -2
  125. claude_mpm/services/diagnostics/checks/common_issues_check.py +3 -3
  126. claude_mpm/services/diagnostics/checks/configuration_check.py +2 -2
  127. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  128. claude_mpm/services/diagnostics/checks/mcp_check.py +1 -1
  129. claude_mpm/services/diagnostics/checks/mcp_services_check.py +9 -9
  130. claude_mpm/services/diagnostics/checks/monitor_check.py +1 -1
  131. claude_mpm/services/diagnostics/doctor_reporter.py +1 -1
  132. claude_mpm/services/event_aggregator.py +1 -1
  133. claude_mpm/services/event_bus/event_bus.py +7 -2
  134. claude_mpm/services/events/consumers/dead_letter.py +2 -2
  135. claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
  136. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
  137. claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
  138. claude_mpm/services/hook_installer_service.py +7 -7
  139. claude_mpm/services/infrastructure/context_preservation.py +7 -7
  140. claude_mpm/services/infrastructure/daemon_manager.py +5 -5
  141. claude_mpm/services/mcp_config_manager.py +169 -48
  142. claude_mpm/services/mcp_gateway/__init__.py +98 -94
  143. claude_mpm/services/mcp_gateway/auto_configure.py +5 -5
  144. claude_mpm/services/mcp_gateway/config/config_loader.py +2 -2
  145. claude_mpm/services/mcp_gateway/config/configuration.py +3 -3
  146. claude_mpm/services/mcp_gateway/core/process_pool.py +3 -3
  147. claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
  148. claude_mpm/services/mcp_gateway/core/startup_verification.py +1 -1
  149. claude_mpm/services/mcp_gateway/main.py +1 -1
  150. claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
  151. claude_mpm/services/mcp_gateway/registry/tool_registry.py +2 -1
  152. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  153. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
  154. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +1 -1
  155. claude_mpm/services/mcp_gateway/tools/hello_world.py +1 -1
  156. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +5 -5
  157. claude_mpm/services/mcp_gateway/utils/update_preferences.py +2 -2
  158. claude_mpm/services/mcp_service_verifier.py +1 -1
  159. claude_mpm/services/memory/builder.py +1 -1
  160. claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
  161. claude_mpm/services/memory/indexed_memory.py +3 -3
  162. claude_mpm/services/monitor/daemon.py +1 -1
  163. claude_mpm/services/monitor/daemon_manager.py +9 -9
  164. claude_mpm/services/monitor/event_emitter.py +1 -1
  165. claude_mpm/services/monitor/handlers/file.py +1 -1
  166. claude_mpm/services/monitor/handlers/hooks.py +3 -3
  167. claude_mpm/services/monitor/management/lifecycle.py +7 -7
  168. claude_mpm/services/monitor/server.py +2 -2
  169. claude_mpm/services/orphan_detection.py +788 -0
  170. claude_mpm/services/port_manager.py +2 -2
  171. claude_mpm/services/project/analyzer.py +3 -3
  172. claude_mpm/services/project/archive_manager.py +13 -13
  173. claude_mpm/services/project/dependency_analyzer.py +4 -4
  174. claude_mpm/services/project/documentation_manager.py +4 -4
  175. claude_mpm/services/project/enhanced_analyzer.py +8 -8
  176. claude_mpm/services/project/registry.py +4 -4
  177. claude_mpm/services/project_port_allocator.py +597 -0
  178. claude_mpm/services/response_tracker.py +1 -1
  179. claude_mpm/services/session_management_service.py +1 -1
  180. claude_mpm/services/session_manager.py +6 -4
  181. claude_mpm/services/socketio/event_normalizer.py +1 -1
  182. claude_mpm/services/socketio/handlers/code_analysis.py +14 -12
  183. claude_mpm/services/socketio/handlers/file.py +1 -1
  184. claude_mpm/services/socketio/migration_utils.py +1 -1
  185. claude_mpm/services/socketio/server/core.py +1 -1
  186. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +1 -1
  187. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +4 -4
  188. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -1
  189. claude_mpm/services/unified/config_strategies/config_schema.py +4 -4
  190. claude_mpm/services/unified/config_strategies/context_strategy.py +6 -6
  191. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +10 -10
  192. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +5 -5
  193. claude_mpm/services/unified/config_strategies/unified_config_service.py +8 -8
  194. claude_mpm/services/unified/config_strategies/validation_strategy.py +15 -15
  195. claude_mpm/services/unified/deployment_strategies/base.py +4 -4
  196. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +15 -15
  197. claude_mpm/services/unified/deployment_strategies/local.py +9 -9
  198. claude_mpm/services/unified/deployment_strategies/utils.py +9 -9
  199. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -7
  200. claude_mpm/services/unified/unified_config.py +5 -5
  201. claude_mpm/services/unified/unified_deployment.py +2 -2
  202. claude_mpm/services/utility_service.py +1 -1
  203. claude_mpm/services/version_control/conflict_resolution.py +2 -2
  204. claude_mpm/services/version_control/git_operations.py +3 -3
  205. claude_mpm/services/version_control/semantic_versioning.py +13 -13
  206. claude_mpm/services/version_control/version_parser.py +1 -1
  207. claude_mpm/storage/state_storage.py +12 -13
  208. claude_mpm/tools/code_tree_analyzer.py +5 -5
  209. claude_mpm/tools/code_tree_builder.py +4 -4
  210. claude_mpm/tools/socketio_debug.py +1 -1
  211. claude_mpm/utils/agent_dependency_loader.py +4 -4
  212. claude_mpm/utils/common.py +2 -2
  213. claude_mpm/utils/config_manager.py +3 -3
  214. claude_mpm/utils/dependency_cache.py +2 -2
  215. claude_mpm/utils/dependency_strategies.py +6 -6
  216. claude_mpm/utils/file_utils.py +11 -11
  217. claude_mpm/utils/log_cleanup.py +1 -1
  218. claude_mpm/utils/path_operations.py +1 -1
  219. claude_mpm/validation/agent_validator.py +2 -2
  220. claude_mpm/validation/frontmatter_validator.py +1 -1
  221. {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/METADATA +1 -1
  222. {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/RECORD +226 -223
  223. {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/WHEEL +0 -0
  224. {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/entry_points.txt +0 -0
  225. {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/licenses/LICENSE +0 -0
  226. {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/top_level.txt +0 -0
@@ -474,7 +474,7 @@ class PortManager:
474
474
  """Load registered instances from file."""
475
475
  try:
476
476
  if self.instances_file.exists():
477
- with open(self.instances_file) as f:
477
+ with self.instances_file.open() as f:
478
478
  return json.load(f)
479
479
  except Exception as e:
480
480
  self.logger.warning(f"Failed to load instances file: {e}")
@@ -484,7 +484,7 @@ class PortManager:
484
484
  def save_instances(self, instances: Dict) -> None:
485
485
  """Save registered instances to file."""
486
486
  try:
487
- with open(self.instances_file, "w") as f:
487
+ with self.instances_file.open("w") as f:
488
488
  json.dump(instances, f, indent=2)
489
489
  except Exception as e:
490
490
  self.logger.error(f"Failed to save instances file: {e}")
@@ -313,7 +313,7 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
313
313
  ) -> None:
314
314
  """Parse package.json for Node.js project details."""
315
315
  try:
316
- with open(package_path) as f:
316
+ with package_path.open() as f:
317
317
  package_data = json.load(f)
318
318
 
319
319
  # Extract dependencies
@@ -382,7 +382,7 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
382
382
  f"TOML parsing not available for {deps_path}"
383
383
  )
384
384
  return
385
- with open(deps_path, "rb") as f:
385
+ with deps_path.open("rb") as f:
386
386
  data = tomllib.load(f)
387
387
  deps = list(data.get("project", {}).get("dependencies", []))
388
388
  deps.extend(
@@ -430,7 +430,7 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
430
430
  except ImportError:
431
431
  self.logger.warning(f"TOML parsing not available for {cargo_path}")
432
432
  return
433
- with open(cargo_path, "rb") as f:
433
+ with cargo_path.open("rb") as f:
434
434
  cargo_data = tomllib.load(f)
435
435
 
436
436
  deps = cargo_data.get("dependencies", {})
@@ -24,7 +24,7 @@ import json
24
24
  import re
25
25
  import shutil
26
26
  import subprocess
27
- from datetime import datetime, timedelta
27
+ from datetime import datetime, timedelta, timezone
28
28
  from pathlib import Path
29
29
  from typing import Dict, List, Optional, Tuple
30
30
 
@@ -116,7 +116,7 @@ Generated by Claude MPM Archive Manager
116
116
 
117
117
  try:
118
118
  # Generate archive filename
119
- timestamp = datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
119
+ timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H-%M-%S")
120
120
  archive_name = f"{file_path.name}.{timestamp}{file_path.suffix}"
121
121
  archive_file_path = self.archive_path / archive_name
122
122
 
@@ -130,7 +130,7 @@ Generated by Claude MPM Archive Manager
130
130
  meta_data.update(
131
131
  {
132
132
  "original_path": str(file_path),
133
- "archived_at": datetime.now().isoformat(),
133
+ "archived_at": datetime.now(timezone.utc).isoformat(),
134
134
  "reason": reason or "Manual archive",
135
135
  "file_size": file_path.stat().st_size,
136
136
  "file_hash": self._calculate_file_hash(file_path),
@@ -152,7 +152,7 @@ Generated by Claude MPM Archive Manager
152
152
  def _calculate_file_hash(self, file_path: Path) -> str:
153
153
  """Calculate MD5 hash of file."""
154
154
  hasher = hashlib.md5()
155
- with open(file_path, "rb") as f:
155
+ with file_path.open("rb") as f:
156
156
  for chunk in iter(lambda: f.read(4096), b""):
157
157
  hasher.update(chunk)
158
158
  return hasher.hexdigest()
@@ -172,7 +172,7 @@ Generated by Claude MPM Archive Manager
172
172
  logger.info(f"Removed old archive: {archive.name}")
173
173
 
174
174
  # Compress old archives
175
- cutoff_compress = datetime.now() - timedelta(days=self.COMPRESS_AFTER_DAYS)
175
+ cutoff_compress = datetime.now(timezone.utc) - timedelta(days=self.COMPRESS_AFTER_DAYS)
176
176
  for archive in archives:
177
177
  if archive.suffix != ".gz":
178
178
  mtime = datetime.fromtimestamp(archive.stat().st_mtime)
@@ -180,7 +180,7 @@ Generated by Claude MPM Archive Manager
180
180
  self._compress_archive(archive)
181
181
 
182
182
  # Delete very old archives
183
- cutoff_delete = datetime.now() - timedelta(days=self.DELETE_AFTER_DAYS)
183
+ cutoff_delete = datetime.now(timezone.utc) - timedelta(days=self.DELETE_AFTER_DAYS)
184
184
  for archive in archives:
185
185
  mtime = datetime.fromtimestamp(archive.stat().st_mtime)
186
186
  if mtime < cutoff_delete:
@@ -204,7 +204,7 @@ Generated by Claude MPM Archive Manager
204
204
  try:
205
205
  compressed_path = archive_path.with_suffix(archive_path.suffix + ".gz")
206
206
 
207
- with open(archive_path, "rb") as f_in:
207
+ with archive_path.open("rb") as f_in:
208
208
  with gzip.open(compressed_path, "wb") as f_out:
209
209
  shutil.copyfileobj(f_in, f_out)
210
210
 
@@ -321,7 +321,7 @@ Generated by Claude MPM Archive Manager
321
321
  if archive_file.suffix == ".gz":
322
322
  # Decompress first
323
323
  with gzip.open(archive_file, "rb") as f_in:
324
- with open(target_path, "wb") as f_out:
324
+ with target_path.open("wb") as f_out:
325
325
  shutil.copyfileobj(f_in, f_out)
326
326
  else:
327
327
  shutil.copy2(archive_file, target_path)
@@ -519,7 +519,7 @@ Generated by Claude MPM Archive Manager
519
519
  def review_documentation(self, check_git: bool = True) -> Dict:
520
520
  """Comprehensive documentation review with outdated detection."""
521
521
  report = {
522
- "timestamp": datetime.now().isoformat(),
522
+ "timestamp": datetime.now(timezone.utc).isoformat(),
523
523
  "files_reviewed": {},
524
524
  "outdated_sections": [],
525
525
  "synchronization_issues": [],
@@ -698,7 +698,7 @@ Generated by Claude MPM Archive Manager
698
698
  if changelog_path.exists():
699
699
  last_modified = self.get_file_last_modified(changelog_path)
700
700
  if last_modified:
701
- days_old = (datetime.now() - last_modified).days
701
+ days_old = (datetime.now(timezone.utc) - last_modified).days
702
702
  if days_old > 30:
703
703
  issues.append(
704
704
  {
@@ -800,7 +800,7 @@ Generated by Claude MPM Archive Manager
800
800
  # Check if file hasn't been updated in git for long time
801
801
  if file_report.get("last_git_update"):
802
802
  last_update = datetime.fromisoformat(file_report["last_git_update"])
803
- days_old = (datetime.now() - last_update).days
803
+ days_old = (datetime.now(timezone.utc) - last_update).days
804
804
  if days_old > 90:
805
805
  should_archive = True
806
806
  archive_reason.append(f"No updates for {days_old} days")
@@ -913,7 +913,7 @@ Generated by Claude MPM Archive Manager
913
913
  changelog_content = changelog_path.read_text()
914
914
  if f"## [{current_version}]" not in changelog_content:
915
915
  # Add new version section
916
- today = datetime.now().strftime("%Y-%m-%d")
916
+ today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
917
917
  new_section = f"\n## [{current_version}] - {today}\n\n### Added\n\n### Changed\n\n### Fixed\n\n"
918
918
 
919
919
  # Insert after header
@@ -981,7 +981,7 @@ Generated by Claude MPM Archive Manager
981
981
  last_updated = "Unknown"
982
982
  if report.get("last_git_update"):
983
983
  last_date = datetime.fromisoformat(report["last_git_update"])
984
- days_ago = (datetime.now() - last_date).days
984
+ days_ago = (datetime.now(timezone.utc) - last_date).days
985
985
  last_updated = f"{days_ago} days ago"
986
986
 
987
987
  table.add_row(filename, status, str(issues), last_updated)
@@ -279,7 +279,7 @@ class DependencyAnalyzerService:
279
279
  package_json_path = self.working_directory / "package.json"
280
280
  if package_json_path.exists():
281
281
  try:
282
- with open(package_json_path) as f:
282
+ with package_json_path.open() as f:
283
283
  package_data = json.load(f)
284
284
  except Exception as e:
285
285
  self.logger.warning(f"Error reading package.json: {e}")
@@ -324,7 +324,7 @@ class DependencyAnalyzerService:
324
324
  ) -> None:
325
325
  """Parse package.json for dependencies."""
326
326
  try:
327
- with open(path) as f:
327
+ with path.open() as f:
328
328
  data = json.load(f)
329
329
 
330
330
  # Production dependencies
@@ -382,7 +382,7 @@ class DependencyAnalyzerService:
382
382
  except ImportError:
383
383
  return
384
384
 
385
- with open(path, "rb") as f:
385
+ with path.open("rb") as f:
386
386
  data = tomllib.load(f)
387
387
 
388
388
  # PEP 621 dependencies
@@ -433,7 +433,7 @@ class DependencyAnalyzerService:
433
433
  except ImportError:
434
434
  return
435
435
 
436
- with open(path, "rb") as f:
436
+ with path.open("rb") as f:
437
437
  data = tomllib.load(f)
438
438
 
439
439
  # Production dependencies
@@ -19,7 +19,7 @@ Created: 2025-01-26
19
19
  import difflib
20
20
  import hashlib
21
21
  import re
22
- from datetime import datetime
22
+ from datetime import datetime, timezone
23
23
  from pathlib import Path
24
24
  from typing import Dict, List, Tuple
25
25
 
@@ -384,7 +384,7 @@ class DocumentationManager:
384
384
 
385
385
  def _add_metadata(self, content: str) -> str:
386
386
  """Add metadata to the document."""
387
- timestamp = datetime.now().isoformat()
387
+ timestamp = datetime.now(timezone.utc).isoformat()
388
388
 
389
389
  # Check if meta section exists
390
390
  if "## 📝 Meta:" not in content and "## Meta:" not in content:
@@ -417,7 +417,7 @@ class DocumentationManager:
417
417
  def generate_update_report(self, old_content: str, new_content: str) -> Dict:
418
418
  """Generate a report of changes between old and new content."""
419
419
  report = {
420
- "timestamp": datetime.now().isoformat(),
420
+ "timestamp": datetime.now(timezone.utc).isoformat(),
421
421
  "changes": [],
422
422
  "additions": [],
423
423
  "deletions": [],
@@ -547,7 +547,7 @@ class DocumentationManager:
547
547
 
548
548
  ## 📝 Meta: Maintaining This Document
549
549
 
550
- - **Last Updated**: {datetime.now().isoformat()}
550
+ - **Last Updated**: {datetime.now(timezone.utc).isoformat()}
551
551
  - **Created By**: Claude MPM /mpm-init
552
552
  - **Update Frequency**: As needed when requirements change
553
553
  """
@@ -17,7 +17,7 @@ Created: 2025-01-26
17
17
  """
18
18
 
19
19
  import subprocess
20
- from datetime import datetime, timedelta
20
+ from datetime import datetime, timedelta, timezone
21
21
  from pathlib import Path
22
22
  from typing import Dict, List, Optional
23
23
 
@@ -74,7 +74,7 @@ class EnhancedProjectAnalyzer:
74
74
 
75
75
  def _get_recent_commits(self, days: int) -> List[Dict]:
76
76
  """Get recent commits within specified days."""
77
- since_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
77
+ since_date = (datetime.now(timezone.utc) - timedelta(days=days)).strftime("%Y-%m-%d")
78
78
 
79
79
  # Get commit log with structured format
80
80
  output = self._run_git_command(
@@ -107,7 +107,7 @@ class EnhancedProjectAnalyzer:
107
107
 
108
108
  def _get_changed_files(self, days: int) -> Dict:
109
109
  """Get files changed in recent commits."""
110
- since_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
110
+ since_date = (datetime.now(timezone.utc) - timedelta(days=days)).strftime("%Y-%m-%d")
111
111
 
112
112
  output = self._run_git_command(
113
113
  [
@@ -138,7 +138,7 @@ class EnhancedProjectAnalyzer:
138
138
 
139
139
  def _get_recently_added_files(self, days: int) -> List[str]:
140
140
  """Get files added in recent commits."""
141
- since_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
141
+ since_date = (datetime.now(timezone.utc) - timedelta(days=days)).strftime("%Y-%m-%d")
142
142
 
143
143
  output = self._run_git_command(
144
144
  [
@@ -162,7 +162,7 @@ class EnhancedProjectAnalyzer:
162
162
 
163
163
  def _get_author_stats(self, days: int) -> Dict:
164
164
  """Get author contribution statistics."""
165
- since_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
165
+ since_date = (datetime.now(timezone.utc) - timedelta(days=days)).strftime("%Y-%m-%d")
166
166
 
167
167
  output = self._run_git_command(
168
168
  [
@@ -228,7 +228,7 @@ class EnhancedProjectAnalyzer:
228
228
 
229
229
  def _get_documentation_changes(self, days: int) -> Dict:
230
230
  """Track changes to documentation files."""
231
- since_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
231
+ since_date = (datetime.now(timezone.utc) - timedelta(days=days)).strftime("%Y-%m-%d")
232
232
 
233
233
  # Get changes to documentation files
234
234
  doc_patterns = ["*.md", "*.rst", "*.txt", "docs/*", "README*", "CLAUDE*"]
@@ -448,7 +448,7 @@ class EnhancedProjectAnalyzer:
448
448
  )
449
449
  if first_commit:
450
450
  age_days = (
451
- datetime.now() - datetime.fromtimestamp(int(first_commit))
451
+ datetime.now(timezone.utc) - datetime.fromtimestamp(int(first_commit))
452
452
  ).days
453
453
  indicators.append(f"{age_days} days old")
454
454
 
@@ -470,7 +470,7 @@ class EnhancedProjectAnalyzer:
470
470
  """Generate comprehensive project analysis report."""
471
471
  report = {
472
472
  "project_path": str(self.project_path),
473
- "timestamp": datetime.now().isoformat(),
473
+ "timestamp": datetime.now(timezone.utc).isoformat(),
474
474
  }
475
475
 
476
476
  # Basic project info
@@ -69,7 +69,7 @@ class ProjectRegistry:
69
69
  self.registry_dir.mkdir(parents=True, exist_ok=True)
70
70
  except Exception as e:
71
71
  self.logger.error(f"Failed to create registry directory: {e}")
72
- raise ProjectRegistryError(f"Cannot create registry directory: {e}")
72
+ raise ProjectRegistryError(f"Cannot create registry directory: {e}") from e
73
73
 
74
74
  def get_or_create_project_entry(self) -> Dict[str, Any]:
75
75
  """
@@ -104,7 +104,7 @@ class ProjectRegistry:
104
104
 
105
105
  except Exception as e:
106
106
  self.logger.error(f"Failed to get or create project entry: {e}")
107
- raise ProjectRegistryError(f"Registry operation failed: {e}")
107
+ raise ProjectRegistryError(f"Registry operation failed: {e}") from e
108
108
 
109
109
  def _find_existing_entry(self) -> Optional[Dict[str, Any]]:
110
110
  """
@@ -491,7 +491,7 @@ class ProjectRegistry:
491
491
  # Remove internal fields before saving
492
492
  save_data = {k: v for k, v in data.items() if not k.startswith("_")}
493
493
 
494
- with open(registry_file, "w", encoding="utf-8") as f:
494
+ with registry_file.open("w", encoding="utf-8") as f:
495
495
  yaml.dump(
496
496
  save_data, f, default_flow_style=False, sort_keys=False, indent=2
497
497
  )
@@ -500,7 +500,7 @@ class ProjectRegistry:
500
500
 
501
501
  except Exception as e:
502
502
  self.logger.error(f"Failed to save registry data: {e}")
503
- raise ProjectRegistryError(f"Failed to save registry: {e}")
503
+ raise ProjectRegistryError(f"Failed to save registry: {e}") from e
504
504
 
505
505
  def list_projects(self) -> List[Dict[str, Any]]:
506
506
  """