claude-mpm 5.4.54__py3-none-any.whl → 5.4.56__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/cli/startup.py +191 -160
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/services/skills/git_skill_source_manager.py +20 -8
- {claude_mpm-5.4.54.dist-info → claude_mpm-5.4.56.dist-info}/METADATA +1 -1
- {claude_mpm-5.4.54.dist-info → claude_mpm-5.4.56.dist-info}/RECORD +11 -10
- {claude_mpm-5.4.54.dist-info → claude_mpm-5.4.56.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.54.dist-info → claude_mpm-5.4.56.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.54.dist-info → claude_mpm-5.4.56.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.54.dist-info → claude_mpm-5.4.56.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.54.dist-info → claude_mpm-5.4.56.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.4.
|
|
1
|
+
5.4.56
|
claude_mpm/cli/startup.py
CHANGED
|
@@ -990,160 +990,188 @@ def sync_remote_skills_on_startup():
|
|
|
990
990
|
|
|
991
991
|
# Phase 2: Scan agents and save to configuration.yaml
|
|
992
992
|
# This step populates configuration.yaml with agent-referenced skills
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
# Phase 3: Resolve which skills to deploy (user_defined or agent_referenced)
|
|
1004
|
-
skills_to_deploy, skill_source = get_skills_to_deploy(project_config_path)
|
|
1005
|
-
|
|
1006
|
-
# Phase 4: Apply profile filtering if active
|
|
1007
|
-
if active_profile and profile_manager.active_profile:
|
|
1008
|
-
# Filter skills based on profile
|
|
1009
|
-
if skills_to_deploy:
|
|
1010
|
-
# Filter the resolved skill list
|
|
1011
|
-
original_count = len(skills_to_deploy)
|
|
1012
|
-
filtered_skills = [
|
|
1013
|
-
skill
|
|
1014
|
-
for skill in skills_to_deploy
|
|
1015
|
-
if profile_manager.is_skill_enabled(skill)
|
|
1016
|
-
]
|
|
1017
|
-
filtered_count = original_count - len(filtered_skills)
|
|
1018
|
-
|
|
1019
|
-
# SAFEGUARD: Warn if all skills were filtered out (misconfiguration)
|
|
1020
|
-
if not filtered_skills and original_count > 0:
|
|
1021
|
-
logger.warning(
|
|
1022
|
-
f"Profile '{active_profile}' filtered ALL {original_count} skills. "
|
|
1023
|
-
f"This may indicate a naming mismatch in the profile."
|
|
1024
|
-
)
|
|
1025
|
-
elif filtered_count > 0:
|
|
1026
|
-
logger.info(
|
|
1027
|
-
f"Profile '{active_profile}' filtered {filtered_count} skills "
|
|
1028
|
-
f"({len(filtered_skills)} remaining)"
|
|
1029
|
-
)
|
|
993
|
+
# CRITICAL: Always scan agents to populate agent_referenced, even when using cached skills.
|
|
994
|
+
# Without this, skill_filter=None causes ALL skills to deploy and NO cleanup to run.
|
|
995
|
+
agents_dir = Path.cwd() / ".claude" / "agents"
|
|
996
|
+
|
|
997
|
+
# Scan agents for skill requirements (ALWAYS run to ensure cleanup works)
|
|
998
|
+
agent_skills = get_required_skills_from_agents(agents_dir)
|
|
999
|
+
logger.info(
|
|
1000
|
+
f"Agent scan found {len(agent_skills)} unique skills across deployed agents"
|
|
1001
|
+
)
|
|
1030
1002
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
skill["name"]
|
|
1038
|
-
for skill in all_skills
|
|
1039
|
-
if profile_manager.is_skill_enabled(skill["name"])
|
|
1040
|
-
]
|
|
1041
|
-
skills_to_deploy = filtered_skills
|
|
1042
|
-
skill_source = "profile filtered"
|
|
1043
|
-
logger.info(
|
|
1044
|
-
f"Profile '{active_profile}': "
|
|
1045
|
-
f"{len(filtered_skills)} skills enabled from {len(all_skills)} available"
|
|
1046
|
-
)
|
|
1003
|
+
# Save to project-level configuration.yaml
|
|
1004
|
+
project_config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
|
|
1005
|
+
save_agent_skills_to_config(list(agent_skills), project_config_path)
|
|
1006
|
+
logger.debug(
|
|
1007
|
+
f"Saved {len(agent_skills)} agent-referenced skills to {project_config_path}"
|
|
1008
|
+
)
|
|
1047
1009
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
total_skill_count = len(all_skills)
|
|
1010
|
+
# Phase 3: Resolve which skills to deploy (user_defined or agent_referenced)
|
|
1011
|
+
skills_to_deploy, skill_source = get_skills_to_deploy(project_config_path)
|
|
1051
1012
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1013
|
+
# CRITICAL DEBUG: Log deployment resolution to diagnose cleanup issues
|
|
1014
|
+
if skills_to_deploy:
|
|
1015
|
+
logger.info(
|
|
1016
|
+
f"Resolved {len(skills_to_deploy)} skills from {skill_source} (cleanup will run)"
|
|
1017
|
+
)
|
|
1018
|
+
else:
|
|
1019
|
+
logger.warning(
|
|
1020
|
+
f"No skills resolved from {skill_source} - will deploy ALL skills WITHOUT cleanup! "
|
|
1021
|
+
f"This may indicate agent_referenced is empty in configuration.yaml."
|
|
1055
1022
|
)
|
|
1056
1023
|
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1024
|
+
# Phase 4: Apply profile filtering if active
|
|
1025
|
+
if active_profile and profile_manager.active_profile:
|
|
1026
|
+
# Filter skills based on profile
|
|
1027
|
+
if skills_to_deploy:
|
|
1028
|
+
# Filter the resolved skill list
|
|
1029
|
+
original_count = len(skills_to_deploy)
|
|
1030
|
+
filtered_skills = [
|
|
1031
|
+
skill
|
|
1032
|
+
for skill in skills_to_deploy
|
|
1033
|
+
if profile_manager.is_skill_enabled(skill)
|
|
1034
|
+
]
|
|
1035
|
+
filtered_count = original_count - len(filtered_skills)
|
|
1036
|
+
|
|
1037
|
+
# SAFEGUARD: Warn if all skills were filtered out (misconfiguration)
|
|
1038
|
+
if not filtered_skills and original_count > 0:
|
|
1039
|
+
logger.warning(
|
|
1040
|
+
f"Profile '{active_profile}' filtered ALL {original_count} skills. "
|
|
1041
|
+
f"This may indicate a naming mismatch in the profile."
|
|
1042
|
+
)
|
|
1043
|
+
elif filtered_count > 0:
|
|
1044
|
+
logger.info(
|
|
1045
|
+
f"Profile '{active_profile}' filtered {filtered_count} skills "
|
|
1046
|
+
f"({len(filtered_skills)} remaining)"
|
|
1047
|
+
)
|
|
1060
1048
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1049
|
+
skills_to_deploy = filtered_skills
|
|
1050
|
+
skill_source = f"{skill_source} + profile filtered"
|
|
1051
|
+
else:
|
|
1052
|
+
# No explicit skill list - filter from all available
|
|
1053
|
+
all_skills = manager.get_all_skills()
|
|
1054
|
+
filtered_skills = [
|
|
1055
|
+
skill["name"]
|
|
1056
|
+
for skill in all_skills
|
|
1057
|
+
if profile_manager.is_skill_enabled(skill["name"])
|
|
1058
|
+
]
|
|
1059
|
+
skills_to_deploy = filtered_skills
|
|
1060
|
+
skill_source = "profile filtered"
|
|
1061
|
+
logger.info(
|
|
1062
|
+
f"Profile '{active_profile}': "
|
|
1063
|
+
f"{len(filtered_skills)} skills enabled from {len(all_skills)} available"
|
|
1066
1064
|
)
|
|
1067
1065
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
target_dir=Path.home() / ".claude" / "skills",
|
|
1072
|
-
force=False,
|
|
1073
|
-
skill_filter=set(skills_to_deploy) if skills_to_deploy else None,
|
|
1074
|
-
)
|
|
1066
|
+
# Get all skills to determine counts
|
|
1067
|
+
all_skills = manager.get_all_skills()
|
|
1068
|
+
total_skill_count = len(all_skills)
|
|
1075
1069
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
total_available = deployed + skipped
|
|
1070
|
+
# Determine skill count based on resolution
|
|
1071
|
+
skill_count = (
|
|
1072
|
+
len(skills_to_deploy) if skills_to_deploy else total_skill_count
|
|
1073
|
+
)
|
|
1081
1074
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
else
|
|
1093
|
-
|
|
1094
|
-
deploy_progress = ProgressBar(
|
|
1095
|
-
total=1,
|
|
1096
|
-
prefix="Deploying skill directories",
|
|
1097
|
-
show_percentage=False,
|
|
1098
|
-
show_counter=False,
|
|
1099
|
-
)
|
|
1100
|
-
deploy_progress.update(1)
|
|
1075
|
+
if skill_count > 0:
|
|
1076
|
+
# Deploy skills with resolved filter
|
|
1077
|
+
# Deploy ONLY to project directory (not user-level)
|
|
1078
|
+
# DESIGN DECISION: Project-level deployment keeps skills isolated per project,
|
|
1079
|
+
# avoiding pollution of user's global ~/.claude/skills/ directory.
|
|
1080
|
+
|
|
1081
|
+
# Deploy to project-local directory with cleanup
|
|
1082
|
+
deployment_result = manager.deploy_skills(
|
|
1083
|
+
target_dir=Path.cwd() / ".claude" / "skills",
|
|
1084
|
+
force=False,
|
|
1085
|
+
skill_filter=set(skills_to_deploy) if skills_to_deploy else None,
|
|
1086
|
+
)
|
|
1101
1087
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1088
|
+
# REMOVED: User-level deployment (lines 1068-1074)
|
|
1089
|
+
# Reason: Skills should be project-specific, not user-global.
|
|
1090
|
+
# Claude Code can read from project-level .claude/skills/ directory.
|
|
1091
|
+
|
|
1092
|
+
# Get actual counts from deployment result (use project-local for display)
|
|
1093
|
+
deployed = deployment_result.get("deployed_count", 0)
|
|
1094
|
+
skipped = deployment_result.get("skipped_count", 0)
|
|
1095
|
+
filtered = deployment_result.get("filtered_count", 0)
|
|
1096
|
+
removed = deployment_result.get("removed_count", 0)
|
|
1097
|
+
total_available = deployed + skipped
|
|
1098
|
+
|
|
1099
|
+
# Only show progress bar if there are skills to deploy
|
|
1100
|
+
if total_available > 0:
|
|
1101
|
+
deploy_progress = ProgressBar(
|
|
1102
|
+
total=total_available,
|
|
1103
|
+
prefix="Deploying skill directories",
|
|
1104
|
+
show_percentage=True,
|
|
1105
|
+
show_counter=True,
|
|
1107
1106
|
)
|
|
1107
|
+
# Update progress bar to completion
|
|
1108
|
+
deploy_progress.update(total_available)
|
|
1109
|
+
else:
|
|
1110
|
+
# No skills to deploy - create dummy progress for message only
|
|
1111
|
+
deploy_progress = ProgressBar(
|
|
1112
|
+
total=1,
|
|
1113
|
+
prefix="Deploying skill directories",
|
|
1114
|
+
show_percentage=False,
|
|
1115
|
+
show_counter=False,
|
|
1116
|
+
)
|
|
1117
|
+
deploy_progress.update(1)
|
|
1118
|
+
|
|
1119
|
+
# Show total available skills (deployed + already existing)
|
|
1120
|
+
# Include source indication (user_defined vs agent_referenced)
|
|
1121
|
+
# Note: total_skill_count is from cache, total_available is what's deployed/needed
|
|
1122
|
+
source_label = (
|
|
1123
|
+
"user override" if skill_source == "user_defined" else "from agents"
|
|
1124
|
+
)
|
|
1108
1125
|
|
|
1126
|
+
# Build finish message with cleanup info
|
|
1127
|
+
if deployed > 0 or removed > 0:
|
|
1128
|
+
parts = []
|
|
1109
1129
|
if deployed > 0:
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
)
|
|
1120
|
-
elif filtered > 0:
|
|
1121
|
-
# Skills filtered means agents require fewer skills than available
|
|
1130
|
+
parts.append(f"{deployed} new")
|
|
1131
|
+
if skipped > 0:
|
|
1132
|
+
parts.append(f"{skipped} unchanged")
|
|
1133
|
+
if removed > 0:
|
|
1134
|
+
parts.append(f"{removed} removed")
|
|
1135
|
+
|
|
1136
|
+
status = ", ".join(parts)
|
|
1137
|
+
|
|
1138
|
+
if filtered > 0:
|
|
1122
1139
|
deploy_progress.finish(
|
|
1123
|
-
f"
|
|
1140
|
+
f"Complete: {status} ({total_available} {source_label}, {filtered} files in cache)"
|
|
1124
1141
|
)
|
|
1125
1142
|
else:
|
|
1126
1143
|
deploy_progress.finish(
|
|
1127
|
-
f"Complete: {total_available} skills {source_label} "
|
|
1128
|
-
f"({total_skill_count} files in cache)"
|
|
1144
|
+
f"Complete: {status} ({total_available} skills {source_label} from {total_skill_count} files in cache)"
|
|
1129
1145
|
)
|
|
1146
|
+
elif filtered > 0:
|
|
1147
|
+
# Skills filtered means agents require fewer skills than available
|
|
1148
|
+
deploy_progress.finish(
|
|
1149
|
+
f"No skills needed ({source_label}, {total_skill_count} files in cache)"
|
|
1150
|
+
)
|
|
1151
|
+
else:
|
|
1152
|
+
# No changes - all skills already deployed
|
|
1153
|
+
msg = f"Complete: {total_available} skills {source_label}"
|
|
1154
|
+
if removed > 0:
|
|
1155
|
+
msg += f", {removed} removed"
|
|
1156
|
+
msg += f" ({total_skill_count} files in cache)"
|
|
1157
|
+
deploy_progress.finish(msg)
|
|
1158
|
+
|
|
1159
|
+
# Log deployment errors if any
|
|
1160
|
+
from ..core.logger import get_logger
|
|
1130
1161
|
|
|
1131
|
-
|
|
1132
|
-
from ..core.logger import get_logger
|
|
1133
|
-
|
|
1134
|
-
logger = get_logger("cli")
|
|
1162
|
+
logger = get_logger("cli")
|
|
1135
1163
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1164
|
+
errors = deployment_result.get("errors", [])
|
|
1165
|
+
if errors:
|
|
1166
|
+
logger.warning(
|
|
1167
|
+
f"Skill deployment completed with {len(errors)} errors: {errors}"
|
|
1168
|
+
)
|
|
1141
1169
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1170
|
+
# Log sync errors if any
|
|
1171
|
+
if results["failed_count"] > 0:
|
|
1172
|
+
logger.warning(
|
|
1173
|
+
f"Skill sync completed with {results['failed_count']} failures"
|
|
1174
|
+
)
|
|
1147
1175
|
|
|
1148
1176
|
except Exception as e:
|
|
1149
1177
|
# Non-critical - log but don't fail startup
|
|
@@ -1243,61 +1271,64 @@ def show_skill_summary():
|
|
|
1243
1271
|
Display skill availability summary on startup.
|
|
1244
1272
|
|
|
1245
1273
|
WHY: Users should see at a glance how many skills are deployed and available
|
|
1246
|
-
from
|
|
1274
|
+
from cache, similar to the agent summary showing "X deployed / Y cached".
|
|
1275
|
+
|
|
1276
|
+
DESIGN DECISION: Fast, non-blocking check that counts skills from:
|
|
1277
|
+
- Deployed skills: PROJECT-level .claude/skills/ directory
|
|
1278
|
+
- Cached skills: ~/.claude-mpm/cache/skills/ directory (from remote sources)
|
|
1247
1279
|
|
|
1248
|
-
|
|
1249
|
-
directory and collection repos. Shows "X installed (Y available)" format.
|
|
1280
|
+
Shows format: "✓ Skills: X deployed / Y cached"
|
|
1250
1281
|
Failures are silent to avoid blocking startup.
|
|
1251
1282
|
"""
|
|
1252
1283
|
try:
|
|
1253
1284
|
from pathlib import Path
|
|
1254
1285
|
|
|
1255
|
-
# Count deployed skills (
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
if
|
|
1286
|
+
# Count deployed skills (PROJECT-level, not user-level)
|
|
1287
|
+
project_skills_dir = Path.cwd() / ".claude" / "skills"
|
|
1288
|
+
deployed_count = 0
|
|
1289
|
+
if project_skills_dir.exists():
|
|
1259
1290
|
# Count directories with SKILL.md (excludes collection repos)
|
|
1260
1291
|
# Exclude collection directories (obra-superpowers, etc.)
|
|
1261
1292
|
skill_dirs = [
|
|
1262
1293
|
d
|
|
1263
|
-
for d in
|
|
1294
|
+
for d in project_skills_dir.iterdir()
|
|
1264
1295
|
if d.is_dir()
|
|
1265
1296
|
and (d / "SKILL.md").exists()
|
|
1266
1297
|
and not (d / ".git").exists() # Exclude collection repos
|
|
1267
1298
|
]
|
|
1268
|
-
|
|
1299
|
+
deployed_count = len(skill_dirs)
|
|
1269
1300
|
|
|
1270
|
-
# Count
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
):
|
|
1301
|
+
# Count cached skills (from remote sources, not deployed yet)
|
|
1302
|
+
# This matches the agent summary pattern: deployed vs cached
|
|
1303
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "skills"
|
|
1304
|
+
cached_count = 0
|
|
1305
|
+
if cache_dir.exists():
|
|
1306
|
+
# Scan all repository directories in cache
|
|
1307
|
+
# Cache structure: ~/.claude-mpm/cache/skills/{owner}/{repo}/...
|
|
1308
|
+
for repo_dir in cache_dir.rglob("*"):
|
|
1309
|
+
if not repo_dir.is_dir():
|
|
1279
1310
|
continue
|
|
1280
1311
|
|
|
1281
|
-
# Count skill directories
|
|
1312
|
+
# Count skill directories (those with SKILL.md)
|
|
1282
1313
|
# Skills can be nested in: skills/category/skill-name/SKILL.md
|
|
1283
1314
|
# or in flat structure: skill-name/SKILL.md
|
|
1284
|
-
for root, dirs, files in os.walk(
|
|
1315
|
+
for root, dirs, files in os.walk(repo_dir):
|
|
1285
1316
|
if "SKILL.md" in files:
|
|
1286
|
-
# Exclude build artifacts and hidden directories
|
|
1287
|
-
# Get relative path from collection_dir to avoid excluding based on .claude parent
|
|
1317
|
+
# Exclude build artifacts and hidden directories
|
|
1288
1318
|
root_path = Path(root)
|
|
1289
|
-
relative_parts = root_path.relative_to(collection_dir).parts
|
|
1290
1319
|
if not any(
|
|
1291
1320
|
part.startswith(".")
|
|
1292
1321
|
or part in ["dist", "build", "__pycache__"]
|
|
1293
|
-
for part in
|
|
1322
|
+
for part in root_path.parts
|
|
1294
1323
|
):
|
|
1295
|
-
|
|
1324
|
+
cached_count += 1
|
|
1296
1325
|
|
|
1297
|
-
# Display summary
|
|
1298
|
-
|
|
1326
|
+
# Display summary using agent summary format: "X deployed / Y cached"
|
|
1327
|
+
# Only show non-deployed cached skills (subtract deployed from cached)
|
|
1328
|
+
non_deployed_cached = max(0, cached_count - deployed_count)
|
|
1329
|
+
if deployed_count > 0 or non_deployed_cached > 0:
|
|
1299
1330
|
print(
|
|
1300
|
-
f"✓ Skills: {
|
|
1331
|
+
f"✓ Skills: {deployed_count} deployed / {non_deployed_cached} cached",
|
|
1301
1332
|
flush=True,
|
|
1302
1333
|
)
|
|
1303
1334
|
|
|
Binary file
|
|
@@ -991,12 +991,17 @@ class GitSkillSourceManager:
|
|
|
991
991
|
progress_callback=None,
|
|
992
992
|
skill_filter: Optional[Set[str]] = None,
|
|
993
993
|
) -> Dict[str, Any]:
|
|
994
|
-
"""Deploy skills from cache to target directory with flat structure.
|
|
994
|
+
"""Deploy skills from cache to target directory with flat structure and automatic cleanup.
|
|
995
995
|
|
|
996
996
|
Flattens nested Git repository structure into Claude Code compatible
|
|
997
997
|
flat directory structure. Each skill directory is copied with a
|
|
998
998
|
hyphen-separated name derived from its path.
|
|
999
999
|
|
|
1000
|
+
CRITICAL: When skill_filter is provided (agent-referenced skills), this function:
|
|
1001
|
+
1. Deploys ONLY the filtered skills
|
|
1002
|
+
2. REMOVES orphaned skills (deployed but not in filter)
|
|
1003
|
+
3. Returns removed_count and removed_skills in result
|
|
1004
|
+
|
|
1000
1005
|
Transformation Example:
|
|
1001
1006
|
Cache: collaboration/dispatching-parallel-agents/SKILL.md
|
|
1002
1007
|
Deploy: collaboration-dispatching-parallel-agents/SKILL.md
|
|
@@ -1006,8 +1011,8 @@ class GitSkillSourceManager:
|
|
|
1006
1011
|
force: Overwrite existing skills
|
|
1007
1012
|
progress_callback: Optional callback(increment: int) called for each skill deployed
|
|
1008
1013
|
skill_filter: Optional set of skill names to deploy (selective deployment).
|
|
1009
|
-
If None, deploys
|
|
1010
|
-
|
|
1014
|
+
If None, deploys ALL skills WITHOUT cleanup.
|
|
1015
|
+
If provided, deploys ONLY filtered skills AND removes orphans.
|
|
1011
1016
|
|
|
1012
1017
|
Returns:
|
|
1013
1018
|
Dict with deployment results:
|
|
@@ -1018,7 +1023,9 @@ class GitSkillSourceManager:
|
|
|
1018
1023
|
"deployed_skills": List[str],
|
|
1019
1024
|
"skipped_skills": List[str],
|
|
1020
1025
|
"errors": List[str],
|
|
1021
|
-
"filtered_count": int # Number of skills filtered out
|
|
1026
|
+
"filtered_count": int, # Number of skills filtered out
|
|
1027
|
+
"removed_count": int, # Number of orphaned skills removed
|
|
1028
|
+
"removed_skills": List[str] # Names of removed orphaned skills
|
|
1022
1029
|
}
|
|
1023
1030
|
|
|
1024
1031
|
Example:
|
|
@@ -1026,10 +1033,10 @@ class GitSkillSourceManager:
|
|
|
1026
1033
|
>>> result = manager.deploy_skills()
|
|
1027
1034
|
>>> print(f"Deployed {result['deployed_count']} skills")
|
|
1028
1035
|
|
|
1029
|
-
# Selective deployment based on agent requirements:
|
|
1036
|
+
# Selective deployment based on agent requirements (with cleanup):
|
|
1030
1037
|
>>> required = {"typescript-core", "react-patterns"}
|
|
1031
1038
|
>>> result = manager.deploy_skills(skill_filter=required)
|
|
1032
|
-
>>> print(f"Deployed {result['deployed_count']}
|
|
1039
|
+
>>> print(f"Deployed {result['deployed_count']}, removed {result['removed_count']} orphans")
|
|
1033
1040
|
"""
|
|
1034
1041
|
if target_dir is None:
|
|
1035
1042
|
target_dir = Path.home() / ".claude" / "skills"
|
|
@@ -1040,6 +1047,7 @@ class GitSkillSourceManager:
|
|
|
1040
1047
|
skipped = []
|
|
1041
1048
|
errors = []
|
|
1042
1049
|
filtered_count = 0
|
|
1050
|
+
removed_skills = [] # Track removed orphaned skills
|
|
1043
1051
|
|
|
1044
1052
|
# Get all skills from all sources
|
|
1045
1053
|
all_skills = self.get_all_skills()
|
|
@@ -1082,11 +1090,12 @@ class GitSkillSourceManager:
|
|
|
1082
1090
|
)
|
|
1083
1091
|
|
|
1084
1092
|
# Cleanup: Remove skills from target directory that aren't in the filtered set
|
|
1085
|
-
# This ensures only
|
|
1093
|
+
# This ensures only agent-referenced skills remain deployed
|
|
1086
1094
|
removed_skills = self._cleanup_unfiltered_skills(target_dir, all_skills)
|
|
1087
1095
|
if removed_skills:
|
|
1088
1096
|
self.logger.info(
|
|
1089
|
-
f"Removed {len(removed_skills)} skills not
|
|
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 "")
|
|
1090
1099
|
)
|
|
1091
1100
|
|
|
1092
1101
|
self.logger.info(
|
|
@@ -1130,6 +1139,7 @@ class GitSkillSourceManager:
|
|
|
1130
1139
|
self.logger.info(
|
|
1131
1140
|
f"Deployment complete: {len(deployed)} deployed, "
|
|
1132
1141
|
f"{len(skipped)} skipped, {len(errors)} errors"
|
|
1142
|
+
+ (f", {len(removed_skills)} removed" if removed_skills else "")
|
|
1133
1143
|
)
|
|
1134
1144
|
|
|
1135
1145
|
return {
|
|
@@ -1140,6 +1150,8 @@ class GitSkillSourceManager:
|
|
|
1140
1150
|
"skipped_skills": skipped,
|
|
1141
1151
|
"errors": errors,
|
|
1142
1152
|
"filtered_count": filtered_count,
|
|
1153
|
+
"removed_count": len(removed_skills),
|
|
1154
|
+
"removed_skills": removed_skills,
|
|
1143
1155
|
}
|
|
1144
1156
|
|
|
1145
1157
|
def _cleanup_unfiltered_skills(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
|
|
2
|
-
claude_mpm/VERSION,sha256=
|
|
2
|
+
claude_mpm/VERSION,sha256=nwC2X1qTiadu5lECbdz8Av1yO5Df8yo2mz7YehUJ0yI,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=CU7v8LZT-cFCNNLZU4dpaMD-4c3ib16v8fVE620wUjk,6761
|
|
@@ -41,7 +41,7 @@ claude_mpm/cli/chrome_devtools_installer.py,sha256=efA_ZX1iR3oaJi3222079BQw6DEG8
|
|
|
41
41
|
claude_mpm/cli/executor.py,sha256=cetKiY2YS4XETUBXmfySdHYloI_M_lBJUFViRQ9TcS4,10544
|
|
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=
|
|
44
|
+
claude_mpm/cli/startup.py,sha256=3NuNrGG7keeTbC5YNcmgEVgtFQlIz9ui6XNy-1YEF7c,72965
|
|
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
|
|
@@ -339,6 +339,7 @@ claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc,sha256=EGpgXq
|
|
|
339
339
|
claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc,sha256=SQX5iiP9bQZkLL-cj_2tlGH7lpAzarO0mYal7btj3tc,3521
|
|
340
340
|
claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc,sha256=T9FMRyRjvHTRJm0LXosba7MezdUVw6I-nt_KP--LTwA,35923
|
|
341
341
|
claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc,sha256=AsvVXkge1Pio3jgnS-zNbPt9brySB8ZeVPSn7VvuKjs,29654
|
|
342
|
+
claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc,sha256=9mpAKY4gNcbU5VvZ5tGbf2UM0uIEWdreKSUvVr_BKcM,33917
|
|
342
343
|
claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc,sha256=YbwauQDKSGvXkT1972faalJLuxwyvq328DYQhkCnel0,10513
|
|
343
344
|
claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc,sha256=0xWsBZ63F-akLopSiRi36-hmhh1v9R5aKFBM0z93Jd0,16730
|
|
344
345
|
claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc,sha256=ZjcNfNY5Ht6FhalPeh7M7OzMffcey5iF4AVjDDg9kak,10694
|
|
@@ -700,7 +701,7 @@ claude_mpm/services/shared/lifecycle_service_base.py,sha256=YJZHs2sUrnIsbHHjrd8l
|
|
|
700
701
|
claude_mpm/services/shared/manager_base.py,sha256=kmjhpVqgfYC1N4YQnPAilCfdrSpAh9Qz7wcQ602L4x4,9296
|
|
701
702
|
claude_mpm/services/shared/service_factory.py,sha256=9yvnD62urrNQCGmtk_3OcR5tVUCnoS6wHkaI5PK34mg,9891
|
|
702
703
|
claude_mpm/services/skills/__init__.py,sha256=X1fPRCGZjteLd35HlhWv2M6tAJ_WbYrEv84kbaqBAiU,742
|
|
703
|
-
claude_mpm/services/skills/git_skill_source_manager.py,sha256=
|
|
704
|
+
claude_mpm/services/skills/git_skill_source_manager.py,sha256=H0MEug2lCix6RHqF4nVt3-Olfe9DM9bKlm_Bw9OJC4g,51529
|
|
704
705
|
claude_mpm/services/skills/selective_skill_deployer.py,sha256=7iTtPYSSO33rLCeZEZ_ZNNa369rhKsYCiqL0QcpMVbg,26478
|
|
705
706
|
claude_mpm/services/skills/skill_discovery_service.py,sha256=riy0PTnJS8e5R2ai8y1KPhBIR7SxlYIa9bnI9YccRMQ,20247
|
|
706
707
|
claude_mpm/services/skills/skill_to_agent_mapper.py,sha256=4PRwcSDSNGS55lg4t-VmBK2ottE_cGFq1zsvjiumAlI,14847
|
|
@@ -858,10 +859,10 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
|
|
|
858
859
|
claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
|
|
859
860
|
claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
|
|
860
861
|
claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
|
|
861
|
-
claude_mpm-5.4.
|
|
862
|
-
claude_mpm-5.4.
|
|
863
|
-
claude_mpm-5.4.
|
|
864
|
-
claude_mpm-5.4.
|
|
865
|
-
claude_mpm-5.4.
|
|
866
|
-
claude_mpm-5.4.
|
|
867
|
-
claude_mpm-5.4.
|
|
862
|
+
claude_mpm-5.4.56.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
|
|
863
|
+
claude_mpm-5.4.56.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
|
|
864
|
+
claude_mpm-5.4.56.dist-info/METADATA,sha256=TNxOdaTaMPQctoM85R8jZl7eixue-OGtgCrzj13lpCk,37997
|
|
865
|
+
claude_mpm-5.4.56.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
866
|
+
claude_mpm-5.4.56.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
|
|
867
|
+
claude_mpm-5.4.56.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
|
|
868
|
+
claude_mpm-5.4.56.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|