claude-mpm 5.4.64__py3-none-any.whl → 5.4.96__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md +405 -0
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +107 -1928
- claude_mpm/agents/PM_INSTRUCTIONS.md +82 -686
- 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/autotodos.py +526 -0
- claude_mpm/cli/commands/configure.py +620 -21
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +2 -2
- claude_mpm/cli/commands/skills.py +166 -14
- claude_mpm/cli/executor.py +89 -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 +59 -1
- claude_mpm/cli/startup.py +202 -367
- claude_mpm/cli/startup_display.py +72 -5
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/commands/mpm-session-resume.md +1 -1
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +2 -2
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +7 -7
- claude_mpm/core/output_style_manager.py +21 -13
- claude_mpm/core/unified_config.py +50 -8
- claude_mpm/core/unified_paths.py +30 -13
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +9 -9
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +486 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +216 -11
- claude_mpm/hooks/claude_hooks/hook_handler.py +28 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -1
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +20 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +30 -6
- claude_mpm/hooks/session_resume_hook.py +85 -1
- claude_mpm/init.py +1 -1
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/startup_sync.py +5 -2
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_log.py +317 -0
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -2
- claude_mpm/services/monitor/server.py +106 -16
- claude_mpm/services/pm_skills_deployer.py +177 -83
- claude_mpm/services/skills/git_skill_source_manager.py +5 -1
- claude_mpm/services/skills/selective_skill_deployer.py +114 -26
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/skill_manager.py +4 -4
- claude_mpm/utils/agent_dependency_loader.py +103 -4
- claude_mpm/utils/robust_installer.py +45 -24
- claude_mpm-5.4.96.dist-info/METADATA +377 -0
- {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/RECORD +153 -131
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
- claude_mpm-5.4.64.dist-info/METADATA +0 -999
- /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
- {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/top_level.txt +0 -0
|
@@ -118,7 +118,7 @@ class MonitorCommand(BaseCommand):
|
|
|
118
118
|
# Check if it's actually running
|
|
119
119
|
if not self.daemon.lifecycle.is_running():
|
|
120
120
|
return CommandResult.error_result(
|
|
121
|
-
"Monitor daemon failed to start. Check ~/.claude-mpm/monitor-daemon
|
|
121
|
+
"Monitor daemon failed to start. Check ~/.claude-mpm/logs/monitor-daemon-*.log for details."
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
# Get the actual PID
|
|
@@ -146,7 +146,7 @@ class MonitorCommand(BaseCommand):
|
|
|
146
146
|
pass
|
|
147
147
|
|
|
148
148
|
return CommandResult.error_result(
|
|
149
|
-
"Failed to start unified monitor daemon. Check ~/.claude-mpm/monitor-daemon
|
|
149
|
+
"Failed to start unified monitor daemon. Check ~/.claude-mpm/logs/monitor-daemon-*.log for details."
|
|
150
150
|
)
|
|
151
151
|
|
|
152
152
|
def _stop_monitor(self, args) -> CommandResult:
|
|
@@ -688,9 +688,9 @@ class MPMInitCommand:
|
|
|
688
688
|
return len(text) // 4
|
|
689
689
|
|
|
690
690
|
def _deploy_pm_skills(self) -> None:
|
|
691
|
-
"""Deploy PM skills templates to project .claude
|
|
691
|
+
"""Deploy PM skills templates to project .claude directory.
|
|
692
692
|
|
|
693
|
-
Copies PM skills from bundled templates to .claude
|
|
693
|
+
Copies PM skills from bundled templates to .claude/skills/
|
|
694
694
|
with version tracking and checksum validation.
|
|
695
695
|
"""
|
|
696
696
|
try:
|
|
@@ -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)
|
|
@@ -236,6 +237,92 @@ def execute_command(command: str, args) -> int:
|
|
|
236
237
|
print(f"Unknown hook-errors subcommand: {subcommand}")
|
|
237
238
|
return 1
|
|
238
239
|
|
|
240
|
+
# Handle autotodos command with lazy import
|
|
241
|
+
if command == "autotodos":
|
|
242
|
+
# Lazy import to avoid loading unless needed
|
|
243
|
+
from .commands.autotodos import (
|
|
244
|
+
clear_autotodos,
|
|
245
|
+
inject_autotodos,
|
|
246
|
+
list_autotodos,
|
|
247
|
+
list_pm_violations,
|
|
248
|
+
scan_delegation_patterns,
|
|
249
|
+
show_autotodos_status,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Get subcommand
|
|
253
|
+
subcommand = getattr(args, "autotodos_command", "status")
|
|
254
|
+
if not subcommand:
|
|
255
|
+
subcommand = "status"
|
|
256
|
+
|
|
257
|
+
# Map subcommands to functions
|
|
258
|
+
handlers = {
|
|
259
|
+
"list": list_autotodos,
|
|
260
|
+
"inject": inject_autotodos,
|
|
261
|
+
"clear": clear_autotodos,
|
|
262
|
+
"status": show_autotodos_status,
|
|
263
|
+
"scan": scan_delegation_patterns,
|
|
264
|
+
"violations": list_pm_violations,
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
# Get handler and call it with standalone_mode=False
|
|
268
|
+
handler = handlers.get(subcommand)
|
|
269
|
+
if handler:
|
|
270
|
+
try:
|
|
271
|
+
# Build argument list for Click command
|
|
272
|
+
click_args = []
|
|
273
|
+
|
|
274
|
+
if subcommand == "list":
|
|
275
|
+
fmt = getattr(args, "format", "table")
|
|
276
|
+
click_args = ["--format", fmt]
|
|
277
|
+
elif subcommand == "inject":
|
|
278
|
+
output = getattr(args, "output", None)
|
|
279
|
+
if output:
|
|
280
|
+
click_args = ["--output", output]
|
|
281
|
+
elif subcommand == "clear":
|
|
282
|
+
error_key = getattr(args, "error_key", None)
|
|
283
|
+
event_type = getattr(args, "event_type", "all")
|
|
284
|
+
if error_key:
|
|
285
|
+
click_args.append("--error-key")
|
|
286
|
+
click_args.append(error_key)
|
|
287
|
+
if event_type != "all":
|
|
288
|
+
click_args.append("--event-type")
|
|
289
|
+
click_args.append(event_type)
|
|
290
|
+
if getattr(args, "yes", False):
|
|
291
|
+
click_args.append("-y")
|
|
292
|
+
elif subcommand == "scan":
|
|
293
|
+
text = getattr(args, "text", None)
|
|
294
|
+
file = getattr(args, "file", None)
|
|
295
|
+
fmt = getattr(args, "format", "table")
|
|
296
|
+
save = getattr(args, "save", False)
|
|
297
|
+
|
|
298
|
+
if text:
|
|
299
|
+
click_args.append(text)
|
|
300
|
+
if file:
|
|
301
|
+
click_args.extend(["--file", file])
|
|
302
|
+
if fmt != "table":
|
|
303
|
+
click_args.extend(["--format", fmt])
|
|
304
|
+
if save:
|
|
305
|
+
click_args.append("--save")
|
|
306
|
+
elif subcommand == "violations":
|
|
307
|
+
fmt = getattr(args, "format", "table")
|
|
308
|
+
if fmt != "table":
|
|
309
|
+
click_args.extend(["--format", fmt])
|
|
310
|
+
|
|
311
|
+
# Call Click command with argument list and standalone_mode=False
|
|
312
|
+
handler(click_args, standalone_mode=False)
|
|
313
|
+
return 0
|
|
314
|
+
except SystemExit as e:
|
|
315
|
+
return e.code if e.code is not None else 0
|
|
316
|
+
except Exception as e:
|
|
317
|
+
print(f"Error: {e}")
|
|
318
|
+
import traceback
|
|
319
|
+
|
|
320
|
+
traceback.print_exc()
|
|
321
|
+
return 1
|
|
322
|
+
else:
|
|
323
|
+
print(f"Unknown autotodos subcommand: {subcommand}")
|
|
324
|
+
return 1
|
|
325
|
+
|
|
239
326
|
# Map stable commands to their implementations
|
|
240
327
|
command_map = {
|
|
241
328
|
CLICommands.RUN.value: run_session,
|
|
@@ -286,6 +373,8 @@ def execute_command(command: str, args) -> int:
|
|
|
286
373
|
"local-deploy",
|
|
287
374
|
"skill-source",
|
|
288
375
|
"agent-source",
|
|
376
|
+
"hook-errors",
|
|
377
|
+
"autotodos",
|
|
289
378
|
]
|
|
290
379
|
|
|
291
380
|
suggestion = suggest_similar_commands(command, all_commands)
|
|
@@ -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
|
]
|
|
@@ -12,8 +12,12 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Any, Dict, List, Optional, Tuple
|
|
13
13
|
|
|
14
14
|
import questionary
|
|
15
|
-
from questionary import Style
|
|
16
15
|
|
|
16
|
+
from claude_mpm.cli.interactive.questionary_styles import (
|
|
17
|
+
BANNER_WIDTH,
|
|
18
|
+
MPM_STYLE,
|
|
19
|
+
print_section_header,
|
|
20
|
+
)
|
|
17
21
|
from claude_mpm.core.logging_config import get_logger
|
|
18
22
|
from claude_mpm.services.agents.local_template_manager import (
|
|
19
23
|
LocalAgentTemplate,
|
|
@@ -23,16 +27,6 @@ from claude_mpm.utils.agent_filters import apply_all_filters
|
|
|
23
27
|
|
|
24
28
|
logger = get_logger(__name__)
|
|
25
29
|
|
|
26
|
-
# Questionary style matching Rich cyan theme (consistent with configure.py)
|
|
27
|
-
QUESTIONARY_STYLE = Style(
|
|
28
|
-
[
|
|
29
|
-
("selected", "fg:cyan bold"),
|
|
30
|
-
("pointer", "fg:cyan bold"),
|
|
31
|
-
("highlighted", "fg:cyan"),
|
|
32
|
-
("question", "fg:cyan bold"),
|
|
33
|
-
]
|
|
34
|
-
)
|
|
35
|
-
|
|
36
30
|
|
|
37
31
|
class AgentWizard:
|
|
38
32
|
"""
|
|
@@ -113,9 +107,7 @@ class AgentWizard:
|
|
|
113
107
|
Tuple of (success, message)
|
|
114
108
|
"""
|
|
115
109
|
try:
|
|
116
|
-
|
|
117
|
-
print("🧙♂️ Agent Creation Wizard")
|
|
118
|
-
print("=" * 60)
|
|
110
|
+
print_section_header("🧙♂️", "Agent Creation Wizard", width=BANNER_WIDTH)
|
|
119
111
|
print("\nI'll guide you through creating a custom local agent.")
|
|
120
112
|
print("Press Ctrl+C anytime to cancel.\n")
|
|
121
113
|
|
|
@@ -281,9 +273,7 @@ class AgentWizard:
|
|
|
281
273
|
# Get merged agents from all sources
|
|
282
274
|
all_agents = self._merge_agent_sources()
|
|
283
275
|
|
|
284
|
-
|
|
285
|
-
print("🔧 Agent Management Menu")
|
|
286
|
-
print("=" * 60)
|
|
276
|
+
print_section_header("🔧", "Agent Management Menu", width=BANNER_WIDTH)
|
|
287
277
|
|
|
288
278
|
if not all_agents:
|
|
289
279
|
print(
|
|
@@ -384,7 +374,7 @@ class AgentWizard:
|
|
|
384
374
|
choice = questionary.select(
|
|
385
375
|
"Agent Management Menu:",
|
|
386
376
|
choices=menu_choices,
|
|
387
|
-
style=
|
|
377
|
+
style=MPM_STYLE,
|
|
388
378
|
).ask()
|
|
389
379
|
|
|
390
380
|
if not choice: # User pressed Esc
|
|
@@ -776,9 +766,7 @@ class AgentWizard:
|
|
|
776
766
|
|
|
777
767
|
def _confirm_creation(self, config: Dict[str, Any]) -> bool:
|
|
778
768
|
"""Show preview and get confirmation from user."""
|
|
779
|
-
|
|
780
|
-
print("📋 Agent Configuration Preview")
|
|
781
|
-
print("=" * 60)
|
|
769
|
+
print_section_header("📋", "Agent Configuration Preview", width=BANNER_WIDTH)
|
|
782
770
|
|
|
783
771
|
print(f"Agent ID: {config['agent_id']}")
|
|
784
772
|
print(f"Name: {config['name']}")
|
|
@@ -795,7 +783,8 @@ class AgentWizard:
|
|
|
795
783
|
print("\nInstructions Preview:")
|
|
796
784
|
print(f" {config['instructions_preview']}")
|
|
797
785
|
|
|
798
|
-
print(
|
|
786
|
+
print()
|
|
787
|
+
print("=" * BANNER_WIDTH)
|
|
799
788
|
|
|
800
789
|
while True:
|
|
801
790
|
confirm = input("\nCreate this agent? [Y/n]: ").strip().lower()
|
|
@@ -1046,8 +1035,7 @@ class AgentWizard:
|
|
|
1046
1035
|
|
|
1047
1036
|
def _interactive_delete_menu(self, templates: list) -> Tuple[bool, str]:
|
|
1048
1037
|
"""Interactive deletion menu for multiple agents."""
|
|
1049
|
-
|
|
1050
|
-
print("=" * 50)
|
|
1038
|
+
print_section_header("🗑️", "Delete Agents", width=BANNER_WIDTH)
|
|
1051
1039
|
|
|
1052
1040
|
if not templates:
|
|
1053
1041
|
return False, "No agents available to delete"
|
|
@@ -1154,9 +1142,9 @@ class AgentWizard:
|
|
|
1154
1142
|
Args:
|
|
1155
1143
|
agent: Agent metadata dictionary
|
|
1156
1144
|
"""
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1145
|
+
print_section_header(
|
|
1146
|
+
"📄", f"Agent Details: {agent['agent_id']}", width=BANNER_WIDTH
|
|
1147
|
+
)
|
|
1160
1148
|
print(f"Name: {agent['name']}")
|
|
1161
1149
|
print(f"Category: {agent['category'] or 'N/A'}")
|
|
1162
1150
|
print(f"Source: [{agent['source_type']}] {agent['source_identifier']}")
|
|
@@ -1188,9 +1176,7 @@ class AgentWizard:
|
|
|
1188
1176
|
input("\nPress Enter to continue...")
|
|
1189
1177
|
return
|
|
1190
1178
|
|
|
1191
|
-
|
|
1192
|
-
print("📦 Deploy Agent")
|
|
1193
|
-
print("=" * 60)
|
|
1179
|
+
print_section_header("📦", "Deploy Agent", width=BANNER_WIDTH)
|
|
1194
1180
|
print(f"\n{len(deployable)} agent(s) available to deploy:\n")
|
|
1195
1181
|
|
|
1196
1182
|
# Build agent selection choices with arrow-key navigation
|
|
@@ -1200,7 +1186,7 @@ class AgentWizard:
|
|
|
1200
1186
|
]
|
|
1201
1187
|
|
|
1202
1188
|
choice = questionary.select(
|
|
1203
|
-
"Select agent to deploy:", choices=agent_choices, style=
|
|
1189
|
+
"Select agent to deploy:", choices=agent_choices, style=MPM_STYLE
|
|
1204
1190
|
).ask()
|
|
1205
1191
|
|
|
1206
1192
|
if not choice: # User pressed Esc
|
|
@@ -1296,9 +1282,7 @@ class AgentWizard:
|
|
|
1296
1282
|
return
|
|
1297
1283
|
|
|
1298
1284
|
while True:
|
|
1299
|
-
|
|
1300
|
-
print("🔍 Browse & Filter Agents")
|
|
1301
|
-
print("=" * 60)
|
|
1285
|
+
print_section_header("🔍", "Browse & Filter Agents", width=BANNER_WIDTH)
|
|
1302
1286
|
|
|
1303
1287
|
# Show filter menu with arrow-key navigation
|
|
1304
1288
|
print("\n[bold]Filter by:[/bold]")
|
|
@@ -1314,7 +1298,7 @@ class AgentWizard:
|
|
|
1314
1298
|
choice = questionary.select(
|
|
1315
1299
|
"Browse & Filter Agents:",
|
|
1316
1300
|
choices=filter_choices,
|
|
1317
|
-
style=
|
|
1301
|
+
style=MPM_STYLE,
|
|
1318
1302
|
).ask()
|
|
1319
1303
|
|
|
1320
1304
|
if not choice or "Back" in choice:
|
|
@@ -1343,7 +1327,7 @@ class AgentWizard:
|
|
|
1343
1327
|
cat_choices = [f"{idx}. {cat}" for idx, cat in enumerate(categories, 1)]
|
|
1344
1328
|
|
|
1345
1329
|
cat_choice = questionary.select(
|
|
1346
|
-
"Select category:", choices=cat_choices, style=
|
|
1330
|
+
"Select category:", choices=cat_choices, style=MPM_STYLE
|
|
1347
1331
|
).ask()
|
|
1348
1332
|
|
|
1349
1333
|
if not cat_choice: # User pressed Esc
|
|
@@ -1457,9 +1441,11 @@ class AgentWizard:
|
|
|
1457
1441
|
continue
|
|
1458
1442
|
|
|
1459
1443
|
# Display filtered results
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1444
|
+
print_section_header(
|
|
1445
|
+
"📋",
|
|
1446
|
+
f"{filter_description} ({len(filtered_agents)} agents)",
|
|
1447
|
+
width=BANNER_WIDTH,
|
|
1448
|
+
)
|
|
1463
1449
|
|
|
1464
1450
|
if not filtered_agents:
|
|
1465
1451
|
print("\n[yellow]No agents found matching filter[/yellow]")
|
|
@@ -1523,7 +1509,7 @@ class AgentWizard:
|
|
|
1523
1509
|
]
|
|
1524
1510
|
|
|
1525
1511
|
agent_choice = questionary.select(
|
|
1526
|
-
"Select agent to deploy:", choices=agent_choices, style=
|
|
1512
|
+
"Select agent to deploy:", choices=agent_choices, style=MPM_STYLE
|
|
1527
1513
|
).ask()
|
|
1528
1514
|
|
|
1529
1515
|
if not agent_choice: # User pressed Esc
|
|
@@ -1629,7 +1615,7 @@ class AgentWizard:
|
|
|
1629
1615
|
]
|
|
1630
1616
|
|
|
1631
1617
|
agent_choice = questionary.select(
|
|
1632
|
-
"Select agent to view:", choices=agent_choices, style=
|
|
1618
|
+
"Select agent to view:", choices=agent_choices, style=MPM_STYLE
|
|
1633
1619
|
).ask()
|
|
1634
1620
|
|
|
1635
1621
|
if not agent_choice: # User pressed Esc
|
|
@@ -1652,9 +1638,7 @@ class AgentWizard:
|
|
|
1652
1638
|
preset_service = AgentPresetService(self.source_manager)
|
|
1653
1639
|
|
|
1654
1640
|
while True:
|
|
1655
|
-
|
|
1656
|
-
print("📦 Deploy Agent Preset")
|
|
1657
|
-
print("=" * 60)
|
|
1641
|
+
print_section_header("📦", "Deploy Agent Preset", width=BANNER_WIDTH)
|
|
1658
1642
|
|
|
1659
1643
|
# List available presets
|
|
1660
1644
|
presets = preset_service.list_presets()
|
|
@@ -1690,9 +1674,7 @@ class AgentWizard:
|
|
|
1690
1674
|
preset_name = presets[idx]["name"]
|
|
1691
1675
|
|
|
1692
1676
|
# Show preset details
|
|
1693
|
-
|
|
1694
|
-
print(f"📦 Preset: {preset_name}")
|
|
1695
|
-
print("=" * 60)
|
|
1677
|
+
print_section_header("📦", f"Preset: {preset_name}", width=BANNER_WIDTH)
|
|
1696
1678
|
print(f"\n[bold]Description:[/bold] {presets[idx]['description']}\n")
|
|
1697
1679
|
|
|
1698
1680
|
# Resolve preset
|
|
@@ -1872,9 +1854,7 @@ class AgentWizard:
|
|
|
1872
1854
|
input("\nPress Enter to continue...")
|
|
1873
1855
|
return
|
|
1874
1856
|
|
|
1875
|
-
|
|
1876
|
-
print("🔗 Manage Agent Sources")
|
|
1877
|
-
print("=" * 60)
|
|
1857
|
+
print_section_header("🔗", "Manage Agent Sources", width=BANNER_WIDTH)
|
|
1878
1858
|
|
|
1879
1859
|
try:
|
|
1880
1860
|
from claude_mpm.config.agent_sources import AgentSourceConfiguration
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Shared questionary styles for consistent TUI across Claude MPM.
|
|
2
|
+
|
|
3
|
+
This module provides unified styling for all interactive questionary interfaces
|
|
4
|
+
to ensure visual consistency across agent wizard, skill selector, and other TUI components.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from questionary import Style
|
|
8
|
+
|
|
9
|
+
# Standard cyan-themed style for all selectors
|
|
10
|
+
# Matches the pattern used in agent_wizard.py and skill_selector.py
|
|
11
|
+
MPM_STYLE = Style(
|
|
12
|
+
[
|
|
13
|
+
("qmark", "fg:cyan bold"),
|
|
14
|
+
("question", "bold"),
|
|
15
|
+
("answer", "fg:cyan"),
|
|
16
|
+
("pointer", "fg:cyan bold"),
|
|
17
|
+
("highlighted", "fg:cyan bold"),
|
|
18
|
+
("selected", "fg:cyan"),
|
|
19
|
+
]
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Banner constants for consistent formatting
|
|
23
|
+
BANNER_WIDTH = 60
|
|
24
|
+
BANNER_CHAR = "="
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def print_banner(title: str, width: int = BANNER_WIDTH) -> None:
|
|
28
|
+
"""Print a styled banner matching agent selector format.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
title: Title text to display in the banner
|
|
32
|
+
width: Total width of the banner in characters (default: 60)
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
>>> print_banner("Agent Creation Wizard")
|
|
36
|
+
============================================================
|
|
37
|
+
Agent Creation Wizard
|
|
38
|
+
============================================================
|
|
39
|
+
"""
|
|
40
|
+
print()
|
|
41
|
+
print(BANNER_CHAR * width)
|
|
42
|
+
print(f"{title:^{width}}")
|
|
43
|
+
print(BANNER_CHAR * width)
|
|
44
|
+
print()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def print_section_header(emoji: str, title: str, width: int = BANNER_WIDTH) -> None:
|
|
48
|
+
"""Print a section header with emoji and title.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
emoji: Emoji to display before the title
|
|
52
|
+
title: Section title text
|
|
53
|
+
width: Total width of the header line (default: 60)
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
>>> print_section_header("🔧", "Agent Management Menu")
|
|
57
|
+
|
|
58
|
+
============================================================
|
|
59
|
+
🔧 Agent Management Menu
|
|
60
|
+
============================================================
|
|
61
|
+
"""
|
|
62
|
+
print()
|
|
63
|
+
print(BANNER_CHAR * width)
|
|
64
|
+
print(f"{emoji} {title}")
|
|
65
|
+
print(BANNER_CHAR * width)
|