claude-mpm 5.4.70__py3-none-any.whl → 5.4.73__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/__init__.py +5 -1
- claude_mpm/cli/commands/agents.py +2 -4
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/skills.py +166 -14
- claude_mpm/cli/executor.py +1 -0
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +30 -50
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/base_parser.py +5 -0
- claude_mpm/cli/startup.py +17 -8
- claude_mpm/constants.py +1 -0
- claude_mpm/core/unified_config.py +33 -8
- claude_mpm/services/agents/deployment/deployment_reconciler.py +539 -0
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/startup_sync.py +5 -2
- claude_mpm/utils/agent_dependency_loader.py +4 -2
- claude_mpm/utils/robust_installer.py +10 -6
- {claude_mpm-5.4.70.dist-info → claude_mpm-5.4.73.dist-info}/METADATA +1 -1
- {claude_mpm-5.4.70.dist-info → claude_mpm-5.4.73.dist-info}/RECORD +26 -21
- {claude_mpm-5.4.70.dist-info → claude_mpm-5.4.73.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.70.dist-info → claude_mpm-5.4.73.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.70.dist-info → claude_mpm-5.4.73.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.70.dist-info → claude_mpm-5.4.73.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.70.dist-info → claude_mpm-5.4.73.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.4.
|
|
1
|
+
5.4.71
|
claude_mpm/cli/__init__.py
CHANGED
|
@@ -91,7 +91,11 @@ def main(argv: Optional[list] = None):
|
|
|
91
91
|
)
|
|
92
92
|
|
|
93
93
|
try:
|
|
94
|
-
|
|
94
|
+
# Check for --force-sync flag or environment variable
|
|
95
|
+
force_sync = getattr(args, "force_sync", False) or os.environ.get(
|
|
96
|
+
"CLAUDE_MPM_FORCE_SYNC", "0"
|
|
97
|
+
) in ("1", "true", "True", "yes")
|
|
98
|
+
run_background_services(force_sync=force_sync)
|
|
95
99
|
launch_progress.finish(message="Ready")
|
|
96
100
|
|
|
97
101
|
# Inform user about Claude Code initialization delay (3-5 seconds)
|
|
@@ -1379,7 +1379,7 @@ class AgentsCommand(AgentCommand):
|
|
|
1379
1379
|
return CommandResult.error_result("agent_id is required")
|
|
1380
1380
|
|
|
1381
1381
|
import os
|
|
1382
|
-
import subprocess
|
|
1382
|
+
import subprocess # nosec B404
|
|
1383
1383
|
|
|
1384
1384
|
from ...services.agents.local_template_manager import (
|
|
1385
1385
|
LocalAgentTemplateManager,
|
|
@@ -1415,7 +1415,7 @@ class AgentsCommand(AgentCommand):
|
|
|
1415
1415
|
|
|
1416
1416
|
# Use system editor
|
|
1417
1417
|
editor = getattr(args, "editor", None) or os.environ.get("EDITOR", "nano")
|
|
1418
|
-
subprocess.run([editor, str(template_file)], check=True)
|
|
1418
|
+
subprocess.run([editor, str(template_file)], check=True) # nosec B603
|
|
1419
1419
|
return CommandResult.success_result(
|
|
1420
1420
|
f"Agent '{agent_id}' edited successfully"
|
|
1421
1421
|
)
|
|
@@ -1519,8 +1519,6 @@ class AgentsCommand(AgentCommand):
|
|
|
1519
1519
|
console.print("For a better experience with integrated configuration:")
|
|
1520
1520
|
console.print(" • Agent management")
|
|
1521
1521
|
console.print(" • Skills management")
|
|
1522
|
-
console.print(" • Template editing")
|
|
1523
|
-
console.print(" • Behavior configuration")
|
|
1524
1522
|
console.print(" • Startup settings\n")
|
|
1525
1523
|
|
|
1526
1524
|
console.print("Please use: [bold green]claude-mpm config[/bold green]\n")
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent/Skill Reconciliation CLI Command
|
|
3
|
+
|
|
4
|
+
Shows the reconciliation view between configured and deployed agents/skills,
|
|
5
|
+
and performs reconciliation (deploy missing, remove unneeded).
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
claude-mpm agents reconcile [--dry-run] [--show-only]
|
|
9
|
+
claude-mpm skills reconcile [--dry-run] [--show-only]
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.table import Table
|
|
16
|
+
|
|
17
|
+
from ...core.unified_config import UnifiedConfig
|
|
18
|
+
from ...services.agents.deployment.deployment_reconciler import (
|
|
19
|
+
DeploymentReconciler,
|
|
20
|
+
ReconciliationState,
|
|
21
|
+
)
|
|
22
|
+
from ..shared import BaseCommand, CommandResult
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AgentsReconcileCommand(BaseCommand):
|
|
26
|
+
"""CLI command for agent reconciliation."""
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
super().__init__("agents-reconcile")
|
|
30
|
+
self.console = Console()
|
|
31
|
+
|
|
32
|
+
def run(self, args) -> CommandResult:
|
|
33
|
+
"""Execute reconciliation."""
|
|
34
|
+
# Load config
|
|
35
|
+
config = UnifiedConfig()
|
|
36
|
+
reconciler = DeploymentReconciler(config)
|
|
37
|
+
|
|
38
|
+
# Get project path
|
|
39
|
+
project_path = Path(getattr(args, "project_path", "."))
|
|
40
|
+
|
|
41
|
+
# Show current state
|
|
42
|
+
if getattr(args, "show_only", False) or getattr(args, "dry_run", False):
|
|
43
|
+
return self._show_reconciliation_view(reconciler, project_path)
|
|
44
|
+
|
|
45
|
+
# Perform reconciliation
|
|
46
|
+
return self._reconcile_agents(reconciler, project_path)
|
|
47
|
+
|
|
48
|
+
def _show_reconciliation_view(
|
|
49
|
+
self, reconciler: DeploymentReconciler, project_path: Path
|
|
50
|
+
) -> CommandResult:
|
|
51
|
+
"""Show reconciliation view without making changes."""
|
|
52
|
+
view = reconciler.get_reconciliation_view(project_path)
|
|
53
|
+
agent_state = view["agents"]
|
|
54
|
+
skill_state = view["skills"]
|
|
55
|
+
|
|
56
|
+
# Display agents table
|
|
57
|
+
self.console.print(
|
|
58
|
+
"\n[bold blue]═══ Agent Reconciliation View ═══[/bold blue]\n"
|
|
59
|
+
)
|
|
60
|
+
agent_table = self._build_reconciliation_table(agent_state, "Agent")
|
|
61
|
+
self.console.print(agent_table)
|
|
62
|
+
|
|
63
|
+
# Display skills table
|
|
64
|
+
self.console.print(
|
|
65
|
+
"\n[bold blue]═══ Skill Reconciliation View ═══[/bold blue]\n"
|
|
66
|
+
)
|
|
67
|
+
skill_table = self._build_reconciliation_table(skill_state, "Skill")
|
|
68
|
+
self.console.print(skill_table)
|
|
69
|
+
|
|
70
|
+
# Show summary
|
|
71
|
+
self._show_summary(agent_state, skill_state)
|
|
72
|
+
|
|
73
|
+
return CommandResult.success_result("Reconciliation view displayed")
|
|
74
|
+
|
|
75
|
+
def _build_reconciliation_table(
|
|
76
|
+
self, state: ReconciliationState, item_type: str
|
|
77
|
+
) -> Table:
|
|
78
|
+
"""Build Rich table for reconciliation state."""
|
|
79
|
+
table = Table(title=f"{item_type} Deployment Status")
|
|
80
|
+
|
|
81
|
+
table.add_column(f"{item_type}", style="cyan", no_wrap=True)
|
|
82
|
+
table.add_column("Configured", style="green")
|
|
83
|
+
table.add_column("Deployed", style="yellow")
|
|
84
|
+
table.add_column("Action", style="magenta")
|
|
85
|
+
|
|
86
|
+
# All items to consider
|
|
87
|
+
all_items = state.configured | state.deployed | state.cached
|
|
88
|
+
|
|
89
|
+
for item_id in sorted(all_items):
|
|
90
|
+
configured = "✓" if item_id in state.configured else "✗"
|
|
91
|
+
deployed = "✓" if item_id in state.deployed else "✗"
|
|
92
|
+
|
|
93
|
+
# Determine action
|
|
94
|
+
if item_id in state.to_deploy:
|
|
95
|
+
if item_id in state.cached:
|
|
96
|
+
action = "Will deploy"
|
|
97
|
+
else:
|
|
98
|
+
action = "[red]Missing in cache![/red]"
|
|
99
|
+
elif item_id in state.to_remove:
|
|
100
|
+
action = "Will remove"
|
|
101
|
+
elif item_id in state.unchanged:
|
|
102
|
+
action = "-"
|
|
103
|
+
elif item_id in state.cached and item_id not in state.configured:
|
|
104
|
+
action = "[dim]Available (not configured)[/dim]"
|
|
105
|
+
else:
|
|
106
|
+
action = "-"
|
|
107
|
+
|
|
108
|
+
table.add_row(item_id, configured, deployed, action)
|
|
109
|
+
|
|
110
|
+
return table
|
|
111
|
+
|
|
112
|
+
def _show_summary(
|
|
113
|
+
self, agent_state: ReconciliationState, skill_state: ReconciliationState
|
|
114
|
+
) -> None:
|
|
115
|
+
"""Show reconciliation summary."""
|
|
116
|
+
self.console.print("\n[bold]Summary:[/bold]")
|
|
117
|
+
|
|
118
|
+
# Agents
|
|
119
|
+
self.console.print("\nAgents:")
|
|
120
|
+
self.console.print(f" Configured: {len(agent_state.configured)}")
|
|
121
|
+
self.console.print(f" Deployed: {len(agent_state.deployed)}")
|
|
122
|
+
self.console.print(f" To deploy: {len(agent_state.to_deploy)}")
|
|
123
|
+
self.console.print(f" To remove: {len(agent_state.to_remove)}")
|
|
124
|
+
self.console.print(f" Unchanged: {len(agent_state.unchanged)}")
|
|
125
|
+
|
|
126
|
+
# Skills
|
|
127
|
+
self.console.print("\nSkills:")
|
|
128
|
+
self.console.print(f" Configured: {len(skill_state.configured)}")
|
|
129
|
+
self.console.print(f" Deployed: {len(skill_state.deployed)}")
|
|
130
|
+
self.console.print(f" To deploy: {len(skill_state.to_deploy)}")
|
|
131
|
+
self.console.print(f" To remove: {len(skill_state.to_remove)}")
|
|
132
|
+
self.console.print(f" Unchanged: {len(skill_state.unchanged)}")
|
|
133
|
+
|
|
134
|
+
# Show next steps
|
|
135
|
+
if agent_state.to_deploy or skill_state.to_deploy:
|
|
136
|
+
self.console.print(
|
|
137
|
+
"\n[yellow]Run without --show-only to perform deployment[/yellow]"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def _reconcile_agents(
|
|
141
|
+
self, reconciler: DeploymentReconciler, project_path: Path
|
|
142
|
+
) -> CommandResult:
|
|
143
|
+
"""Perform agent and skill reconciliation."""
|
|
144
|
+
# Show current state first
|
|
145
|
+
self._show_reconciliation_view(reconciler, project_path)
|
|
146
|
+
|
|
147
|
+
self.console.print("\n[bold blue]Performing reconciliation...[/bold blue]\n")
|
|
148
|
+
|
|
149
|
+
# Reconcile agents
|
|
150
|
+
self.console.print("[cyan]Reconciling agents...[/cyan]")
|
|
151
|
+
agent_result = reconciler.reconcile_agents(project_path)
|
|
152
|
+
|
|
153
|
+
if agent_result.deployed:
|
|
154
|
+
self.console.print(
|
|
155
|
+
f" [green]✓ Deployed: {', '.join(agent_result.deployed)}[/green]"
|
|
156
|
+
)
|
|
157
|
+
if agent_result.removed:
|
|
158
|
+
self.console.print(
|
|
159
|
+
f" [yellow]✓ Removed: {', '.join(agent_result.removed)}[/yellow]"
|
|
160
|
+
)
|
|
161
|
+
if agent_result.errors:
|
|
162
|
+
for error in agent_result.errors:
|
|
163
|
+
self.console.print(f" [red]✗ {error}[/red]")
|
|
164
|
+
|
|
165
|
+
# Reconcile skills
|
|
166
|
+
self.console.print("\n[cyan]Reconciling skills...[/cyan]")
|
|
167
|
+
skill_result = reconciler.reconcile_skills(project_path)
|
|
168
|
+
|
|
169
|
+
if skill_result.deployed:
|
|
170
|
+
self.console.print(
|
|
171
|
+
f" [green]✓ Deployed: {', '.join(skill_result.deployed)}[/green]"
|
|
172
|
+
)
|
|
173
|
+
if skill_result.removed:
|
|
174
|
+
self.console.print(
|
|
175
|
+
f" [yellow]✓ Removed: {', '.join(skill_result.removed)}[/yellow]"
|
|
176
|
+
)
|
|
177
|
+
if skill_result.errors:
|
|
178
|
+
for error in skill_result.errors:
|
|
179
|
+
self.console.print(f" [red]✗ {error}[/red]")
|
|
180
|
+
|
|
181
|
+
# Final summary
|
|
182
|
+
total_errors = len(agent_result.errors) + len(skill_result.errors)
|
|
183
|
+
if total_errors == 0:
|
|
184
|
+
self.console.print("\n[bold green]✓ Reconciliation complete![/bold green]")
|
|
185
|
+
return CommandResult.success_result("Reconciliation successful")
|
|
186
|
+
self.console.print(
|
|
187
|
+
f"\n[bold yellow]⚠ Reconciliation complete with {total_errors} errors[/bold yellow]"
|
|
188
|
+
)
|
|
189
|
+
return CommandResult.error_result(f"Reconciliation had {total_errors} errors")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class SkillsReconcileCommand(AgentsReconcileCommand):
|
|
193
|
+
"""CLI command for skill reconciliation (alias to agents reconcile)."""
|
|
194
|
+
|
|
195
|
+
def __init__(self):
|
|
196
|
+
BaseCommand.__init__(self, "skills-reconcile")
|
|
197
|
+
self.console = Console()
|
|
@@ -18,7 +18,7 @@ ARCHITECTURE:
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
import os
|
|
21
|
-
import subprocess
|
|
21
|
+
import subprocess # nosec B404
|
|
22
22
|
from typing import Optional
|
|
23
23
|
|
|
24
24
|
from rich.console import Console
|
|
@@ -84,6 +84,7 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
84
84
|
SkillsCommands.INFO.value: self._show_skill_info,
|
|
85
85
|
SkillsCommands.CONFIG.value: self._manage_config,
|
|
86
86
|
SkillsCommands.CONFIGURE.value: self._configure_skills,
|
|
87
|
+
SkillsCommands.SELECT.value: self._select_skills_interactive,
|
|
87
88
|
# GitHub deployment commands
|
|
88
89
|
SkillsCommands.DEPLOY_FROM_GITHUB.value: self._deploy_from_github,
|
|
89
90
|
SkillsCommands.LIST_AVAILABLE.value: self._list_available_github_skills,
|
|
@@ -504,7 +505,7 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
504
505
|
# Open in editor
|
|
505
506
|
editor = os.environ.get("EDITOR", "nano")
|
|
506
507
|
try:
|
|
507
|
-
subprocess.run([editor, str(config_path)], check=True)
|
|
508
|
+
subprocess.run([editor, str(config_path)], check=True) # nosec B603
|
|
508
509
|
console.print(
|
|
509
510
|
f"\n[green]Configuration saved to {config_path}[/green]\n"
|
|
510
511
|
)
|
|
@@ -673,33 +674,91 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
673
674
|
def _check_deployed_skills(self, args) -> CommandResult:
|
|
674
675
|
"""Check currently deployed skills in ~/.claude/skills/."""
|
|
675
676
|
try:
|
|
676
|
-
|
|
677
|
+
# Get deployed skills
|
|
678
|
+
deployed_result = self.skills_deployer.check_deployed_skills()
|
|
679
|
+
deployed_names = {skill["name"] for skill in deployed_result["skills"]}
|
|
677
680
|
|
|
678
681
|
console.print("\n[bold cyan]Claude Code Skills Status:[/bold cyan]\n")
|
|
679
|
-
console.print(
|
|
682
|
+
console.print(
|
|
683
|
+
f"[dim]Directory: {deployed_result['claude_skills_dir']}[/dim]\n"
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
# Fetch available skills from GitHub to get full list
|
|
687
|
+
try:
|
|
688
|
+
available_result = self.skills_deployer.list_available_skills()
|
|
689
|
+
all_skills = available_result.get("skills", [])
|
|
690
|
+
except Exception as e:
|
|
691
|
+
console.print(
|
|
692
|
+
f"[yellow]Warning: Could not fetch available skills: {e}[/yellow]\n"
|
|
693
|
+
)
|
|
694
|
+
all_skills = []
|
|
680
695
|
|
|
681
|
-
|
|
682
|
-
|
|
696
|
+
# Combine deployed and available skills
|
|
697
|
+
skill_map = {}
|
|
698
|
+
|
|
699
|
+
# Add available skills
|
|
700
|
+
for skill in all_skills:
|
|
701
|
+
skill_name = skill.get("name", "")
|
|
702
|
+
if skill_name:
|
|
703
|
+
skill_map[skill_name] = {
|
|
704
|
+
"name": skill.get("display_name")
|
|
705
|
+
or skill_name.replace("-", " ").title(),
|
|
706
|
+
"skill_id": skill_name,
|
|
707
|
+
"source": "MPM Skills",
|
|
708
|
+
"is_deployed": skill_name in deployed_names,
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
# Add any deployed skills not in available list (local/custom skills)
|
|
712
|
+
for skill in deployed_result["skills"]:
|
|
713
|
+
skill_name = skill["name"]
|
|
714
|
+
if skill_name not in skill_map:
|
|
715
|
+
skill_map[skill_name] = {
|
|
716
|
+
"name": skill_name.replace("-", " ").title(),
|
|
717
|
+
"skill_id": skill_name,
|
|
718
|
+
"source": "Local",
|
|
719
|
+
"is_deployed": True,
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if not skill_map:
|
|
723
|
+
console.print("[yellow]No skills available.[/yellow]")
|
|
683
724
|
console.print(
|
|
684
725
|
"[dim]Use 'claude-mpm skills deploy-github' to deploy skills.[/dim]\n"
|
|
685
726
|
)
|
|
686
727
|
return CommandResult(success=True, exit_code=0)
|
|
687
728
|
|
|
688
|
-
|
|
689
|
-
|
|
729
|
+
# Create table matching agent management format
|
|
730
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
731
|
+
table.add_column("#", style="bright_black", width=6, no_wrap=True)
|
|
732
|
+
table.add_column(
|
|
733
|
+
"Skill ID", style="bright_black", no_wrap=True, overflow="ellipsis"
|
|
690
734
|
)
|
|
735
|
+
table.add_column(
|
|
736
|
+
"Name", style="bright_cyan", no_wrap=True, overflow="ellipsis"
|
|
737
|
+
)
|
|
738
|
+
table.add_column("Source", style="bright_yellow", no_wrap=True)
|
|
739
|
+
table.add_column("Status", style="bright_black", no_wrap=True)
|
|
691
740
|
|
|
692
|
-
#
|
|
693
|
-
|
|
694
|
-
table.add_column("Skill Name", style="green")
|
|
695
|
-
table.add_column("Path", style="dim")
|
|
741
|
+
# Sort skills by name for consistent display
|
|
742
|
+
sorted_skills = sorted(skill_map.values(), key=lambda s: s["skill_id"])
|
|
696
743
|
|
|
697
|
-
for skill in
|
|
698
|
-
|
|
744
|
+
for idx, skill in enumerate(sorted_skills, 1):
|
|
745
|
+
status = (
|
|
746
|
+
"[green]Installed[/green]" if skill["is_deployed"] else "Available"
|
|
747
|
+
)
|
|
748
|
+
table.add_row(
|
|
749
|
+
str(idx), skill["skill_id"], skill["name"], skill["source"], status
|
|
750
|
+
)
|
|
699
751
|
|
|
700
752
|
console.print(table)
|
|
701
753
|
console.print()
|
|
702
754
|
|
|
755
|
+
# Show summary
|
|
756
|
+
deployed_count = sum(1 for s in skill_map.values() if s["is_deployed"])
|
|
757
|
+
console.print(
|
|
758
|
+
f"[dim]Showing {len(skill_map)} skills ({deployed_count} installed, "
|
|
759
|
+
f"{len(skill_map) - deployed_count} available)[/dim]\n"
|
|
760
|
+
)
|
|
761
|
+
|
|
703
762
|
return CommandResult(success=True, exit_code=0)
|
|
704
763
|
|
|
705
764
|
except Exception as e:
|
|
@@ -1222,6 +1281,99 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
1222
1281
|
console.print(f"[dim]{traceback.format_exc()}[/dim]")
|
|
1223
1282
|
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
1224
1283
|
|
|
1284
|
+
def _select_skills_interactive(self, args) -> CommandResult:
|
|
1285
|
+
"""Interactive skill selection with topic grouping.
|
|
1286
|
+
|
|
1287
|
+
This command provides a two-tier selection interface:
|
|
1288
|
+
1. Select topic groups (toolchains) to explore
|
|
1289
|
+
2. Multi-select skills within each topic group
|
|
1290
|
+
|
|
1291
|
+
Features:
|
|
1292
|
+
- Groups skills by toolchain (universal, python, typescript, etc.)
|
|
1293
|
+
- Shows skills auto-included by agent dependencies
|
|
1294
|
+
- Displays token counts for each skill
|
|
1295
|
+
- Updates config and runs reconciliation
|
|
1296
|
+
|
|
1297
|
+
Returns:
|
|
1298
|
+
CommandResult with success/failure status
|
|
1299
|
+
"""
|
|
1300
|
+
try:
|
|
1301
|
+
from ...cli.interactive.skill_selector import run_skill_selector
|
|
1302
|
+
from ...core.unified_config import UnifiedConfig
|
|
1303
|
+
from ...services.agents.deployment.deployment_reconciler import (
|
|
1304
|
+
DeploymentReconciler,
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
console.print("\n[bold cyan]Interactive Skill Selector[/bold cyan]\n")
|
|
1308
|
+
|
|
1309
|
+
# Run skill selector
|
|
1310
|
+
selected_skills = run_skill_selector()
|
|
1311
|
+
|
|
1312
|
+
if selected_skills is None:
|
|
1313
|
+
console.print("\n[yellow]Skill selection cancelled[/yellow]")
|
|
1314
|
+
return CommandResult(success=True, exit_code=0)
|
|
1315
|
+
|
|
1316
|
+
# Update config with selected skills
|
|
1317
|
+
config = UnifiedConfig()
|
|
1318
|
+
config.skills.enabled = selected_skills
|
|
1319
|
+
|
|
1320
|
+
# Save config
|
|
1321
|
+
try:
|
|
1322
|
+
config.save()
|
|
1323
|
+
console.print(
|
|
1324
|
+
f"\n[green]✓ Saved {len(selected_skills)} skills to configuration[/green]"
|
|
1325
|
+
)
|
|
1326
|
+
except Exception as e:
|
|
1327
|
+
console.print(f"\n[red]Failed to save configuration: {e}[/red]")
|
|
1328
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
1329
|
+
|
|
1330
|
+
# Run reconciliation to deploy skills
|
|
1331
|
+
console.print("\n[cyan]Running skill reconciliation...[/cyan]")
|
|
1332
|
+
reconciler = DeploymentReconciler(config)
|
|
1333
|
+
|
|
1334
|
+
try:
|
|
1335
|
+
from pathlib import Path
|
|
1336
|
+
|
|
1337
|
+
project_path = Path.cwd()
|
|
1338
|
+
result = reconciler.reconcile_skills(project_path)
|
|
1339
|
+
|
|
1340
|
+
if result.deployed:
|
|
1341
|
+
console.print(
|
|
1342
|
+
f" [green]✓ Deployed: {', '.join(result.deployed)}[/green]"
|
|
1343
|
+
)
|
|
1344
|
+
if result.removed:
|
|
1345
|
+
console.print(
|
|
1346
|
+
f" [yellow]✓ Removed: {', '.join(result.removed)}[/yellow]"
|
|
1347
|
+
)
|
|
1348
|
+
if result.errors:
|
|
1349
|
+
for error in result.errors:
|
|
1350
|
+
console.print(f" [red]✗ {error}[/red]")
|
|
1351
|
+
|
|
1352
|
+
if result.success:
|
|
1353
|
+
console.print(
|
|
1354
|
+
"\n[bold green]✓ Skill deployment complete![/bold green]"
|
|
1355
|
+
)
|
|
1356
|
+
return CommandResult(success=True, exit_code=0)
|
|
1357
|
+
console.print(
|
|
1358
|
+
f"\n[yellow]⚠ Deployment had {len(result.errors)} errors[/yellow]"
|
|
1359
|
+
)
|
|
1360
|
+
return CommandResult(
|
|
1361
|
+
success=False,
|
|
1362
|
+
message=f"{len(result.errors)} deployment errors",
|
|
1363
|
+
exit_code=1,
|
|
1364
|
+
)
|
|
1365
|
+
|
|
1366
|
+
except Exception as e:
|
|
1367
|
+
console.print(f"\n[red]Reconciliation failed: {e}[/red]")
|
|
1368
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
1369
|
+
|
|
1370
|
+
except Exception as e:
|
|
1371
|
+
console.print(f"[red]Skill selection error: {e}[/red]")
|
|
1372
|
+
import traceback
|
|
1373
|
+
|
|
1374
|
+
console.print(f"[dim]{traceback.format_exc()}[/dim]")
|
|
1375
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
1376
|
+
|
|
1225
1377
|
|
|
1226
1378
|
def manage_skills(args) -> int:
|
|
1227
1379
|
"""
|
claude_mpm/cli/executor.py
CHANGED
|
@@ -66,6 +66,7 @@ def ensure_run_attributes(args):
|
|
|
66
66
|
args.monitor = getattr(args, "monitor", False)
|
|
67
67
|
args.force = getattr(args, "force", False)
|
|
68
68
|
args.reload_agents = getattr(args, "reload_agents", False)
|
|
69
|
+
args.force_sync = getattr(args, "force_sync", False)
|
|
69
70
|
# Include dependency checking attributes
|
|
70
71
|
args.check_dependencies = getattr(args, "check_dependencies", True)
|
|
71
72
|
args.force_check_dependencies = getattr(args, "force_check_dependencies", False)
|
|
@@ -10,12 +10,22 @@ from .agent_wizard import (
|
|
|
10
10
|
run_interactive_agent_manager,
|
|
11
11
|
run_interactive_agent_wizard,
|
|
12
12
|
)
|
|
13
|
+
from .questionary_styles import (
|
|
14
|
+
BANNER_WIDTH,
|
|
15
|
+
MPM_STYLE,
|
|
16
|
+
print_banner,
|
|
17
|
+
print_section_header,
|
|
18
|
+
)
|
|
13
19
|
from .skills_wizard import SkillsWizard, discover_and_link_runtime_skills
|
|
14
20
|
|
|
15
21
|
__all__ = [
|
|
22
|
+
"BANNER_WIDTH",
|
|
23
|
+
"MPM_STYLE",
|
|
16
24
|
"AgentWizard",
|
|
17
25
|
"SkillsWizard",
|
|
18
26
|
"discover_and_link_runtime_skills",
|
|
27
|
+
"print_banner",
|
|
28
|
+
"print_section_header",
|
|
19
29
|
"run_interactive_agent_manager",
|
|
20
30
|
"run_interactive_agent_wizard",
|
|
21
31
|
]
|