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
@@ -8,7 +8,7 @@ Reduces duplication by sharing common cloud deployment patterns.
8
8
 
9
9
  import json
10
10
  import subprocess
11
- from datetime import datetime
11
+ from datetime import datetime, timezone
12
12
  from pathlib import Path
13
13
  from typing import Any, Dict, List
14
14
 
@@ -48,7 +48,7 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
48
48
  # Check Railway CLI
49
49
  try:
50
50
  subprocess.run(["railway", "--version"], capture_output=True, check=True)
51
- except:
51
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
52
52
  errors.append(
53
53
  "Railway CLI not installed. Install with: npm i -g @railway/cli"
54
54
  )
@@ -56,7 +56,7 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
56
56
  # Check authentication
57
57
  try:
58
58
  subprocess.run(["railway", "whoami"], capture_output=True, check=True)
59
- except:
59
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
60
60
  errors.append("Not authenticated with Railway. Run: railway login")
61
61
 
62
62
  return errors
@@ -97,13 +97,13 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
97
97
  break
98
98
 
99
99
  return {
100
- "deployment_id": f"railway_{datetime.now().timestamp()}",
100
+ "deployment_id": f"railway_{datetime.now(timezone.utc).timestamp()}",
101
101
  "deployment_url": deployment_url,
102
102
  "deployed_path": deploy_dir,
103
103
  "stdout": result.stdout,
104
104
  }
105
105
  except subprocess.CalledProcessError as e:
106
- raise Exception(f"Railway deployment failed: {e.stderr}")
106
+ raise Exception(f"Railway deployment failed: {e.stderr}") from e
107
107
 
108
108
  def verify(
109
109
  self, context: DeploymentContext, deployment_info: Dict[str, Any]
@@ -150,7 +150,7 @@ class AWSDeploymentStrategy(DeploymentStrategy):
150
150
  # Check AWS CLI
151
151
  try:
152
152
  subprocess.run(["aws", "--version"], capture_output=True, check=True)
153
- except:
153
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
154
154
  errors.append("AWS CLI not installed")
155
155
 
156
156
  # Check credentials
@@ -158,7 +158,7 @@ class AWSDeploymentStrategy(DeploymentStrategy):
158
158
  subprocess.run(
159
159
  ["aws", "sts", "get-caller-identity"], capture_output=True, check=True
160
160
  )
161
- except:
161
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
162
162
  errors.append("AWS credentials not configured")
163
163
 
164
164
  # Validate service type
@@ -218,7 +218,7 @@ class AWSDeploymentStrategy(DeploymentStrategy):
218
218
  "--zip-file",
219
219
  f"fileb://{artifact}",
220
220
  ]
221
- except:
221
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
222
222
  # Create new function
223
223
  cmd = [
224
224
  "aws",
@@ -277,7 +277,7 @@ class AWSDeploymentStrategy(DeploymentStrategy):
277
277
  ]
278
278
  subprocess.run(cmd, capture_output=True, check=True)
279
279
  return True
280
- except:
280
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
281
281
  return False
282
282
 
283
283
  return True
@@ -301,7 +301,7 @@ class AWSDeploymentStrategy(DeploymentStrategy):
301
301
  try:
302
302
  subprocess.run(cmd, check=True)
303
303
  return True
304
- except:
304
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
305
305
  pass
306
306
  return False
307
307
 
@@ -334,7 +334,7 @@ class DockerDeploymentStrategy(DeploymentStrategy):
334
334
  # Check Docker
335
335
  try:
336
336
  subprocess.run(["docker", "--version"], capture_output=True, check=True)
337
- except:
337
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
338
338
  errors.append("Docker not installed or not running")
339
339
 
340
340
  # Check Dockerfile exists
@@ -356,7 +356,7 @@ class DockerDeploymentStrategy(DeploymentStrategy):
356
356
  """Execute Docker deployment."""
357
357
  source_dir = artifacts[0] if artifacts[0].is_dir() else artifacts[0].parent
358
358
  image_name = context.config.get(
359
- "image_name", f"app_{datetime.now().timestamp()}"
359
+ "image_name", f"app_{datetime.now(timezone.utc).timestamp()}"
360
360
  )
361
361
  container_name = context.config.get("container_name", image_name)
362
362
 
@@ -444,7 +444,7 @@ class GitDeploymentStrategy(DeploymentStrategy):
444
444
  # Check Git
445
445
  try:
446
446
  subprocess.run(["git", "--version"], capture_output=True, check=True)
447
- except:
447
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
448
448
  errors.append("Git not installed")
449
449
 
450
450
  # Check remote URL
@@ -529,7 +529,7 @@ class GitDeploymentStrategy(DeploymentStrategy):
529
529
  check=True,
530
530
  )
531
531
  return True
532
- except:
532
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
533
533
  return False
534
534
 
535
535
  def rollback(self, context: DeploymentContext, result: DeploymentResult) -> bool:
@@ -553,7 +553,7 @@ class GitDeploymentStrategy(DeploymentStrategy):
553
553
  check=True,
554
554
  )
555
555
  return True
556
- except:
556
+ except (subprocess.CalledProcessError, FileNotFoundError, OSError):
557
557
  pass
558
558
  return False
559
559
 
@@ -13,7 +13,7 @@ Consolidates functionality from:
13
13
  import json
14
14
  import shutil
15
15
  import tempfile
16
- from datetime import datetime
16
+ from datetime import datetime, timezone
17
17
  from pathlib import Path
18
18
  from typing import Any, Dict, List, Optional
19
19
 
@@ -183,7 +183,7 @@ class LocalDeploymentStrategy(DeploymentStrategy):
183
183
  "deployed_path": target_path,
184
184
  "deployed_files": deployed_files,
185
185
  "artifacts": [str(a) for a in artifacts],
186
- "timestamp": datetime.now().isoformat(),
186
+ "timestamp": datetime.now(timezone.utc).isoformat(),
187
187
  }
188
188
 
189
189
  def verify(
@@ -300,7 +300,7 @@ class LocalDeploymentStrategy(DeploymentStrategy):
300
300
  def _check_write_permission(self, path: Path) -> bool:
301
301
  """Check if we have write permission to path."""
302
302
  try:
303
- test_file = path / f".write_test_{datetime.now().timestamp()}"
303
+ test_file = path / f".write_test_{datetime.now(timezone.utc).timestamp()}"
304
304
  test_file.touch()
305
305
  test_file.unlink()
306
306
  return True
@@ -310,7 +310,7 @@ class LocalDeploymentStrategy(DeploymentStrategy):
310
310
  def _generate_deployment_id(self) -> str:
311
311
  """Generate unique deployment ID."""
312
312
  return (
313
- f"local_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{id(self) % 10000:04d}"
313
+ f"local_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}_{id(self) % 10000:04d}"
314
314
  )
315
315
 
316
316
  def _create_backup(self, context: DeploymentContext) -> Optional[Path]:
@@ -324,7 +324,7 @@ class LocalDeploymentStrategy(DeploymentStrategy):
324
324
  backup_dir = Path(tempfile.gettempdir()) / "claude_mpm_backups"
325
325
  backup_dir.mkdir(parents=True, exist_ok=True)
326
326
 
327
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
327
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
328
328
  backup_name = f"{target_path.name}.backup_{timestamp}"
329
329
  backup_path = backup_dir / backup_name
330
330
 
@@ -343,7 +343,7 @@ class LocalDeploymentStrategy(DeploymentStrategy):
343
343
  def _write_version_file(self, target_path: Path, version: str) -> None:
344
344
  """Write version file to deployment."""
345
345
  version_file = target_path / ".version"
346
- version_file.write_text(f"{version}\n{datetime.now().isoformat()}\n")
346
+ version_file.write_text(f"{version}\n{datetime.now(timezone.utc).isoformat()}\n")
347
347
 
348
348
  # Agent deployment methods (consolidating agent_deployment.py patterns)
349
349
 
@@ -409,7 +409,7 @@ class LocalDeploymentStrategy(DeploymentStrategy):
409
409
 
410
410
  for yaml_file in yaml_files:
411
411
  try:
412
- with open(yaml_file) as f:
412
+ with yaml_file.open() as f:
413
413
  data = yaml.safe_load(f)
414
414
  # Basic agent structure validation
415
415
  if not isinstance(data, dict):
@@ -425,11 +425,11 @@ class LocalDeploymentStrategy(DeploymentStrategy):
425
425
 
426
426
  def _convert_json_to_yaml(self, json_path: Path) -> Path:
427
427
  """Convert JSON agent to YAML format."""
428
- with open(json_path) as f:
428
+ with json_path.open() as f:
429
429
  data = json.load(f)
430
430
 
431
431
  yaml_path = Path(tempfile.gettempdir()) / f"{json_path.stem}.yaml"
432
- with open(yaml_path, "w") as f:
432
+ with yaml_path.open("w") as f:
433
433
  yaml.dump(data, f, default_flow_style=False, sort_keys=False)
434
434
 
435
435
  return yaml_path
@@ -19,7 +19,7 @@ import json
19
19
  import shutil
20
20
  import subprocess
21
21
  import tempfile
22
- from datetime import datetime
22
+ from datetime import datetime, timezone
23
23
  from pathlib import Path
24
24
  from typing import Any, Dict, List, Optional, Tuple, Union
25
25
 
@@ -162,7 +162,7 @@ def prepare_deployment_artifact(
162
162
  metadata = {
163
163
  "source": str(source_path),
164
164
  "type": artifact_type,
165
- "created_at": datetime.now().isoformat(),
165
+ "created_at": datetime.now(timezone.utc).isoformat(),
166
166
  }
167
167
 
168
168
  # Auto-detect type
@@ -257,7 +257,7 @@ def verify_deployment_health(
257
257
  """
258
258
  health = {
259
259
  "status": "unknown",
260
- "timestamp": datetime.now().isoformat(),
260
+ "timestamp": datetime.now(timezone.utc).isoformat(),
261
261
  "checks": {},
262
262
  "errors": [],
263
263
  }
@@ -464,7 +464,7 @@ def get_version_info(path: Union[str, Path]) -> Dict[str, Any]:
464
464
 
465
465
  if file_path.exists():
466
466
  if version_file == "package.json":
467
- with open(file_path) as f:
467
+ with file_path.open() as f:
468
468
  data = json.load(f)
469
469
  version_info["version"] = data.get("version")
470
470
  version_info["source"] = "package.json"
@@ -512,7 +512,7 @@ def update_version(
512
512
  shutil.copy2(version_file, backup_file)
513
513
 
514
514
  # Write new version
515
- version_file.write_text(f"{new_version}\n{datetime.now().isoformat()}\n")
515
+ version_file.write_text(f"{new_version}\n{datetime.now(timezone.utc).isoformat()}\n")
516
516
  return True
517
517
 
518
518
  except Exception as e:
@@ -539,7 +539,7 @@ def calculate_checksum(path: Union[str, Path], algorithm: str = "sha256") -> str
539
539
  hasher = hashlib.new(algorithm)
540
540
 
541
541
  if path.is_file():
542
- with open(path, "rb") as f:
542
+ with path.open("rb") as f:
543
543
  for chunk in iter(lambda: f.read(4096), b""):
544
544
  hasher.update(chunk)
545
545
  elif path.is_dir():
@@ -547,7 +547,7 @@ def calculate_checksum(path: Union[str, Path], algorithm: str = "sha256") -> str
547
547
  for file_path in sorted(path.rglob("*")):
548
548
  if file_path.is_file():
549
549
  hasher.update(str(file_path.relative_to(path)).encode())
550
- with open(file_path, "rb") as f:
550
+ with file_path.open("rb") as f:
551
551
  for chunk in iter(lambda: f.read(4096), b""):
552
552
  hasher.update(chunk)
553
553
 
@@ -616,7 +616,7 @@ def load_env_file(env_file: Union[str, Path]) -> Dict[str, str]:
616
616
  env_path = Path(env_file)
617
617
 
618
618
  if env_path.exists():
619
- with open(env_path) as f:
619
+ with env_path.open() as f:
620
620
  for line in f:
621
621
  line = line.strip()
622
622
  if line and not line.startswith("#") and "=" in line:
@@ -656,7 +656,7 @@ def export_env_to_file(env_vars: Dict[str, str], output_file: Union[str, Path])
656
656
  output_path = Path(output_file)
657
657
  output_path.parent.mkdir(parents=True, exist_ok=True)
658
658
 
659
- with open(output_path, "w") as f:
659
+ with output_path.open("w") as f:
660
660
  for key, value in env_vars.items():
661
661
  # Escape special characters in value
662
662
  if " " in value or '"' in value:
@@ -9,7 +9,7 @@ Consolidates Vercel deployment patterns from multiple services.
9
9
  import json
10
10
  import subprocess
11
11
  import tempfile
12
- from datetime import datetime
12
+ from datetime import datetime, timezone
13
13
  from pathlib import Path
14
14
  from typing import Any, Dict, List, Optional
15
15
 
@@ -203,13 +203,13 @@ class VercelDeploymentStrategy(DeploymentStrategy):
203
203
  "deployed_path": deploy_dir,
204
204
  "production": context.config.get("production", False),
205
205
  "stdout": result.stdout,
206
- "timestamp": datetime.now().isoformat(),
206
+ "timestamp": datetime.now(timezone.utc).isoformat(),
207
207
  }
208
208
  raise Exception("Could not parse deployment URL from Vercel output")
209
209
 
210
210
  except subprocess.CalledProcessError as e:
211
211
  self._logger.error(f"Vercel deployment failed: {e.stderr}")
212
- raise Exception(f"Deployment failed: {e.stderr}")
212
+ raise Exception(f"Deployment failed: {e.stderr}") from e
213
213
 
214
214
  def verify(
215
215
  self, context: DeploymentContext, deployment_info: Dict[str, Any]
@@ -336,7 +336,7 @@ class VercelDeploymentStrategy(DeploymentStrategy):
336
336
  health["checks"][f"function_{func_name}"] = (
337
337
  response.status < 500
338
338
  )
339
- except:
339
+ except (urllib.error.URLError, OSError, TimeoutError):
340
340
  health["checks"][f"function_{func_name}"] = False
341
341
 
342
342
  # Determine overall status
@@ -416,7 +416,7 @@ class VercelDeploymentStrategy(DeploymentStrategy):
416
416
 
417
417
  if vercel_config:
418
418
  config_path = deploy_dir / "vercel.json"
419
- with open(config_path, "w") as f:
419
+ with config_path.open("w") as f:
420
420
  json.dump(vercel_config, f, indent=2)
421
421
  return config_path
422
422
 
@@ -430,7 +430,7 @@ class VercelDeploymentStrategy(DeploymentStrategy):
430
430
 
431
431
  if env_vars:
432
432
  env_file = deploy_dir / ".env"
433
- with open(env_file, "w") as f:
433
+ with env_file.open("w") as f:
434
434
  for key, value in env_vars.items():
435
435
  f.write(f"{key}={value}\n")
436
436
  return env_file
@@ -472,5 +472,5 @@ class VercelDeploymentStrategy(DeploymentStrategy):
472
472
  def _generate_deployment_id(self) -> str:
473
473
  """Generate unique deployment ID."""
474
474
  return (
475
- f"vercel_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{id(self) % 10000:04d}"
475
+ f"vercel_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}_{id(self) % 10000:04d}"
476
476
  )
@@ -335,14 +335,14 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
335
335
 
336
336
  # Save based on file extension
337
337
  if target_path.suffix == ".json":
338
- with open(target_path, "w") as f:
338
+ with target_path.open("w") as f:
339
339
  json.dump(transformed_config, f, indent=2)
340
340
  elif target_path.suffix in [".yaml", ".yml"]:
341
341
  # Would use yaml library here
342
- with open(target_path, "w") as f:
342
+ with target_path.open("w") as f:
343
343
  f.write(str(transformed_config))
344
344
  else:
345
- with open(target_path, "w") as f:
345
+ with target_path.open("w") as f:
346
346
  f.write(str(transformed_config))
347
347
 
348
348
  return ConfigurationResult(
@@ -685,6 +685,6 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
685
685
 
686
686
  def _get_timestamp(self) -> str:
687
687
  """Get current timestamp."""
688
- from datetime import datetime
688
+ from datetime import datetime, timezone
689
689
 
690
- return datetime.now().isoformat()
690
+ return datetime.now(timezone.utc).isoformat()
@@ -460,6 +460,6 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
460
460
 
461
461
  def _get_timestamp(self) -> str:
462
462
  """Get current timestamp."""
463
- from datetime import datetime
463
+ from datetime import datetime, timezone
464
464
 
465
- return datetime.now().isoformat()
465
+ return datetime.now(timezone.utc).isoformat()
@@ -110,7 +110,7 @@ class UtilityService(BaseService, UtilityServiceInterface):
110
110
  **event_data,
111
111
  }
112
112
 
113
- with open(log_file, "a") as f:
113
+ with log_file.open("a") as f:
114
114
  f.write(json.dumps(log_entry) + "\n")
115
115
 
116
116
  except OSError as e:
@@ -321,7 +321,7 @@ class ConflictResolutionManager:
321
321
 
322
322
  # Check content (simple heuristic)
323
323
  try:
324
- with open(file_path, "rb") as f:
324
+ with file_path.open("rb") as f:
325
325
  chunk = f.read(1024)
326
326
  if b"\0" in chunk:
327
327
  return True
@@ -596,7 +596,7 @@ class ConflictResolutionManager:
596
596
  )
597
597
 
598
598
  # Write resolved content
599
- with open(file_path, "w", encoding="utf-8") as f:
599
+ with file_path.open("w", encoding="utf-8") as f:
600
600
  f.write(resolved_content)
601
601
 
602
602
  return ConflictResolution(
@@ -147,10 +147,10 @@ class GitOperationsManager:
147
147
 
148
148
  return result
149
149
 
150
- except FileNotFoundError:
151
- raise GitOperationError("Git is not installed or not in PATH")
150
+ except FileNotFoundError as e:
151
+ raise GitOperationError("Git is not installed or not in PATH") from e
152
152
  except Exception as e:
153
- raise GitOperationError(f"Error running Git command: {e}")
153
+ raise GitOperationError(f"Error running Git command: {e}") from e
154
154
 
155
155
  def get_current_branch(self) -> str:
156
156
  """Get the current Git branch name."""
@@ -100,7 +100,7 @@ class SemanticVersion:
100
100
  version += f"+{self.build}"
101
101
  return version
102
102
 
103
- def __lt__(self, other: "SemanticVersion") -> bool: # noqa: PLR0911
103
+ def __lt__(self, other: "SemanticVersion") -> bool:
104
104
  """Compare versions for sorting according to semver precedence.
105
105
 
106
106
  Comparison Rules:
@@ -416,7 +416,7 @@ class SemanticVersionManager:
416
416
  return self._parse_toml_version_regex(file_path)
417
417
 
418
418
  try:
419
- with open(file_path, "rb") as f:
419
+ with file_path.open("rb") as f:
420
420
  data = tomllib.load(f)
421
421
 
422
422
  # Try different locations for version
@@ -437,7 +437,7 @@ class SemanticVersionManager:
437
437
  def _parse_toml_version_regex(self, file_path: Path) -> Optional[str]:
438
438
  """Parse version from TOML file using regex."""
439
439
  try:
440
- with open(file_path) as f:
440
+ with file_path.open() as f:
441
441
  content = f.read()
442
442
 
443
443
  # Look for version = "x.y.z" pattern
@@ -463,7 +463,7 @@ class SemanticVersionManager:
463
463
  def _parse_version_file(self, file_path: Path) -> Optional[str]:
464
464
  """Parse version from simple version file."""
465
465
  try:
466
- with open(file_path) as f:
466
+ with file_path.open() as f:
467
467
  return f.read().strip()
468
468
  except Exception:
469
469
  return None
@@ -471,7 +471,7 @@ class SemanticVersionManager:
471
471
  def _parse_pom_xml_version(self, file_path: Path) -> Optional[str]:
472
472
  """Parse version from Maven pom.xml."""
473
473
  try:
474
- with open(file_path) as f:
474
+ with file_path.open() as f:
475
475
  content = f.read()
476
476
 
477
477
  # Simple regex to find version in pom.xml
@@ -673,7 +673,7 @@ class SemanticVersionManager:
673
673
  def _update_toml_version(self, file_path: Path, new_version: str) -> bool:
674
674
  """Update version in TOML file."""
675
675
  try:
676
- with open(file_path) as f:
676
+ with file_path.open() as f:
677
677
  content = f.read()
678
678
 
679
679
  # Replace version field
@@ -691,7 +691,7 @@ class SemanticVersionManager:
691
691
  break
692
692
 
693
693
  if updated:
694
- with open(file_path, "w") as f:
694
+ with file_path.open("w") as f:
695
695
  f.write(content)
696
696
  return True
697
697
 
@@ -703,7 +703,7 @@ class SemanticVersionManager:
703
703
  def _update_simple_version_file(self, file_path: Path, new_version: str) -> bool:
704
704
  """Update version in simple version file."""
705
705
  try:
706
- with open(file_path, "w") as f:
706
+ with file_path.open("w") as f:
707
707
  f.write(new_version + "\n")
708
708
  return True
709
709
  except Exception:
@@ -712,7 +712,7 @@ class SemanticVersionManager:
712
712
  def _update_pom_xml_version(self, file_path: Path, new_version: str) -> bool:
713
713
  """Update version in Maven pom.xml."""
714
714
  try:
715
- with open(file_path) as f:
715
+ with file_path.open() as f:
716
716
  content = f.read()
717
717
 
718
718
  # Replace first version tag (project version)
@@ -722,7 +722,7 @@ class SemanticVersionManager:
722
722
  new_content = re.sub(pattern, replacement, content, count=1)
723
723
 
724
724
  if new_content != content:
725
- with open(file_path, "w") as f:
725
+ with file_path.open("w") as f:
726
726
  f.write(new_content)
727
727
  return True
728
728
 
@@ -841,7 +841,7 @@ class SemanticVersionManager:
841
841
 
842
842
  # Read existing changelog or create new one
843
843
  if changelog_path.exists():
844
- with open(changelog_path) as f:
844
+ with changelog_path.open() as f:
845
845
  existing_content = f.read()
846
846
 
847
847
  # Insert new entry after title
@@ -864,7 +864,7 @@ class SemanticVersionManager:
864
864
  content = f"# Changelog\n\n{new_entry}\n"
865
865
 
866
866
  # Write updated changelog
867
- with open(changelog_path, "w") as f:
867
+ with changelog_path.open("w") as f:
868
868
  f.write(content)
869
869
 
870
870
  self.logger.info(f"Updated {changelog_file} with version {version}")
@@ -945,7 +945,7 @@ class SemanticVersionManager:
945
945
  versions = []
946
946
 
947
947
  try:
948
- with open(changelog_path) as f:
948
+ with changelog_path.open() as f:
949
949
  content = f.read()
950
950
 
951
951
  # Find version entries
@@ -365,7 +365,7 @@ class EnhancedVersionParser:
365
365
  package_file = self.project_root / "package.json"
366
366
  if package_file.exists():
367
367
  try:
368
- with open(package_file) as f:
368
+ with package_file.open() as f:
369
369
  data = json.load(f)
370
370
  version = data.get("version")
371
371
  if version and self._version_pattern.match(version):
@@ -24,6 +24,10 @@ import time
24
24
  from contextlib import contextmanager, suppress
25
25
  from typing import Any, Dict, Optional, Tuple, Union
26
26
 
27
+ from claude_mpm.core.logging_utils import get_logger
28
+
29
+ logger = get_logger(__name__)
30
+
27
31
 
28
32
  class StateStorage:
29
33
  """Reliable state storage with atomic operations."""
@@ -37,11 +41,6 @@ class StateStorage:
37
41
  self.storage_dir = storage_dir or Path.home() / ".claude-mpm" / "storage"
38
42
  self.storage_dir.mkdir(parents=True, exist_ok=True)
39
43
 
40
- # Logging
41
- from claude_mpm.core.logging_utils import get_logger
42
-
43
- logger = get_logger(__name__)
44
-
45
44
  # File locking support (Unix-like systems)
46
45
  self.supports_locking = platform.system() != "Windows"
47
46
 
@@ -80,7 +79,7 @@ logger = get_logger(__name__)
80
79
  with gzip.open(file_path, "wt", encoding="utf-8") as f:
81
80
  json.dump(data, f, indent=2, default=str)
82
81
  else:
83
- with open(file_path, "w") as f:
82
+ with file_path.open("w") as f:
84
83
  json.dump(data, f, indent=2, default=str)
85
84
 
86
85
  self.write_count += 1
@@ -119,7 +118,7 @@ logger = get_logger(__name__)
119
118
  with gzip.open(file_path, "rt", encoding="utf-8") as f:
120
119
  data = json.load(f)
121
120
  else:
122
- with open(file_path) as f:
121
+ with file_path.open() as f:
123
122
  data = json.load(f)
124
123
 
125
124
  self.read_count += 1
@@ -160,7 +159,7 @@ logger = get_logger(__name__)
160
159
  with gzip.open(file_path, "wb") as f:
161
160
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
162
161
  else:
163
- with open(file_path, "wb") as f:
162
+ with file_path.open("wb") as f:
164
163
  pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
165
164
 
166
165
  self.write_count += 1
@@ -199,7 +198,7 @@ logger = get_logger(__name__)
199
198
  with gzip.open(file_path, "rb") as f:
200
199
  data = pickle.load(f)
201
200
  else:
202
- with open(file_path, "rb") as f:
201
+ with file_path.open("rb") as f:
203
202
  data = pickle.load(f)
204
203
 
205
204
  self.read_count += 1
@@ -328,7 +327,7 @@ logger = get_logger(__name__)
328
327
 
329
328
  # Calculate checksum
330
329
  hasher = hashlib.sha256()
331
- with open(file_path, "rb") as f:
330
+ with file_path.open("rb") as f:
332
331
  for chunk in iter(lambda: f.read(4096), b""):
333
332
  hasher.update(chunk)
334
333
 
@@ -336,7 +335,7 @@ logger = get_logger(__name__)
336
335
 
337
336
  # Write checksum file
338
337
  checksum_path = file_path.with_suffix(file_path.suffix + ".sha256")
339
- with open(checksum_path, "w") as f:
338
+ with checksum_path.open("w") as f:
340
339
  f.write(checksum)
341
340
 
342
341
  except Exception as e:
@@ -359,12 +358,12 @@ logger = get_logger(__name__)
359
358
  return True # No checksum to verify
360
359
 
361
360
  # Read expected checksum
362
- with open(checksum_path) as f:
361
+ with checksum_path.open() as f:
363
362
  expected = f.read().strip()
364
363
 
365
364
  # Calculate actual checksum
366
365
  hasher = hashlib.sha256()
367
- with open(file_path, "rb") as f:
366
+ with file_path.open("rb") as f:
368
367
  for chunk in iter(lambda: f.read(4096), b""):
369
368
  hasher.update(chunk)
370
369