claude-mpm 5.4.74__py3-none-any.whl → 5.4.75__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/cli/commands/configure.py +334 -111
- {claude_mpm-5.4.74.dist-info → claude_mpm-5.4.75.dist-info}/METADATA +1 -1
- {claude_mpm-5.4.74.dist-info → claude_mpm-5.4.75.dist-info}/RECORD +8 -8
- {claude_mpm-5.4.74.dist-info → claude_mpm-5.4.75.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.74.dist-info → claude_mpm-5.4.75.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.74.dist-info → claude_mpm-5.4.75.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.74.dist-info → claude_mpm-5.4.75.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.74.dist-info → claude_mpm-5.4.75.dist-info}/top_level.txt +0 -0
|
@@ -656,25 +656,22 @@ class ConfigureCommand(BaseCommand):
|
|
|
656
656
|
self.behavior_manager.manage_behaviors()
|
|
657
657
|
|
|
658
658
|
def _manage_skills(self) -> None:
|
|
659
|
-
"""Skills management interface with
|
|
659
|
+
"""Skills management interface with questionary checkbox selection."""
|
|
660
660
|
from ...cli.interactive.skills_wizard import SkillsWizard
|
|
661
|
-
from ...skills.registry import get_registry
|
|
662
661
|
from ...skills.skill_manager import get_manager
|
|
663
662
|
|
|
664
663
|
wizard = SkillsWizard()
|
|
665
664
|
manager = get_manager()
|
|
666
|
-
registry = get_registry()
|
|
667
665
|
|
|
668
666
|
while True:
|
|
669
667
|
self.console.clear()
|
|
670
668
|
self._display_header()
|
|
671
669
|
|
|
672
|
-
|
|
673
|
-
self._display_skills_table(registry)
|
|
670
|
+
self.console.print("\n[bold]Skills Management[/bold]")
|
|
674
671
|
|
|
675
672
|
# Show action options
|
|
676
673
|
self.console.print("\n[bold]Actions:[/bold]")
|
|
677
|
-
self.console.print(" [1]
|
|
674
|
+
self.console.print(" [1] Install/Uninstall skills")
|
|
678
675
|
self.console.print(" [2] Configure skills for agents")
|
|
679
676
|
self.console.print(" [3] View current skill mappings")
|
|
680
677
|
self.console.print(" [4] Auto-link skills to agents")
|
|
@@ -684,57 +681,8 @@ class ConfigureCommand(BaseCommand):
|
|
|
684
681
|
choice = Prompt.ask("[bold blue]Select an option[/bold blue]", default="b")
|
|
685
682
|
|
|
686
683
|
if choice == "1":
|
|
687
|
-
#
|
|
688
|
-
self.
|
|
689
|
-
self._display_header()
|
|
690
|
-
self._display_skills_table(registry)
|
|
691
|
-
|
|
692
|
-
skill_num = Prompt.ask(
|
|
693
|
-
"\n[bold blue]Enter skill number to toggle (or 'b' to go back)[/bold blue]",
|
|
694
|
-
default="b",
|
|
695
|
-
)
|
|
696
|
-
|
|
697
|
-
if skill_num == "b":
|
|
698
|
-
continue
|
|
699
|
-
|
|
700
|
-
try:
|
|
701
|
-
skill_idx = int(skill_num) - 1
|
|
702
|
-
all_skills = self._get_all_skills_sorted(registry)
|
|
703
|
-
|
|
704
|
-
if 0 <= skill_idx < len(all_skills):
|
|
705
|
-
skill = all_skills[skill_idx]
|
|
706
|
-
deployed_ids = self._get_deployed_skill_ids()
|
|
707
|
-
|
|
708
|
-
if skill.skill_id in deployed_ids:
|
|
709
|
-
# Uninstall
|
|
710
|
-
confirm = Confirm.ask(
|
|
711
|
-
f"\n[yellow]Uninstall skill '{skill.name}'?[/yellow]",
|
|
712
|
-
default=False,
|
|
713
|
-
)
|
|
714
|
-
if confirm:
|
|
715
|
-
self._uninstall_skill(skill)
|
|
716
|
-
self.console.print(
|
|
717
|
-
f"\n[green]✓ Skill '{skill.name}' uninstalled[/green]"
|
|
718
|
-
)
|
|
719
|
-
else:
|
|
720
|
-
# Install
|
|
721
|
-
confirm = Confirm.ask(
|
|
722
|
-
f"\n[cyan]Install skill '{skill.name}'?[/cyan]",
|
|
723
|
-
default=True,
|
|
724
|
-
)
|
|
725
|
-
if confirm:
|
|
726
|
-
self._install_skill(skill)
|
|
727
|
-
self.console.print(
|
|
728
|
-
f"\n[green]✓ Skill '{skill.name}' installed[/green]"
|
|
729
|
-
)
|
|
730
|
-
else:
|
|
731
|
-
self.console.print("[red]Invalid skill number[/red]")
|
|
732
|
-
except ValueError:
|
|
733
|
-
self.console.print(
|
|
734
|
-
"[red]Invalid input. Please enter a number.[/red]"
|
|
735
|
-
)
|
|
736
|
-
|
|
737
|
-
Prompt.ask("\nPress Enter to continue")
|
|
684
|
+
# Install/Uninstall skills with category-based selection
|
|
685
|
+
self._manage_skill_installation()
|
|
738
686
|
|
|
739
687
|
elif choice == "2":
|
|
740
688
|
# Configure skills interactively
|
|
@@ -857,72 +805,304 @@ class ConfigureCommand(BaseCommand):
|
|
|
857
805
|
self.console.print("[red]Invalid choice. Please try again.[/red]")
|
|
858
806
|
Prompt.ask("\nPress Enter to continue")
|
|
859
807
|
|
|
860
|
-
def
|
|
861
|
-
"""
|
|
862
|
-
|
|
863
|
-
from rich.table import Table
|
|
808
|
+
def _manage_skill_installation(self) -> None:
|
|
809
|
+
"""Manage skill installation with category-based questionary checkbox selection."""
|
|
810
|
+
import questionary
|
|
864
811
|
|
|
865
|
-
# Get all skills
|
|
866
|
-
all_skills = self.
|
|
867
|
-
|
|
812
|
+
# Get all skills
|
|
813
|
+
all_skills = self._get_all_skills_from_git()
|
|
814
|
+
if not all_skills:
|
|
815
|
+
self.console.print(
|
|
816
|
+
"[yellow]No skills available. Try syncing skills first.[/yellow]"
|
|
817
|
+
)
|
|
818
|
+
Prompt.ask("\nPress Enter to continue")
|
|
819
|
+
return
|
|
868
820
|
|
|
869
|
-
#
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
#
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
821
|
+
# Get deployed skills
|
|
822
|
+
deployed = self._get_deployed_skill_ids()
|
|
823
|
+
|
|
824
|
+
# Group by category
|
|
825
|
+
grouped = {}
|
|
826
|
+
for skill in all_skills:
|
|
827
|
+
# Try to get category from tags or use toolchain
|
|
828
|
+
category = None
|
|
829
|
+
tags = skill.get("tags", [])
|
|
830
|
+
|
|
831
|
+
# Look for category tag
|
|
832
|
+
for tag in tags:
|
|
833
|
+
if tag in [
|
|
834
|
+
"universal",
|
|
835
|
+
"python",
|
|
836
|
+
"typescript",
|
|
837
|
+
"javascript",
|
|
838
|
+
"go",
|
|
839
|
+
"rust",
|
|
840
|
+
]:
|
|
841
|
+
category = tag
|
|
842
|
+
break
|
|
884
843
|
|
|
885
|
-
#
|
|
886
|
-
if
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
844
|
+
# Fallback to toolchain or universal
|
|
845
|
+
if not category:
|
|
846
|
+
category = skill.get("toolchain", "universal")
|
|
847
|
+
|
|
848
|
+
if category not in grouped:
|
|
849
|
+
grouped[category] = []
|
|
850
|
+
grouped[category].append(skill)
|
|
851
|
+
|
|
852
|
+
# Category icons
|
|
853
|
+
icons = {
|
|
854
|
+
"universal": "🌐",
|
|
855
|
+
"python": "🐍",
|
|
856
|
+
"typescript": "📘",
|
|
857
|
+
"javascript": "📒",
|
|
858
|
+
"go": "🔷",
|
|
859
|
+
"rust": "⚙️",
|
|
860
|
+
}
|
|
894
861
|
|
|
895
|
-
|
|
896
|
-
|
|
862
|
+
# Sort categories: universal first, then alphabetically
|
|
863
|
+
categories = sorted(grouped.keys(), key=lambda x: (x != "universal", x))
|
|
897
864
|
|
|
898
|
-
|
|
865
|
+
while True:
|
|
866
|
+
# Show category selection first
|
|
867
|
+
self.console.clear()
|
|
868
|
+
self._display_header()
|
|
869
|
+
self.console.print("\n[bold cyan]Skills Management[/bold cyan]")
|
|
870
|
+
self.console.print(
|
|
871
|
+
f"[dim]{len(all_skills)} skills available, {len(deployed)} installed[/dim]\n"
|
|
872
|
+
)
|
|
899
873
|
|
|
900
|
-
|
|
874
|
+
cat_choices = [
|
|
875
|
+
Choice(
|
|
876
|
+
title=f"{icons.get(cat, '📦')} {cat.title()} ({len(grouped[cat])} skills)",
|
|
877
|
+
value=cat,
|
|
878
|
+
)
|
|
879
|
+
for cat in categories
|
|
880
|
+
]
|
|
881
|
+
cat_choices.append(Choice(title="← Back to main menu", value="back"))
|
|
901
882
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
883
|
+
selected_cat = questionary.select(
|
|
884
|
+
"Select a category:", choices=cat_choices, style=self.QUESTIONARY_STYLE
|
|
885
|
+
).ask()
|
|
886
|
+
|
|
887
|
+
if selected_cat is None or selected_cat == "back":
|
|
888
|
+
return
|
|
907
889
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
# Get skills from all sources
|
|
911
|
-
bundled = registry.list_skills(source="bundled")
|
|
912
|
-
user = registry.list_skills(source="user")
|
|
913
|
-
project = registry.list_skills(source="project")
|
|
890
|
+
# Show skills in category with checkbox selection
|
|
891
|
+
category_skills = grouped[selected_cat]
|
|
914
892
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
893
|
+
# Build choices with current installation status
|
|
894
|
+
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]
|
|
921
899
|
|
|
922
|
-
|
|
900
|
+
# Check if installed
|
|
901
|
+
is_installed = deploy_name in deployed or skill_id in deployed
|
|
902
|
+
|
|
903
|
+
skill_choices.append(
|
|
904
|
+
Choice(
|
|
905
|
+
title=f"{skill_id} - {description}",
|
|
906
|
+
value=skill_id,
|
|
907
|
+
checked=is_installed,
|
|
908
|
+
)
|
|
909
|
+
)
|
|
910
|
+
|
|
911
|
+
self.console.clear()
|
|
912
|
+
self._display_header()
|
|
913
|
+
self.console.print(
|
|
914
|
+
f"\n{icons.get(selected_cat, '📦')} [bold]{selected_cat.title()}[/bold]"
|
|
915
|
+
)
|
|
916
|
+
self.console.print("[dim]Use spacebar to toggle, enter to confirm[/dim]\n")
|
|
917
|
+
|
|
918
|
+
selected = questionary.checkbox(
|
|
919
|
+
"Select skills to install:",
|
|
920
|
+
choices=skill_choices,
|
|
921
|
+
style=self.QUESTIONARY_STYLE,
|
|
922
|
+
).ask()
|
|
923
|
+
|
|
924
|
+
if selected is None:
|
|
925
|
+
continue # User cancelled, go back to category selection
|
|
926
|
+
|
|
927
|
+
# Process changes
|
|
928
|
+
selected_set = set(selected)
|
|
929
|
+
current_in_cat = set()
|
|
930
|
+
|
|
931
|
+
# Find currently installed skills in this category
|
|
932
|
+
for skill in category_skills:
|
|
933
|
+
skill_id = skill.get("name", skill.get("skill_id", "unknown"))
|
|
934
|
+
deploy_name = skill.get("deployment_name", skill_id)
|
|
935
|
+
if deploy_name in deployed or skill_id in deployed:
|
|
936
|
+
current_in_cat.add(skill_id)
|
|
937
|
+
|
|
938
|
+
# Install newly selected
|
|
939
|
+
to_install = selected_set - current_in_cat
|
|
940
|
+
for skill_id in to_install:
|
|
941
|
+
skill = next(
|
|
942
|
+
(
|
|
943
|
+
s
|
|
944
|
+
for s in category_skills
|
|
945
|
+
if s.get("name") == skill_id or s.get("skill_id") == skill_id
|
|
946
|
+
),
|
|
947
|
+
None,
|
|
948
|
+
)
|
|
949
|
+
if skill:
|
|
950
|
+
self._install_skill_from_dict(skill)
|
|
951
|
+
self.console.print(f"[green]✓ Installed {skill_id}[/green]")
|
|
952
|
+
|
|
953
|
+
# Uninstall deselected
|
|
954
|
+
to_uninstall = current_in_cat - selected_set
|
|
955
|
+
for skill_id in to_uninstall:
|
|
956
|
+
# Find the skill to get deployment_name
|
|
957
|
+
skill = next(
|
|
958
|
+
(
|
|
959
|
+
s
|
|
960
|
+
for s in category_skills
|
|
961
|
+
if s.get("name") == skill_id or s.get("skill_id") == skill_id
|
|
962
|
+
),
|
|
963
|
+
None,
|
|
964
|
+
)
|
|
965
|
+
if skill:
|
|
966
|
+
deploy_name = skill.get("deployment_name", skill_id)
|
|
967
|
+
# Use the name that's actually in deployed set
|
|
968
|
+
name_to_uninstall = (
|
|
969
|
+
deploy_name if deploy_name in deployed else skill_id
|
|
970
|
+
)
|
|
971
|
+
self._uninstall_skill_by_name(name_to_uninstall)
|
|
972
|
+
self.console.print(f"[yellow]✗ Uninstalled {skill_id}[/yellow]")
|
|
973
|
+
|
|
974
|
+
# Update deployed set for next iteration
|
|
975
|
+
deployed = self._get_deployed_skill_ids()
|
|
976
|
+
|
|
977
|
+
# Show completion message
|
|
978
|
+
if to_install or to_uninstall:
|
|
979
|
+
Prompt.ask("\nPress Enter to continue")
|
|
980
|
+
|
|
981
|
+
def _get_all_skills_from_git(self) -> list:
|
|
982
|
+
"""Get all skills from Git-based skill manager.
|
|
983
|
+
|
|
984
|
+
Returns:
|
|
985
|
+
List of skill dicts with full metadata from GitSkillSourceManager.
|
|
986
|
+
"""
|
|
987
|
+
from ...config.skill_sources import SkillSourceConfiguration
|
|
988
|
+
from ...services.skills.git_skill_source_manager import GitSkillSourceManager
|
|
989
|
+
|
|
990
|
+
try:
|
|
991
|
+
config = SkillSourceConfiguration()
|
|
992
|
+
manager = GitSkillSourceManager(config)
|
|
993
|
+
return manager.get_all_skills()
|
|
994
|
+
except Exception as e:
|
|
995
|
+
self.console.print(
|
|
996
|
+
f"[yellow]Warning: Could not load Git skills: {e}[/yellow]"
|
|
997
|
+
)
|
|
998
|
+
return []
|
|
999
|
+
|
|
1000
|
+
def _display_skills_table_grouped(self) -> None:
|
|
1001
|
+
"""Display skills in a table grouped by category, like agents."""
|
|
1002
|
+
from rich import box
|
|
1003
|
+
from rich.table import Table
|
|
1004
|
+
|
|
1005
|
+
# Get all skills from Git manager
|
|
1006
|
+
all_skills = self._get_all_skills_from_git()
|
|
1007
|
+
deployed_ids = self._get_deployed_skill_ids()
|
|
1008
|
+
|
|
1009
|
+
if not all_skills:
|
|
1010
|
+
self.console.print(
|
|
1011
|
+
"[yellow]No skills available. Try syncing skills first.[/yellow]"
|
|
1012
|
+
)
|
|
1013
|
+
return
|
|
1014
|
+
|
|
1015
|
+
# Group skills by category/toolchain
|
|
1016
|
+
grouped = {}
|
|
1017
|
+
for skill in all_skills:
|
|
1018
|
+
# Try to get category from tags or use toolchain
|
|
1019
|
+
category = None
|
|
1020
|
+
tags = skill.get("tags", [])
|
|
1021
|
+
|
|
1022
|
+
# Look for category tag
|
|
1023
|
+
for tag in tags:
|
|
1024
|
+
if tag in [
|
|
1025
|
+
"universal",
|
|
1026
|
+
"python",
|
|
1027
|
+
"typescript",
|
|
1028
|
+
"javascript",
|
|
1029
|
+
"go",
|
|
1030
|
+
"rust",
|
|
1031
|
+
]:
|
|
1032
|
+
category = tag
|
|
1033
|
+
break
|
|
1034
|
+
|
|
1035
|
+
# Fallback to toolchain or universal
|
|
1036
|
+
if not category:
|
|
1037
|
+
category = skill.get("toolchain", "universal")
|
|
1038
|
+
|
|
1039
|
+
if category not in grouped:
|
|
1040
|
+
grouped[category] = []
|
|
1041
|
+
grouped[category].append(skill)
|
|
1042
|
+
|
|
1043
|
+
# Sort categories: universal first, then alphabetically
|
|
1044
|
+
categories = sorted(grouped.keys(), key=lambda x: (x != "universal", x))
|
|
1045
|
+
|
|
1046
|
+
# Track global skill number across all categories
|
|
1047
|
+
skill_counter = 0
|
|
1048
|
+
|
|
1049
|
+
for category in categories:
|
|
1050
|
+
category_skills = grouped[category]
|
|
1051
|
+
|
|
1052
|
+
# Category header with icon
|
|
1053
|
+
icons = {
|
|
1054
|
+
"universal": "🌐",
|
|
1055
|
+
"python": "🐍",
|
|
1056
|
+
"typescript": "📘",
|
|
1057
|
+
"javascript": "📒",
|
|
1058
|
+
"go": "🔷",
|
|
1059
|
+
"rust": "⚙️",
|
|
1060
|
+
}
|
|
1061
|
+
icon = icons.get(category, "📦")
|
|
1062
|
+
self.console.print(
|
|
1063
|
+
f"\n{icon} [bold cyan]{category.title()}[/bold cyan] ({len(category_skills)} skills)"
|
|
1064
|
+
)
|
|
1065
|
+
|
|
1066
|
+
# Create table for this category
|
|
1067
|
+
table = Table(show_header=True, header_style="bold", box=box.SIMPLE)
|
|
1068
|
+
table.add_column("#", style="dim", width=4)
|
|
1069
|
+
table.add_column("Skill ID", style="cyan", width=35)
|
|
1070
|
+
table.add_column("Description", style="white", width=45)
|
|
1071
|
+
table.add_column("Status", style="green", width=12)
|
|
1072
|
+
|
|
1073
|
+
for skill in sorted(category_skills, key=lambda x: x.get("name", "")):
|
|
1074
|
+
skill_counter += 1
|
|
1075
|
+
skill_id = skill.get("name", skill.get("skill_id", "unknown"))
|
|
1076
|
+
# Use deployment_name for matching if available
|
|
1077
|
+
deploy_name = skill.get("deployment_name", skill_id)
|
|
1078
|
+
description = skill.get("description", "")[:45]
|
|
1079
|
+
|
|
1080
|
+
# Check if installed - handle both deployment_name and skill_id
|
|
1081
|
+
is_installed = deploy_name in deployed_ids or skill_id in deployed_ids
|
|
1082
|
+
status = "[green]✓ Installed[/green]" if is_installed else "Available"
|
|
1083
|
+
|
|
1084
|
+
table.add_row(str(skill_counter), skill_id, description, status)
|
|
1085
|
+
|
|
1086
|
+
self.console.print(table)
|
|
1087
|
+
|
|
1088
|
+
# Summary
|
|
1089
|
+
total = len(all_skills)
|
|
1090
|
+
installed = sum(
|
|
1091
|
+
1
|
|
1092
|
+
for s in all_skills
|
|
1093
|
+
if s.get("deployment_name", s.get("name", "")) in deployed_ids
|
|
1094
|
+
or s.get("name", "") in deployed_ids
|
|
1095
|
+
)
|
|
1096
|
+
self.console.print(
|
|
1097
|
+
f"\n[dim]Showing {total} skills ({installed} installed)[/dim]"
|
|
1098
|
+
)
|
|
923
1099
|
|
|
924
1100
|
def _get_deployed_skill_ids(self) -> set:
|
|
925
|
-
"""Get set of deployed skill IDs from .claude/skills/ directory.
|
|
1101
|
+
"""Get set of deployed skill IDs from .claude/skills/ directory.
|
|
1102
|
+
|
|
1103
|
+
Returns:
|
|
1104
|
+
Set of skill directory names and common variations for matching.
|
|
1105
|
+
"""
|
|
926
1106
|
from pathlib import Path
|
|
927
1107
|
|
|
928
1108
|
skills_dir = Path.cwd() / ".claude" / "skills"
|
|
@@ -933,7 +1113,11 @@ class ConfigureCommand(BaseCommand):
|
|
|
933
1113
|
deployed_ids = set()
|
|
934
1114
|
for skill_dir in skills_dir.iterdir():
|
|
935
1115
|
if skill_dir.is_dir() and not skill_dir.name.startswith("."):
|
|
1116
|
+
# Add both the directory name and common variations
|
|
936
1117
|
deployed_ids.add(skill_dir.name)
|
|
1118
|
+
# Also add without prefix for matching (e.g., universal-testing -> testing)
|
|
1119
|
+
if skill_dir.name.startswith("universal-"):
|
|
1120
|
+
deployed_ids.add(skill_dir.name.replace("universal-", "", 1))
|
|
937
1121
|
|
|
938
1122
|
return deployed_ids
|
|
939
1123
|
|
|
@@ -967,6 +1151,45 @@ class ConfigureCommand(BaseCommand):
|
|
|
967
1151
|
if target_dir.exists():
|
|
968
1152
|
shutil.rmtree(target_dir)
|
|
969
1153
|
|
|
1154
|
+
def _install_skill_from_dict(self, skill_dict: dict) -> None:
|
|
1155
|
+
"""Install a skill from Git skill dict to .claude/skills/ directory.
|
|
1156
|
+
|
|
1157
|
+
Args:
|
|
1158
|
+
skill_dict: Skill metadata dict from GitSkillSourceManager.get_all_skills()
|
|
1159
|
+
"""
|
|
1160
|
+
from pathlib import Path
|
|
1161
|
+
|
|
1162
|
+
skill_id = skill_dict.get("name", skill_dict.get("skill_id", "unknown"))
|
|
1163
|
+
content = skill_dict.get("content", "")
|
|
1164
|
+
|
|
1165
|
+
if not content:
|
|
1166
|
+
self.console.print(
|
|
1167
|
+
f"[yellow]Warning: Skill '{skill_id}' has no content[/yellow]"
|
|
1168
|
+
)
|
|
1169
|
+
return
|
|
1170
|
+
|
|
1171
|
+
# Target directory using deployment_name if available
|
|
1172
|
+
deploy_name = skill_dict.get("deployment_name", skill_id)
|
|
1173
|
+
target_dir = Path.cwd() / ".claude" / "skills" / deploy_name
|
|
1174
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
1175
|
+
|
|
1176
|
+
# Write skill content to skill.md
|
|
1177
|
+
skill_file = target_dir / "skill.md"
|
|
1178
|
+
skill_file.write_text(content, encoding="utf-8")
|
|
1179
|
+
|
|
1180
|
+
def _uninstall_skill_by_name(self, skill_name: str) -> None:
|
|
1181
|
+
"""Uninstall a skill by name from .claude/skills/ directory.
|
|
1182
|
+
|
|
1183
|
+
Args:
|
|
1184
|
+
skill_name: Name of skill directory to remove
|
|
1185
|
+
"""
|
|
1186
|
+
import shutil
|
|
1187
|
+
from pathlib import Path
|
|
1188
|
+
|
|
1189
|
+
target_dir = Path.cwd() / ".claude" / "skills" / skill_name
|
|
1190
|
+
if target_dir.exists():
|
|
1191
|
+
shutil.rmtree(target_dir)
|
|
1192
|
+
|
|
970
1193
|
def _display_behavior_files(self) -> None:
|
|
971
1194
|
"""Display current behavior files."""
|
|
972
1195
|
self.behavior_manager.display_behavior_files()
|
|
@@ -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=
|
|
63
|
+
claude_mpm/cli/commands/configure.py,sha256=yav4ipRbZ5tc1tjBHkU8Pf6Ls4FtGirqZmN94H0WPic,127811
|
|
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
|
|
@@ -993,10 +993,10 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
|
|
|
993
993
|
claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
|
|
994
994
|
claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
|
|
995
995
|
claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
|
|
996
|
-
claude_mpm-5.4.
|
|
997
|
-
claude_mpm-5.4.
|
|
998
|
-
claude_mpm-5.4.
|
|
999
|
-
claude_mpm-5.4.
|
|
1000
|
-
claude_mpm-5.4.
|
|
1001
|
-
claude_mpm-5.4.
|
|
1002
|
-
claude_mpm-5.4.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|