claude-mpm 5.4.75__py3-none-any.whl → 5.4.82__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 (42) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/cli/commands/configure.py +230 -19
  3. claude_mpm/cli/startup.py +7 -4
  4. claude_mpm/core/claude_runner.py +2 -2
  5. claude_mpm/core/interactive_session.py +7 -7
  6. claude_mpm/core/output_style_manager.py +7 -7
  7. claude_mpm/core/unified_config.py +16 -0
  8. claude_mpm/core/unified_paths.py +30 -13
  9. claude_mpm/services/agents/deployment/deployment_reconciler.py +39 -1
  10. claude_mpm/services/skills/git_skill_source_manager.py +5 -1
  11. claude_mpm/services/skills/selective_skill_deployer.py +0 -10
  12. {claude_mpm-5.4.75.dist-info → claude_mpm-5.4.82.dist-info}/METADATA +1 -1
  13. {claude_mpm-5.4.75.dist-info → claude_mpm-5.4.82.dist-info}/RECORD +18 -42
  14. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  15. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
  16. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  17. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  18. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
  19. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  20. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
  21. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  22. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  23. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
  24. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  25. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
  26. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  27. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
  28. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  29. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
  30. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  31. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
  32. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  33. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
  34. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  35. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
  36. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  37. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
  38. {claude_mpm-5.4.75.dist-info → claude_mpm-5.4.82.dist-info}/WHEEL +0 -0
  39. {claude_mpm-5.4.75.dist-info → claude_mpm-5.4.82.dist-info}/entry_points.txt +0 -0
  40. {claude_mpm-5.4.75.dist-info → claude_mpm-5.4.82.dist-info}/licenses/LICENSE +0 -0
  41. {claude_mpm-5.4.75.dist-info → claude_mpm-5.4.82.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  42. {claude_mpm-5.4.75.dist-info → claude_mpm-5.4.82.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 5.4.71
1
+ 5.4.82
@@ -26,6 +26,7 @@ from rich.prompt import Confirm, Prompt
26
26
  from rich.text import Text
27
27
 
28
28
  from ...core.config import Config
29
+ from ...core.unified_config import UnifiedConfig
29
30
  from ...services.agents.agent_recommendation_service import AgentRecommendationService
30
31
  from ...services.version_service import VersionService
31
32
  from ...utils.agent_filters import apply_all_filters, get_deployed_agent_ids
@@ -79,6 +80,7 @@ class ConfigureCommand(BaseCommand):
79
80
  self._template_editor = None # Lazy-initialized
80
81
  self._startup_manager = None # Lazy-initialized
81
82
  self._recommendation_service = None # Lazy-initialized
83
+ self._unified_config = None # Lazy-initialized
82
84
 
83
85
  def validate_args(self, args) -> Optional[str]:
84
86
  """Validate command arguments."""
@@ -162,6 +164,18 @@ class ConfigureCommand(BaseCommand):
162
164
  self._recommendation_service = AgentRecommendationService()
163
165
  return self._recommendation_service
164
166
 
167
+ @property
168
+ def unified_config(self) -> UnifiedConfig:
169
+ """Lazy-initialize unified config."""
170
+ if self._unified_config is None:
171
+ try:
172
+ self._unified_config = UnifiedConfig()
173
+ except Exception as e:
174
+ self.logger.warning(f"Failed to load unified config: {e}")
175
+ # Fallback to default config
176
+ self._unified_config = UnifiedConfig()
177
+ return self._unified_config
178
+
165
179
  def run(self, args) -> CommandResult:
166
180
  """Execute the configure command."""
167
181
  # Set configuration scope
@@ -805,6 +819,86 @@ class ConfigureCommand(BaseCommand):
805
819
  self.console.print("[red]Invalid choice. Please try again.[/red]")
806
820
  Prompt.ask("\nPress Enter to continue")
807
821
 
822
+ def _detect_skill_patterns(self, skills: list[dict]) -> dict[str, list[dict]]:
823
+ """Group skills by detected common prefixes.
824
+
825
+ Args:
826
+ skills: List of skill dictionaries
827
+
828
+ Returns:
829
+ Dict mapping pattern prefix to list of skills.
830
+ Skills without pattern match go under "" (empty string) key.
831
+ """
832
+ from collections import defaultdict
833
+
834
+ # Count prefix occurrences (try 1-segment and 2-segment prefixes)
835
+ prefix_counts = defaultdict(list)
836
+
837
+ for skill in skills:
838
+ skill_id = skill.get("name", skill.get("skill_id", ""))
839
+
840
+ # Try to extract prefixes (split by hyphen)
841
+ parts = skill_id.split("-")
842
+
843
+ if len(parts) >= 2:
844
+ # Try 2-segment prefix first (e.g., "toolchains-universal")
845
+ two_seg_prefix = f"{parts[0]}-{parts[1]}"
846
+ prefix_counts[two_seg_prefix].append(skill)
847
+
848
+ # Also try 1-segment prefix (e.g., "digitalocean")
849
+ one_seg_prefix = parts[0]
850
+ if one_seg_prefix != two_seg_prefix:
851
+ prefix_counts[one_seg_prefix].append(skill)
852
+
853
+ # Build pattern groups (require at least 2 skills per pattern)
854
+ pattern_groups = defaultdict(list)
855
+ used_skills = set()
856
+
857
+ # Prefer longer (more specific) prefixes
858
+ sorted_prefixes = sorted(prefix_counts.keys(), key=lambda x: (-len(x), x))
859
+
860
+ for prefix in sorted_prefixes:
861
+ matching_skills = prefix_counts[prefix]
862
+
863
+ # Only create a pattern group if we have 2+ skills and they're not already grouped
864
+ available_skills = [s for s in matching_skills if id(s) not in used_skills]
865
+
866
+ if len(available_skills) >= 2:
867
+ pattern_groups[prefix] = available_skills
868
+ used_skills.update(id(s) for s in available_skills)
869
+
870
+ # Add ungrouped skills to "" (Other) group
871
+ for skill in skills:
872
+ if id(skill) not in used_skills:
873
+ pattern_groups[""].append(skill)
874
+
875
+ return dict(pattern_groups)
876
+
877
+ def _get_pattern_icon(self, prefix: str) -> str:
878
+ """Get icon for a pattern prefix.
879
+
880
+ Args:
881
+ prefix: Pattern prefix (e.g., "digitalocean", "vercel")
882
+
883
+ Returns:
884
+ Emoji icon for the pattern
885
+ """
886
+ pattern_icons = {
887
+ "digitalocean": "🌊",
888
+ "aws": "☁️",
889
+ "github": "🐙",
890
+ "google": "🔍",
891
+ "vercel": "▲",
892
+ "netlify": "🦋",
893
+ "universal-testing": "🧪",
894
+ "universal-debugging": "🐛",
895
+ "universal-security": "🔒",
896
+ "toolchains-python": "🐍",
897
+ "toolchains-typescript": "📘",
898
+ "toolchains-javascript": "📒",
899
+ }
900
+ return pattern_icons.get(prefix, "📦")
901
+
808
902
  def _manage_skill_installation(self) -> None:
809
903
  """Manage skill installation with category-based questionary checkbox selection."""
810
904
  import questionary
@@ -890,30 +984,99 @@ class ConfigureCommand(BaseCommand):
890
984
  # Show skills in category with checkbox selection
891
985
  category_skills = grouped[selected_cat]
892
986
 
893
- # Build choices with current installation status
987
+ # Detect pattern groups within category
988
+ pattern_groups = self._detect_skill_patterns(category_skills)
989
+
990
+ # Build choices with pattern grouping and installation status
894
991
  skill_choices = []
895
- for skill in sorted(category_skills, key=lambda x: x.get("name", "")):
896
- skill_id = skill.get("name", skill.get("skill_id", "unknown"))
897
- deploy_name = skill.get("deployment_name", skill_id)
898
- description = skill.get("description", "")[:50]
899
992
 
900
- # Check if installed
901
- is_installed = deploy_name in deployed or skill_id in deployed
993
+ # Track which skills belong to which group for expansion later
994
+ group_to_skills = {}
902
995
 
903
- skill_choices.append(
904
- Choice(
905
- title=f"{skill_id} - {description}",
906
- value=skill_id,
907
- checked=is_installed,
996
+ # Sort pattern groups: "" (Other) last, rest alphabetically
997
+ sorted_patterns = sorted(pattern_groups.keys(), key=lambda x: (x == "", x))
998
+
999
+ for pattern in sorted_patterns:
1000
+ pattern_skills = pattern_groups[pattern]
1001
+
1002
+ # Skip empty groups
1003
+ if not pattern_skills:
1004
+ continue
1005
+
1006
+ # Collect skill IDs in this group
1007
+ skill_ids_in_group = []
1008
+ for skill in pattern_skills:
1009
+ skill_id = skill.get("name", skill.get("skill_id", "unknown"))
1010
+ skill_ids_in_group.append(skill_id)
1011
+
1012
+ # Check if all skills in group are installed
1013
+ all_installed = all(
1014
+ skill.get(
1015
+ "deployment_name", skill.get("name", skill.get("skill_id"))
908
1016
  )
1017
+ in deployed
1018
+ or skill.get("name", skill.get("skill_id")) in deployed
1019
+ for skill in pattern_skills
909
1020
  )
910
1021
 
1022
+ # Add pattern group header as selectable choice
1023
+ if pattern:
1024
+ # Named pattern group
1025
+ pattern_icon = self._get_pattern_icon(pattern)
1026
+ skill_count = len(pattern_skills)
1027
+ group_key = f"__group__:{pattern}"
1028
+ group_to_skills[group_key] = skill_ids_in_group
1029
+
1030
+ skill_choices.append(
1031
+ Choice(
1032
+ title=f"{pattern_icon} {pattern} ({skill_count} skills) [Select All]",
1033
+ value=group_key,
1034
+ checked=all_installed,
1035
+ )
1036
+ )
1037
+ elif pattern_skills:
1038
+ # "Other" group - only show if there are skills
1039
+ group_key = "__group__:Other"
1040
+ group_to_skills[group_key] = skill_ids_in_group
1041
+
1042
+ skill_choices.append(
1043
+ Choice(
1044
+ title=f"📦 Other ({len(pattern_skills)} skills) [Select All]",
1045
+ value=group_key,
1046
+ checked=all_installed,
1047
+ )
1048
+ )
1049
+
1050
+ # Add skills in this pattern group
1051
+ for skill in sorted(pattern_skills, key=lambda x: x.get("name", "")):
1052
+ skill_id = skill.get("name", skill.get("skill_id", "unknown"))
1053
+ deploy_name = skill.get("deployment_name", skill_id)
1054
+ description = skill.get("description", "")[:50]
1055
+
1056
+ # Check if installed
1057
+ is_installed = deploy_name in deployed or skill_id in deployed
1058
+
1059
+ # Add indentation for pattern-grouped skills (all skills are indented)
1060
+ skill_choices.append(
1061
+ Choice(
1062
+ title=f" {skill_id} - {description}",
1063
+ value=skill_id,
1064
+ checked=is_installed,
1065
+ )
1066
+ )
1067
+
1068
+ # Add spacing between pattern groups (not after last group)
1069
+ if pattern != sorted_patterns[-1]:
1070
+ skill_choices.append(Separator())
1071
+
911
1072
  self.console.clear()
912
1073
  self._display_header()
913
1074
  self.console.print(
914
1075
  f"\n{icons.get(selected_cat, '📦')} [bold]{selected_cat.title()}[/bold]"
915
1076
  )
916
- self.console.print("[dim]Use spacebar to toggle, enter to confirm[/dim]\n")
1077
+ self.console.print(
1078
+ "[dim]Use spacebar to toggle individual skills or entire groups, enter to confirm[/dim]\n"
1079
+ )
917
1080
 
918
1081
  selected = questionary.checkbox(
919
1082
  "Select skills to install:",
@@ -924,8 +1087,16 @@ class ConfigureCommand(BaseCommand):
924
1087
  if selected is None:
925
1088
  continue # User cancelled, go back to category selection
926
1089
 
927
- # Process changes
928
- selected_set = set(selected)
1090
+ # Process group selections - expand to individual skills
1091
+ selected_set = set()
1092
+ for item in selected:
1093
+ if item.startswith("__group__:"):
1094
+ # Expand group selection to all skills in that group
1095
+ selected_set.update(group_to_skills[item])
1096
+ else:
1097
+ # Individual skill selection
1098
+ selected_set.add(item)
1099
+
929
1100
  current_in_cat = set()
930
1101
 
931
1102
  # Find currently installed skills in this category
@@ -1905,18 +2076,32 @@ class ConfigureCommand(BaseCommand):
1905
2076
  )
1906
2077
  display_name = self._format_display_name(raw_display_name)
1907
2078
 
1908
- # Check if agent is deployed (exists in .claude/agents/)
2079
+ # Check if agent is required (cannot be unchecked)
2080
+ required_agents = set(self.unified_config.agents.required)
2081
+ is_required = (
2082
+ agent_leaf_name in required_agents
2083
+ or agent_id in required_agents
2084
+ )
1909
2085
 
1910
- # Format choice text (no asterisk needed)
1911
- choice_text = f" {display_name}"
2086
+ # Format choice text with [Required] indicator
2087
+ if is_required:
2088
+ choice_text = f" {display_name} [Required]"
2089
+ else:
2090
+ choice_text = f" {display_name}"
1912
2091
 
1913
- is_selected = agent_id in current_selection
2092
+ # Required agents are always selected
2093
+ is_selected = is_required or agent_id in current_selection
2094
+
2095
+ # Add to current selection if required
2096
+ if is_required:
2097
+ current_selection.add(agent_id)
1914
2098
 
1915
2099
  choices.append(
1916
2100
  Choice(
1917
2101
  title=choice_text,
1918
2102
  value=agent_id, # Use agent_id for value
1919
2103
  checked=is_selected,
2104
+ disabled=is_required, # Disable checkbox for required agents
1920
2105
  )
1921
2106
  )
1922
2107
 
@@ -1925,6 +2110,7 @@ class ConfigureCommand(BaseCommand):
1925
2110
  self.console.print(
1926
2111
  "[dim][ ] Unchecked = Available (check to install)[/dim]"
1927
2112
  )
2113
+ self.console.print("[dim][Required] = Core agents (always installed)[/dim]")
1928
2114
  self.console.print(
1929
2115
  "[dim]Use arrow keys to navigate, space to toggle, Enter to apply[/dim]\n"
1930
2116
  )
@@ -2011,12 +2197,37 @@ class ConfigureCommand(BaseCommand):
2011
2197
 
2012
2198
  # No controls selected - use the individual selections as final
2013
2199
  final_selection = set(selected_values)
2200
+
2201
+ # Ensure required agents are always in the final selection
2202
+ required_agents = set(self.unified_config.agents.required)
2203
+ for agent in agents:
2204
+ agent_id = getattr(agent, "agent_id", agent.name)
2205
+ agent_leaf_name = agent_id.split("/")[-1]
2206
+ if agent_leaf_name in required_agents or agent_id in required_agents:
2207
+ final_selection.add(agent_id)
2208
+
2014
2209
  break
2015
2210
 
2016
2211
  # Determine changes
2017
2212
  to_deploy = final_selection - deployed_full_paths
2018
2213
  to_remove = deployed_full_paths - final_selection
2019
2214
 
2215
+ # Prevent removal of required agents
2216
+ required_agents = set(self.unified_config.agents.required)
2217
+ to_remove_filtered = set()
2218
+ for agent_id in to_remove:
2219
+ agent_leaf_name = agent_id.split("/")[-1]
2220
+ if (
2221
+ agent_leaf_name not in required_agents
2222
+ and agent_id not in required_agents
2223
+ ):
2224
+ to_remove_filtered.add(agent_id)
2225
+ else:
2226
+ self.console.print(
2227
+ f"[yellow]⚠ Cannot remove required agent: {agent_id}[/yellow]"
2228
+ )
2229
+ to_remove = to_remove_filtered
2230
+
2020
2231
  if not to_deploy and not to_remove:
2021
2232
  self.console.print("[yellow]No changes needed[/yellow]")
2022
2233
  Prompt.ask("\nPress Enter to continue")
claude_mpm/cli/startup.py CHANGED
@@ -700,8 +700,7 @@ def sync_remote_agents_on_startup(force_sync: bool = False):
700
700
  agent_files = [
701
701
  f
702
702
  for f in all_md_files
703
- if
704
- (
703
+ if (
705
704
  # Must be in an agent directory
706
705
  # Supports: cache/agents/{category}/... (flat)
707
706
  # Supports: cache/agents/{owner}/{repo}/agents/{category}/... (GitHub sync)
@@ -1467,7 +1466,9 @@ def run_background_services(force_sync: bool = False):
1467
1466
  check_mcp_auto_configuration()
1468
1467
  verify_mcp_gateway_startup()
1469
1468
  check_for_updates_async()
1470
- sync_remote_agents_on_startup(force_sync=force_sync) # Sync agents from remote sources
1469
+ sync_remote_agents_on_startup(
1470
+ force_sync=force_sync
1471
+ ) # Sync agents from remote sources
1471
1472
  show_agent_summary() # Display agent counts after deployment
1472
1473
 
1473
1474
  # Skills deployment order (precedence: remote > bundled)
@@ -1476,7 +1477,9 @@ def run_background_services(force_sync: bool = False):
1476
1477
  # 3. Discover and link runtime skills (user-added skills)
1477
1478
  # This ensures remote skills take precedence over bundled skills when names conflict
1478
1479
  deploy_bundled_skills() # Base layer: package-bundled skills
1479
- sync_remote_skills_on_startup(force_sync=force_sync) # Override layer: Git-based skills (takes precedence)
1480
+ sync_remote_skills_on_startup(
1481
+ force_sync=force_sync
1482
+ ) # Override layer: Git-based skills (takes precedence)
1480
1483
  discover_and_link_runtime_skills() # Discovery: user-added skills
1481
1484
  show_skill_summary() # Display skill counts after deployment
1482
1485
  verify_and_show_pm_skills() # PM skills verification and status
@@ -730,7 +730,7 @@ Use these agents to delegate specialized work via the Task tool.
730
730
  import json
731
731
 
732
732
  settings = json.loads(settings_file.read_text())
733
- if settings.get("activeOutputStyle") == "claude-mpm":
733
+ if settings.get("activeOutputStyle") == "Claude MPM":
734
734
  # Already active, check if file exists
735
735
  output_style_file = (
736
736
  Path.home() / ".claude" / "output-styles" / "claude-mpm.md"
@@ -740,7 +740,7 @@ Use these agents to delegate specialized work via the Task tool.
740
740
  "Output style 'Claude MPM' already deployed and active"
741
741
  )
742
742
  return
743
- except Exception:
743
+ except Exception: # nosec B110
744
744
  pass # Continue with deployment if we can't read settings
745
745
 
746
746
  # Read the OUTPUT_STYLE.md content if it exists
@@ -12,7 +12,7 @@ of InteractiveSession without circular dependency issues.
12
12
 
13
13
  import contextlib
14
14
  import os
15
- import subprocess
15
+ import subprocess # nosec B404
16
16
  import uuid
17
17
  from pathlib import Path
18
18
  from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple
@@ -359,19 +359,19 @@ class InteractiveSession:
359
359
  osm = self.runner.framework_loader.output_style_manager
360
360
  if osm:
361
361
  if osm.claude_version and osm.supports_output_styles():
362
- # Check if claude-mpm style is active
362
+ # Check if Claude MPM style is active
363
363
  settings_file = osm.settings_file
364
364
  if settings_file.exists():
365
365
  import json
366
366
 
367
367
  settings = json.loads(settings_file.read_text())
368
368
  active_style = settings.get("activeOutputStyle")
369
- if active_style == "claude-mpm":
370
- return "Output Style: claude-mpm ✅"
369
+ if active_style in ("Claude MPM", "Claude MPM Teacher"):
370
+ return f"Output Style: {active_style} ✅"
371
371
  return f"Output Style: {active_style or 'none'}"
372
372
  return "Output Style: Available"
373
373
  return "Output Style: Injected (legacy)"
374
- except Exception:
374
+ except Exception: # nosec B110
375
375
  pass
376
376
  return None
377
377
 
@@ -582,7 +582,7 @@ class InteractiveSession:
582
582
  )
583
583
 
584
584
  # This will not return if successful
585
- os.execvpe(cmd[0], cmd, env)
585
+ os.execvpe(cmd[0], cmd, env) # nosec B606
586
586
  return False # Only reached on failure
587
587
 
588
588
  def _launch_subprocess_mode(self, cmd: list, env: dict) -> bool:
@@ -641,7 +641,7 @@ class InteractiveSession:
641
641
  cmd = environment["command"]
642
642
  env = environment["environment"]
643
643
 
644
- result = subprocess.run(
644
+ result = subprocess.run( # nosec B603
645
645
  cmd, stdin=None, stdout=None, stderr=None, env=env, check=False
646
646
  )
647
647
 
@@ -13,7 +13,7 @@ Users can change it if they want, and the system will respect their choice.
13
13
 
14
14
  import json
15
15
  import re
16
- import subprocess
16
+ import subprocess # nosec B404
17
17
  from pathlib import Path
18
18
  from typing import Any, Dict, Literal, Optional, TypedDict, cast
19
19
 
@@ -62,14 +62,14 @@ class OutputStyleManager:
62
62
  / "agents"
63
63
  / "CLAUDE_MPM_OUTPUT_STYLE.md",
64
64
  target=self.output_style_dir / "claude-mpm.md",
65
- name="claude-mpm",
65
+ name="Claude MPM",
66
66
  ),
67
67
  "teaching": StyleConfig(
68
68
  source=Path(__file__).parent.parent
69
69
  / "agents"
70
70
  / "CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md",
71
71
  target=self.output_style_dir / "claude-mpm-teacher.md",
72
- name="claude-mpm-teacher",
72
+ name="Claude MPM Teacher",
73
73
  ),
74
74
  }
75
75
 
@@ -93,7 +93,7 @@ class OutputStyleManager:
93
93
 
94
94
  try:
95
95
  # Run claude --version command
96
- result = subprocess.run(
96
+ result = subprocess.run( # nosec B603 B607
97
97
  ["claude", "--version"],
98
98
  capture_output=True,
99
99
  text=True,
@@ -300,12 +300,12 @@ class OutputStyleManager:
300
300
  self.logger.error(f"Failed to deploy {style} style: {e}")
301
301
  return False
302
302
 
303
- def _activate_output_style(self, style_name: str = "claude-mpm") -> bool:
303
+ def _activate_output_style(self, style_name: str = "Claude MPM") -> bool:
304
304
  """
305
305
  Update Claude Code settings to activate a specific output style.
306
306
 
307
307
  Args:
308
- style_name: Name of the style to activate (e.g., "claude-mpm", "claude-mpm-teach")
308
+ style_name: Name of the style to activate (e.g., "Claude MPM", "Claude MPM Teacher")
309
309
 
310
310
  Returns:
311
311
  True if activated successfully, False otherwise
@@ -443,7 +443,7 @@ class OutputStyleManager:
443
443
 
444
444
  # Activate the default style if requested
445
445
  if activate_default and results.get("professional", False):
446
- self._activate_output_style("claude-mpm")
446
+ self._activate_output_style("Claude MPM")
447
447
 
448
448
  return results
449
449
 
@@ -72,6 +72,22 @@ class AgentConfig(BaseModel):
72
72
  description="Explicit list of agent IDs to deploy (empty = use auto_discover)",
73
73
  )
74
74
 
75
+ # Required agents that are always deployed
76
+ required: List[str] = Field(
77
+ default_factory=lambda: [
78
+ "research",
79
+ "mpm-skills-manager",
80
+ "mpm-agent-manager",
81
+ "memory-manager",
82
+ ],
83
+ description="Agents that are always deployed (core system agents)",
84
+ )
85
+
86
+ include_universal: bool = Field(
87
+ default=True,
88
+ description="Auto-include all agents with 'universal' toolchain/category",
89
+ )
90
+
75
91
  auto_discover: bool = Field(
76
92
  default=False,
77
93
  description="Enable automatic agent discovery (deprecated, use enabled list)",
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python3
2
1
  """
3
2
  Unified Path Management System for Claude MPM
4
3
  ==============================================
@@ -36,6 +35,24 @@ from claude_mpm.core.logging_utils import get_logger
36
35
  logger = get_logger(__name__)
37
36
 
38
37
 
38
+ def _safe_cwd() -> Path:
39
+ """Safely get the current working directory.
40
+
41
+ If the current directory no longer exists (deleted/moved), fall back to home directory.
42
+ This prevents FileNotFoundError when Path.cwd() is called from a deleted directory.
43
+
44
+ Returns:
45
+ Path: Current working directory, or home directory if cwd doesn't exist
46
+ """
47
+ try:
48
+ return Path.cwd()
49
+ except (FileNotFoundError, OSError) as e:
50
+ logger.debug(
51
+ f"Current directory doesn't exist ({e}), falling back to home directory"
52
+ )
53
+ return Path.home()
54
+
55
+
39
56
  class PathType(Enum):
40
57
  """Enumeration of different path types for categorization."""
41
58
 
@@ -95,7 +112,7 @@ class PathContext:
95
112
 
96
113
  # Additional check: If we're running from within a claude-mpm development directory
97
114
  # This handles the case where pipx claude-mpm is invoked from within the dev directory
98
- cwd = Path.cwd()
115
+ cwd = _safe_cwd()
99
116
  current = cwd
100
117
  for _ in range(5): # Check up to 5 levels up from current directory
101
118
  if (current / "pyproject.toml").exists() and (
@@ -114,7 +131,7 @@ class PathContext:
114
131
  # Verify this is a development setup by checking for key files
115
132
  if (current / "scripts" / "claude-mpm").exists():
116
133
  return True
117
- except Exception:
134
+ except Exception: # nosec B110
118
135
  pass
119
136
  if current == current.parent:
120
137
  break
@@ -140,7 +157,7 @@ class PathContext:
140
157
  f"Found editable install via .pth file: {pth_file}"
141
158
  )
142
159
  return True
143
- except Exception:
160
+ except Exception: # nosec B112
144
161
  continue
145
162
 
146
163
  # Check for egg-link files
@@ -156,7 +173,7 @@ class PathContext:
156
173
  f"Found editable install via egg-link: {egg_link}"
157
174
  )
158
175
  return True
159
- except Exception:
176
+ except Exception: # nosec B112
160
177
  continue
161
178
  except ImportError:
162
179
  pass
@@ -186,7 +203,7 @@ class PathContext:
186
203
 
187
204
  # Check if current working directory is a claude-mpm development project
188
205
  # This handles the case where pipx claude-mpm is run from within the dev directory
189
- cwd = Path.cwd()
206
+ cwd = _safe_cwd()
190
207
  current = cwd
191
208
  for _ in range(5): # Check up to 5 levels up from current directory
192
209
  if (current / "pyproject.toml").exists() and (
@@ -206,7 +223,7 @@ class PathContext:
206
223
  "Using development mode for local source preference"
207
224
  )
208
225
  return DeploymentContext.DEVELOPMENT
209
- except Exception:
226
+ except Exception: # nosec B110
210
227
  pass
211
228
  if current == current.parent:
212
229
  break
@@ -228,7 +245,7 @@ class PathContext:
228
245
  if "pipx" in str(module_path):
229
246
  # Running via pipx but from within a development directory
230
247
  # Use development mode to prefer local source over pipx installation
231
- cwd = Path.cwd()
248
+ cwd = _safe_cwd()
232
249
  current = cwd
233
250
  for _ in range(5):
234
251
  if (current / "src" / "claude_mpm").exists() and (
@@ -346,7 +363,7 @@ class UnifiedPathManager:
346
363
  ):
347
364
  # For development mode, first check if we're running from within a dev directory
348
365
  # This handles the case where pipx is invoked from a development directory
349
- cwd = Path.cwd()
366
+ cwd = _safe_cwd()
350
367
  current = cwd
351
368
  for _ in range(5):
352
369
  if (current / "src" / "claude_mpm").exists() and (
@@ -360,7 +377,7 @@ class UnifiedPathManager:
360
377
  f"Found framework root via cwd at {current}"
361
378
  )
362
379
  return current
363
- except Exception:
380
+ except Exception: # nosec B110
364
381
  pass
365
382
  if current == current.parent:
366
383
  break
@@ -403,7 +420,7 @@ class UnifiedPathManager:
403
420
  @lru_cache(maxsize=1)
404
421
  def project_root(self) -> Path:
405
422
  """Get the current project root directory."""
406
- current = Path.cwd()
423
+ current = _safe_cwd()
407
424
  while current != current.parent:
408
425
  for marker in self._project_markers:
409
426
  if (current / marker).exists():
@@ -413,7 +430,7 @@ class UnifiedPathManager:
413
430
 
414
431
  # Fallback to current directory
415
432
  logger.warning("Could not find project root, using current directory")
416
- return Path.cwd()
433
+ return _safe_cwd()
417
434
 
418
435
  @property
419
436
  def package_root(self) -> Path:
@@ -562,7 +579,7 @@ class UnifiedPathManager:
562
579
  self, filename: str, start_path: Optional[Path] = None
563
580
  ) -> Optional[Path]:
564
581
  """Search for a file by traversing up the directory tree."""
565
- current = start_path or Path.cwd()
582
+ current = start_path or _safe_cwd()
566
583
 
567
584
  while current != current.parent:
568
585
  candidate = current / filename
@@ -240,12 +240,50 @@ class DeploymentReconciler:
240
240
  self, cache_dir: Path, deploy_dir: Path
241
241
  ) -> ReconciliationState:
242
242
  """Get current agent deployment state."""
243
+ # Start with enabled agents
244
+ configured_agents = set(self.config.agents.enabled)
245
+
246
+ # Add required agents (cannot be disabled)
247
+ configured_agents.update(self.config.agents.required)
248
+
249
+ # Add universal agents if enabled
250
+ if self.config.agents.include_universal:
251
+ universal_agents = self._get_universal_agents(cache_dir)
252
+ configured_agents.update(universal_agents)
253
+
243
254
  return ReconciliationState(
244
- configured=set(self.config.agents.enabled),
255
+ configured=configured_agents,
245
256
  deployed=self._list_deployed_agents(deploy_dir),
246
257
  cached=self._list_cached_agents(cache_dir),
247
258
  )
248
259
 
260
+ def _get_universal_agents(self, cache_dir: Path) -> Set[str]:
261
+ """Get all agents with 'universal' toolchain/category."""
262
+ universal_agents = set()
263
+ if not cache_dir.exists():
264
+ return universal_agents
265
+
266
+ for agent_file in cache_dir.glob("**/*.md"):
267
+ try:
268
+ # Read frontmatter to check toolchain/category
269
+ content = agent_file.read_text(encoding="utf-8")
270
+
271
+ # Check for universal markers in frontmatter (within first 1000 chars)
272
+ frontmatter_section = content[:1000].lower()
273
+ if (
274
+ "toolchain: universal" in frontmatter_section
275
+ or "category: universal" in frontmatter_section
276
+ or "toolchain:\n - universal" in frontmatter_section
277
+ ):
278
+ universal_agents.add(agent_file.stem)
279
+ except Exception as e:
280
+ logger.debug(
281
+ f"Failed to check universal marker for {agent_file.name}: {e}"
282
+ )
283
+ continue
284
+
285
+ return universal_agents
286
+
249
287
  def _list_deployed_agents(self, deploy_dir: Path) -> Set[str]:
250
288
  """List agent IDs currently deployed."""
251
289
  if not deploy_dir.exists():
@@ -1095,7 +1095,11 @@ class GitSkillSourceManager:
1095
1095
  if removed_skills:
1096
1096
  self.logger.info(
1097
1097
  f"Removed {len(removed_skills)} orphaned skills not referenced by agents: {removed_skills[:10]}"
1098
- + (f" (and {len(removed_skills) - 10} more)" if len(removed_skills) > 10 else "")
1098
+ + (
1099
+ f" (and {len(removed_skills) - 10} more)"
1100
+ if len(removed_skills) > 10
1101
+ else ""
1102
+ )
1099
1103
  )
1100
1104
 
1101
1105
  self.logger.info(
@@ -44,7 +44,6 @@ from typing import Any, Dict, List, Set, Tuple
44
44
  import yaml
45
45
 
46
46
  from claude_mpm.core.logging_config import get_logger
47
- from claude_mpm.services.skills.skill_to_agent_mapper import SkillToAgentMapper
48
47
 
49
48
  logger = get_logger(__name__)
50
49
 
@@ -60,26 +59,20 @@ CORE_SKILLS = {
60
59
  "universal-debugging-verification-before-completion",
61
60
  "universal-verification-pre-merge",
62
61
  "universal-verification-screenshot",
63
-
64
62
  # Universal testing patterns (2 skills)
65
63
  "universal-testing-test-driven-development",
66
64
  "universal-testing-testing-anti-patterns",
67
-
68
65
  # Universal architecture and design (1 skill)
69
66
  "universal-architecture-software-patterns",
70
-
71
67
  # Universal infrastructure (3 skills)
72
68
  "universal-infrastructure-env-manager",
73
69
  "universal-infrastructure-docker",
74
70
  "universal-infrastructure-github-actions",
75
-
76
71
  # Universal collaboration (1 skill)
77
72
  "universal-collaboration-stacked-prs",
78
-
79
73
  # Universal emergency/operations (1 skill)
80
74
  "toolchains-universal-emergency-release",
81
75
  "toolchains-universal-dependency-audit",
82
-
83
76
  # Common language toolchains (6 skills)
84
77
  "toolchains-typescript-core",
85
78
  "toolchains-python-core",
@@ -87,17 +80,14 @@ CORE_SKILLS = {
87
80
  "toolchains-python-tooling-mypy",
88
81
  "toolchains-typescript-testing-vitest",
89
82
  "toolchains-python-frameworks-flask",
90
-
91
83
  # Common web frameworks (4 skills)
92
84
  "toolchains-javascript-frameworks-nextjs",
93
85
  "toolchains-nextjs-core",
94
86
  "toolchains-typescript-frameworks-nodejs-backend",
95
87
  "toolchains-javascript-frameworks-react-state-machine",
96
-
97
88
  # Common testing tools (2 skills)
98
89
  "toolchains-javascript-testing-playwright",
99
90
  "toolchains-typescript-testing-jest",
100
-
101
91
  # Common data/UI tools (3 skills)
102
92
  "universal-data-xlsx",
103
93
  "toolchains-ui-styling-tailwind",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 5.4.75
3
+ Version: 5.4.82
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
2
- claude_mpm/VERSION,sha256=QoOyA6jrOQzU3ZyWxgg9_V2pQvTXI7aXIojmHZFOkTw,7
2
+ claude_mpm/VERSION,sha256=1GNPudton6MxkdoDRg8-2KdCRDrycUsY-IcEjRdvDFY,7
3
3
  claude_mpm/__init__.py,sha256=AGfh00BHKvLYD-UVFw7qbKtl7NMRIzRXOWw7vEuZ-h4,2214
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=pz3lTrZZR5HhV3eZzYtIbtBwWo7iM6pkBHP_ixxmI6Y,6827
@@ -41,7 +41,7 @@ claude_mpm/cli/chrome_devtools_installer.py,sha256=efA_ZX1iR3oaJi3222079BQw6DEG8
41
41
  claude_mpm/cli/executor.py,sha256=1MQdNPNoIewSR1q8nXjJuES3zKEi_IqVcZQzt9bsxw8,10601
42
42
  claude_mpm/cli/helpers.py,sha256=CypEhw0tbNH6_GzVTaQdi4w7ThCWO43Ep92YbJzPR4I,3638
43
43
  claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
44
- claude_mpm/cli/startup.py,sha256=EJcx1Fyta93Vj22_vmVCZZpegSs-FKLileVApn7AaEA,74370
44
+ claude_mpm/cli/startup.py,sha256=6sfkFbapu7X76hBPmKjxkUEMlo9DUjF4x7mhaVE7IJw,74374
45
45
  claude_mpm/cli/startup_display.py,sha256=R_QIamjfdaY5o_VxpIeymyYj1Qde2B9hPXy1P-KmUKI,14972
46
46
  claude_mpm/cli/startup_logging.py,sha256=RTuyd6CbhiFQz7Z07LDDhK_ZAnZfuJ9B0NghVSntHFI,29390
47
47
  claude_mpm/cli/utils.py,sha256=FSMPftBZM8MeUyTtiB63Lz7oFOgkzwTetQs58RbRb_Q,8785
@@ -60,7 +60,7 @@ claude_mpm/cli/commands/auto_configure.py,sha256=0Suzil6O0SBNeHUCwHOkt2q7gfuXRTy
60
60
  claude_mpm/cli/commands/cleanup.py,sha256=RQikOGLuLFWXzjeoHArdr5FA4Pf7tSK9w2NXL4vCrok,19769
61
61
  claude_mpm/cli/commands/cleanup_orphaned_agents.py,sha256=JR8crvgrz7Sa6d-SI-gKywok5S9rwc_DzDVk_h85sVs,4467
62
62
  claude_mpm/cli/commands/config.py,sha256=2M9VUPYcQkBUCIyyB-v1qTL3xYvao9YI2l_JGBUDauA,23374
63
- claude_mpm/cli/commands/configure.py,sha256=yav4ipRbZ5tc1tjBHkU8Pf6Ls4FtGirqZmN94H0WPic,127811
63
+ claude_mpm/cli/commands/configure.py,sha256=VUokhUcV90GzEEivV3xNmfQHogM94mdDadW3S4mp83M,136509
64
64
  claude_mpm/cli/commands/configure_agent_display.py,sha256=oSvUhR861o_Pyqmop4ACAQNjwL02-Rf6TMqFvmQNh24,10575
65
65
  claude_mpm/cli/commands/configure_behavior_manager.py,sha256=_tfpcKW0KgMGO52q6IHFXL3W5xwjC8-q2_KpIvHVuoI,6827
66
66
  claude_mpm/cli/commands/configure_hook_manager.py,sha256=1X5brU6cgKRRF-2lQYA0aiKD7ZjTClqNHUSWuayktEw,9205
@@ -177,7 +177,7 @@ claude_mpm/core/agent_session_manager.py,sha256=F10LS-nyTQxzMP3fkhbI94klsJy5xpSA
177
177
  claude_mpm/core/api_validator.py,sha256=zxeUykC2asy1KwHBDu5w3Eoo64E51PJyNe4PT7CTJf0,12282
178
178
  claude_mpm/core/base_service.py,sha256=4Zrt-vQ6g_KVk4hEfvd4QccuItYoOf7wUHCimIW6zJQ,29953
179
179
  claude_mpm/core/cache.py,sha256=orh8B40oYnRRGmXdANR4P4f-KVMIHV0vg7vrsemk0no,17232
180
- claude_mpm/core/claude_runner.py,sha256=a17NiQZtgEGrPX3-zeBMdnNkA1Mg7ePQaYmfCxu99VM,34249
180
+ claude_mpm/core/claude_runner.py,sha256=Wle-wI-ag25oC0EYX3n8dDC56I5GIdbpi5NtvT4IgBw,34263
181
181
  claude_mpm/core/config.py,sha256=RLjN1OSW5AadWju6kooEEbud8mntSkorapP1wzUrPGk,42491
182
182
  claude_mpm/core/config_aliases.py,sha256=QpNNECkTY4TYYAhVlFZvB-msPnZrui90g19u0-v0HDE,9703
183
183
  claude_mpm/core/config_constants.py,sha256=MEF35Y2Lj5FMzRdhgSgZrZeTzHfCzistPGZVY8INta4,10073
@@ -194,7 +194,7 @@ claude_mpm/core/hook_manager.py,sha256=FI5wfa1zczm_SJQXOtpL7BYKxVZD4BMXRbqCBZQkD
194
194
  claude_mpm/core/hook_performance_config.py,sha256=e7a7oFctkRhA3aPXMO5Wavr-E6ku7ikLxMzPU7P1-yg,5779
195
195
  claude_mpm/core/injectable_service.py,sha256=9N4mHt6a_PwoP0pQo-QhVTnXLJlgDCCOg358d0jPEs4,7384
196
196
  claude_mpm/core/instruction_reinforcement_hook.py,sha256=hSYvUp_ducWnhcKTkUbUoCLUb_yCzbIgsqEp7VpF9h0,9542
197
- claude_mpm/core/interactive_session.py,sha256=1o3sXJMnXUGiOy_cUJVkNT7zbDb7aUwbnptPEaGg_MQ,27851
197
+ claude_mpm/core/interactive_session.py,sha256=CW3_HNSMQ5pRi0mIh9_zBMncywARFV2AXLITBTaOxIU,27936
198
198
  claude_mpm/core/interfaces.py,sha256=sSipQa2tjf9EbRaKhxeCE31E-alS_iddvUfI0X_I0LQ,26909
199
199
  claude_mpm/core/lazy.py,sha256=pyCfEqGHyLz18yXTu_uG52-II-9nCaBcpzwwQGBrQro,14808
200
200
  claude_mpm/core/log_manager.py,sha256=yf82AKC-DYLtl7h0ka5IEoVC8aC0_II-zCjHOwD3RxQ,24661
@@ -206,7 +206,7 @@ claude_mpm/core/mixins.py,sha256=vmZ7Nu2ZOnKjbhN07Ixk4noIej9nsJiknrp-Sclfu0A,534
206
206
  claude_mpm/core/oneshot_session.py,sha256=nA86Zk7W3Rh_yIhPuegFL7Xgc9S63vQ_MqfLk52doV0,21994
207
207
  claude_mpm/core/optimized_agent_loader.py,sha256=yevEwTZWzVeZYEJhV3czD45OU7ukJIaJos4MGnFP7YQ,15857
208
208
  claude_mpm/core/optimized_startup.py,sha256=U5I4f7PNYXCBOLbCkbWT2V2sv01T8iWP2Bw-f928Q9M,17927
209
- claude_mpm/core/output_style_manager.py,sha256=5jKurbBlQQXSlXhugGC3pNGg09gZhOXnATb4dQ_I_Jk,17056
209
+ claude_mpm/core/output_style_manager.py,sha256=QkH62HRCH6FYxg2lop_3Xml3BLOieE12024vAjS6SyI,17091
210
210
  claude_mpm/core/pm_hook_interceptor.py,sha256=92C8TrpK-XVQD8BiXbqs8lSCX72PU0KZG5oAjhf8GOQ,11197
211
211
  claude_mpm/core/service_registry.py,sha256=QpmAMWCov8XXaxQwE7WiNbgv6u_CRjpKPB64kLYvZKk,11722
212
212
  claude_mpm/core/session_manager.py,sha256=iEDZWKBYHSu001nFX8vFvH33RvQOW0eIgomWhFM53sw,12078
@@ -216,8 +216,8 @@ claude_mpm/core/tool_access_control.py,sha256=dpdxxp_77SuxGM2C7SsHUZbtysJmHw1rLD
216
216
  claude_mpm/core/types.py,sha256=Sv62QhMYvfxbt7oIGoAhhN_jxonFTeLRf-BuhxZ4vYw,7719
217
217
  claude_mpm/core/typing_utils.py,sha256=qny3rA9mAeXqdLgUj9DZg642shw4LmLbkPqADN-765s,13314
218
218
  claude_mpm/core/unified_agent_registry.py,sha256=YbL-oWeHU85zdf1mF7tyMHBYKtFBupsMeH9BCdzD6ZI,34161
219
- claude_mpm/core/unified_config.py,sha256=wXlg-1pkCVsBqdeJVZLICHfvyBwMpgWtgv2BDtxGrG0,21265
220
- claude_mpm/core/unified_paths.py,sha256=Sb_9omp2P2O7p2LiUqOna-g5r6TOkrv2-5UNBVQP4nk,36052
219
+ claude_mpm/core/unified_config.py,sha256=DUC5PB9P9s_27xs6_87vc3t-rkrU6jITwOFu6W8At7o,21743
220
+ claude_mpm/core/unified_paths.py,sha256=F2NYAK6RNtn_xsZnVHVfP7MErzDh_O9hyaa3B4OyT9A,36690
221
221
  claude_mpm/core/framework/__init__.py,sha256=IJCp6-MQO8gW31uG8aMWHdNg54NgGvXb4GvOuwZF6Iw,736
222
222
  claude_mpm/core/framework/formatters/__init__.py,sha256=OKkLN2x21rcbg3d3feZLixIS-UjHPlxl768uGmQy7Qc,307
223
223
  claude_mpm/core/framework/formatters/capability_generator.py,sha256=mZpnuKiNhGtE7R39VftWiHaSCabnpUDnUbH3FKKTMUk,14649
@@ -338,36 +338,12 @@ claude_mpm/hooks/claude_hooks/installer.py,sha256=VbvVGMcrmCXQB3Pf9zOdjeGET2AFqb
338
338
  claude_mpm/hooks/claude_hooks/memory_integration.py,sha256=73w7A5-3s5i1oYdkbEgw7qhgalQvSuJjfx6OFqfaw64,9963
339
339
  claude_mpm/hooks/claude_hooks/response_tracking.py,sha256=bz_8csYxxUZ3k_SI6q9uvtE7wfH-T15v_jpP2nq45nk,16896
340
340
  claude_mpm/hooks/claude_hooks/tool_analysis.py,sha256=3_o2PP9D7wEMwLriCtIBOw0cj2fSZfepN7lI4P1meSQ,7862
341
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc,sha256=EGpgXqhPM0iRRZtCqHaLVQ6wDH42OH_M7Gt5GiFLyro,346
342
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc,sha256=RdPlaoNPDoSlTFV36Ku4vxs7xYqh7t2038D4pyULy-g,322
343
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc,sha256=SQX5iiP9bQZkLL-cj_2tlGH7lpAzarO0mYal7btj3tc,3521
344
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc,sha256=T9FMRyRjvHTRJm0LXosba7MezdUVw6I-nt_KP--LTwA,35923
345
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc,sha256=-ayyVTxDW5_BVD2TD14e4zDteH0l_mXIcyEG8AQCERg,32006
346
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc,sha256=AsvVXkge1Pio3jgnS-zNbPt9brySB8ZeVPSn7VvuKjs,29654
347
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc,sha256=heIj2o28Pw6QF5zgZBAebUInR8nxi6Ezdlfau9p-WJQ,27040
348
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc,sha256=9mpAKY4gNcbU5VvZ5tGbf2UM0uIEWdreKSUvVr_BKcM,33917
349
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc,sha256=YbwauQDKSGvXkT1972faalJLuxwyvq328DYQhkCnel0,10513
350
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc,sha256=K-FbzUxbOffBSol-RUZkyFr9k1Ktg0HRdykSKbAn0NI,9489
351
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc,sha256=0xWsBZ63F-akLopSiRi36-hmhh1v9R5aKFBM0z93Jd0,16730
352
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc,sha256=QZDMBrRbhD5lnm1sDcONSU5s5qsrcRme-vQOGUD5J3U,14632
353
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc,sha256=ZjcNfNY5Ht6FhalPeh7M7OzMffcey5iF4AVjDDg9kak,10694
354
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc,sha256=T98zonvVkllflFNw_pptXXAXbDrIgeBfY6aXvSY8el8,9071
355
341
  claude_mpm/hooks/claude_hooks/services/__init__.py,sha256=OIYOKsUNw1BHYawOCp-KFK5kmQKuj92cCqCEPO0nwo0,585
356
342
  claude_mpm/hooks/claude_hooks/services/connection_manager.py,sha256=l-aKzxwK-PWKL3TO1Iiu0sfSbj6Y9JMBOm3pgAiUYZc,9378
357
343
  claude_mpm/hooks/claude_hooks/services/connection_manager_http.py,sha256=n14k1byOBbviu0nFab3q0gb7p6eMqGO8hS0b7Gt2JRg,10262
358
344
  claude_mpm/hooks/claude_hooks/services/duplicate_detector.py,sha256=Fh9LmEMsVmQM9t0U1v2l_fuBwvNpVkl_0EF8Wu5KLHQ,3882
359
345
  claude_mpm/hooks/claude_hooks/services/state_manager.py,sha256=QB0JPJQThTVg0TGRO3Dc_3y3bac-hkulgMqqzo_71ng,11189
360
346
  claude_mpm/hooks/claude_hooks/services/subagent_processor.py,sha256=f7a_vgo_kuG9MalDTka2UPXwDyCkqNgCvG8i1hp0oRo,15263
361
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc,sha256=xBfLBSqnpcKfcQBWfh7xUm454g1lq1LvbO7SxGvcOPc,644
362
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc,sha256=75pkmoqE7CeBOc2ZHTYfgSR-mtVjKrcKaOA6PxFGW64,565
363
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc,sha256=bvZ_QcuI0j125Ebv8RzeWUh1BkuRTUfufGi0NV7HjuY,12359
364
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc,sha256=HEBjsWvdkCpV8X4UyDsKhm0HXpstuHnObck_Yr-QQBA,11177
365
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc,sha256=Yy_REAUhJCiFjOhxeDb4v0qyEvEbUtCmXD9PAz40dhw,5321
366
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc,sha256=ef_Tx9Uv1CvS18tC_PXmGVvIoMDsRnEUhKRUZaUdGBw,4751
367
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc,sha256=TPkEc-Zi3oNS5dCXBpGbSZwg_8RQvzNzd4pVx9B3WeM,12364
368
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc,sha256=uDZ1o2NYu0e2-sXxHovFOy28cklRaMOOX4vkLTRDjq0,11477
369
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc,sha256=YjWbj0qXMjew5bZCgvHWrb3dxp3BQZkpuOqsXgu4Wis,15045
370
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc,sha256=c2Y-gHruenFjPNTimrkiSUvXamZayjpMinAKIppzMoM,13611
371
347
  claude_mpm/hooks/failure_learning/__init__.py,sha256=iJ80AKFHiT8DjIH2a72DQVJvL6nAFrizNA2yTKwZ4rw,1805
372
348
  claude_mpm/hooks/failure_learning/failure_detection_hook.py,sha256=KENoB5N-dBm5hb0SxeIZtCvNKbmG2BKHOJSrSO-3Z_I,7500
373
349
  claude_mpm/hooks/failure_learning/fix_detection_hook.py,sha256=XUk1bnBVLdfhQ9AMQSvGsTSeFQsKsVud2wbWX-Jjor8,7164
@@ -461,7 +437,7 @@ claude_mpm/services/agents/deployment/agents_directory_resolver.py,sha256=8Bavjt
461
437
  claude_mpm/services/agents/deployment/async_agent_deployment.py,sha256=niPalcfjtl2Ko5k3f0nq-xbsuFLIC7cMI_cVpSt1axA,28549
462
438
  claude_mpm/services/agents/deployment/base_agent_locator.py,sha256=szw9N1Di6AJuuWGIZHRfgWij6wwMbag--6XzjFvmpiA,4751
463
439
  claude_mpm/services/agents/deployment/deployment_config_loader.py,sha256=xma4xWUp5QLQL0z4wSM9KTXmVR19CSw0iXAlaFyr6ow,6739
464
- claude_mpm/services/agents/deployment/deployment_reconciler.py,sha256=D87yeOfa1xnkrkfHxjK0saX5pK8ulPXmrnEYsIAgiMY,19144
440
+ claude_mpm/services/agents/deployment/deployment_reconciler.py,sha256=L3Z92beXFYzGjMZ3xwbOPvh-wcscfAh2oGtF3dhDoY8,20672
465
441
  claude_mpm/services/agents/deployment/deployment_results_manager.py,sha256=oNJ8DhmeXswD4_6qmLpDusI2edyJy2gd203ePxmJEy8,6609
466
442
  claude_mpm/services/agents/deployment/deployment_type_detector.py,sha256=8VavaJX1T-sWf5_XwVB4NZXh5WnHg-F7J8TzN_TwLnM,4201
467
443
  claude_mpm/services/agents/deployment/deployment_wrapper.py,sha256=RfmplaLjbxfWGJRT3i7eDtNsiC-S3n3lJDrDn8MQByI,4761
@@ -717,8 +693,8 @@ claude_mpm/services/shared/lifecycle_service_base.py,sha256=YJZHs2sUrnIsbHHjrd8l
717
693
  claude_mpm/services/shared/manager_base.py,sha256=kmjhpVqgfYC1N4YQnPAilCfdrSpAh9Qz7wcQ602L4x4,9296
718
694
  claude_mpm/services/shared/service_factory.py,sha256=9yvnD62urrNQCGmtk_3OcR5tVUCnoS6wHkaI5PK34mg,9891
719
695
  claude_mpm/services/skills/__init__.py,sha256=X1fPRCGZjteLd35HlhWv2M6tAJ_WbYrEv84kbaqBAiU,742
720
- claude_mpm/services/skills/git_skill_source_manager.py,sha256=H0MEug2lCix6RHqF4nVt3-Olfe9DM9bKlm_Bw9OJC4g,51529
721
- claude_mpm/services/skills/selective_skill_deployer.py,sha256=XfNmNn4U8LL6nIPbRhB7j_yMaFsR7tv9bGvx6BrobIU,25836
696
+ claude_mpm/services/skills/git_skill_source_manager.py,sha256=q8pKRLBza7Uh3vEpCXuQKdp1pF0b9P1CTUzUkL5VBJA,51623
697
+ claude_mpm/services/skills/selective_skill_deployer.py,sha256=l20QnElbYXHTNuZozDU_a8c_799RTbjesqrILZBDQcQ,25747
722
698
  claude_mpm/services/skills/skill_discovery_service.py,sha256=riy0PTnJS8e5R2ai8y1KPhBIR7SxlYIa9bnI9YccRMQ,20247
723
699
  claude_mpm/services/skills/skill_to_agent_mapper.py,sha256=4PRwcSDSNGS55lg4t-VmBK2ottE_cGFq1zsvjiumAlI,14847
724
700
  claude_mpm/services/socketio/__init__.py,sha256=PS-2twllga-2mhSfKdu4MgpikfKp_730gMLAqU_9YX4,556
@@ -993,10 +969,10 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
993
969
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
994
970
  claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
995
971
  claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
996
- claude_mpm-5.4.75.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
997
- claude_mpm-5.4.75.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
998
- claude_mpm-5.4.75.dist-info/METADATA,sha256=64ZleLArD4nY_HFCsrqzXn1K2RzAscpaNflWxTNRWOg,38503
999
- claude_mpm-5.4.75.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1000
- claude_mpm-5.4.75.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
1001
- claude_mpm-5.4.75.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
1002
- claude_mpm-5.4.75.dist-info/RECORD,,
972
+ claude_mpm-5.4.82.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
973
+ claude_mpm-5.4.82.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
974
+ claude_mpm-5.4.82.dist-info/METADATA,sha256=ofAd7jlgMNdr991W2fT3g8dkCYsHSYjn8azaLnwj7HI,38503
975
+ claude_mpm-5.4.82.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
976
+ claude_mpm-5.4.82.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
977
+ claude_mpm-5.4.82.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
978
+ claude_mpm-5.4.82.dist-info/RECORD,,