claude-mpm 4.4.3__py3-none-any.whl → 4.4.5__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 (118) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +3 -2
  3. claude_mpm/agents/agent_loader_integration.py +2 -1
  4. claude_mpm/agents/async_agent_loader.py +2 -2
  5. claude_mpm/agents/base_agent_loader.py +2 -2
  6. claude_mpm/agents/frontmatter_validator.py +1 -0
  7. claude_mpm/agents/system_agent_config.py +2 -1
  8. claude_mpm/cli/commands/doctor.py +44 -5
  9. claude_mpm/cli/commands/mpm_init.py +116 -62
  10. claude_mpm/cli/parsers/configure_parser.py +3 -1
  11. claude_mpm/cli/startup_logging.py +1 -3
  12. claude_mpm/config/agent_config.py +1 -1
  13. claude_mpm/config/paths.py +2 -1
  14. claude_mpm/core/agent_name_normalizer.py +1 -0
  15. claude_mpm/core/config.py +2 -1
  16. claude_mpm/core/config_aliases.py +2 -1
  17. claude_mpm/core/file_utils.py +0 -1
  18. claude_mpm/core/framework/__init__.py +6 -6
  19. claude_mpm/core/framework/formatters/__init__.py +2 -2
  20. claude_mpm/core/framework/formatters/capability_generator.py +19 -8
  21. claude_mpm/core/framework/formatters/content_formatter.py +8 -3
  22. claude_mpm/core/framework/formatters/context_generator.py +7 -3
  23. claude_mpm/core/framework/loaders/__init__.py +3 -3
  24. claude_mpm/core/framework/loaders/agent_loader.py +7 -3
  25. claude_mpm/core/framework/loaders/file_loader.py +16 -6
  26. claude_mpm/core/framework/loaders/instruction_loader.py +16 -6
  27. claude_mpm/core/framework/loaders/packaged_loader.py +36 -12
  28. claude_mpm/core/framework/processors/__init__.py +2 -2
  29. claude_mpm/core/framework/processors/memory_processor.py +14 -6
  30. claude_mpm/core/framework/processors/metadata_processor.py +5 -5
  31. claude_mpm/core/framework/processors/template_processor.py +12 -6
  32. claude_mpm/core/framework_loader.py +44 -20
  33. claude_mpm/core/log_manager.py +2 -1
  34. claude_mpm/core/tool_access_control.py +1 -0
  35. claude_mpm/core/unified_agent_registry.py +2 -1
  36. claude_mpm/core/unified_paths.py +1 -0
  37. claude_mpm/experimental/cli_enhancements.py +1 -0
  38. claude_mpm/hooks/base_hook.py +1 -0
  39. claude_mpm/hooks/instruction_reinforcement.py +1 -0
  40. claude_mpm/hooks/kuzu_memory_hook.py +20 -13
  41. claude_mpm/hooks/validation_hooks.py +1 -1
  42. claude_mpm/scripts/mpm_doctor.py +1 -0
  43. claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
  44. claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
  45. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
  46. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
  47. claude_mpm/services/agents/management/agent_management_service.py +1 -1
  48. claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
  49. claude_mpm/services/agents/memory/memory_file_service.py +6 -2
  50. claude_mpm/services/agents/memory/memory_format_service.py +0 -1
  51. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  52. claude_mpm/services/async_session_logger.py +1 -1
  53. claude_mpm/services/claude_session_logger.py +1 -0
  54. claude_mpm/services/core/path_resolver.py +1 -0
  55. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  56. claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
  57. claude_mpm/services/diagnostics/checks/mcp_services_check.py +451 -0
  58. claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
  59. claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
  60. claude_mpm/services/event_bus/direct_relay.py +2 -1
  61. claude_mpm/services/event_bus/event_bus.py +1 -0
  62. claude_mpm/services/event_bus/relay.py +3 -2
  63. claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
  64. claude_mpm/services/infrastructure/daemon_manager.py +1 -1
  65. claude_mpm/services/mcp_config_manager.py +301 -54
  66. claude_mpm/services/mcp_gateway/core/process_pool.py +62 -23
  67. claude_mpm/services/mcp_gateway/tools/__init__.py +6 -5
  68. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +3 -1
  69. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +16 -31
  70. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  71. claude_mpm/services/project/archive_manager.py +159 -96
  72. claude_mpm/services/project/documentation_manager.py +64 -45
  73. claude_mpm/services/project/enhanced_analyzer.py +132 -89
  74. claude_mpm/services/project/project_organizer.py +225 -131
  75. claude_mpm/services/response_tracker.py +1 -1
  76. claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
  77. claude_mpm/services/unified/__init__.py +1 -1
  78. claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
  79. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
  80. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
  81. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
  82. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
  83. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
  84. claude_mpm/services/unified/config_strategies/__init__.py +111 -126
  85. claude_mpm/services/unified/config_strategies/config_schema.py +157 -111
  86. claude_mpm/services/unified/config_strategies/context_strategy.py +91 -89
  87. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +183 -173
  88. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +160 -152
  89. claude_mpm/services/unified/config_strategies/unified_config_service.py +124 -112
  90. claude_mpm/services/unified/config_strategies/validation_strategy.py +298 -259
  91. claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
  92. claude_mpm/services/unified/deployment_strategies/base.py +24 -28
  93. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
  94. claude_mpm/services/unified/deployment_strategies/local.py +49 -34
  95. claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
  96. claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
  97. claude_mpm/services/unified/interfaces.py +0 -26
  98. claude_mpm/services/unified/migration.py +17 -40
  99. claude_mpm/services/unified/strategies.py +9 -26
  100. claude_mpm/services/unified/unified_analyzer.py +48 -44
  101. claude_mpm/services/unified/unified_config.py +21 -19
  102. claude_mpm/services/unified/unified_deployment.py +21 -26
  103. claude_mpm/storage/state_storage.py +1 -0
  104. claude_mpm/utils/agent_dependency_loader.py +18 -6
  105. claude_mpm/utils/common.py +14 -12
  106. claude_mpm/utils/database_connector.py +15 -12
  107. claude_mpm/utils/error_handler.py +1 -0
  108. claude_mpm/utils/log_cleanup.py +1 -0
  109. claude_mpm/utils/path_operations.py +1 -0
  110. claude_mpm/utils/session_logging.py +1 -1
  111. claude_mpm/utils/subprocess_utils.py +1 -0
  112. claude_mpm/validation/agent_validator.py +1 -1
  113. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/METADATA +35 -15
  114. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/RECORD +118 -117
  115. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/WHEEL +0 -0
  116. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/entry_points.txt +0 -0
  117. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/licenses/LICENSE +0 -0
  118. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/top_level.txt +0 -0
@@ -29,21 +29,21 @@ Design Principles:
29
29
  5. Metrics and monitoring integration
30
30
  """
31
31
 
32
- from .base import DeploymentStrategy, DeploymentContext, DeploymentResult
33
- from .local import LocalDeploymentStrategy
34
- from .vercel import VercelDeploymentStrategy
32
+ from .base import DeploymentContext, DeploymentResult, DeploymentStrategy
35
33
  from .cloud_strategies import (
36
- RailwayDeploymentStrategy,
37
34
  AWSDeploymentStrategy,
38
35
  DockerDeploymentStrategy,
39
36
  GitDeploymentStrategy,
37
+ RailwayDeploymentStrategy,
40
38
  )
39
+ from .local import LocalDeploymentStrategy
41
40
  from .utils import (
42
- validate_deployment_config,
43
41
  prepare_deployment_artifact,
44
- verify_deployment_health,
45
42
  rollback_deployment,
43
+ validate_deployment_config,
44
+ verify_deployment_health,
46
45
  )
46
+ from .vercel import VercelDeploymentStrategy
47
47
 
48
48
  __all__ = [
49
49
  # Base classes
@@ -94,4 +94,4 @@ def get_deployment_strategy(deployment_type: str) -> type[DeploymentStrategy]:
94
94
  f"Unsupported deployment type: {deployment_type}. "
95
95
  f"Supported types: {', '.join(DEPLOYMENT_STRATEGIES.keys())}"
96
96
  )
97
- return strategy_class
97
+ return strategy_class
@@ -31,6 +31,7 @@ from claude_mpm.services.unified.strategies import (
31
31
 
32
32
  class DeploymentStatus(Enum):
33
33
  """Deployment status enumeration."""
34
+
34
35
  PENDING = "pending"
35
36
  VALIDATING = "validating"
36
37
  PREPARING = "preparing"
@@ -43,6 +44,7 @@ class DeploymentStatus(Enum):
43
44
 
44
45
  class DeploymentType(Enum):
45
46
  """Types of deployments."""
47
+
46
48
  AGENT = "agent"
47
49
  CONFIG = "config"
48
50
  RESOURCE = "resource"
@@ -62,6 +64,7 @@ class DeploymentContext:
62
64
  - multi_source_deployment_service.py
63
65
  - deployment_config_loader.py
64
66
  """
67
+
65
68
  # Core deployment info
66
69
  source: Union[str, Path]
67
70
  target: Union[str, Path]
@@ -110,6 +113,7 @@ class DeploymentResult:
110
113
 
111
114
  Consolidates result patterns from multiple deployment services.
112
115
  """
116
+
113
117
  # Core result
114
118
  success: bool
115
119
  status: DeploymentStatus
@@ -156,7 +160,9 @@ class DeploymentResult:
156
160
  "version": self.version,
157
161
  "previous_version": self.previous_version,
158
162
  "started_at": self.started_at.isoformat() if self.started_at else None,
159
- "completed_at": self.completed_at.isoformat() if self.completed_at else None,
163
+ "completed_at": (
164
+ self.completed_at.isoformat() if self.completed_at else None
165
+ ),
160
166
  "duration_seconds": self.duration_seconds,
161
167
  "artifacts": [str(a) for a in self.artifacts],
162
168
  "logs": self.logs,
@@ -255,7 +261,9 @@ class DeploymentStrategy(BaseDeploymentStrategy):
255
261
  try:
256
262
  # Validation phase
257
263
  result.status = DeploymentStatus.VALIDATING
258
- self._logger.info(f"Validating deployment: {context.source} -> {context.target}")
264
+ self._logger.info(
265
+ f"Validating deployment: {context.source} -> {context.target}"
266
+ )
259
267
 
260
268
  validation_errors = self.validate(context)
261
269
  if validation_errors:
@@ -309,7 +317,7 @@ class DeploymentStrategy(BaseDeploymentStrategy):
309
317
  result.message = "Dry run completed successfully"
310
318
 
311
319
  except Exception as e:
312
- self._logger.error(f"Deployment failed: {str(e)}")
320
+ self._logger.error(f"Deployment failed: {e!s}")
313
321
  result.status = DeploymentStatus.FAILED
314
322
  result.message = str(e)
315
323
  result.errors.append(str(e))
@@ -322,8 +330,8 @@ class DeploymentStrategy(BaseDeploymentStrategy):
322
330
  result.status = DeploymentStatus.ROLLED_BACK
323
331
  result.message += " (rolled back)"
324
332
  except Exception as rollback_error:
325
- self._logger.error(f"Rollback failed: {str(rollback_error)}")
326
- result.errors.append(f"Rollback failed: {str(rollback_error)}")
333
+ self._logger.error(f"Rollback failed: {rollback_error!s}")
334
+ result.errors.append(f"Rollback failed: {rollback_error!s}")
327
335
 
328
336
  finally:
329
337
  result.completed_at = datetime.now()
@@ -353,7 +361,6 @@ class DeploymentStrategy(BaseDeploymentStrategy):
353
361
  Returns:
354
362
  List of validation errors (empty if valid)
355
363
  """
356
- pass
357
364
 
358
365
  @abstractmethod
359
366
  def prepare(self, context: DeploymentContext) -> List[Path]:
@@ -366,7 +373,6 @@ class DeploymentStrategy(BaseDeploymentStrategy):
366
373
  Returns:
367
374
  List of prepared artifact paths
368
375
  """
369
- pass
370
376
 
371
377
  @abstractmethod
372
378
  def execute(
@@ -382,7 +388,6 @@ class DeploymentStrategy(BaseDeploymentStrategy):
382
388
  Returns:
383
389
  Deployment information including deployment_id, deployed_path, etc.
384
390
  """
385
- pass
386
391
 
387
392
  @abstractmethod
388
393
  def verify(
@@ -398,12 +403,9 @@ class DeploymentStrategy(BaseDeploymentStrategy):
398
403
  Returns:
399
404
  True if deployment verified successfully
400
405
  """
401
- pass
402
406
 
403
407
  @abstractmethod
404
- def rollback(
405
- self, context: DeploymentContext, result: DeploymentResult
406
- ) -> bool:
408
+ def rollback(self, context: DeploymentContext, result: DeploymentResult) -> bool:
407
409
  """
408
410
  Rollback failed deployment.
409
411
 
@@ -414,12 +416,9 @@ class DeploymentStrategy(BaseDeploymentStrategy):
414
416
  Returns:
415
417
  True if rollback successful
416
418
  """
417
- pass
418
419
 
419
420
  @abstractmethod
420
- def get_health_status(
421
- self, deployment_info: Dict[str, Any]
422
- ) -> Dict[str, Any]:
421
+ def get_health_status(self, deployment_info: Dict[str, Any]) -> Dict[str, Any]:
423
422
  """
424
423
  Get health status of deployment.
425
424
 
@@ -429,7 +428,6 @@ class DeploymentStrategy(BaseDeploymentStrategy):
429
428
  Returns:
430
429
  Health status information
431
430
  """
432
- pass
433
431
 
434
432
  # Helper methods
435
433
 
@@ -458,14 +456,13 @@ class DeploymentStrategy(BaseDeploymentStrategy):
458
456
 
459
457
  if "agent" in source_path.name.lower():
460
458
  return DeploymentType.AGENT
461
- elif "config" in source_path.name.lower():
459
+ if "config" in source_path.name.lower():
462
460
  return DeploymentType.CONFIG
463
- elif "template" in source_path.name.lower():
461
+ if "template" in source_path.name.lower():
464
462
  return DeploymentType.TEMPLATE
465
- elif source_path.suffix in [".yaml", ".yml", ".json"]:
463
+ if source_path.suffix in [".yaml", ".yml", ".json"]:
466
464
  return DeploymentType.CONFIG
467
- else:
468
- return DeploymentType.RESOURCE
465
+ return DeploymentType.RESOURCE
469
466
 
470
467
  def _collect_metrics(
471
468
  self, context: DeploymentContext, result: DeploymentResult
@@ -484,9 +481,7 @@ class DeploymentStrategy(BaseDeploymentStrategy):
484
481
  "deployment_type": context.deployment_type.value,
485
482
  "source_size": self._get_size(context.source) if context.source else 0,
486
483
  "artifact_count": len(result.artifacts),
487
- "artifact_total_size": sum(
488
- self._get_size(a) for a in result.artifacts
489
- ),
484
+ "artifact_total_size": sum(self._get_size(a) for a in result.artifacts),
490
485
  "duration_seconds": result.duration_seconds,
491
486
  "error_count": len(result.errors),
492
487
  "warning_count": len(result.warnings),
@@ -497,7 +492,7 @@ class DeploymentStrategy(BaseDeploymentStrategy):
497
492
  path = Path(path)
498
493
  if path.is_file():
499
494
  return path.stat().st_size
500
- elif path.is_dir():
495
+ if path.is_dir():
501
496
  return sum(f.stat().st_size for f in path.rglob("*") if f.is_file())
502
497
  return 0
503
498
 
@@ -550,8 +545,9 @@ class DeploymentStrategy(BaseDeploymentStrategy):
550
545
  target_path.unlink()
551
546
  elif target_path.is_dir():
552
547
  import shutil
548
+
553
549
  shutil.rmtree(target_path)
554
550
  return True
555
551
  except Exception as e:
556
- self._logger.error(f"Cleanup failed: {str(e)}")
557
- return False
552
+ self._logger.error(f"Cleanup failed: {e!s}")
553
+ return False
@@ -10,7 +10,7 @@ import json
10
10
  import subprocess
11
11
  from datetime import datetime
12
12
  from pathlib import Path
13
- from typing import Any, Dict, List, Optional
13
+ from typing import Any, Dict, List
14
14
 
15
15
  from claude_mpm.core.logging_utils import get_logger
16
16
  from claude_mpm.services.unified.strategies import StrategyMetadata, StrategyPriority
@@ -29,14 +29,16 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
29
29
 
30
30
  def __init__(self):
31
31
  """Initialize Railway strategy."""
32
- super().__init__(StrategyMetadata(
33
- name="RailwayDeploymentStrategy",
34
- description="Deploy to Railway cloud platform",
35
- supported_types=["application", "service", "*"],
36
- supported_operations=["deploy", "rollback", "verify"],
37
- priority=StrategyPriority.NORMAL,
38
- tags={"railway", "cloud", "paas"},
39
- ))
32
+ super().__init__(
33
+ StrategyMetadata(
34
+ name="RailwayDeploymentStrategy",
35
+ description="Deploy to Railway cloud platform",
36
+ supported_types=["application", "service", "*"],
37
+ supported_operations=["deploy", "rollback", "verify"],
38
+ priority=StrategyPriority.NORMAL,
39
+ tags={"railway", "cloud", "paas"},
40
+ )
41
+ )
40
42
  self._logger = get_logger(f"{__name__}.RailwayDeploymentStrategy")
41
43
 
42
44
  def validate(self, context: DeploymentContext) -> List[str]:
@@ -47,7 +49,9 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
47
49
  try:
48
50
  subprocess.run(["railway", "--version"], capture_output=True, check=True)
49
51
  except:
50
- errors.append("Railway CLI not installed. Install with: npm i -g @railway/cli")
52
+ errors.append(
53
+ "Railway CLI not installed. Install with: npm i -g @railway/cli"
54
+ )
51
55
 
52
56
  # Check authentication
53
57
  try:
@@ -64,7 +68,9 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
64
68
  )
65
69
  return [artifact_path]
66
70
 
67
- def execute(self, context: DeploymentContext, artifacts: List[Path]) -> Dict[str, Any]:
71
+ def execute(
72
+ self, context: DeploymentContext, artifacts: List[Path]
73
+ ) -> Dict[str, Any]:
68
74
  """Execute Railway deployment."""
69
75
  deploy_dir = artifacts[0] if artifacts else Path(context.source)
70
76
 
@@ -75,13 +81,16 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
75
81
  cmd.extend(["--environment", context.config["environment"]])
76
82
 
77
83
  try:
78
- result = subprocess.run(cmd, cwd=deploy_dir, capture_output=True, text=True, check=True)
84
+ result = subprocess.run(
85
+ cmd, cwd=deploy_dir, capture_output=True, text=True, check=True
86
+ )
79
87
 
80
88
  # Parse deployment URL from output
81
89
  deployment_url = None
82
90
  for line in result.stdout.split("\n"):
83
91
  if "https://" in line:
84
92
  import re
93
+
85
94
  match = re.search(r"https://[^\s]+", line)
86
95
  if match:
87
96
  deployment_url = match.group(0)
@@ -96,11 +105,16 @@ class RailwayDeploymentStrategy(DeploymentStrategy):
96
105
  except subprocess.CalledProcessError as e:
97
106
  raise Exception(f"Railway deployment failed: {e.stderr}")
98
107
 
99
- def verify(self, context: DeploymentContext, deployment_info: Dict[str, Any]) -> bool:
108
+ def verify(
109
+ self, context: DeploymentContext, deployment_info: Dict[str, Any]
110
+ ) -> bool:
100
111
  """Verify Railway deployment."""
101
- return verify_deployment_health(
102
- "railway", deployment_info, ["accessibility"]
103
- )["status"] == "healthy"
112
+ return (
113
+ verify_deployment_health("railway", deployment_info, ["accessibility"])[
114
+ "status"
115
+ ]
116
+ == "healthy"
117
+ )
104
118
 
105
119
  def rollback(self, context: DeploymentContext, result: DeploymentResult) -> bool:
106
120
  """Railway doesn't support CLI rollback."""
@@ -117,14 +131,16 @@ class AWSDeploymentStrategy(DeploymentStrategy):
117
131
 
118
132
  def __init__(self):
119
133
  """Initialize AWS strategy."""
120
- super().__init__(StrategyMetadata(
121
- name="AWSDeploymentStrategy",
122
- description="Deploy to AWS services",
123
- supported_types=["lambda", "ec2", "ecs", "application", "*"],
124
- supported_operations=["deploy", "rollback", "verify"],
125
- priority=StrategyPriority.NORMAL,
126
- tags={"aws", "cloud", "serverless"},
127
- ))
134
+ super().__init__(
135
+ StrategyMetadata(
136
+ name="AWSDeploymentStrategy",
137
+ description="Deploy to AWS services",
138
+ supported_types=["lambda", "ec2", "ecs", "application", "*"],
139
+ supported_operations=["deploy", "rollback", "verify"],
140
+ priority=StrategyPriority.NORMAL,
141
+ tags={"aws", "cloud", "serverless"},
142
+ )
143
+ )
128
144
  self._logger = get_logger(f"{__name__}.AWSDeploymentStrategy")
129
145
 
130
146
  def validate(self, context: DeploymentContext) -> List[str]:
@@ -139,7 +155,9 @@ class AWSDeploymentStrategy(DeploymentStrategy):
139
155
 
140
156
  # Check credentials
141
157
  try:
142
- subprocess.run(["aws", "sts", "get-caller-identity"], capture_output=True, check=True)
158
+ subprocess.run(
159
+ ["aws", "sts", "get-caller-identity"], capture_output=True, check=True
160
+ )
143
161
  except:
144
162
  errors.append("AWS credentials not configured")
145
163
 
@@ -160,24 +178,26 @@ class AWSDeploymentStrategy(DeploymentStrategy):
160
178
  context.source, "zip", context.config
161
179
  )
162
180
  return [artifact_path]
163
- else:
164
- artifact_path, _ = prepare_deployment_artifact(
165
- context.source, "directory", context.config
166
- )
167
- return [artifact_path]
181
+ artifact_path, _ = prepare_deployment_artifact(
182
+ context.source, "directory", context.config
183
+ )
184
+ return [artifact_path]
168
185
 
169
- def execute(self, context: DeploymentContext, artifacts: List[Path]) -> Dict[str, Any]:
186
+ def execute(
187
+ self, context: DeploymentContext, artifacts: List[Path]
188
+ ) -> Dict[str, Any]:
170
189
  """Execute AWS deployment."""
171
190
  service = context.config.get("service", "lambda")
172
191
 
173
192
  if service == "lambda":
174
193
  return self._deploy_lambda(context, artifacts[0])
175
- elif service == "s3":
194
+ if service == "s3":
176
195
  return self._deploy_s3(context, artifacts[0])
177
- else:
178
- raise NotImplementedError(f"AWS {service} deployment not implemented")
196
+ raise NotImplementedError(f"AWS {service} deployment not implemented")
179
197
 
180
- def _deploy_lambda(self, context: DeploymentContext, artifact: Path) -> Dict[str, Any]:
198
+ def _deploy_lambda(
199
+ self, context: DeploymentContext, artifact: Path
200
+ ) -> Dict[str, Any]:
181
201
  """Deploy AWS Lambda function."""
182
202
  function_name = context.config.get("function_name", artifact.stem)
183
203
 
@@ -185,23 +205,35 @@ class AWSDeploymentStrategy(DeploymentStrategy):
185
205
  try:
186
206
  subprocess.run(
187
207
  ["aws", "lambda", "get-function", "--function-name", function_name],
188
- capture_output=True, check=True
208
+ capture_output=True,
209
+ check=True,
189
210
  )
190
211
  # Update existing function
191
212
  cmd = [
192
- "aws", "lambda", "update-function-code",
193
- "--function-name", function_name,
194
- "--zip-file", f"fileb://{artifact}"
213
+ "aws",
214
+ "lambda",
215
+ "update-function-code",
216
+ "--function-name",
217
+ function_name,
218
+ "--zip-file",
219
+ f"fileb://{artifact}",
195
220
  ]
196
221
  except:
197
222
  # Create new function
198
223
  cmd = [
199
- "aws", "lambda", "create-function",
200
- "--function-name", function_name,
201
- "--runtime", context.config.get("runtime", "python3.9"),
202
- "--role", context.config.get("role"),
203
- "--handler", context.config.get("handler", "index.handler"),
204
- "--zip-file", f"fileb://{artifact}"
224
+ "aws",
225
+ "lambda",
226
+ "create-function",
227
+ "--function-name",
228
+ function_name,
229
+ "--runtime",
230
+ context.config.get("runtime", "python3.9"),
231
+ "--role",
232
+ context.config.get("role"),
233
+ "--handler",
234
+ context.config.get("handler", "index.handler"),
235
+ "--zip-file",
236
+ f"fileb://{artifact}",
205
237
  ]
206
238
 
207
239
  result = subprocess.run(cmd, capture_output=True, text=True, check=True)
@@ -228,14 +260,21 @@ class AWSDeploymentStrategy(DeploymentStrategy):
228
260
  "deployed_path": artifact,
229
261
  }
230
262
 
231
- def verify(self, context: DeploymentContext, deployment_info: Dict[str, Any]) -> bool:
263
+ def verify(
264
+ self, context: DeploymentContext, deployment_info: Dict[str, Any]
265
+ ) -> bool:
232
266
  """Verify AWS deployment."""
233
267
  service = context.config.get("service", "lambda")
234
268
 
235
269
  if service == "lambda" and "function_arn" in deployment_info:
236
270
  try:
237
- cmd = ["aws", "lambda", "get-function", "--function-name",
238
- deployment_info["function_arn"]]
271
+ cmd = [
272
+ "aws",
273
+ "lambda",
274
+ "get-function",
275
+ "--function-name",
276
+ deployment_info["function_arn"],
277
+ ]
239
278
  subprocess.run(cmd, capture_output=True, check=True)
240
279
  return True
241
280
  except:
@@ -249,10 +288,15 @@ class AWSDeploymentStrategy(DeploymentStrategy):
249
288
  if context.config.get("service") == "lambda" and result.previous_version:
250
289
  function_name = context.config.get("function_name")
251
290
  cmd = [
252
- "aws", "lambda", "update-alias",
253
- "--function-name", function_name,
254
- "--name", "PROD",
255
- "--function-version", result.previous_version
291
+ "aws",
292
+ "lambda",
293
+ "update-alias",
294
+ "--function-name",
295
+ function_name,
296
+ "--name",
297
+ "PROD",
298
+ "--function-version",
299
+ result.previous_version,
256
300
  ]
257
301
  try:
258
302
  subprocess.run(cmd, check=True)
@@ -271,14 +315,16 @@ class DockerDeploymentStrategy(DeploymentStrategy):
271
315
 
272
316
  def __init__(self):
273
317
  """Initialize Docker strategy."""
274
- super().__init__(StrategyMetadata(
275
- name="DockerDeploymentStrategy",
276
- description="Deploy using Docker containers",
277
- supported_types=["container", "application", "service", "*"],
278
- supported_operations=["deploy", "rollback", "verify", "stop"],
279
- priority=StrategyPriority.HIGH,
280
- tags={"docker", "container", "microservice"},
281
- ))
318
+ super().__init__(
319
+ StrategyMetadata(
320
+ name="DockerDeploymentStrategy",
321
+ description="Deploy using Docker containers",
322
+ supported_types=["container", "application", "service", "*"],
323
+ supported_operations=["deploy", "rollback", "verify", "stop"],
324
+ priority=StrategyPriority.HIGH,
325
+ tags={"docker", "container", "microservice"},
326
+ )
327
+ )
282
328
  self._logger = get_logger(f"{__name__}.DockerDeploymentStrategy")
283
329
 
284
330
  def validate(self, context: DeploymentContext) -> List[str]:
@@ -304,10 +350,14 @@ class DockerDeploymentStrategy(DeploymentStrategy):
304
350
  """Prepare Docker artifacts."""
305
351
  return [Path(context.source)]
306
352
 
307
- def execute(self, context: DeploymentContext, artifacts: List[Path]) -> Dict[str, Any]:
353
+ def execute(
354
+ self, context: DeploymentContext, artifacts: List[Path]
355
+ ) -> Dict[str, Any]:
308
356
  """Execute Docker deployment."""
309
357
  source_dir = artifacts[0] if artifacts[0].is_dir() else artifacts[0].parent
310
- image_name = context.config.get("image_name", f"app_{datetime.now().timestamp()}")
358
+ image_name = context.config.get(
359
+ "image_name", f"app_{datetime.now().timestamp()}"
360
+ )
311
361
  container_name = context.config.get("container_name", image_name)
312
362
 
313
363
  # Build image
@@ -315,8 +365,12 @@ class DockerDeploymentStrategy(DeploymentStrategy):
315
365
  subprocess.run(build_cmd, check=True)
316
366
 
317
367
  # Stop existing container if exists
318
- subprocess.run(["docker", "stop", container_name], capture_output=True, check=False)
319
- subprocess.run(["docker", "rm", container_name], capture_output=True, check=False)
368
+ subprocess.run(
369
+ ["docker", "stop", container_name], capture_output=True, check=False
370
+ )
371
+ subprocess.run(
372
+ ["docker", "rm", container_name], capture_output=True, check=False
373
+ )
320
374
 
321
375
  # Run container
322
376
  run_cmd = ["docker", "run", "-d", "--name", container_name]
@@ -344,7 +398,9 @@ class DockerDeploymentStrategy(DeploymentStrategy):
344
398
  "deployed_path": source_dir,
345
399
  }
346
400
 
347
- def verify(self, context: DeploymentContext, deployment_info: Dict[str, Any]) -> bool:
401
+ def verify(
402
+ self, context: DeploymentContext, deployment_info: Dict[str, Any]
403
+ ) -> bool:
348
404
  """Verify Docker deployment."""
349
405
  return check_docker_container(deployment_info.get("container_id"))
350
406
 
@@ -369,14 +425,16 @@ class GitDeploymentStrategy(DeploymentStrategy):
369
425
 
370
426
  def __init__(self):
371
427
  """Initialize Git strategy."""
372
- super().__init__(StrategyMetadata(
373
- name="GitDeploymentStrategy",
374
- description="Deploy using Git repositories",
375
- supported_types=["repository", "code", "*"],
376
- supported_operations=["deploy", "rollback", "verify"],
377
- priority=StrategyPriority.NORMAL,
378
- tags={"git", "github", "gitlab", "version-control"},
379
- ))
428
+ super().__init__(
429
+ StrategyMetadata(
430
+ name="GitDeploymentStrategy",
431
+ description="Deploy using Git repositories",
432
+ supported_types=["repository", "code", "*"],
433
+ supported_operations=["deploy", "rollback", "verify"],
434
+ priority=StrategyPriority.NORMAL,
435
+ tags={"git", "github", "gitlab", "version-control"},
436
+ )
437
+ )
380
438
  self._logger = get_logger(f"{__name__}.GitDeploymentStrategy")
381
439
 
382
440
  def validate(self, context: DeploymentContext) -> List[str]:
@@ -399,7 +457,9 @@ class GitDeploymentStrategy(DeploymentStrategy):
399
457
  """Prepare Git artifacts."""
400
458
  return [Path(context.source)]
401
459
 
402
- def execute(self, context: DeploymentContext, artifacts: List[Path]) -> Dict[str, Any]:
460
+ def execute(
461
+ self, context: DeploymentContext, artifacts: List[Path]
462
+ ) -> Dict[str, Any]:
403
463
  """Execute Git deployment."""
404
464
  source_dir = artifacts[0] if artifacts[0].is_dir() else artifacts[0].parent
405
465
  remote_url = context.config.get("remote_url")
@@ -412,7 +472,9 @@ class GitDeploymentStrategy(DeploymentStrategy):
412
472
  # Add remote
413
473
  subprocess.run(
414
474
  ["git", "remote", "add", "deploy", remote_url],
415
- cwd=source_dir, capture_output=True, check=False
475
+ cwd=source_dir,
476
+ capture_output=True,
477
+ check=False,
416
478
  )
417
479
 
418
480
  # Add all files
@@ -422,19 +484,23 @@ class GitDeploymentStrategy(DeploymentStrategy):
422
484
  commit_msg = context.config.get("commit_message", "Deploy via Claude MPM")
423
485
  subprocess.run(
424
486
  ["git", "commit", "-m", commit_msg],
425
- cwd=source_dir, capture_output=True, check=False
487
+ cwd=source_dir,
488
+ capture_output=True,
489
+ check=False,
426
490
  )
427
491
 
428
492
  # Push
429
493
  subprocess.run(
430
- ["git", "push", "-u", "deploy", branch],
431
- cwd=source_dir, check=True
494
+ ["git", "push", "-u", "deploy", branch], cwd=source_dir, check=True
432
495
  )
433
496
 
434
497
  # Get commit hash
435
498
  result = subprocess.run(
436
499
  ["git", "rev-parse", "HEAD"],
437
- cwd=source_dir, capture_output=True, text=True, check=True
500
+ cwd=source_dir,
501
+ capture_output=True,
502
+ text=True,
503
+ check=True,
438
504
  )
439
505
  commit_hash = result.stdout.strip()
440
506
 
@@ -446,14 +512,21 @@ class GitDeploymentStrategy(DeploymentStrategy):
446
512
  "deployed_path": source_dir,
447
513
  }
448
514
 
449
- def verify(self, context: DeploymentContext, deployment_info: Dict[str, Any]) -> bool:
515
+ def verify(
516
+ self, context: DeploymentContext, deployment_info: Dict[str, Any]
517
+ ) -> bool:
450
518
  """Verify Git deployment."""
451
519
  # Check if commit exists on remote
452
520
  try:
453
521
  subprocess.run(
454
- ["git", "ls-remote", deployment_info.get("remote_url"),
455
- deployment_info.get("commit_hash")],
456
- capture_output=True, check=True
522
+ [
523
+ "git",
524
+ "ls-remote",
525
+ deployment_info.get("remote_url"),
526
+ deployment_info.get("commit_hash"),
527
+ ],
528
+ capture_output=True,
529
+ check=True,
457
530
  )
458
531
  return True
459
532
  except:
@@ -465,12 +538,19 @@ class GitDeploymentStrategy(DeploymentStrategy):
465
538
  try:
466
539
  subprocess.run(
467
540
  ["git", "checkout", result.previous_version],
468
- cwd=result.deployed_path, check=True
541
+ cwd=result.deployed_path,
542
+ check=True,
469
543
  )
470
544
  subprocess.run(
471
- ["git", "push", "--force", "deploy",
472
- f"{result.previous_version}:{context.config.get('branch', 'main')}"],
473
- cwd=result.deployed_path, check=True
545
+ [
546
+ "git",
547
+ "push",
548
+ "--force",
549
+ "deploy",
550
+ f"{result.previous_version}:{context.config.get('branch', 'main')}",
551
+ ],
552
+ cwd=result.deployed_path,
553
+ check=True,
474
554
  )
475
555
  return True
476
556
  except:
@@ -483,4 +563,4 @@ class GitDeploymentStrategy(DeploymentStrategy):
483
563
  "status": "healthy" if deployment_info.get("commit_hash") else "unhealthy",
484
564
  "commit": deployment_info.get("commit_hash", "unknown"),
485
565
  "branch": deployment_info.get("branch", "unknown"),
486
- }
566
+ }