claude-mpm 4.0.13__py3-none-any.whl → 4.0.15__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.
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 4.0.12
1
+ 4.0.13
@@ -0,0 +1,83 @@
1
+ # Agent Profile Template Configuration
2
+ # Inspired by awesome-claude-code's template system
3
+
4
+ profile:
5
+ name: "{{AGENT_NAME}}"
6
+ version: "{{VERSION}}"
7
+ description: "{{DESCRIPTION}}"
8
+ author: "{{AUTHOR}}"
9
+ created: "{{CREATED_DATE}}"
10
+
11
+ # Categories for organizing agents
12
+ categories:
13
+ - id: analysis
14
+ title: "Code Analysis Agents"
15
+ description: |
16
+ > Agents specialized in analyzing codebases, identifying patterns, and providing insights
17
+ icon: "🔍"
18
+
19
+ - id: implementation
20
+ title: "Implementation Agents"
21
+ description: |
22
+ > Agents focused on writing and modifying code
23
+ icon: "🛠️"
24
+
25
+ - id: testing
26
+ title: "Testing & QA Agents"
27
+ description: |
28
+ > Agents dedicated to testing, quality assurance, and validation
29
+ icon: "🧪"
30
+
31
+ - id: security
32
+ title: "Security Agents"
33
+ description: |
34
+ > Agents specialized in security analysis and vulnerability detection
35
+ icon: "🔒"
36
+
37
+ agents:
38
+ - name: "{{AGENT_ID}}"
39
+ category: "{{CATEGORY}}"
40
+ role: "{{ROLE}}"
41
+ description: "{{AGENT_DESCRIPTION}}"
42
+
43
+ capabilities:
44
+ - "{{CAPABILITY_1}}"
45
+ - "{{CAPABILITY_2}}"
46
+ - "{{CAPABILITY_3}}"
47
+
48
+ constraints:
49
+ - "{{CONSTRAINT_1}}"
50
+ - "{{CONSTRAINT_2}}"
51
+
52
+ tools:
53
+ - name: "{{TOOL_NAME}}"
54
+ description: "{{TOOL_DESCRIPTION}}"
55
+ required: true
56
+
57
+ prompt_template: |
58
+ You are a {{ROLE}} agent specializing in {{SPECIALIZATION}}.
59
+
60
+ ## Your Capabilities:
61
+ {{CAPABILITIES_LIST}}
62
+
63
+ ## Your Constraints:
64
+ {{CONSTRAINTS_LIST}}
65
+
66
+ ## Context:
67
+ {context}
68
+
69
+ ## Task:
70
+ {task}
71
+
72
+ ## Additional Instructions:
73
+ {{ADDITIONAL_INSTRUCTIONS}}
74
+
75
+ examples:
76
+ - scenario: "{{EXAMPLE_SCENARIO}}"
77
+ input: "{{EXAMPLE_INPUT}}"
78
+ expected_output: "{{EXAMPLE_OUTPUT}}"
79
+
80
+ best_practices:
81
+ - "{{BEST_PRACTICE_1}}"
82
+ - "{{BEST_PRACTICE_2}}"
83
+ - "{{BEST_PRACTICE_3}}"
@@ -55,7 +55,7 @@ def filter_claude_mpm_args(claude_args):
55
55
  "--intercept-commands",
56
56
  "--no-native-agents",
57
57
  "--launch-method",
58
- "--resume",
58
+ "--mpm-resume",
59
59
  # Dependency checking flags (MPM-specific)
60
60
  "--no-check-dependencies",
61
61
  "--force-check-dependencies",
@@ -99,7 +99,7 @@ def filter_claude_mpm_args(claude_args):
99
99
  "--input",
100
100
  }
101
101
  optional_value_flags = {
102
- "--resume"
102
+ "--mpm-resume"
103
103
  } # These flags can have optional values (nargs="?")
104
104
 
105
105
  if arg in value_expecting_flags and i < len(claude_args):
@@ -205,8 +205,8 @@ def run_session(args):
205
205
  resume_session_id = None
206
206
  resume_context = None
207
207
 
208
- if hasattr(args, "resume") and args.resume:
209
- if args.resume == "last":
208
+ if hasattr(args, "mpm_resume") and args.mpm_resume:
209
+ if args.mpm_resume == "last":
210
210
  # Resume the last interactive session
211
211
  resume_session_id = session_manager.get_last_interactive_session()
212
212
  if resume_session_id:
@@ -226,7 +226,7 @@ def run_session(args):
226
226
  print("ℹ️ No recent interactive sessions found to resume")
227
227
  else:
228
228
  # Resume specific session by ID
229
- resume_session_id = args.resume
229
+ resume_session_id = args.mpm_resume
230
230
  session_data = session_manager.get_session_by_id(resume_session_id)
231
231
  if session_data:
232
232
  resume_context = session_data.get("context", "default")
@@ -728,8 +728,8 @@ def _check_claude_json_memory(args, logger):
728
728
  args: Parsed command line arguments
729
729
  logger: Logger instance for output
730
730
  """
731
- # Only check if using --resume
732
- if not hasattr(args, "resume") or not args.resume:
731
+ # Only check if using --mpm-resume
732
+ if not hasattr(args, "mpm_resume") or not args.mpm_resume:
733
733
  return
734
734
 
735
735
  claude_json_path = Path.home() / ".claude.json"
@@ -25,8 +25,8 @@ class RunConfigChecker:
25
25
  memory, leading to 2GB+ memory consumption.
26
26
  """
27
27
  try:
28
- # Only check if --resume is being used
29
- if not getattr(args, "resume", False):
28
+ # Only check if --mpm-resume is being used
29
+ if not getattr(args, "mpm_resume", False):
30
30
  return
31
31
 
32
32
  claude_json_path = Path.cwd() / ".claude.json"
@@ -50,7 +50,7 @@ class RunConfigChecker:
50
50
  print(
51
51
  f"\n⚠️ WARNING: Large .claude.json file detected ({format_size(file_size)})"
52
52
  )
53
- print(" This may cause memory issues when using --resume")
53
+ print(" This may cause memory issues when using --mpm-resume")
54
54
  print(
55
55
  " 💡 Consider running 'claude-mpm cleanup-memory' to archive old conversations\n"
56
56
  )
@@ -181,11 +181,11 @@ def add_top_level_run_arguments(parser: argparse.ArgumentParser) -> None:
181
181
  help="WebSocket server port (default: 8765)",
182
182
  )
183
183
  run_group.add_argument(
184
- "--resume",
184
+ "--mpm-resume",
185
185
  type=str,
186
186
  nargs="?",
187
187
  const="last",
188
- help="Resume a session (last session if no ID specified, or specific session ID)",
188
+ help="Resume an MPM session (last session if no ID specified, or specific session ID)",
189
189
  )
190
190
  run_group.add_argument(
191
191
  "--force",
@@ -69,11 +69,11 @@ def add_run_arguments(parser: argparse.ArgumentParser) -> None:
69
69
  help="Force operations even with warnings (e.g., large .claude.json file)",
70
70
  )
71
71
  run_group.add_argument(
72
- "--resume",
72
+ "--mpm-resume",
73
73
  type=str,
74
74
  nargs="?",
75
75
  const="last",
76
- help="Resume a session (last session if no ID specified, or specific session ID)",
76
+ help="Resume an MPM session (last session if no ID specified, or specific session ID)",
77
77
  )
78
78
 
79
79
  # Dependency checking options
@@ -2,10 +2,23 @@
2
2
 
3
3
  import logging
4
4
  import os
5
+ import sys
5
6
  from datetime import datetime
6
7
  from pathlib import Path
7
8
  from typing import Any, Dict, Optional
8
9
 
10
+ # Import resource handling for packaged installations
11
+ try:
12
+ # Python 3.9+
13
+ from importlib.resources import files
14
+ except ImportError:
15
+ # Python 3.8 fallback
16
+ try:
17
+ from importlib_resources import files
18
+ except ImportError:
19
+ # Final fallback for development environments
20
+ files = None
21
+
9
22
  from ..utils.imports import safe_import
10
23
 
11
24
  # Import with fallback support - using absolute imports as primary since we're at module level
@@ -47,8 +60,53 @@ class FrameworkLoader:
47
60
  self.agent_registry = AgentRegistryAdapter(self.framework_path)
48
61
 
49
62
  def _detect_framework_path(self) -> Optional[Path]:
50
- """Auto-detect claude-mpm framework."""
51
- # First check if we're in claude-mpm project
63
+ """Auto-detect claude-mpm framework using unified path management."""
64
+ try:
65
+ # Use the unified path manager for consistent detection
66
+ from ..core.unified_paths import get_path_manager, DeploymentContext
67
+
68
+ path_manager = get_path_manager()
69
+ deployment_context = path_manager._deployment_context
70
+
71
+ # Check if we're in a packaged installation
72
+ if deployment_context in [DeploymentContext.PIP_INSTALL, DeploymentContext.PIPX_INSTALL, DeploymentContext.SYSTEM_PACKAGE]:
73
+ self.logger.info(f"Running from packaged installation (context: {deployment_context})")
74
+ # Return a marker path to indicate packaged installation
75
+ return Path("__PACKAGED__")
76
+ elif deployment_context == DeploymentContext.DEVELOPMENT:
77
+ # Development mode - use framework root
78
+ framework_root = path_manager.framework_root
79
+ if (framework_root / "src" / "claude_mpm" / "agents").exists():
80
+ self.logger.info(f"Using claude-mpm development installation at: {framework_root}")
81
+ return framework_root
82
+ elif deployment_context == DeploymentContext.EDITABLE_INSTALL:
83
+ # Editable install - similar to development
84
+ framework_root = path_manager.framework_root
85
+ if (framework_root / "src" / "claude_mpm" / "agents").exists():
86
+ self.logger.info(f"Using claude-mpm editable installation at: {framework_root}")
87
+ return framework_root
88
+
89
+ except Exception as e:
90
+ self.logger.warning(f"Failed to use unified path manager for framework detection: {e}")
91
+ # Fall back to original detection logic
92
+ pass
93
+
94
+ # Fallback: Original detection logic for compatibility
95
+ try:
96
+ # Check if the package is installed
97
+ import claude_mpm
98
+ package_file = Path(claude_mpm.__file__)
99
+
100
+ # For packaged installations, we don't need a framework path
101
+ # since we'll use importlib.resources to load files
102
+ if 'site-packages' in str(package_file) or 'dist-packages' in str(package_file):
103
+ self.logger.info(f"Running from packaged installation at: {package_file.parent}")
104
+ # Return a marker path to indicate packaged installation
105
+ return Path("__PACKAGED__")
106
+ except ImportError:
107
+ pass
108
+
109
+ # Then check if we're in claude-mpm project (development mode)
52
110
  current_file = Path(__file__)
53
111
  if "claude-mpm" in str(current_file):
54
112
  # We're running from claude-mpm, use its agents
@@ -110,7 +168,7 @@ class FrameworkLoader:
110
168
  if self.agents_dir and self.agents_dir.exists():
111
169
  agents_dir = self.agents_dir
112
170
  self.logger.info(f"Using custom agents directory: {agents_dir}")
113
- elif self.framework_path:
171
+ elif self.framework_path and self.framework_path != Path("__PACKAGED__"):
114
172
  # Prioritize templates directory over main agents directory
115
173
  templates_dir = (
116
174
  self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
@@ -190,7 +248,7 @@ class FrameworkLoader:
190
248
 
191
249
  Precedence:
192
250
  1. Project-specific: .claude-mpm/agents/WORKFLOW.md
193
- 2. System default: src/claude_mpm/agents/WORKFLOW.md
251
+ 2. System default: src/claude_mpm/agents/WORKFLOW.md or packaged
194
252
 
195
253
  Args:
196
254
  content: Dictionary to update with workflow instructions
@@ -208,7 +266,7 @@ class FrameworkLoader:
208
266
  return
209
267
 
210
268
  # Fall back to system workflow
211
- if self.framework_path:
269
+ if self.framework_path and self.framework_path != Path("__PACKAGED__"):
212
270
  system_workflow_path = (
213
271
  self.framework_path / "src" / "claude_mpm" / "agents" / "WORKFLOW.md"
214
272
  )
@@ -227,7 +285,7 @@ class FrameworkLoader:
227
285
 
228
286
  Precedence:
229
287
  1. Project-specific: .claude-mpm/agents/MEMORY.md
230
- 2. System default: src/claude_mpm/agents/MEMORY.md
288
+ 2. System default: src/claude_mpm/agents/MEMORY.md or packaged
231
289
 
232
290
  Args:
233
291
  content: Dictionary to update with memory instructions
@@ -245,7 +303,7 @@ class FrameworkLoader:
245
303
  return
246
304
 
247
305
  # Fall back to system memory instructions
248
- if self.framework_path:
306
+ if self.framework_path and self.framework_path != Path("__PACKAGED__"):
249
307
  system_memory_path = (
250
308
  self.framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
251
309
  )
@@ -448,38 +506,44 @@ class FrameworkLoader:
448
506
 
449
507
  if not self.framework_path:
450
508
  return content
451
-
452
- # Load framework's INSTRUCTIONS.md
453
- framework_instructions_path = (
454
- self.framework_path / "src" / "claude_mpm" / "agents" / "INSTRUCTIONS.md"
455
- )
456
- if framework_instructions_path.exists():
457
- loaded_content = self._try_load_file(
458
- framework_instructions_path, "framework INSTRUCTIONS.md"
509
+
510
+ # Check if this is a packaged installation
511
+ if self.framework_path == Path("__PACKAGED__"):
512
+ # Load files using importlib.resources for packaged installations
513
+ self._load_packaged_framework_content(content)
514
+ else:
515
+ # Load from filesystem for development mode
516
+ # Load framework's INSTRUCTIONS.md
517
+ framework_instructions_path = (
518
+ self.framework_path / "src" / "claude_mpm" / "agents" / "INSTRUCTIONS.md"
459
519
  )
460
- if loaded_content:
461
- content["framework_instructions"] = loaded_content
462
- content["loaded"] = True
463
- # Add framework version to content
464
- if self.framework_version:
465
- content["instructions_version"] = self.framework_version
466
- content[
467
- "version"
468
- ] = self.framework_version # Update main version key
469
- # Add modification timestamp to content
470
- if self.framework_last_modified:
471
- content["instructions_last_modified"] = self.framework_last_modified
472
-
473
- # Load BASE_PM.md for core framework requirements
474
- base_pm_path = (
475
- self.framework_path / "src" / "claude_mpm" / "agents" / "BASE_PM.md"
476
- )
477
- if base_pm_path.exists():
478
- base_pm_content = self._try_load_file(
479
- base_pm_path, "BASE_PM framework requirements"
520
+ if framework_instructions_path.exists():
521
+ loaded_content = self._try_load_file(
522
+ framework_instructions_path, "framework INSTRUCTIONS.md"
523
+ )
524
+ if loaded_content:
525
+ content["framework_instructions"] = loaded_content
526
+ content["loaded"] = True
527
+ # Add framework version to content
528
+ if self.framework_version:
529
+ content["instructions_version"] = self.framework_version
530
+ content[
531
+ "version"
532
+ ] = self.framework_version # Update main version key
533
+ # Add modification timestamp to content
534
+ if self.framework_last_modified:
535
+ content["instructions_last_modified"] = self.framework_last_modified
536
+
537
+ # Load BASE_PM.md for core framework requirements
538
+ base_pm_path = (
539
+ self.framework_path / "src" / "claude_mpm" / "agents" / "BASE_PM.md"
480
540
  )
481
- if base_pm_content:
482
- content["base_pm_instructions"] = base_pm_content
541
+ if base_pm_path.exists():
542
+ base_pm_content = self._try_load_file(
543
+ base_pm_path, "BASE_PM framework requirements"
544
+ )
545
+ if base_pm_content:
546
+ content["base_pm_instructions"] = base_pm_content
483
547
 
484
548
  # Load WORKFLOW.md - check for project-specific first, then system
485
549
  self._load_workflow_instructions(content)
@@ -497,6 +561,149 @@ class FrameworkLoader:
497
561
  self._load_agents_directory(content, agents_dir, templates_dir, main_dir)
498
562
 
499
563
  return content
564
+
565
+ def _load_packaged_framework_content(self, content: Dict[str, Any]) -> None:
566
+ """Load framework content from packaged installation using importlib.resources."""
567
+ if not files:
568
+ self.logger.warning("importlib.resources not available, cannot load packaged framework")
569
+ self.logger.debug(f"files variable is: {files}")
570
+ # Try alternative import methods
571
+ try:
572
+ from importlib import resources
573
+ self.logger.info("Using importlib.resources as fallback")
574
+ self._load_packaged_framework_content_fallback(content, resources)
575
+ return
576
+ except ImportError:
577
+ self.logger.error("No importlib.resources available, using minimal framework")
578
+ return
579
+
580
+ try:
581
+ # Load INSTRUCTIONS.md
582
+ instructions_content = self._load_packaged_file("INSTRUCTIONS.md")
583
+ if instructions_content:
584
+ content["framework_instructions"] = instructions_content
585
+ content["loaded"] = True
586
+ # Extract and store version/timestamp metadata
587
+ self._extract_metadata_from_content(instructions_content, "INSTRUCTIONS.md")
588
+ if self.framework_version:
589
+ content["instructions_version"] = self.framework_version
590
+ content["version"] = self.framework_version
591
+ if self.framework_last_modified:
592
+ content["instructions_last_modified"] = self.framework_last_modified
593
+
594
+ # Load BASE_PM.md
595
+ base_pm_content = self._load_packaged_file("BASE_PM.md")
596
+ if base_pm_content:
597
+ content["base_pm_instructions"] = base_pm_content
598
+
599
+ # Load WORKFLOW.md
600
+ workflow_content = self._load_packaged_file("WORKFLOW.md")
601
+ if workflow_content:
602
+ content["workflow_instructions"] = workflow_content
603
+ content["project_workflow"] = "system"
604
+
605
+ # Load MEMORY.md
606
+ memory_content = self._load_packaged_file("MEMORY.md")
607
+ if memory_content:
608
+ content["memory_instructions"] = memory_content
609
+ content["project_memory"] = "system"
610
+
611
+ except Exception as e:
612
+ self.logger.error(f"Failed to load packaged framework content: {e}")
613
+
614
+ def _load_packaged_framework_content_fallback(self, content: Dict[str, Any], resources) -> None:
615
+ """Load framework content using importlib.resources fallback."""
616
+ try:
617
+ # Load INSTRUCTIONS.md
618
+ instructions_content = self._load_packaged_file_fallback("INSTRUCTIONS.md", resources)
619
+ if instructions_content:
620
+ content["framework_instructions"] = instructions_content
621
+ content["loaded"] = True
622
+ # Extract and store version/timestamp metadata
623
+ self._extract_metadata_from_content(instructions_content, "INSTRUCTIONS.md")
624
+ if self.framework_version:
625
+ content["instructions_version"] = self.framework_version
626
+ content["version"] = self.framework_version
627
+ if self.framework_last_modified:
628
+ content["instructions_last_modified"] = self.framework_last_modified
629
+
630
+ # Load BASE_PM.md
631
+ base_pm_content = self._load_packaged_file_fallback("BASE_PM.md", resources)
632
+ if base_pm_content:
633
+ content["base_pm_instructions"] = base_pm_content
634
+
635
+ # Load WORKFLOW.md
636
+ workflow_content = self._load_packaged_file_fallback("WORKFLOW.md", resources)
637
+ if workflow_content:
638
+ content["workflow_instructions"] = workflow_content
639
+ content["project_workflow"] = "system"
640
+
641
+ # Load MEMORY.md
642
+ memory_content = self._load_packaged_file_fallback("MEMORY.md", resources)
643
+ if memory_content:
644
+ content["memory_instructions"] = memory_content
645
+ content["project_memory"] = "system"
646
+
647
+ except Exception as e:
648
+ self.logger.error(f"Failed to load packaged framework content with fallback: {e}")
649
+
650
+ def _load_packaged_file_fallback(self, filename: str, resources) -> Optional[str]:
651
+ """Load a file from the packaged installation using importlib.resources fallback."""
652
+ try:
653
+ # Try different resource loading methods
654
+ try:
655
+ # Method 1: resources.read_text (Python 3.9+)
656
+ content = resources.read_text('claude_mpm.agents', filename)
657
+ self.logger.info(f"Loaded {filename} from package using read_text")
658
+ return content
659
+ except AttributeError:
660
+ # Method 2: resources.files (Python 3.9+)
661
+ agents_files = resources.files('claude_mpm.agents')
662
+ file_path = agents_files / filename
663
+ if file_path.is_file():
664
+ content = file_path.read_text()
665
+ self.logger.info(f"Loaded {filename} from package using files")
666
+ return content
667
+ else:
668
+ self.logger.warning(f"File {filename} not found in package")
669
+ return None
670
+ except Exception as e:
671
+ self.logger.error(f"Failed to load {filename} from package with fallback: {e}")
672
+ return None
673
+
674
+ def _load_packaged_file(self, filename: str) -> Optional[str]:
675
+ """Load a file from the packaged installation."""
676
+ try:
677
+ # Use importlib.resources to load file from package
678
+ agents_package = files('claude_mpm.agents')
679
+ file_path = agents_package / filename
680
+
681
+ if file_path.is_file():
682
+ content = file_path.read_text()
683
+ self.logger.info(f"Loaded {filename} from package")
684
+ return content
685
+ else:
686
+ self.logger.warning(f"File {filename} not found in package")
687
+ return None
688
+ except Exception as e:
689
+ self.logger.error(f"Failed to load {filename} from package: {e}")
690
+ return None
691
+
692
+ def _extract_metadata_from_content(self, content: str, filename: str) -> None:
693
+ """Extract metadata from content string."""
694
+ import re
695
+
696
+ # Extract version
697
+ version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
698
+ if version_match and "INSTRUCTIONS.md" in filename:
699
+ self.framework_version = version_match.group(1)
700
+ self.logger.info(f"Framework version: {self.framework_version}")
701
+
702
+ # Extract timestamp
703
+ timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
704
+ if timestamp_match and "INSTRUCTIONS.md" in filename:
705
+ self.framework_last_modified = timestamp_match.group(1).strip()
706
+ self.logger.info(f"Last modified: {self.framework_last_modified}")
500
707
 
501
708
  def get_framework_instructions(self) -> str:
502
709
  """
@@ -74,7 +74,11 @@ class PathContext:
74
74
  module_path = Path(claude_mpm.__file__).parent
75
75
 
76
76
  # Check for development mode
77
- if (module_path.parent / "src").exists():
77
+ # module_path is typically /path/to/project/src/claude_mpm
78
+ # So we need to check if /path/to/project/src exists (module_path.parent)
79
+ # and if /path/to/project/src/claude_mpm exists (module_path itself)
80
+ if (module_path.parent.name == "src" and
81
+ (module_path.parent.parent / "src" / "claude_mpm").exists()):
78
82
  return DeploymentContext.DEVELOPMENT
79
83
 
80
84
  # Check for editable install
@@ -3,6 +3,7 @@
3
3
  from abc import ABC, abstractmethod
4
4
  from dataclasses import dataclass
5
5
  from enum import Enum
6
+ from typing import Optional
6
7
 
7
8
  from claude_mpm.core.logger import get_logger
8
9
 
@@ -145,22 +145,29 @@ class AgentProcessor:
145
145
  else:
146
146
  needs_update = True
147
147
  reason = "New agent in project mode"
148
- elif not needs_update and context.target_file.exists():
149
- # In update mode, check version compatibility
150
- needs_update, reason = self.version_manager.check_agent_needs_update(
151
- context.target_file, context.template_file, context.base_agent_version
152
- )
153
- if needs_update:
154
- # Check if this is a migration from old format
155
- if "migration needed" in reason:
156
- is_migration = True
157
- self.logger.info(
158
- f"Migration needed for agent {context.agent_name}: {reason}"
159
- )
160
- else:
161
- self.logger.info(
162
- f"Agent {context.agent_name} needs update: {reason}"
163
- )
148
+ elif not needs_update:
149
+ # Check if target file exists
150
+ if not context.target_file.exists():
151
+ # File doesn't exist, needs to be deployed
152
+ needs_update = True
153
+ reason = "New agent deployment"
154
+ self.logger.debug(f"Agent {context.agent_name} doesn't exist, will deploy")
155
+ else:
156
+ # File exists, check version compatibility
157
+ needs_update, reason = self.version_manager.check_agent_needs_update(
158
+ context.target_file, context.template_file, context.base_agent_version
159
+ )
160
+ if needs_update:
161
+ # Check if this is a migration from old format
162
+ if "migration needed" in reason:
163
+ is_migration = True
164
+ self.logger.info(
165
+ f"Migration needed for agent {context.agent_name}: {reason}"
166
+ )
167
+ else:
168
+ self.logger.info(
169
+ f"Agent {context.agent_name} needs update: {reason}"
170
+ )
164
171
 
165
172
  return needs_update, is_migration, reason
166
173
 
@@ -1,6 +1,7 @@
1
1
  """Project-specific agent deployment strategy."""
2
2
 
3
3
  from pathlib import Path
4
+ from typing import List
4
5
 
5
6
  from .base_strategy import BaseDeploymentStrategy, DeploymentContext
6
7
 
@@ -1,6 +1,7 @@
1
1
  """System agent deployment strategy."""
2
2
 
3
3
  from pathlib import Path
4
+ from typing import List
4
5
 
5
6
  from claude_mpm.core.unified_paths import get_path_manager
6
7
 
@@ -1,6 +1,7 @@
1
1
  """User-specific agent deployment strategy."""
2
2
 
3
3
  from pathlib import Path
4
+ from typing import List
4
5
 
5
6
  from .base_strategy import BaseDeploymentStrategy, DeploymentContext
6
7
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.0.13
3
+ Version: 4.0.15
4
4
  Summary: Claude Multi-agent Project Manager - Clean orchestration with ticket management
5
5
  Home-page: https://github.com/bobmatnyc/claude-mpm
6
6
  Author: Claude MPM Team
@@ -39,6 +39,7 @@ Requires-Dist: mistune>=3.0.0
39
39
  Requires-Dist: aiofiles>=23.0.0
40
40
  Requires-Dist: mcp>=0.1.0
41
41
  Requires-Dist: ijson>=3.2.0
42
+ Requires-Dist: importlib-resources>=5.0; python_version < "3.9"
42
43
  Provides-Extra: dev
43
44
  Requires-Dist: pytest>=7.0; extra == "dev"
44
45
  Requires-Dist: pytest-asyncio; extra == "dev"
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=lClFCBcT1eNYIwcwgsxZcVeZ3Ebeb7-A7a1Zx8FU8xQ,4
2
- claude_mpm/VERSION,sha256=yhlGYA-ap4Q0WINJ-SW3triW4wZnsQydxP4V33JURNw,7
2
+ claude_mpm/VERSION,sha256=oiInrYO1q1FPSK6ab-8xePckdmDSYuIi1dPr6VwsTE8,7
3
3
  claude_mpm/__init__.py,sha256=lyTZAYGH4DTaFGLRNWJKk5Q5oTjzN5I6AXmfVX-Jff0,1512
4
4
  claude_mpm/__main__.py,sha256=Lfi2z17WSKiMrTAhA0LNsdLJRiV-J2dAezXPt0R9Qis,643
5
5
  claude_mpm/constants.py,sha256=cwfhDsstU5KK7esKnoq0PtSUg7LjneujdHjR-o5dX00,5597
@@ -11,6 +11,7 @@ claude_mpm/agents/INSTRUCTIONS.md,sha256=gQK3E0lcWntCyMoTXmwxuXPSyh-9zX94MU8nQT7
11
11
  claude_mpm/agents/MEMORY.md,sha256=zzwq4ytOrRaj64iq1q7brC6WOCQ4PDDC75TTRT8QudA,3493
12
12
  claude_mpm/agents/WORKFLOW.md,sha256=K1XqSlPNAs6HkcOSBTrOD7-0BcWCn90Sb6zX1EXtV6c,4686
13
13
  claude_mpm/agents/__init__.py,sha256=CPLqdKz9t_0gsSNdMSCZFw09jWQKSQ_piszPRFUyhKM,3220
14
+ claude_mpm/agents/agent-template.yaml,sha256=mRlz5Yd0SmknTeoJWgFkZXzEF5T7OmGBJGs2-KPT93k,1969
14
15
  claude_mpm/agents/agent_loader.py,sha256=jLn2KBH_V7gm76MDiAnR1AKOCcp-DqcYJffaYhF9BRs,31786
15
16
  claude_mpm/agents/agent_loader_integration.py,sha256=fkdakWWN9hKC-H_H9KQqBmreM-vDF1dRr5DTaq3_Nwk,7275
16
17
  claude_mpm/agents/agents_metadata.py,sha256=IWF2VxAJChrN0fpPV2bi3Cn-Gva-FaBU7EbWvd9N3As,5881
@@ -66,18 +67,18 @@ claude_mpm/cli/commands/mcp_server_commands.py,sha256=MV3mLDf1F2c_YpCw0UNqLwlFJo
66
67
  claude_mpm/cli/commands/mcp_tool_commands.py,sha256=q17GzlFT3JiLTrDqwPO2tz1-fKmPO5QU449syTnKTz4,1283
67
68
  claude_mpm/cli/commands/memory.py,sha256=UqMSrwFhXEt4lsOOcgHDOKWmlwLe0rwCuc4E2FNi3BE,36807
68
69
  claude_mpm/cli/commands/monitor.py,sha256=L8ID5Z2CAgPhGBWh85rmwrM3ZgHNOZj2nKNHvZEkcps,23148
69
- claude_mpm/cli/commands/run.py,sha256=lXWlJ8-4hqqpf4BvGERvsUWG2uC5sMlSk_Zf_eUOnZg,37228
70
- claude_mpm/cli/commands/run_config_checker.py,sha256=TonwgJXCIbs3XvCgFoLXpplDAWTWof8rQG8fkZEpiQo,6950
70
+ claude_mpm/cli/commands/run.py,sha256=fXZBz6d3GTrg0XeeZGvjOMy1tx-SyOqaZeI4iv_j8go,37264
71
+ claude_mpm/cli/commands/run_config_checker.py,sha256=OVH6KwhQPRXCk1GpjuBVHyc3WhdntPGYJfOK3uQc6FA,6962
71
72
  claude_mpm/cli/commands/socketio_monitor.py,sha256=3QnUrbd7l6wZyYKA3mGoT_AbenhSgw2JfRgf4OHJ8Ug,9588
72
73
  claude_mpm/cli/commands/tickets.py,sha256=CU8_SupT6KCRKqGKAY8eE3_3K5nSvBC8PBD-WQFsdUM,25977
73
74
  claude_mpm/cli/parsers/__init__.py,sha256=z6xJz7lumf54qkqv5hvDYr3P1ib_MqvoxSW8-gFz9Kg,1005
74
75
  claude_mpm/cli/parsers/agents_parser.py,sha256=KK2XQjheedr2OpQ2vGfH1iOWHYLgGgpNZx0yU5un_Aw,4576
75
- claude_mpm/cli/parsers/base_parser.py,sha256=DfQC148y86Alo5jYSur3cyuZMKOlWHcyYanoyjhOyfU,11486
76
+ claude_mpm/cli/parsers/base_parser.py,sha256=Keh3ToQyWhdj0_1zPPV_6P_LiXqv7KNy5jo5Av8CROA,11495
76
77
  claude_mpm/cli/parsers/config_parser.py,sha256=wp6NbV8_p9txP28MXFcQrri0JDIfGFM7u4aJbYJXcYQ,2699
77
78
  claude_mpm/cli/parsers/mcp_parser.py,sha256=SUwOagXlNP3qbRUvjuNU17plTyCD2ppJXBIPLQ0rmvw,5050
78
79
  claude_mpm/cli/parsers/memory_parser.py,sha256=ZwCDxJEgp-w03L-1tZsWTgisiwamP42s424bA5bvDJc,4760
79
80
  claude_mpm/cli/parsers/monitor_parser.py,sha256=lkiAzMfU8DDdv5cJ-OHQ4sS5b-kcmACIuAwsqWkVdik,4453
80
- claude_mpm/cli/parsers/run_parser.py,sha256=0616Uk_66tuXL8Q6xStlU8_NiXfhqcAhvpG_sqmmeDM,4576
81
+ claude_mpm/cli/parsers/run_parser.py,sha256=nBCEIPRSMHIhRRuvVb8eq_gBXBmVCW63Fq2xh59be3w,4585
81
82
  claude_mpm/cli/parsers/tickets_parser.py,sha256=FYl-VNH7PrZzfZUCcjnf6F7g6JXnL8YDxwrmR5svIcg,6966
82
83
  claude_mpm/cli_module/__init__.py,sha256=CbBbzKiJASmLmq3ElvXbOKS4Y4A_ugZo1bMv3kUBf6k,392
83
84
  claude_mpm/cli_module/args.py,sha256=QHxD6ockBSKQojBcmh9HmEMMlyscBgtNtIyGe78NG_o,8474
@@ -102,7 +103,7 @@ claude_mpm/core/constants.py,sha256=6e_IMQMOeW3oMgUsLFGvbqzM8Sf4fDYMpn3rGpfWVhM,
102
103
  claude_mpm/core/container.py,sha256=SERH3YOH9BXtHbv-kWu0bViNpdcGccDXR0NXFXbw1Pc,32155
103
104
  claude_mpm/core/exceptions.py,sha256=lNVLqVuRjygHe89NJg1rPAyevVdzpLOKgHFMQtGSxdA,19654
104
105
  claude_mpm/core/factories.py,sha256=A7WcjYWjhkc-tzUnef0YaW0Jj8oxMP-7_g2jIj1XYa8,7265
105
- claude_mpm/core/framework_loader.py,sha256=E_l5hrqwrGvAWCE-CHwjqAQErjxdzwgJ7AY31au5Hhk,42122
106
+ claude_mpm/core/framework_loader.py,sha256=kXHTB8GdQGY0BsWPCay3N7lD6vUUFpem6sNnsqAi4bs,52625
106
107
  claude_mpm/core/hook_manager.py,sha256=N-54QwNsyrUZSrH533HAo6hlJKPFbgMeDirg92H8en8,11014
107
108
  claude_mpm/core/hook_performance_config.py,sha256=Cqf-89mjiLlFJ-v4PhxfzsaOVovYYQa5pa-RMm42Ki8,5748
108
109
  claude_mpm/core/injectable_service.py,sha256=HXuviYX-h0sNxOFzgZiYjf-gLDUnQIeG-0-KuWdfCzk,7397
@@ -125,7 +126,7 @@ claude_mpm/core/types.py,sha256=RQ6MQlV_G3ohLPSdQRRAlQkoCt1BuLK-vnl2JbuFQYA,7835
125
126
  claude_mpm/core/typing_utils.py,sha256=IV-AaalNeJaXIqgfnPqY2yO46az8ji42ENuhVCLhkaU,13477
126
127
  claude_mpm/core/unified_agent_registry.py,sha256=57So2ivXX8UiEWYkPGjX-dZgWVxJDlyMwbfoRpNEhmM,24561
127
128
  claude_mpm/core/unified_config.py,sha256=zMqUPiszLIA4D3PZgGjuKCaPc7EdadsNjnGnERNt3a0,19694
128
- claude_mpm/core/unified_paths.py,sha256=wt6gr7rIQOeHDxVKyl21PHKT6b9tIJQ9Oz0KM4HM-_Q,19146
129
+ claude_mpm/core/unified_paths.py,sha256=bh5Oe99o4mmBYYFYHnyakQt-BXOq5fAeqobm2Hk3p3o,19461
129
130
  claude_mpm/dashboard/index.html,sha256=d0DPXBFdtIYWPv0TsLnnYBY8jY2wnoAL9EYAkrUN7UM,452
130
131
  claude_mpm/dashboard/open_dashboard.py,sha256=q6KuQg1ZWvr1SvYXKJdSMfyNsXzDElxBxeMihcc-EMU,2237
131
132
  claude_mpm/dashboard/test_dashboard.html,sha256=Aakmm9O-pWld_CCXLuUBOJC81Ix9D1avytTN93u0zfc,15090
@@ -262,23 +263,23 @@ claude_mpm/services/agents/deployment/pipeline/pipeline_context.py,sha256=HDuKKX
262
263
  claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py,sha256=N8dhwvNZk875TOseekcqJ8FWjSVDPNDEpbmMyxNU02o,6040
263
264
  claude_mpm/services/agents/deployment/pipeline/steps/__init__.py,sha256=5ERyPV2NI9Re2PkibM2idcHibwbuOTjW2I4QQ1yW5Qc,562
264
265
  claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py,sha256=P2BMyc3Jv-dO-EoDjDzqBZSKP91cUNwnKJwaxerGuV4,7128
265
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py,sha256=lOaCMHLr7Hq4snTdyfrakGgpQu8z1HYtOvE2wyr0LLE,3252
266
+ claude_mpm/services/agents/deployment/pipeline/steps/base_step.py,sha256=N3A2Qfn8tSksdgI_O5pVUX2FKU4RfnZAv8zMHcjrGO4,3280
266
267
  claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py,sha256=Lz-yASIJHlrWCw952jYU9iz7-Hb659PLiKLBZHEgllE,2568
267
268
  claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py,sha256=wY5FAsq9Dk_3vTgIMQ8NNfI0LME858hGi8cWnQ1uTOs,3199
268
269
  claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py,sha256=fMYtIPQDW0qwEy6D1v_LuOwd1ozqjVbpnq34M9zLkko,3330
269
270
  claude_mpm/services/agents/deployment/processors/__init__.py,sha256=UWQPqCzPHiwBw12xo-xGeXmVVRE088xqU0_hwXi7UHo,448
270
271
  claude_mpm/services/agents/deployment/processors/agent_deployment_context.py,sha256=9HZ30cGBgeUfhUDJ0bLolGK7mXwHnT70EfnXPPQj4OM,2893
271
272
  claude_mpm/services/agents/deployment/processors/agent_deployment_result.py,sha256=3wcDlZcI6lbh18KM2lMPeQ1wcKRWbbTRV3Z6GuHD4ec,6476
272
- claude_mpm/services/agents/deployment/processors/agent_processor.py,sha256=DC-0RT8HulqOcx6x_Gz_YGTUeSgBf0BkSOm9UU-KpqM,9320
273
+ claude_mpm/services/agents/deployment/processors/agent_processor.py,sha256=fHcLDSP_PdHG6XWtr6Scy2o9AkBbZxxLDtWAjEvTDlo,9688
273
274
  claude_mpm/services/agents/deployment/results/__init__.py,sha256=lwNNSe33wnnfrSs0rbcOi7yXm9wLmuYtGVgvFyL_op8,351
274
275
  claude_mpm/services/agents/deployment/results/deployment_metrics.py,sha256=Ig6pKuoxDBBUd4r-2ZJ63cgrREOSVpQky4S3EFfotQY,6492
275
276
  claude_mpm/services/agents/deployment/results/deployment_result_builder.py,sha256=B6C_Gig8IJwhpaFvEkZ-YiWRaMH3ZfgmJXlvpLmxhIs,7633
276
277
  claude_mpm/services/agents/deployment/strategies/__init__.py,sha256=NGBh41PXhJ2kksaDemLGT1mB5v_kO7uj6HiuQ_c60BM,986
277
278
  claude_mpm/services/agents/deployment/strategies/base_strategy.py,sha256=cqhYAEG3QhrrrbKGYx04_oLOQdZygurDhgLfPeBX9Oo,3452
278
- claude_mpm/services/agents/deployment/strategies/project_strategy.py,sha256=1Y7hh7HQhnP3ULBdyHIRsEQq-0qc6kDsOtsEZDH7Fso,4789
279
+ claude_mpm/services/agents/deployment/strategies/project_strategy.py,sha256=L8pLCmO4jlYgJ2Avq-f44VSHUp8x_orDpeD1Te57z44,4813
279
280
  claude_mpm/services/agents/deployment/strategies/strategy_selector.py,sha256=lWgDrsUOtOCGf7l3CgVLaAoUQymCm4pog9pqXaFE1mU,4065
280
- claude_mpm/services/agents/deployment/strategies/system_strategy.py,sha256=y3rvCxrRmF81IgQ3kTPydezBbZ-aG84fLPZfmBpcxgE,3698
281
- claude_mpm/services/agents/deployment/strategies/user_strategy.py,sha256=6pbmx6FlDWLOXhlNV8ZVmn6kuOKnVuazHT90H073iHM,4319
281
+ claude_mpm/services/agents/deployment/strategies/system_strategy.py,sha256=-lgT98wVd6PIjyOGf5jNMJrXGxuThTppA_fbljYpHbc,3722
282
+ claude_mpm/services/agents/deployment/strategies/user_strategy.py,sha256=OrfztRdpKjGeS9t-nT0Ik78crefp68ATD37Vz-rlCX8,4343
282
283
  claude_mpm/services/agents/deployment/validation/__init__.py,sha256=Vly1JMH0wwq75BSALLLfkzN4iGQBEklcId0c-qmUYRw,562
283
284
  claude_mpm/services/agents/deployment/validation/agent_validator.py,sha256=qzcKSRKhXVyZeJ8gbAraFGcT6dnRffbB0pCAa4pvG8w,11015
284
285
  claude_mpm/services/agents/deployment/validation/deployment_validator.py,sha256=Fn0LALAcbEfPmRiNj89ZfNjTUILeCfRASqqI4KmT_0o,8395
@@ -410,9 +411,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=e74VlIPozCljZss_0SwLO3J1ZuIKRT9FrrFi
410
411
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
411
412
  claude_mpm/validation/agent_validator.py,sha256=szbK9d29v_T6xE_KvW845WLKXbS_yYpXQscrSrSeldI,20937
412
413
  claude_mpm/validation/frontmatter_validator.py,sha256=Q_aTyjigfKZQG7eSwLtwMfd0h_eyS9FQAm59ZFf5VYA,7036
413
- claude_mpm-4.0.13.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
414
- claude_mpm-4.0.13.dist-info/METADATA,sha256=L4XvP_C3zs10lko6ZFid-VA9s_YSN-TbNg7LHmNt-k4,11819
415
- claude_mpm-4.0.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
416
- claude_mpm-4.0.13.dist-info/entry_points.txt,sha256=uafLVeHm4AXrzvdR77fXO3a2MmvvfGtmVU2iY8uIPt8,403
417
- claude_mpm-4.0.13.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
418
- claude_mpm-4.0.13.dist-info/RECORD,,
414
+ claude_mpm-4.0.15.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
415
+ claude_mpm-4.0.15.dist-info/METADATA,sha256=jaHndVS-uT8RMb5yHZE6rg7qw0D5hQjz1q4A_JvwExI,11883
416
+ claude_mpm-4.0.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
417
+ claude_mpm-4.0.15.dist-info/entry_points.txt,sha256=uafLVeHm4AXrzvdR77fXO3a2MmvvfGtmVU2iY8uIPt8,403
418
+ claude_mpm-4.0.15.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
419
+ claude_mpm-4.0.15.dist-info/RECORD,,