claude-mpm 5.6.5__py3-none-any.whl → 5.6.9__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 (39) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/cli/commands/skill_source.py +51 -2
  3. claude_mpm/cli/commands/skills.py +5 -3
  4. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  5. claude_mpm/cli/parsers/skills_parser.py +5 -0
  6. claude_mpm/commander/api/errors.py +21 -0
  7. claude_mpm/commander/api/routes/sessions.py +18 -5
  8. claude_mpm/config/skill_sources.py +16 -0
  9. claude_mpm/core/config.py +27 -19
  10. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
  11. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
  12. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
  13. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
  14. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  15. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
  16. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
  17. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
  18. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
  19. claude_mpm/hooks/claude_hooks/installer.py +41 -0
  20. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
  21. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
  22. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
  23. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
  24. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
  25. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
  26. claude_mpm/scripts/claude-hook-handler.sh +5 -5
  27. claude_mpm/services/agents/agent_selection_service.py +2 -2
  28. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  29. claude_mpm/services/skills/git_skill_source_manager.py +79 -8
  30. claude_mpm/services/skills/selective_skill_deployer.py +28 -0
  31. claude_mpm/services/skills/skill_discovery_service.py +17 -1
  32. claude_mpm/services/skills_deployer.py +31 -5
  33. {claude_mpm-5.6.5.dist-info → claude_mpm-5.6.9.dist-info}/METADATA +1 -1
  34. {claude_mpm-5.6.5.dist-info → claude_mpm-5.6.9.dist-info}/RECORD +39 -26
  35. {claude_mpm-5.6.5.dist-info → claude_mpm-5.6.9.dist-info}/WHEEL +0 -0
  36. {claude_mpm-5.6.5.dist-info → claude_mpm-5.6.9.dist-info}/entry_points.txt +0 -0
  37. {claude_mpm-5.6.5.dist-info → claude_mpm-5.6.9.dist-info}/licenses/LICENSE +0 -0
  38. {claude_mpm-5.6.5.dist-info → claude_mpm-5.6.9.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  39. {claude_mpm-5.6.5.dist-info → claude_mpm-5.6.9.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 5.6.5
1
+ 5.6.9
@@ -11,6 +11,7 @@ for better UX. Handles errors gracefully with actionable messages.
11
11
 
12
12
  import json
13
13
  import logging
14
+ import os
14
15
  import re
15
16
 
16
17
  from ...config.skill_sources import SkillSource, SkillSourceConfiguration
@@ -20,6 +21,33 @@ from ...services.skills.skill_discovery_service import SkillDiscoveryService
20
21
  logger = logging.getLogger(__name__)
21
22
 
22
23
 
24
+ def _get_github_token(source: SkillSource | None = None) -> str | None:
25
+ """Get GitHub token with source-specific override support.
26
+
27
+ Priority: source.token > GITHUB_TOKEN > GH_TOKEN
28
+
29
+ Args:
30
+ source: Optional SkillSource to check for per-source token
31
+
32
+ Returns:
33
+ GitHub token if found, None otherwise
34
+
35
+ Security Note:
36
+ Token is never logged or printed to avoid exposure.
37
+ """
38
+ # Priority 1: Per-source token (env var reference or direct)
39
+ if source and source.token:
40
+ if source.token.startswith("$"):
41
+ # Env var reference: $VAR_NAME -> os.environ.get("VAR_NAME")
42
+ env_var_name = source.token[1:]
43
+ return os.environ.get(env_var_name)
44
+ # Direct token (not recommended but supported)
45
+ return source.token
46
+
47
+ # Priority 2-3: Global environment variables
48
+ return os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
49
+
50
+
23
51
  def _test_skill_repository_access(source: SkillSource) -> dict:
24
52
  """Test if skill repository is accessible via GitHub API.
25
53
 
@@ -58,7 +86,13 @@ def _test_skill_repository_access(source: SkillSource) -> dict:
58
86
  # Test GitHub API access
59
87
  api_url = f"https://api.github.com/repos/{owner_repo}"
60
88
 
61
- response = requests.get(api_url, timeout=10)
89
+ # Build headers with authentication if token available
90
+ headers = {"Accept": "application/vnd.github+json"}
91
+ token = _get_github_token(source)
92
+ if token:
93
+ headers["Authorization"] = f"token {token}"
94
+
95
+ response = requests.get(api_url, headers=headers, timeout=10)
62
96
 
63
97
  if response.status_code == 200:
64
98
  return {"accessible": True, "error": None}
@@ -68,9 +102,14 @@ def _test_skill_repository_access(source: SkillSource) -> dict:
68
102
  "error": f"Repository not found: {owner_repo}",
69
103
  }
70
104
  if response.status_code == 403:
105
+ error_msg = "Access denied (private repository or rate limit)"
106
+ if not token:
107
+ error_msg += (
108
+ ". Try setting GITHUB_TOKEN environment variable for private repos"
109
+ )
71
110
  return {
72
111
  "accessible": False,
73
- "error": "Access denied (private repository or rate limit)",
112
+ "error": error_msg,
74
113
  }
75
114
  return {
76
115
  "accessible": False,
@@ -263,6 +302,15 @@ def handle_add_skill_source(args) -> int:
263
302
 
264
303
  # Create new source
265
304
  enabled = not args.disabled
305
+ token = getattr(args, "token", None)
306
+
307
+ # Security warning for direct tokens
308
+ if token and not token.startswith("$"):
309
+ print("⚠️ Warning: Direct token values in config are not recommended")
310
+ print(" Consider using environment variable reference instead:")
311
+ print(" --token $MY_PRIVATE_TOKEN")
312
+ print()
313
+
266
314
  source = SkillSource(
267
315
  id=source_id,
268
316
  type="git",
@@ -270,6 +318,7 @@ def handle_add_skill_source(args) -> int:
270
318
  branch=args.branch,
271
319
  priority=args.priority,
272
320
  enabled=enabled,
321
+ token=token,
273
322
  )
274
323
 
275
324
  # Determine if we should test
@@ -538,6 +538,7 @@ class SkillsManagementCommand(BaseCommand):
538
538
  toolchain = getattr(args, "toolchain", None)
539
539
  categories = getattr(args, "categories", None)
540
540
  force = getattr(args, "force", False)
541
+ deploy_all = getattr(args, "all", False)
541
542
 
542
543
  if collection:
543
544
  console.print(
@@ -548,14 +549,15 @@ class SkillsManagementCommand(BaseCommand):
548
549
  "\n[bold cyan]Deploying skills from default collection...[/bold cyan]\n"
549
550
  )
550
551
 
551
- # Selective deployment is ALWAYS enabled (deploy only agent-referenced skills)
552
- # This ensures only skills linked to deployed agents are deployed
552
+ # Use selective deployment unless --all flag is provided
553
+ # Selective mode deploys only agent-referenced skills
554
+ # --all mode deploys all available skills from the collection
553
555
  result = self.skills_deployer.deploy_skills(
554
556
  collection=collection,
555
557
  toolchain=toolchain,
556
558
  categories=categories,
557
559
  force=force,
558
- selective=True, # Always use selective deployment
560
+ selective=not deploy_all,
559
561
  )
560
562
 
561
563
  # Display results
@@ -76,6 +76,10 @@ def add_skill_source_subparser(subparsers) -> argparse.ArgumentParser:
76
76
  dest="skip_test",
77
77
  help="Skip immediate testing (not recommended)",
78
78
  )
79
+ add_parser.add_argument(
80
+ "--token",
81
+ help="GitHub token or env var reference (e.g., ghp_xxx or $PRIVATE_TOKEN)",
82
+ )
79
83
 
80
84
  # Remove repository
81
85
  remove_parser = skill_source_subparsers.add_parser(
@@ -167,6 +167,11 @@ def add_skills_subparser(subparsers) -> argparse.ArgumentParser:
167
167
  action="store_true",
168
168
  help="Force redeployment of already deployed skills",
169
169
  )
170
+ deploy_github_parser.add_argument(
171
+ "--all",
172
+ action="store_true",
173
+ help="Deploy all available skills, not just agent-referenced ones",
174
+ )
170
175
 
171
176
  # List available GitHub skills
172
177
  list_available_parser = skills_subparsers.add_parser(
@@ -110,3 +110,24 @@ class InvalidRuntimeError(CommanderAPIError):
110
110
  f"Invalid runtime: {runtime}",
111
111
  400,
112
112
  )
113
+
114
+
115
+ class TmuxNoSpaceError(CommanderAPIError):
116
+ """Raised when tmux has no space for a new pane."""
117
+
118
+ def __init__(self, message: str | None = None):
119
+ """Initialize tmux no space error.
120
+
121
+ Args:
122
+ message: Custom error message (optional)
123
+ """
124
+ default_msg = (
125
+ "Unable to create session: tmux has no space for new pane. "
126
+ "Try closing some sessions or resize your terminal window. "
127
+ "You can also create a new tmux window with `tmux new-window`."
128
+ )
129
+ super().__init__(
130
+ "TMUX_NO_SPACE",
131
+ message or default_msg,
132
+ 409,
133
+ )
@@ -5,13 +5,19 @@ This module implements REST endpoints for creating and managing tool sessions
5
5
  """
6
6
 
7
7
  import logging
8
+ import subprocess # nosec B404 - needed for tmux error handling
8
9
  import uuid
9
10
  from typing import List
10
11
 
11
12
  from fastapi import APIRouter, Response
12
13
 
13
14
  from ...models import ToolSession
14
- from ..errors import InvalidRuntimeError, ProjectNotFoundError, SessionNotFoundError
15
+ from ..errors import (
16
+ InvalidRuntimeError,
17
+ ProjectNotFoundError,
18
+ SessionNotFoundError,
19
+ TmuxNoSpaceError,
20
+ )
15
21
  from ..schemas import CreateSessionRequest, SessionResponse
16
22
 
17
23
  router = APIRouter()
@@ -112,6 +118,7 @@ async def create_session(project_id: str, req: CreateSessionRequest) -> SessionR
112
118
  Raises:
113
119
  ProjectNotFoundError: If project_id doesn't exist
114
120
  InvalidRuntimeError: If runtime is not supported
121
+ TmuxNoSpaceError: If tmux has no space for new pane
115
122
 
116
123
  Example:
117
124
  POST /api/projects/abc-123/sessions
@@ -144,10 +151,16 @@ async def create_session(project_id: str, req: CreateSessionRequest) -> SessionR
144
151
  session_id = str(uuid.uuid4())
145
152
 
146
153
  # Create tmux pane for session
147
- tmux_target = tmux_orch.create_pane(
148
- pane_id=f"{project.name}-{req.runtime}",
149
- working_dir=project.path,
150
- )
154
+ try:
155
+ tmux_target = tmux_orch.create_pane(
156
+ pane_id=f"{project.name}-{req.runtime}",
157
+ working_dir=project.path,
158
+ )
159
+ except subprocess.CalledProcessError as e:
160
+ stderr = e.stderr.decode() if e.stderr else ""
161
+ if "no space for new pane" in stderr.lower():
162
+ raise TmuxNoSpaceError() from None
163
+ raise # Re-raise other subprocess errors
151
164
 
152
165
  # Create session object
153
166
  session = ToolSession(
@@ -54,6 +54,7 @@ class SkillSource:
54
54
  branch: Git branch to use (default: "main")
55
55
  priority: Priority for skill resolution (lower = higher precedence)
56
56
  enabled: Whether this source should be synced
57
+ token: Optional GitHub token or env var reference (e.g., "$MY_TOKEN")
57
58
 
58
59
  Priority System:
59
60
  - 0: Reserved for system repository (highest precedence)
@@ -61,6 +62,12 @@ class SkillSource:
61
62
  - 100-999: Normal priority custom sources
62
63
  - 1000+: Low priority custom sources
63
64
 
65
+ Token Authentication:
66
+ - Direct token: "ghp_xxxxx" (stored in config, not recommended)
67
+ - Env var reference: "$PRIVATE_REPO_TOKEN" (resolved at runtime)
68
+ - If None, falls back to GITHUB_TOKEN or GH_TOKEN env vars
69
+ - Priority: source.token > GITHUB_TOKEN > GH_TOKEN
70
+
64
71
  Example:
65
72
  >>> source = SkillSource(
66
73
  ... id="system",
@@ -70,6 +77,12 @@ class SkillSource:
70
77
  ... )
71
78
  >>> source.validate()
72
79
  []
80
+ >>> private_source = SkillSource(
81
+ ... id="private",
82
+ ... type="git",
83
+ ... url="https://github.com/myorg/private-skills",
84
+ ... token="$PRIVATE_REPO_TOKEN"
85
+ ... )
73
86
  """
74
87
 
75
88
  id: str
@@ -78,6 +91,7 @@ class SkillSource:
78
91
  branch: str = "main"
79
92
  priority: int = 100
80
93
  enabled: bool = True
94
+ token: Optional[str] = None
81
95
 
82
96
  def __post_init__(self):
83
97
  """Validate skill source configuration after initialization.
@@ -262,6 +276,7 @@ class SkillSourceConfiguration:
262
276
  branch=source_data.get("branch", "main"),
263
277
  priority=source_data.get("priority", 100),
264
278
  enabled=source_data.get("enabled", True),
279
+ token=source_data.get("token"),
265
280
  )
266
281
  sources.append(source)
267
282
  except (KeyError, ValueError) as e:
@@ -326,6 +341,7 @@ class SkillSourceConfiguration:
326
341
  "branch": source.branch,
327
342
  "priority": source.priority,
328
343
  "enabled": source.enabled,
344
+ **({"token": source.token} if source.token else {}),
329
345
  }
330
346
  for source in sources
331
347
  ]
claude_mpm/core/config.py CHANGED
@@ -12,11 +12,10 @@ import threading
12
12
  from pathlib import Path
13
13
  from typing import Any, Dict, List, Optional, Tuple, Union
14
14
 
15
- import yaml
16
-
17
15
  from claude_mpm.core.logging_utils import get_logger
18
16
 
19
- from ..utils.config_manager import ConfigurationManager
17
+ # Lazy import ConfigurationManager to avoid importing yaml at module level
18
+ # This prevents hook errors when yaml isn't available in the execution environment
20
19
  from .exceptions import ConfigurationError, FileOperationError
21
20
  from .unified_paths import get_path_manager
22
21
 
@@ -104,6 +103,9 @@ class Config:
104
103
  Config._initialized = True
105
104
  logger.debug("Initializing Config singleton for the first time")
106
105
 
106
+ # Lazy import ConfigurationManager at runtime to avoid yaml import at module level
107
+ from ..utils.config_manager import ConfigurationManager
108
+
107
109
  # Initialize instance variables inside the lock to ensure thread safety
108
110
  self._config: Dict[str, Any] = {}
109
111
  self._env_prefix = env_prefix
@@ -224,21 +226,6 @@ class Config:
224
226
  f"Response logging format: {response_logging.get('format', 'json')}"
225
227
  )
226
228
 
227
- except yaml.YAMLError as e:
228
- logger.error(f"YAML syntax error in {file_path}: {e}")
229
- if hasattr(e, "problem_mark"):
230
- mark = e.problem_mark
231
- logger.error(f"Error at line {mark.line + 1}, column {mark.column + 1}")
232
- logger.info(
233
- "TIP: Validate your YAML at https://www.yamllint.com/ or run: python scripts/validate_configuration.py"
234
- )
235
- logger.info(
236
- "TIP: Common issue - YAML requires spaces, not tabs. Fix with: sed -i '' 's/\t/ /g' "
237
- + str(file_path)
238
- )
239
- # Store error for later retrieval
240
- self._config["_load_error"] = str(e)
241
-
242
229
  except json.JSONDecodeError as e:
243
230
  logger.error(f"JSON syntax error in {file_path}: {e}")
244
231
  logger.error(f"Error at line {e.lineno}, column {e.colno}")
@@ -255,7 +242,28 @@ class Config:
255
242
  },
256
243
  ) from e
257
244
  except Exception as e:
258
- # Catch any remaining unexpected errors and wrap them as configuration errors
245
+ # Handle YAML errors without importing yaml at module level
246
+ # ConfigurationManager.load_yaml raises yaml.YAMLError, but we don't want to import yaml
247
+ # Check if it's a YAML error by class name to avoid import
248
+ if e.__class__.__name__ == "YAMLError":
249
+ logger.error(f"YAML syntax error in {file_path}: {e}")
250
+ if hasattr(e, "problem_mark"):
251
+ mark = e.problem_mark
252
+ logger.error(
253
+ f"Error at line {mark.line + 1}, column {mark.column + 1}"
254
+ )
255
+ logger.info(
256
+ "TIP: Validate your YAML at https://www.yamllint.com/ or run: python scripts/validate_configuration.py"
257
+ )
258
+ logger.info(
259
+ "TIP: Common issue - YAML requires spaces, not tabs. Fix with: sed -i '' 's/\t/ /g' "
260
+ + str(file_path)
261
+ )
262
+ # Store error for later retrieval
263
+ self._config["_load_error"] = str(e)
264
+ return # Don't re-raise, we handled it
265
+
266
+ # Not a YAML error, wrap as configuration error
259
267
  raise ConfigurationError(
260
268
  f"Unexpected error loading configuration from {file_path}: {e}",
261
269
  context={
@@ -537,6 +537,44 @@ main "$@"
537
537
  except Exception as e:
538
538
  self.logger.warning(f"Could not clean up old settings file: {e}")
539
539
 
540
+ def _fix_status_line(self, settings: Dict) -> None:
541
+ """Fix statusLine command to handle both output style schema formats.
542
+
543
+ The statusLine command receives input in different formats:
544
+ - Newer format: {"activeOutputStyle": "Claude MPM", ...}
545
+ - Older format: {"output_style": {"name": "Claude MPM"}, ...}
546
+
547
+ This method ensures the jq expression checks both locations.
548
+
549
+ Args:
550
+ settings: The settings dictionary to update
551
+ """
552
+ if "statusLine" not in settings:
553
+ return
554
+
555
+ status_line = settings.get("statusLine", {})
556
+ if "command" not in status_line:
557
+ return
558
+
559
+ command = status_line["command"]
560
+
561
+ # Pattern to match: '.output_style.name // "default"'
562
+ # We need to update it to: '.output_style.name // .activeOutputStyle // "default"'
563
+ old_pattern = r'\.output_style\.name\s*//\s*"default"'
564
+ new_pattern = '.output_style.name // .activeOutputStyle // "default"'
565
+
566
+ # Check if the command needs updating
567
+ if re.search(old_pattern, command) and ".activeOutputStyle" not in command:
568
+ updated_command = re.sub(old_pattern, new_pattern, command)
569
+ settings["statusLine"]["command"] = updated_command
570
+ self.logger.info(
571
+ "Fixed statusLine command to handle both output style schemas"
572
+ )
573
+ else:
574
+ self.logger.debug(
575
+ "StatusLine command already supports both schemas or not present"
576
+ )
577
+
540
578
  def _update_claude_settings(self, hook_script_path: Path) -> None:
541
579
  """Update Claude settings to use the installed hook."""
542
580
  self.logger.info("Updating Claude settings...")
@@ -598,6 +636,9 @@ main "$@"
598
636
  }
599
637
  ]
600
638
 
639
+ # Fix statusLine command to handle both output style schemas
640
+ self._fix_status_line(settings)
641
+
601
642
  # Write settings to settings.json
602
643
  with self.settings_file.open("w") as f:
603
644
  json.dump(settings, f, indent=2)
@@ -125,7 +125,7 @@ find_python_command() {
125
125
  # 1. Check for UV project first (uv.lock or pyproject.toml with uv)
126
126
  if [ -f "$CLAUDE_MPM_ROOT/uv.lock" ]; then
127
127
  if command -v uv &> /dev/null; then
128
- echo "uv run python"
128
+ echo "uv run --directory \"$CLAUDE_MPM_ROOT\" python"
129
129
  return
130
130
  fi
131
131
  fi
@@ -219,8 +219,8 @@ log_debug() {
219
219
 
220
220
  # Test Python works and module exists
221
221
  # Handle UV's multi-word command specially
222
- if [[ "$PYTHON_CMD" == "uv run python" ]]; then
223
- if ! uv run python -c "import claude_mpm" 2>/dev/null; then
222
+ if [[ "$PYTHON_CMD" == "uv run"* ]]; then
223
+ if ! uv run --directory "$CLAUDE_MPM_ROOT" python -c "import claude_mpm" 2>/dev/null; then
224
224
  log_debug "claude_mpm module not available, continuing without hook"
225
225
  echo '{"action": "continue"}'
226
226
  exit 0
@@ -237,8 +237,8 @@ fi
237
237
  # Use exec to replace the shell process with Python
238
238
  # Handle UV's multi-word command specially
239
239
  # Suppress RuntimeWarning to prevent stderr output (which causes hook errors)
240
- if [[ "$PYTHON_CMD" == "uv run python" ]]; then
241
- exec uv run python -W ignore::RuntimeWarning -m claude_mpm.hooks.claude_hooks.hook_handler "$@" 2>/tmp/claude-mpm-hook-error.log
240
+ if [[ "$PYTHON_CMD" == "uv run"* ]]; then
241
+ exec uv run --directory "$CLAUDE_MPM_ROOT" python -W ignore::RuntimeWarning -m claude_mpm.hooks.claude_hooks.hook_handler "$@" 2>/tmp/claude-mpm-hook-error.log
242
242
  else
243
243
  exec "$PYTHON_CMD" -W ignore::RuntimeWarning -m claude_mpm.hooks.claude_hooks.hook_handler "$@" 2>/tmp/claude-mpm-hook-error.log
244
244
  fi
@@ -39,10 +39,10 @@ import logging
39
39
  from pathlib import Path
40
40
  from typing import Any, Dict, List, Optional, Set, Tuple
41
41
 
42
- from src.claude_mpm.services.agents.single_tier_deployment_service import (
42
+ from claude_mpm.services.agents.single_tier_deployment_service import (
43
43
  SingleTierDeploymentService,
44
44
  )
45
- from src.claude_mpm.services.agents.toolchain_detector import ToolchainDetector
45
+ from claude_mpm.services.agents.toolchain_detector import ToolchainDetector
46
46
 
47
47
  logger = logging.getLogger(__name__)
48
48
 
@@ -30,12 +30,12 @@ from datetime import datetime, timezone
30
30
  from pathlib import Path
31
31
  from typing import Any, Dict, List, Optional
32
32
 
33
- from src.claude_mpm.config.agent_sources import AgentSourceConfiguration
34
- from src.claude_mpm.models.git_repository import GitRepository
35
- from src.claude_mpm.services.agents.deployment.remote_agent_discovery_service import (
33
+ from claude_mpm.config.agent_sources import AgentSourceConfiguration
34
+ from claude_mpm.models.git_repository import GitRepository
35
+ from claude_mpm.services.agents.deployment.remote_agent_discovery_service import (
36
36
  RemoteAgentDiscoveryService,
37
37
  )
38
- from src.claude_mpm.services.agents.git_source_manager import GitSourceManager
38
+ from claude_mpm.services.agents.git_source_manager import GitSourceManager
39
39
 
40
40
  logger = logging.getLogger(__name__)
41
41
 
@@ -16,6 +16,7 @@ Trade-offs:
16
16
  - Flexibility: Easy to extend with skills-specific features
17
17
  """
18
18
 
19
+ import os
19
20
  from concurrent.futures import ThreadPoolExecutor, as_completed
20
21
  from datetime import datetime, timezone
21
22
  from pathlib import Path
@@ -32,6 +33,46 @@ from claude_mpm.services.skills.skill_discovery_service import SkillDiscoverySer
32
33
  logger = get_logger(__name__)
33
34
 
34
35
 
36
+ def _get_github_token(source: Optional[SkillSource] = None) -> Optional[str]:
37
+ """Get GitHub token with source-specific override support.
38
+
39
+ Priority: source.token > GITHUB_TOKEN > GH_TOKEN
40
+
41
+ Args:
42
+ source: Optional SkillSource to check for per-source token
43
+
44
+ Returns:
45
+ GitHub token if found, None otherwise
46
+
47
+ Token Resolution:
48
+ 1. If source has token starting with "$", resolve as env var
49
+ 2. If source has direct token, use it (not recommended for security)
50
+ 3. Fall back to GITHUB_TOKEN env var
51
+ 4. Fall back to GH_TOKEN env var
52
+ 5. Return None if no token found
53
+
54
+ Security Note:
55
+ Token is never logged or printed to avoid exposure.
56
+ Direct tokens in config are discouraged - use env var refs ($VAR_NAME).
57
+
58
+ Example:
59
+ >>> source = SkillSource(..., token="$PRIVATE_TOKEN")
60
+ >>> token = _get_github_token(source) # Resolves $PRIVATE_TOKEN from env
61
+ >>> token = _get_github_token() # Falls back to GITHUB_TOKEN
62
+ """
63
+ # Priority 1: Per-source token (env var reference or direct)
64
+ if source and source.token:
65
+ if source.token.startswith("$"):
66
+ # Env var reference: $VAR_NAME -> os.environ.get("VAR_NAME")
67
+ env_var_name = source.token[1:]
68
+ return os.environ.get(env_var_name)
69
+ # Direct token (not recommended but supported)
70
+ return source.token
71
+
72
+ # Priority 2-3: Global environment variables
73
+ return os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
74
+
75
+
35
76
  class GitSkillSourceManager:
36
77
  """Manages multiple Git-based skill sources with priority resolution.
37
78
 
@@ -217,9 +258,21 @@ class GitSkillSourceManager:
217
258
  )
218
259
 
219
260
  # Discover skills in cache
261
+ self.logger.debug(f"Scanning cache path for skills: {cache_path}")
220
262
  discovery_service = SkillDiscoveryService(cache_path)
221
263
  discovered_skills = discovery_service.discover_skills()
222
264
 
265
+ # Log discovery results
266
+ if len(discovered_skills) == 0:
267
+ self.logger.info(
268
+ f"No SKILL.md files found in {cache_path}. "
269
+ "Ensure your skill source has SKILL.md files with valid frontmatter."
270
+ )
271
+ else:
272
+ self.logger.debug(
273
+ f"Successfully parsed {len(discovered_skills)} skills from {cache_path}"
274
+ )
275
+
223
276
  # Build result
224
277
  result = {
225
278
  "synced": True,
@@ -469,7 +522,7 @@ class GitSkillSourceManager:
469
522
  # Step 1: Discover all files via GitHub Tree API (single request)
470
523
  # This discovers the COMPLETE repository structure (272 files for skills)
471
524
  all_files = self._discover_repository_files_via_tree_api(
472
- owner_repo, source.branch
525
+ owner_repo, source.branch, source
473
526
  )
474
527
 
475
528
  if not all_files:
@@ -504,7 +557,7 @@ class GitSkillSourceManager:
504
557
  raw_url = f"https://raw.githubusercontent.com/{owner_repo}/{source.branch}/{file_path}"
505
558
  cache_file = cache_path / file_path
506
559
  future = executor.submit(
507
- self._download_file_with_etag, raw_url, cache_file, force
560
+ self._download_file_with_etag, raw_url, cache_file, force, source
508
561
  )
509
562
  future_to_file[future] = file_path
510
563
 
@@ -533,7 +586,7 @@ class GitSkillSourceManager:
533
586
  return files_updated, files_cached
534
587
 
535
588
  def _discover_repository_files_via_tree_api(
536
- self, owner_repo: str, branch: str
589
+ self, owner_repo: str, branch: str, source: Optional[SkillSource] = None
537
590
  ) -> List[str]:
538
591
  """Discover all files in repository using GitHub Git Tree API.
539
592
 
@@ -596,9 +649,17 @@ class GitSkillSourceManager:
596
649
  )
597
650
  self.logger.debug(f"Fetching commit SHA from {refs_url}")
598
651
 
599
- refs_response = requests.get(
600
- refs_url, headers={"Accept": "application/vnd.github+json"}, timeout=30
601
- )
652
+ # Build headers with authentication if token available
653
+ headers = {"Accept": "application/vnd.github+json"}
654
+ token = _get_github_token(source)
655
+ if token:
656
+ headers["Authorization"] = f"token {token}"
657
+ if source and source.token:
658
+ self.logger.debug(f"Using source-specific token for {source.id}")
659
+ else:
660
+ self.logger.debug("Using GitHub token for authentication")
661
+
662
+ refs_response = requests.get(refs_url, headers=headers, timeout=30)
602
663
 
603
664
  # Check for rate limiting
604
665
  if refs_response.status_code == 403:
@@ -621,7 +682,7 @@ class GitSkillSourceManager:
621
682
  self.logger.debug(f"Fetching recursive tree from {tree_url}")
622
683
  tree_response = requests.get(
623
684
  tree_url,
624
- headers={"Accept": "application/vnd.github+json"},
685
+ headers=headers, # Reuse headers with auth from Step 1
625
686
  params=params,
626
687
  timeout=30,
627
688
  )
@@ -652,7 +713,11 @@ class GitSkillSourceManager:
652
713
  return all_files
653
714
 
654
715
  def _download_file_with_etag(
655
- self, url: str, local_path: Path, force: bool = False
716
+ self,
717
+ url: str,
718
+ local_path: Path,
719
+ force: bool = False,
720
+ source: Optional[SkillSource] = None,
656
721
  ) -> bool:
657
722
  """Download file from URL with ETag caching (thread-safe).
658
723
 
@@ -660,6 +725,7 @@ class GitSkillSourceManager:
660
725
  url: Raw GitHub URL
661
726
  local_path: Local file path to save to
662
727
  force: Force download even if cached
728
+ source: Optional SkillSource for token resolution
663
729
 
664
730
  Returns:
665
731
  True if file was updated, False if cached
@@ -692,6 +758,11 @@ class GitSkillSourceManager:
692
758
  if cached_etag and not force:
693
759
  headers["If-None-Match"] = cached_etag
694
760
 
761
+ # Add GitHub authentication if token available
762
+ token = _get_github_token(source)
763
+ if token:
764
+ headers["Authorization"] = f"token {token}"
765
+
695
766
  try:
696
767
  response = requests.get(url, headers=headers, timeout=30)
697
768
 
@@ -50,6 +50,22 @@ logger = get_logger(__name__)
50
50
  # Deployment tracking index file
51
51
  DEPLOYED_INDEX_FILE = ".mpm-deployed-skills.json"
52
52
 
53
+ # Core PM skills that should always be deployed
54
+ # These are referenced in PM_INSTRUCTIONS.md with [SKILL: name] markers
55
+ # Without these skills, PM only sees placeholders, not actual content
56
+ PM_CORE_SKILLS = {
57
+ "mpm-delegation-patterns",
58
+ "mpm-verification-protocols",
59
+ "mpm-tool-usage-guide",
60
+ "mpm-git-file-tracking",
61
+ "mpm-pr-workflow",
62
+ "mpm-ticketing-integration",
63
+ "mpm-teaching-mode",
64
+ "mpm-bug-reporting",
65
+ "mpm-circuit-breaker-enforcement",
66
+ "mpm-session-management",
67
+ }
68
+
53
69
  # Core skills that are universally useful across all projects
54
70
  # These are deployed when skill mapping returns too many skills (>60)
55
71
  # Target: ~25-30 core skills for balanced functionality
@@ -376,6 +392,18 @@ def get_required_skills_from_agents(agents_dir: Path) -> Set[str]:
376
392
  "(converted slashes to dashes)"
377
393
  )
378
394
 
395
+ # Always include PM core skills to ensure PM_INSTRUCTIONS.md markers are resolved
396
+ # These skills are referenced in PM_INSTRUCTIONS.md and must be deployed
397
+ # for PM to see actual content instead of [SKILL: name] placeholders
398
+ before_pm_skills = len(normalized_skills)
399
+ normalized_skills = normalized_skills | PM_CORE_SKILLS
400
+ pm_skills_added = len(normalized_skills) - before_pm_skills
401
+
402
+ if pm_skills_added > 0:
403
+ logger.info(
404
+ f"Added {pm_skills_added} PM core skills to ensure PM_INSTRUCTIONS.md markers resolve"
405
+ )
406
+
379
407
  return normalized_skills
380
408
 
381
409
 
@@ -188,6 +188,15 @@ class SkillDiscoveryService:
188
188
  f"and {len(legacy_md_files)} legacy .md files in {self.skills_dir}"
189
189
  )
190
190
 
191
+ # Log first few file paths for debugging
192
+ if all_skill_files:
193
+ sample_files = [
194
+ str(f.relative_to(self.skills_dir)) for f in all_skill_files[:5]
195
+ ]
196
+ self.logger.debug(f"Sample skill files: {sample_files}")
197
+ else:
198
+ self.logger.debug(f"No SKILL.md or .md files found in {self.skills_dir}")
199
+
191
200
  # Track deployment names to detect collisions
192
201
  deployment_names = {}
193
202
 
@@ -226,7 +235,14 @@ class SkillDiscoveryService:
226
235
  except Exception as e:
227
236
  self.logger.warning(f"Failed to parse skill {skill_file}: {e}")
228
237
 
229
- self.logger.info(f"Discovered {len(skills)} skills from {self.skills_dir.name}")
238
+ # Summary logging
239
+ parsed_count = len(skills)
240
+ failed_count = len(all_skill_files) - parsed_count
241
+ self.logger.info(
242
+ f"Discovered {parsed_count} skills from {self.skills_dir.name} "
243
+ f"({len(all_skill_files)} files found, {failed_count} failed to parse)"
244
+ )
245
+
230
246
  return skills
231
247
 
232
248
  def _parse_skill_file(self, skill_file: Path) -> Optional[Dict[str, Any]]:
@@ -28,7 +28,7 @@ References:
28
28
  import json
29
29
  import platform
30
30
  import shutil
31
- import subprocess
31
+ import subprocess # nosec B404 - subprocess needed for safe git operations
32
32
  from pathlib import Path
33
33
  from typing import Any, Dict, List, Optional
34
34
 
@@ -653,7 +653,7 @@ class SkillsDeployerService(LoggerMixin):
653
653
  f"Updating existing collection '{collection_name}' at {target_dir}"
654
654
  )
655
655
  try:
656
- result = subprocess.run(
656
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded git command
657
657
  ["git", "pull"],
658
658
  cwd=target_dir,
659
659
  capture_output=True,
@@ -684,7 +684,7 @@ class SkillsDeployerService(LoggerMixin):
684
684
  f"Installing new collection '{collection_name}' to {target_dir}"
685
685
  )
686
686
  try:
687
- result = subprocess.run(
687
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded git command
688
688
  ["git", "clone", repo_url, str(target_dir)],
689
689
  capture_output=True,
690
690
  text=True,
@@ -773,6 +773,32 @@ class SkillsDeployerService(LoggerMixin):
773
773
  if isinstance(skills_data, dict):
774
774
  flat_skills = []
775
775
 
776
+ # Define valid top-level categories
777
+ VALID_CATEGORIES = {"universal", "toolchains"}
778
+
779
+ # Check for unknown categories and warn user
780
+ unknown_categories = set(skills_data.keys()) - VALID_CATEGORIES
781
+ if unknown_categories:
782
+ # Count skills in unknown categories
783
+ skipped_count = 0
784
+ for cat in unknown_categories:
785
+ cat_data = skills_data.get(cat, [])
786
+ if isinstance(cat_data, list):
787
+ skipped_count += len(cat_data)
788
+ elif isinstance(cat_data, dict):
789
+ # If it's a dict like toolchains, count nested skills
790
+ for skills_list in cat_data.values():
791
+ if isinstance(skills_list, list):
792
+ skipped_count += len(skills_list)
793
+
794
+ self.logger.warning(
795
+ f"Unknown categories in manifest will be skipped: "
796
+ f"{', '.join(sorted(unknown_categories))} ({skipped_count} skills)"
797
+ )
798
+ self.logger.info(
799
+ f"Valid top-level categories: {', '.join(sorted(VALID_CATEGORIES))}"
800
+ )
801
+
776
802
  # Add universal skills
777
803
  universal_skills = skills_data.get("universal", [])
778
804
  if isinstance(universal_skills, list):
@@ -1022,12 +1048,12 @@ class SkillsDeployerService(LoggerMixin):
1022
1048
  """
1023
1049
  try:
1024
1050
  if platform.system() == "Windows":
1025
- result = subprocess.run(
1051
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded tasklist command
1026
1052
  ["tasklist"], check=False, capture_output=True, text=True, timeout=5
1027
1053
  )
1028
1054
  return "claude" in result.stdout.lower()
1029
1055
  # macOS and Linux
1030
- result = subprocess.run(
1056
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded ps command
1031
1057
  ["ps", "aux"], check=False, capture_output=True, text=True, timeout=5
1032
1058
  )
1033
1059
  # Look for "Claude Code" or "claude-code" process
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 5.6.5
3
+ Version: 5.6.9
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=Wwas5xnKQTkqXgApeVHQvWZFinNkdNv7W6HjYbrwERA,6
2
+ claude_mpm/VERSION,sha256=nJST2g_21xhxfQk5QgAosXHOMTc1xwppJdB3d85to-g,6
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
@@ -98,8 +98,8 @@ claude_mpm/cli/commands/postmortem.py,sha256=QkEymFR43IyN2dHBlaEHxsrDVrmhApLNJCp
98
98
  claude_mpm/cli/commands/profile.py,sha256=heXuBrrpIsu3JEsl7k-apUbxV0sVeDENF9Ct9aCJ5NM,10610
99
99
  claude_mpm/cli/commands/run.py,sha256=fWDwyJ6huzG0nyTkbwfxb8IL4UUWGG5HRl2TJWLnWPA,47973
100
100
  claude_mpm/cli/commands/search.py,sha256=alv6udvKcn-xkqeBlLuPRvfSDV1yxEX4n9mjjRT5uLM,16581
101
- claude_mpm/cli/commands/skill_source.py,sha256=UlEA7O3rGT14zmqifMclSXyDJvp7lDUBc1pbZ4qp_0k,22436
102
- claude_mpm/cli/commands/skills.py,sha256=Q6VIPNgGCIB_YGYR7_lna78OIJSnYFS-SEaX6NDCsHM,58232
101
+ claude_mpm/cli/commands/skill_source.py,sha256=qhP2gtr-cnnoVABv84y_XRqktfG5n52zcjLZ-zmZvWE,24227
102
+ claude_mpm/cli/commands/skills.py,sha256=pcsbqD2vkql9gyDr01mZmeXOUiFcgRd9UXWFUwMDs1E,58300
103
103
  claude_mpm/cli/commands/summarize.py,sha256=1eb6i3IEZ3DqLNBT_HRzEygQ3NPHvrLOTdvQI0pURso,12460
104
104
  claude_mpm/cli/commands/tickets.py,sha256=kl2dklTBnG3Y4jUUJ_PcEVsTx4CtVJfkGWboWBx_mQM,21234
105
105
  claude_mpm/cli/commands/uninstall.py,sha256=KGlVG6veEs1efLVjrZ3wSty7e1zVR9wpt-VXQA1RzWw,5945
@@ -138,8 +138,8 @@ claude_mpm/cli/parsers/mpm_init_parser.py,sha256=yIqsUeOtXsUTOD-pJCAEr3euSGxmN3w
138
138
  claude_mpm/cli/parsers/profile_parser.py,sha256=HlPRekiPeDxqRYSpXoR3NlbOtupXww0mCSrRohHedzs,4414
139
139
  claude_mpm/cli/parsers/run_parser.py,sha256=oUB5k3VmIxmsMUlOacfWJxesDw8h4ISf1WkikZLLyzQ,5249
140
140
  claude_mpm/cli/parsers/search_parser.py,sha256=L8-65kndg-zutSKpzj-eCvTNkeySCZ-WlSHdhk7pEak,6916
141
- claude_mpm/cli/parsers/skill_source_parser.py,sha256=D1fMXfL-BDbuLOlznJ8zmwNuo9ixj_rERz6npLwla0Q,4874
142
- claude_mpm/cli/parsers/skills_parser.py,sha256=FGKuDzZkoOyW4vRsUYjd5B-Vqlm6LLrDP0BtDW9jRKM,8741
141
+ claude_mpm/cli/parsers/skill_source_parser.py,sha256=82-ysrXTHJcJI_nOD5FdAUAMU5WeqXLU3Euia8_oojU,5012
142
+ claude_mpm/cli/parsers/skills_parser.py,sha256=rtpmBm-wMZiwvSluV_K3Efz7BVjwTl3ZpJM4J8Du53U,8908
143
143
  claude_mpm/cli/parsers/source_parser.py,sha256=NUYpN6hh-yvL1IQ7or4Y8fs8kDX5Sw7E_rMLVjwwkpo,4023
144
144
  claude_mpm/cli/parsers/tickets_parser.py,sha256=FYl-VNH7PrZzfZUCcjnf6F7g6JXnL8YDxwrmR5svIcg,6966
145
145
  claude_mpm/cli/shared/__init__.py,sha256=c3Ff46Az3U-YpYgcjOowMcNUkSzDngflAJotv6Bs8TE,1019
@@ -165,14 +165,14 @@ claude_mpm/commander/adapters/claude_code.py,sha256=YGWZN9Y3QUdYC0mHQ-D5su7PDT6b
165
165
  claude_mpm/commander/adapters/communication.py,sha256=Gs_vmQ630a_CQLS1x0B0lgcQCOfW82_VZeqto3a9ZYQ,11707
166
166
  claude_mpm/commander/api/__init__.py,sha256=I73MajIx-r6iIEYVJ4eHo-InMwfKOruN78VXF_eMEIk,376
167
167
  claude_mpm/commander/api/app.py,sha256=r7swU1wF0frST6zOObcBjq9VM45VfDHT4aNldAjEPKc,3129
168
- claude_mpm/commander/api/errors.py,sha256=s_CJp9sryKViSEPBCrEwTSgX1NlndBe_ozbrTqOqEHk,2939
168
+ claude_mpm/commander/api/errors.py,sha256=cBwHbC-rt543ZmE1DNLFv5XBqeUD58z7f4fGJF1x5uA,3590
169
169
  claude_mpm/commander/api/schemas.py,sha256=VmoBRP4NUIIvkH0Do3af3nxXS3Q97sYCJpJurv20tXU,4933
170
170
  claude_mpm/commander/api/routes/__init__.py,sha256=xI13W9tT4zYGaCotLMw4rKpGDhjkvi1YqNRoLh-8E5I,229
171
171
  claude_mpm/commander/api/routes/events.py,sha256=XxSEpRdcty9cSrkRMjEMALktqZfcGGx5n-rHexGFZSs,4879
172
172
  claude_mpm/commander/api/routes/inbox.py,sha256=edwse_fHITO_jICd3kOTGFim41tx2GbB0MN55Mg036M,5276
173
173
  claude_mpm/commander/api/routes/messages.py,sha256=-jhR8jYd_CwhVW0WeM4un9WLzSMueLAhMrDrg080E5A,3916
174
174
  claude_mpm/commander/api/routes/projects.py,sha256=rN27P4D45Qzp0kE49PCM1bonLI4ZS65-q-u-3HprRto,7226
175
- claude_mpm/commander/api/routes/sessions.py,sha256=ONvsHNoJA2cplXh75MUQSL_VF-pRf0s0PkUy9016StY,5833
175
+ claude_mpm/commander/api/routes/sessions.py,sha256=LWlehH534YVoPl_4Cfhxa_GePRbRnYQ49hXf3e70x0s,6275
176
176
  claude_mpm/commander/api/routes/work.py,sha256=BKx9fd7iqvgxYUDm1stui7TGev6dfhuvP3X-_8pC2-U,7257
177
177
  claude_mpm/commander/chat/__init__.py,sha256=5Iiya2YPkF54OvtZgL4NNT0zp5PCsZnnE7D6l19aYnA,243
178
178
  claude_mpm/commander/chat/cli.py,sha256=mHWEXjDll7OFIi2frTwfMs0wnJ71aFkFHX3vJr_iEGM,3151
@@ -245,7 +245,7 @@ claude_mpm/config/experimental_features.py,sha256=cH95HqMUEQL-_Hs833dAAC33GHMUE5
245
245
  claude_mpm/config/model_config.py,sha256=34JnIb_U19UYns3yLX-jjpuNywDnVZhiUSvvDzGzx0g,12410
246
246
  claude_mpm/config/paths.py,sha256=wTZxXt6LjD-gK9lG4i2QSuSnFRXe5lFaVU4dIr22ap8,7643
247
247
  claude_mpm/config/skill_presets.py,sha256=CReZz9CAGQnXdfSBIa0fN5S1vM5dDxh-9S-tG0WiY5M,13919
248
- claude_mpm/config/skill_sources.py,sha256=z9JIUfoE9zipAy2OSaLbjD0sk-Du8rSO--BbolhtXaM,19746
248
+ claude_mpm/config/skill_sources.py,sha256=apZDFdSlUFsewhDQWIjC_zwSMkmG2SGdf1go7pb55eo,20504
249
249
  claude_mpm/config/socketio_config.py,sha256=Z8O438z2taOPX2Eh_so-WOvvv-IHiM_WFbf4UBQ4iqg,11342
250
250
  claude_mpm/core/__init__.py,sha256=2bufzjbIXffZnSg5k-JH9czMDTkmtz-Jb9opgHmQY-0,2598
251
251
  claude_mpm/core/agent_name_normalizer.py,sha256=ZvdQsToFqxLWEPbf8gU1Hl8h3M47DBPmZ8zSAkEp-fc,8939
@@ -255,7 +255,7 @@ claude_mpm/core/api_validator.py,sha256=zxeUykC2asy1KwHBDu5w3Eoo64E51PJyNe4PT7CT
255
255
  claude_mpm/core/base_service.py,sha256=4Zrt-vQ6g_KVk4hEfvd4QccuItYoOf7wUHCimIW6zJQ,29953
256
256
  claude_mpm/core/cache.py,sha256=orh8B40oYnRRGmXdANR4P4f-KVMIHV0vg7vrsemk0no,17232
257
257
  claude_mpm/core/claude_runner.py,sha256=Wle-wI-ag25oC0EYX3n8dDC56I5GIdbpi5NtvT4IgBw,34263
258
- claude_mpm/core/config.py,sha256=IGhNAkq8qtoIcayrIqGH0GY64S_J4nzQ1xN4p4LDpNw,42748
258
+ claude_mpm/core/config.py,sha256=0R1ZLdwxTM2N3-uIBgcbr37jDiEe-G7h7x4YmYIVit0,43385
259
259
  claude_mpm/core/config_aliases.py,sha256=QpNNECkTY4TYYAhVlFZvB-msPnZrui90g19u0-v0HDE,9703
260
260
  claude_mpm/core/config_constants.py,sha256=MEF35Y2Lj5FMzRdhgSgZrZeTzHfCzistPGZVY8INta4,10073
261
261
  claude_mpm/core/constants.py,sha256=tm6IkmDxnsEqdEImtdQOeWvvGEHrThWCgAz5FMjckCQ,11557
@@ -414,25 +414,33 @@ claude_mpm/hooks/claude_hooks/correlation_manager.py,sha256=3n-RxzqE8egG4max_Ncp
414
414
  claude_mpm/hooks/claude_hooks/event_handlers.py,sha256=u7qkfthzAJxE5X4vAp5dCYhVDsadfC--vsqZVlmcrvE,45768
415
415
  claude_mpm/hooks/claude_hooks/hook_handler.py,sha256=UOl5IVvz0Ro8Z0Owx4sKUWCxoIhvQpt7VTJ8lRC7Y8o,28266
416
416
  claude_mpm/hooks/claude_hooks/hook_wrapper.sh,sha256=XYkdYtcM0nfnwYvMdyIFCasr80ry3uI5-fLYsLtDGw4,2214
417
- claude_mpm/hooks/claude_hooks/installer.py,sha256=X6m0CQ9mjaESqUu9RF00uOopZx1u5VOeR0-ilyaP6Xg,33275
417
+ claude_mpm/hooks/claude_hooks/installer.py,sha256=GgXqRjm_LpukrMl-eLw3cVDJqwwemNAaEKZvKM0QDYQ,34919
418
418
  claude_mpm/hooks/claude_hooks/memory_integration.py,sha256=fj_d9N7aytLELomdphLLwYApXzmbhBxtwSK4xkmd55o,10759
419
419
  claude_mpm/hooks/claude_hooks/response_tracking.py,sha256=2dyDOK9u-N4KcqWF7qq2T17bkps0grbs8MeWBRSC8vE,16323
420
420
  claude_mpm/hooks/claude_hooks/tool_analysis.py,sha256=3_o2PP9D7wEMwLriCtIBOw0cj2fSZfepN7lI4P1meSQ,7862
421
421
  claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc,sha256=EGpgXqhPM0iRRZtCqHaLVQ6wDH42OH_M7Gt5GiFLyro,346
422
+ claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc,sha256=RdPlaoNPDoSlTFV36Ku4vxs7xYqh7t2038D4pyULy-g,322
422
423
  claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc,sha256=tBzcQ_3WxkmgPTQAPd7uKgFGtz-Yb6r2hEgF9Y_Flwc,319
423
424
  claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc,sha256=7YbusOM2EaL4NqIuNsLTJRCRJWRxo0DhVLXm9ZVFc7Y,20829
425
+ claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc,sha256=aUV7xCwxrzM4iW4Jf0RbUskIs2whf7lXt6HppAEMp1g,18982
424
426
  claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc,sha256=vo_mPXj0KTtBz2_SAU4NZ7TEWPfgBZtLeXD3CMAvJ3M,21381
425
427
  claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc,sha256=SQX5iiP9bQZkLL-cj_2tlGH7lpAzarO0mYal7btj3tc,3521
426
428
  claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc,sha256=43y-O3fzE07cyJx1we9DfLeaIkL0GQR4KKpnzh_94uk,44526
429
+ claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc,sha256=3ezkq2yC1cejVa-II4cl335SWCJhD8dv_NEDtVsCpUo,39235
427
430
  claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc,sha256=DC4owkvPyhcCT7ScUxlKS6pUygaUYEMj0k3eVYZHdMk,42528
428
431
  claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc,sha256=vhJjvAMTdDWkB_qWaWr_PeDb4I8-h7UymR1wDVHeyYM,30789
432
+ claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc,sha256=bj168CD_Md4vpYJfS9YvPafP7-nw1hAUnuuEpzSQNKY,27815
429
433
  claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc,sha256=RVz6WvW-sD7kLbh6S5a96WarpPvZv4_qfFMR5SN8WUo,30603
430
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc,sha256=hxxLzkAFGV4sBK3NiYZ6zVlc1Cq9yTc8YPzp-mf5sxo,37219
434
+ claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc,sha256=Tt3L5Ye7RJCLvIAaz6uLwKe3WGEaMLx6WElvqK60G0Q,38428
435
+ claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc,sha256=Mlynkrh8uwlSOTCEH0LYbDM0gxqJmaCL9Gb5DIt_rJ4,38836
431
436
  claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc,sha256=Xu_hwOf9AG0mZthl5gcDcVv68FiSo5KgZ6lDxdZXCfU,11185
437
+ claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc,sha256=w9SKmvg60p6kvNzuOIddYE-X9LYt-ZQzX3LWiKs4nZY,10055
432
438
  claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc,sha256=oJhMGouqaFI1u3NZryHoRh6ucfPKHPe8GufcsPzi89o,11081
433
439
  claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc,sha256=qJ5xY8yYwo8ZO7P-Gem_GK4VZdqyNeYvs8ANvC45jnw,16228
440
+ claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc,sha256=uyjnluDUFQql1N2oYP6IYP8dxhxnHoSvrmUubEMRNXI,14000
434
441
  claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc,sha256=yu70SIPNsdECY8l_P971JPFuUPXqD4HmjuuGMU-nSAU,15820
435
442
  claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc,sha256=ZjcNfNY5Ht6FhalPeh7M7OzMffcey5iF4AVjDDg9kak,10694
443
+ claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc,sha256=T98zonvVkllflFNw_pptXXAXbDrIgeBfY6aXvSY8el8,9071
436
444
  claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc,sha256=ck8ifVIoVPaMVVRcMgvsM8RfIHnQbwGBUVs25A-yQBw,10771
437
445
  claude_mpm/hooks/claude_hooks/services/__init__.py,sha256=OIYOKsUNw1BHYawOCp-KFK5kmQKuj92cCqCEPO0nwo0,585
438
446
  claude_mpm/hooks/claude_hooks/services/connection_manager.py,sha256=shpoCLJpM9qoCDMUuUhk6L9WEKdzLB_OsPtwtDyJMdk,10197
@@ -441,14 +449,19 @@ claude_mpm/hooks/claude_hooks/services/duplicate_detector.py,sha256=Fh9LmEMsVmQM
441
449
  claude_mpm/hooks/claude_hooks/services/state_manager.py,sha256=PcEpAzwEnZRjw6JnbtbekDRdhIoaKql5VhhZJCEPNt4,10899
442
450
  claude_mpm/hooks/claude_hooks/services/subagent_processor.py,sha256=unHGeU6PJxc00_3xnLyyZHeLa47x98knxn6cl-i8ALA,15040
443
451
  claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc,sha256=xBfLBSqnpcKfcQBWfh7xUm454g1lq1LvbO7SxGvcOPc,644
452
+ claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc,sha256=75pkmoqE7CeBOc2ZHTYfgSR-mtVjKrcKaOA6PxFGW64,565
444
453
  claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc,sha256=nZDxNz67tIFwbZNRqyCRX8cSi0v3JKCZS5U5FhwwApA,562
445
454
  claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc,sha256=SydGEQ9oUWs161Ro4ULHfnPB0wiZgiB7V628B3V6N2U,9613
455
+ claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc,sha256=qdBU-mDyJxcwjwxfGhqzvo_s7YMO4mva-8hdObDAOcY,8616
446
456
  claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc,sha256=PjdPDUyUQWm0FqYRdG2knPoZDSKS0g1vk-BDAXfzCi8,9627
447
457
  claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc,sha256=Yy_REAUhJCiFjOhxeDb4v0qyEvEbUtCmXD9PAz40dhw,5321
458
+ claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc,sha256=ef_Tx9Uv1CvS18tC_PXmGVvIoMDsRnEUhKRUZaUdGBw,4751
448
459
  claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc,sha256=Xy9iNAtQMfXC_eW9rvumG9rFqK5t-QlLPmUahlqza_I,5341
449
460
  claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc,sha256=P-Au2P5H0enEeKm7sP1eQv-SU6AAnCqjjOE5jhXcrgs,12352
450
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc,sha256=-H3-oDao1c8Dy1reMR98kR1W556eNpPmRWOvKGszKz4,13101
461
+ claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc,sha256=g_Lo7LUYOEgIqS_Rz-6hy_caraHW9nzVJ6f0W4Y14rg,11378
462
+ claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc,sha256=2QqT8edjLqG8-9q446zpLJ347lzkgvJxPJG-A8u_HAU,13101
451
463
  claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc,sha256=4SfbElFMcQK07Frewl9mQ0eB5yCqZUe-CGfGYNUUMh0,14931
464
+ claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc,sha256=Cky-0tvyWmn9I44WdupIdJ4Qml0k-qlCs5E0x0Y130Q,13301
452
465
  claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc,sha256=o6Dc1-yyZjUdVh_JWZmEIvVt0qG0R1-aLhr7XTt-oX0,15104
453
466
  claude_mpm/hooks/failure_learning/__init__.py,sha256=iJ80AKFHiT8DjIH2a72DQVJvL6nAFrizNA2yTKwZ4rw,1805
454
467
  claude_mpm/hooks/failure_learning/failure_detection_hook.py,sha256=KENoB5N-dBm5hb0SxeIZtCvNKbmG2BKHOJSrSO-3Z_I,7500
@@ -463,7 +476,7 @@ claude_mpm/models/git_repository.py,sha256=Lp2I5tv4fu6idIXCTW50MCTWgjuIE-rwsgVIr
463
476
  claude_mpm/models/resume_log.py,sha256=aDiFC_2FR7tue_Kn46ZDUiKmuw9a_W9yE9zE7gA6Hys,12515
464
477
  claude_mpm/schemas/__init__.py,sha256=2SLpkojJq34KnwPkVxrsVmw_cEI66872i75QBT1C2To,446
465
478
  claude_mpm/scripts/__init__.py,sha256=IffMdVD99Pxyw85yluRa0VDPi4dRQecIWce764pcfZE,553
466
- claude_mpm/scripts/claude-hook-handler.sh,sha256=B5DbrOcHNX4xUC5kqftsLaGLQXs64WxVjDue7yMAwsU,10824
479
+ claude_mpm/scripts/claude-hook-handler.sh,sha256=1e5ZsZJQdp9lKLwEmmAtqnEGZPf5UIAG2ReGfwmXtOE,10907
467
480
  claude_mpm/scripts/launch_monitor.py,sha256=M0CSAYJp5UnoyXKnICZgrAFwqqP5XAWDCiii_IIcrCk,5348
468
481
  claude_mpm/scripts/mpm_doctor.py,sha256=98vBiTIB4xpaSgOvTP9N3EU22V2Odxd9DivhQizG0VM,8822
469
482
  claude_mpm/scripts/socketio_daemon.py,sha256=wWFcvKkHa_oR-NQwhvV-O8s3m1TgicBp9UQ-NR8AQmU,6041
@@ -497,7 +510,7 @@ claude_mpm/services/self_upgrade_service.py,sha256=O5-uqjdt9BHt0bxLNzuYdzlwgtWF_
497
510
  claude_mpm/services/session_management_service.py,sha256=za_ljDawCJjOq5ezEdxw71MFFFFIbWlV6ujlWL3vImg,10723
498
511
  claude_mpm/services/session_manager.py,sha256=ddVdINaHzBol24KvFCLOyM5SuBG_-Vd8_iT2YTBlGiU,12328
499
512
  claude_mpm/services/skills_config.py,sha256=R9F3BV3BEVmjqlxBy2mZycH4cCH4Ieh3K1n_8w9a5zQ,18005
500
- claude_mpm/services/skills_deployer.py,sha256=TecmqbRPvC7-gZewAwcp8Mjjna_nr6eUFdadwHZMv00,45761
513
+ claude_mpm/services/skills_deployer.py,sha256=iNT939b6akNEe0libu00fyYSceSKh4YYeu7ehb3v5F0,47270
501
514
  claude_mpm/services/socketio_client_manager.py,sha256=cZjIsnoi2VPXFA-5pNhoz5Vv3qv0iuSTy510TgAJU4U,18179
502
515
  claude_mpm/services/socketio_server.py,sha256=yE14_4pHERXBC5L1WQCpIBHuy0tpklsUY_icyl-nLkg,3033
503
516
  claude_mpm/services/subprocess_launcher_service.py,sha256=lYSlg2G_oDAv1dHrOdHaOEIppDwisANCASuNFdp0WqY,11226
@@ -510,7 +523,7 @@ claude_mpm/services/agents/agent_builder.py,sha256=ehnzIgQ3OcF5ThqvbmS4c4ZyA-hbp
510
523
  claude_mpm/services/agents/agent_preset_service.py,sha256=YpIKwaq52Pi4ox6ha3L9qTT4GHc-1nPeGgV0MWGRIAs,8588
511
524
  claude_mpm/services/agents/agent_recommendation_service.py,sha256=f3F6LkPG1S42ZE52o8QnSdFwZFsv_7vgegJ6bCNbWWk,9846
512
525
  claude_mpm/services/agents/agent_review_service.py,sha256=1meV6u8FGbYMx1vhSsCX8OembWbF3gXfl26hRdGd95Y,10001
513
- claude_mpm/services/agents/agent_selection_service.py,sha256=ItCXMuFv3XzBuZAVUvx74gMeRbXTCOBFh5vLlgurJKg,17951
526
+ claude_mpm/services/agents/agent_selection_service.py,sha256=rhbLrwuNsofH-U6sfJIn7Zp0Ek3YDmznNEIQUlJe1tM,17943
514
527
  claude_mpm/services/agents/auto_config_manager.py,sha256=WdrOaosxmK1iD-1Me7eZ-VJzMW-p8liei6iEjGkbodA,30706
515
528
  claude_mpm/services/agents/auto_deploy_index_parser.py,sha256=-29NBjr6u8QEcFYfygt2CqqGtS1XEN6NoJtsM6cDUAU,19465
516
529
  claude_mpm/services/agents/cache_git_manager.py,sha256=gfrcAZULY-oZDBuf20ubUE1STYLBu4c-UIjIu5cYsCA,23583
@@ -518,7 +531,7 @@ claude_mpm/services/agents/git_source_manager.py,sha256=SRGX4T-dUuLn2PDe1EkTL493
518
531
  claude_mpm/services/agents/local_template_manager.py,sha256=v1vlukIVEpiw5u11KseJhEMkhi1tlm6FTp0FYwK9YFU,27980
519
532
  claude_mpm/services/agents/observers.py,sha256=2OUEMc2TzHrME2AHHnBmquWmbhGEMTNpTc08sIoHno0,18484
520
533
  claude_mpm/services/agents/recommender.py,sha256=TC8iLNi_uP0byj8w9jXHhl0PYn0JDfAgRMjbTgSwafE,23756
521
- claude_mpm/services/agents/single_tier_deployment_service.py,sha256=PDkTJmtBdNMzvdlONzUgQ53ymAFTqOsL06vg4NuqpnQ,25396
534
+ claude_mpm/services/agents/single_tier_deployment_service.py,sha256=M1ep-yTcwk8OLhnkg5p2vNsqynpP49rRAxPxvpsG7ac,25380
522
535
  claude_mpm/services/agents/startup_sync.py,sha256=VoTSFtYF-BZZSCzoeAF6LpQ-tq3BjE4Ua-N9sdRikak,9310
523
536
  claude_mpm/services/agents/toolchain_detector.py,sha256=eGzMprsD1M7DXHGN0RhhUz3diITbiXtHZw0uK7rZ6Nk,16854
524
537
  claude_mpm/services/agents/deployment/__init__.py,sha256=iprW-Ww3LBtWu9pVFjAX45_CswfSqnPMoG0QoFPd1Dg,539
@@ -803,9 +816,9 @@ claude_mpm/services/shared/lifecycle_service_base.py,sha256=YJZHs2sUrnIsbHHjrd8l
803
816
  claude_mpm/services/shared/manager_base.py,sha256=kmjhpVqgfYC1N4YQnPAilCfdrSpAh9Qz7wcQ602L4x4,9296
804
817
  claude_mpm/services/shared/service_factory.py,sha256=9yvnD62urrNQCGmtk_3OcR5tVUCnoS6wHkaI5PK34mg,9891
805
818
  claude_mpm/services/skills/__init__.py,sha256=X1fPRCGZjteLd35HlhWv2M6tAJ_WbYrEv84kbaqBAiU,742
806
- claude_mpm/services/skills/git_skill_source_manager.py,sha256=DQ-Zw7O9_a9YWdRT3Os4Jzq2m7ihw2pyUMqOiNHE374,53990
807
- claude_mpm/services/skills/selective_skill_deployer.py,sha256=yUiciVynJ3WDTO-l7Oz6_y9NaqeQS4xwNVp3KXDOtgA,29565
808
- claude_mpm/services/skills/skill_discovery_service.py,sha256=guul1xME46hzHqTRIJeTDIKQz55AQlOX1CRALWvfnoI,22403
819
+ claude_mpm/services/skills/git_skill_source_manager.py,sha256=92fz9I7zYemQ7tV3-s0wzmU5wV7KCMnd-MzKXq6ssfY,56857
820
+ claude_mpm/services/skills/selective_skill_deployer.py,sha256=tWWs2RLatD1cP4MnDcVN6J2-hk6GuYPKg9chTXyDXGM,30639
821
+ claude_mpm/services/skills/skill_discovery_service.py,sha256=uJUdjB54N6w9g8KFi7WmobA-R-pBh3ND12qA2HYxd5I,23003
809
822
  claude_mpm/services/skills/skill_to_agent_mapper.py,sha256=4PRwcSDSNGS55lg4t-VmBK2ottE_cGFq1zsvjiumAlI,14847
810
823
  claude_mpm/services/socketio/__init__.py,sha256=PS-2twllga-2mhSfKdu4MgpikfKp_730gMLAqU_9YX4,556
811
824
  claude_mpm/services/socketio/client_proxy.py,sha256=DFPO5OIl-cHusldHPYWKSbnL0dxSLz8h07D9307FfzY,8853
@@ -1096,10 +1109,10 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
1096
1109
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
1097
1110
  claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
1098
1111
  claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
1099
- claude_mpm-5.6.5.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
1100
- claude_mpm-5.6.5.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
1101
- claude_mpm-5.6.5.dist-info/METADATA,sha256=G50Re3GrZttFycswLOr3Q_yl-JH3cuDqPMJu2UraWTE,14983
1102
- claude_mpm-5.6.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1103
- claude_mpm-5.6.5.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
1104
- claude_mpm-5.6.5.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
1105
- claude_mpm-5.6.5.dist-info/RECORD,,
1112
+ claude_mpm-5.6.9.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
1113
+ claude_mpm-5.6.9.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
1114
+ claude_mpm-5.6.9.dist-info/METADATA,sha256=zFOkKrO7QsszgLAusCpXjQiG-wsHRWCsCsxOIYntIL0,14983
1115
+ claude_mpm-5.6.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1116
+ claude_mpm-5.6.9.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
1117
+ claude_mpm-5.6.9.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
1118
+ claude_mpm-5.6.9.dist-info/RECORD,,