claude-mpm 5.4.73__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 +405 -17
- {claude_mpm-5.4.73.dist-info → claude_mpm-5.4.75.dist-info}/METADATA +1 -1
- {claude_mpm-5.4.73.dist-info → claude_mpm-5.4.75.dist-info}/RECORD +8 -8
- {claude_mpm-5.4.73.dist-info → claude_mpm-5.4.75.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.73.dist-info → claude_mpm-5.4.75.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.73.dist-info → claude_mpm-5.4.75.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.73.dist-info → claude_mpm-5.4.75.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.73.dist-info → claude_mpm-5.4.75.dist-info}/top_level.txt +0 -0
|
@@ -656,7 +656,7 @@ class ConfigureCommand(BaseCommand):
|
|
|
656
656
|
self.behavior_manager.manage_behaviors()
|
|
657
657
|
|
|
658
658
|
def _manage_skills(self) -> None:
|
|
659
|
-
"""Skills management interface."""
|
|
659
|
+
"""Skills management interface with questionary checkbox selection."""
|
|
660
660
|
from ...cli.interactive.skills_wizard import SkillsWizard
|
|
661
661
|
from ...skills.skill_manager import get_manager
|
|
662
662
|
|
|
@@ -667,22 +667,22 @@ class ConfigureCommand(BaseCommand):
|
|
|
667
667
|
self.console.clear()
|
|
668
668
|
self._display_header()
|
|
669
669
|
|
|
670
|
-
self.console.print("\n[bold]Skills Management
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
self.console.print("
|
|
674
|
-
self.console.print(" [
|
|
675
|
-
self.console.print(" [
|
|
670
|
+
self.console.print("\n[bold]Skills Management[/bold]")
|
|
671
|
+
|
|
672
|
+
# Show action options
|
|
673
|
+
self.console.print("\n[bold]Actions:[/bold]")
|
|
674
|
+
self.console.print(" [1] Install/Uninstall skills")
|
|
675
|
+
self.console.print(" [2] Configure skills for agents")
|
|
676
|
+
self.console.print(" [3] View current skill mappings")
|
|
677
|
+
self.console.print(" [4] Auto-link skills to agents")
|
|
678
|
+
self.console.print(" [b] Back to main menu")
|
|
676
679
|
self.console.print()
|
|
677
680
|
|
|
678
681
|
choice = Prompt.ask("[bold blue]Select an option[/bold blue]", default="b")
|
|
679
682
|
|
|
680
683
|
if choice == "1":
|
|
681
|
-
#
|
|
682
|
-
self.
|
|
683
|
-
self._display_header()
|
|
684
|
-
wizard.list_available_skills()
|
|
685
|
-
Prompt.ask("\nPress Enter to continue")
|
|
684
|
+
# Install/Uninstall skills with category-based selection
|
|
685
|
+
self._manage_skill_installation()
|
|
686
686
|
|
|
687
687
|
elif choice == "2":
|
|
688
688
|
# Configure skills interactively
|
|
@@ -805,6 +805,391 @@ class ConfigureCommand(BaseCommand):
|
|
|
805
805
|
self.console.print("[red]Invalid choice. Please try again.[/red]")
|
|
806
806
|
Prompt.ask("\nPress Enter to continue")
|
|
807
807
|
|
|
808
|
+
def _manage_skill_installation(self) -> None:
|
|
809
|
+
"""Manage skill installation with category-based questionary checkbox selection."""
|
|
810
|
+
import questionary
|
|
811
|
+
|
|
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
|
|
820
|
+
|
|
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
|
|
843
|
+
|
|
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
|
+
}
|
|
861
|
+
|
|
862
|
+
# Sort categories: universal first, then alphabetically
|
|
863
|
+
categories = sorted(grouped.keys(), key=lambda x: (x != "universal", x))
|
|
864
|
+
|
|
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
|
+
)
|
|
873
|
+
|
|
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"))
|
|
882
|
+
|
|
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
|
|
889
|
+
|
|
890
|
+
# Show skills in category with checkbox selection
|
|
891
|
+
category_skills = grouped[selected_cat]
|
|
892
|
+
|
|
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]
|
|
899
|
+
|
|
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
|
+
)
|
|
1099
|
+
|
|
1100
|
+
def _get_deployed_skill_ids(self) -> set:
|
|
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
|
+
"""
|
|
1106
|
+
from pathlib import Path
|
|
1107
|
+
|
|
1108
|
+
skills_dir = Path.cwd() / ".claude" / "skills"
|
|
1109
|
+
if not skills_dir.exists():
|
|
1110
|
+
return set()
|
|
1111
|
+
|
|
1112
|
+
# Each deployed skill is a directory in .claude/skills/
|
|
1113
|
+
deployed_ids = set()
|
|
1114
|
+
for skill_dir in skills_dir.iterdir():
|
|
1115
|
+
if skill_dir.is_dir() and not skill_dir.name.startswith("."):
|
|
1116
|
+
# Add both the directory name and common variations
|
|
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))
|
|
1121
|
+
|
|
1122
|
+
return deployed_ids
|
|
1123
|
+
|
|
1124
|
+
def _install_skill(self, skill) -> None:
|
|
1125
|
+
"""Install a skill to .claude/skills/ directory."""
|
|
1126
|
+
import shutil
|
|
1127
|
+
from pathlib import Path
|
|
1128
|
+
|
|
1129
|
+
# Target directory
|
|
1130
|
+
target_dir = Path.cwd() / ".claude" / "skills" / skill.skill_id
|
|
1131
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
1132
|
+
|
|
1133
|
+
# Copy skill file(s)
|
|
1134
|
+
if skill.path.is_file():
|
|
1135
|
+
# Single file skill - copy to skill.md in target directory
|
|
1136
|
+
shutil.copy2(skill.path, target_dir / "skill.md")
|
|
1137
|
+
elif skill.path.is_dir():
|
|
1138
|
+
# Directory-based skill - copy all contents
|
|
1139
|
+
for item in skill.path.iterdir():
|
|
1140
|
+
if item.is_file():
|
|
1141
|
+
shutil.copy2(item, target_dir / item.name)
|
|
1142
|
+
elif item.is_dir():
|
|
1143
|
+
shutil.copytree(item, target_dir / item.name, dirs_exist_ok=True)
|
|
1144
|
+
|
|
1145
|
+
def _uninstall_skill(self, skill) -> None:
|
|
1146
|
+
"""Uninstall a skill from .claude/skills/ directory."""
|
|
1147
|
+
import shutil
|
|
1148
|
+
from pathlib import Path
|
|
1149
|
+
|
|
1150
|
+
target_dir = Path.cwd() / ".claude" / "skills" / skill.skill_id
|
|
1151
|
+
if target_dir.exists():
|
|
1152
|
+
shutil.rmtree(target_dir)
|
|
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
|
+
|
|
808
1193
|
def _display_behavior_files(self) -> None:
|
|
809
1194
|
"""Display current behavior files."""
|
|
810
1195
|
self.behavior_manager.display_behavior_files()
|
|
@@ -1437,18 +1822,20 @@ class ConfigureCommand(BaseCommand):
|
|
|
1437
1822
|
|
|
1438
1823
|
# Add inline control: Select/Deselect all from this collection
|
|
1439
1824
|
if all_selected:
|
|
1825
|
+
deselect_value = f"__DESELECT_ALL_{collection_id}__"
|
|
1440
1826
|
choices.append(
|
|
1441
1827
|
Choice(
|
|
1442
|
-
f" [Deselect all from {collection_id}]",
|
|
1443
|
-
value=
|
|
1828
|
+
f" [Deselect all from {collection_id}]", # nosec B608
|
|
1829
|
+
value=deselect_value,
|
|
1444
1830
|
checked=False,
|
|
1445
1831
|
)
|
|
1446
1832
|
)
|
|
1447
1833
|
else:
|
|
1834
|
+
select_value = f"__SELECT_ALL_{collection_id}__"
|
|
1448
1835
|
choices.append(
|
|
1449
1836
|
Choice(
|
|
1450
|
-
f" [Select all from {collection_id}]",
|
|
1451
|
-
value=
|
|
1837
|
+
f" [Select all from {collection_id}]", # nosec B608
|
|
1838
|
+
value=select_value,
|
|
1452
1839
|
checked=False,
|
|
1453
1840
|
)
|
|
1454
1841
|
)
|
|
@@ -2329,7 +2716,8 @@ class ConfigureCommand(BaseCommand):
|
|
|
2329
2716
|
f" Detection Quality: [{'green' if summary.get('detection_quality') == 'high' else 'yellow'}]{summary.get('detection_quality', 'unknown')}[/]"
|
|
2330
2717
|
)
|
|
2331
2718
|
self.console.print()
|
|
2332
|
-
except Exception:
|
|
2719
|
+
except Exception: # nosec B110 - Suppress broad except for failed safety check
|
|
2720
|
+
# Silent failure on safety check - non-critical feature
|
|
2333
2721
|
pass
|
|
2334
2722
|
|
|
2335
2723
|
# Build mapping: agent_id -> AgentConfig
|
|
@@ -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
|