claude-mpm 5.0.2__py3-none-any.whl → 5.4.3__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_TEACHER_OUTPUT_STYLE.md +2002 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +1218 -905
- claude_mpm/agents/agent_loader.py +10 -17
- claude_mpm/agents/base_agent_loader.py +10 -35
- claude_mpm/agents/frontmatter_validator.py +68 -0
- claude_mpm/agents/templates/circuit-breakers.md +431 -45
- claude_mpm/cli/__init__.py +0 -1
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/agent_state_manager.py +67 -23
- claude_mpm/cli/commands/agents.py +446 -25
- claude_mpm/cli/commands/auto_configure.py +535 -233
- claude_mpm/cli/commands/configure.py +1500 -147
- claude_mpm/cli/commands/configure_agent_display.py +13 -6
- claude_mpm/cli/commands/mpm_init/core.py +158 -1
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
- claude_mpm/cli/commands/postmortem.py +401 -0
- claude_mpm/cli/commands/run.py +1 -39
- claude_mpm/cli/commands/skills.py +322 -19
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +8 -0
- claude_mpm/cli/interactive/agent_wizard.py +302 -195
- claude_mpm/cli/parsers/agents_parser.py +137 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
- claude_mpm/cli/parsers/base_parser.py +9 -0
- claude_mpm/cli/parsers/skills_parser.py +7 -0
- claude_mpm/cli/startup.py +133 -85
- claude_mpm/commands/mpm-agents-auto-configure.md +2 -2
- claude_mpm/commands/mpm-agents-list.md +2 -2
- claude_mpm/commands/mpm-config-view.md +2 -2
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/{mpm-ticket-organize.md → mpm-organize.md} +4 -5
- claude_mpm/commands/mpm-postmortem.md +123 -0
- claude_mpm/commands/mpm-session-resume.md +2 -2
- claude_mpm/commands/mpm-ticket-view.md +2 -2
- claude_mpm/config/agent_presets.py +312 -82
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/config/skill_presets.py +392 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +2 -25
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework/loaders/file_loader.py +54 -101
- claude_mpm/core/interactive_session.py +19 -5
- claude_mpm/core/oneshot_session.py +16 -4
- claude_mpm/core/output_style_manager.py +173 -43
- claude_mpm/core/protocols/__init__.py +23 -0
- claude_mpm/core/protocols/runner_protocol.py +103 -0
- claude_mpm/core/protocols/session_protocol.py +131 -0
- claude_mpm/core/shared/singleton_manager.py +11 -4
- claude_mpm/core/socketio_pool.py +3 -3
- claude_mpm/core/system_context.py +38 -0
- claude_mpm/core/unified_agent_registry.py +134 -16
- claude_mpm/core/unified_config.py +22 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +35 -2
- claude_mpm/hooks/claude_hooks/hook_handler.py +4 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/services/agents/agent_recommendation_service.py +279 -0
- claude_mpm/services/agents/cache_git_manager.py +621 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +3 -2
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +110 -3
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +518 -55
- claude_mpm/services/agents/git_source_manager.py +20 -0
- claude_mpm/services/agents/sources/git_source_sync_service.py +45 -6
- claude_mpm/services/agents/toolchain_detector.py +6 -5
- claude_mpm/services/analysis/__init__.py +35 -0
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- claude_mpm/services/analysis/postmortem_reporter.py +474 -0
- claude_mpm/services/analysis/postmortem_service.py +765 -0
- claude_mpm/services/command_deployment_service.py +106 -5
- claude_mpm/services/core/base.py +7 -2
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
- claude_mpm/services/event_bus/config.py +3 -1
- claude_mpm/services/git/git_operations_service.py +8 -8
- claude_mpm/services/mcp_config_manager.py +75 -145
- claude_mpm/services/mcp_service_verifier.py +6 -3
- claude_mpm/services/monitor/daemon.py +37 -10
- claude_mpm/services/monitor/daemon_manager.py +134 -21
- claude_mpm/services/monitor/server.py +225 -19
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/runner_configuration_service.py +16 -3
- claude_mpm/services/session_management_service.py +16 -4
- claude_mpm/services/socketio/event_normalizer.py +15 -1
- claude_mpm/services/socketio/server/core.py +160 -21
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/utils/agent_filters.py +261 -0
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +372 -0
- claude_mpm/utils/progress.py +5 -1
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/METADATA +69 -84
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/RECORD +112 -153
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/entry_points.txt +0 -2
- claude_mpm/dashboard/analysis_runner.py +0 -455
- claude_mpm/dashboard/index.html +0 -13
- claude_mpm/dashboard/open_dashboard.py +0 -66
- claude_mpm/dashboard/static/css/activity.css +0 -1958
- claude_mpm/dashboard/static/css/connection-status.css +0 -370
- claude_mpm/dashboard/static/css/dashboard.css +0 -4701
- claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
- claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
- claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
- claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
- claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
- claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
- claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
- claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
- claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
- claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
- claude_mpm/dashboard/static/js/connection-manager.js +0 -536
- claude_mpm/dashboard/static/js/dashboard.js +0 -1914
- claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/js/socket-client.js +0 -1474
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/socket.io.min.js +0 -7
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
- claude_mpm/dashboard/templates/code_simple.html +0 -153
- claude_mpm/dashboard/templates/index.html +0 -606
- claude_mpm/dashboard/test_dashboard.html +0 -372
- claude_mpm/scripts/mcp_server.py +0 -75
- claude_mpm/scripts/mcp_wrapper.py +0 -39
- claude_mpm/services/mcp_gateway/__init__.py +0 -159
- claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
- claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
- claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
- claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
- claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
- claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
- claude_mpm/services/mcp_gateway/core/base.py +0 -312
- claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
- claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
- claude_mpm/services/mcp_gateway/core/process_pool.py +0 -971
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
- claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
- claude_mpm/services/mcp_gateway/main.py +0 -589
- claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
- claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
- claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
- claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
- claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
- claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
- /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/top_level.txt +0 -0
|
@@ -6,18 +6,33 @@ local agents with user-friendly prompts, intelligent defaults, and validation.
|
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
8
|
import re
|
|
9
|
+
import shutil
|
|
9
10
|
import sys
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any, Dict, List, Optional, Tuple
|
|
12
13
|
|
|
14
|
+
import questionary
|
|
15
|
+
from questionary import Style
|
|
16
|
+
|
|
13
17
|
from claude_mpm.core.logging_config import get_logger
|
|
14
18
|
from claude_mpm.services.agents.local_template_manager import (
|
|
15
19
|
LocalAgentTemplate,
|
|
16
20
|
LocalAgentTemplateManager,
|
|
17
21
|
)
|
|
22
|
+
from claude_mpm.utils.agent_filters import apply_all_filters
|
|
18
23
|
|
|
19
24
|
logger = get_logger(__name__)
|
|
20
25
|
|
|
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
|
+
|
|
21
36
|
|
|
22
37
|
class AgentWizard:
|
|
23
38
|
"""
|
|
@@ -47,6 +62,50 @@ class AgentWizard:
|
|
|
47
62
|
self.source_manager = None
|
|
48
63
|
self.discovery_enabled = False
|
|
49
64
|
|
|
65
|
+
@staticmethod
|
|
66
|
+
def _calculate_column_widths(
|
|
67
|
+
terminal_width: int, columns: Dict[str, int]
|
|
68
|
+
) -> Dict[str, int]:
|
|
69
|
+
"""Calculate dynamic column widths based on terminal size.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
terminal_width: Current terminal width in characters
|
|
73
|
+
columns: Dict mapping column names to minimum widths
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Dict mapping column names to calculated widths
|
|
77
|
+
|
|
78
|
+
Design:
|
|
79
|
+
- Ensures minimum widths are respected
|
|
80
|
+
- Distributes extra space proportionally
|
|
81
|
+
- Handles narrow terminals gracefully (minimum 80 chars)
|
|
82
|
+
"""
|
|
83
|
+
# Ensure minimum terminal width
|
|
84
|
+
min_terminal_width = 80
|
|
85
|
+
terminal_width = max(terminal_width, min_terminal_width)
|
|
86
|
+
|
|
87
|
+
# Calculate total minimum width needed
|
|
88
|
+
total_min_width = sum(columns.values())
|
|
89
|
+
|
|
90
|
+
# Account for spacing between columns
|
|
91
|
+
overhead = len(columns) + 1
|
|
92
|
+
available_width = terminal_width - overhead
|
|
93
|
+
|
|
94
|
+
# If we have extra space, distribute proportionally
|
|
95
|
+
if available_width > total_min_width:
|
|
96
|
+
extra_space = available_width - total_min_width
|
|
97
|
+
total_weight = sum(columns.values())
|
|
98
|
+
|
|
99
|
+
result = {}
|
|
100
|
+
for col_name, min_width in columns.items():
|
|
101
|
+
# Distribute extra space based on minimum width proportion
|
|
102
|
+
proportion = min_width / total_weight
|
|
103
|
+
extra = int(extra_space * proportion)
|
|
104
|
+
result[col_name] = min_width + extra
|
|
105
|
+
return result
|
|
106
|
+
# Terminal too narrow, use minimum widths
|
|
107
|
+
return columns.copy()
|
|
108
|
+
|
|
50
109
|
def run_interactive_create(self) -> Tuple[bool, str]:
|
|
51
110
|
"""Run interactive agent creation wizard.
|
|
52
111
|
|
|
@@ -206,7 +265,10 @@ class AgentWizard:
|
|
|
206
265
|
if deployed_file.exists() or deployed_file_alt.exists():
|
|
207
266
|
agent_data["deployed"] = True
|
|
208
267
|
|
|
209
|
-
|
|
268
|
+
# Filter BASE_AGENT from all agent lists (1M-502 Phase 1)
|
|
269
|
+
# BASE_AGENT is a build tool, not a deployable agent
|
|
270
|
+
agent_list = list(agents.values())
|
|
271
|
+
return apply_all_filters(agent_list, filter_base=True, filter_deployed=False)
|
|
210
272
|
|
|
211
273
|
def run_interactive_manage(self) -> Tuple[bool, str]:
|
|
212
274
|
"""Run interactive agent management menu.
|
|
@@ -242,50 +304,94 @@ class AgentWizard:
|
|
|
242
304
|
print("❌ Invalid choice. Please try again.")
|
|
243
305
|
continue
|
|
244
306
|
|
|
245
|
-
# Show existing agents in a table
|
|
307
|
+
# Show existing agents in a table with dynamic widths
|
|
246
308
|
print(f"\n📋 Found {len(all_agents)} agent(s):\n")
|
|
309
|
+
|
|
310
|
+
# Calculate dynamic column widths based on terminal size
|
|
311
|
+
terminal_width = shutil.get_terminal_size().columns
|
|
312
|
+
min_widths = {
|
|
313
|
+
"#": 4,
|
|
314
|
+
"Agent ID": 30,
|
|
315
|
+
"Name": 20,
|
|
316
|
+
"Source": 15,
|
|
317
|
+
"Status": 10,
|
|
318
|
+
}
|
|
319
|
+
widths = self._calculate_column_widths(terminal_width, min_widths)
|
|
320
|
+
|
|
321
|
+
# Print header with dynamic widths
|
|
247
322
|
print(
|
|
248
|
-
f"{'#':<
|
|
323
|
+
f"{'#':<{widths['#']}} "
|
|
324
|
+
f"{'Agent ID':<{widths['Agent ID']}} "
|
|
325
|
+
f"{'Name':<{widths['Name']}} "
|
|
326
|
+
f"{'Source':<{widths['Source']}} "
|
|
327
|
+
f"{'Status':<{widths['Status']}}"
|
|
249
328
|
)
|
|
250
|
-
|
|
329
|
+
separator_width = sum(widths.values()) + len(widths) - 1
|
|
330
|
+
print("-" * separator_width)
|
|
251
331
|
|
|
252
332
|
for i, agent in enumerate(all_agents, 1):
|
|
253
333
|
agent_id = agent["agent_id"]
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
334
|
+
# Truncate to fit dynamic width
|
|
335
|
+
if len(agent_id) > widths["Agent ID"]:
|
|
336
|
+
agent_id = agent_id[: widths["Agent ID"] - 1] + "…"
|
|
337
|
+
|
|
338
|
+
name = agent["name"]
|
|
339
|
+
if len(name) > widths["Name"]:
|
|
340
|
+
name = name[: widths["Name"] - 1] + "…"
|
|
341
|
+
|
|
257
342
|
source_label = (
|
|
258
|
-
f"[{agent['source_type']}] {agent['source_identifier']}"
|
|
343
|
+
f"[{agent['source_type']}] {agent['source_identifier']}"
|
|
259
344
|
)
|
|
345
|
+
if len(source_label) > widths["Source"]:
|
|
346
|
+
source_label = source_label[: widths["Source"] - 1] + "…"
|
|
347
|
+
|
|
260
348
|
status = "✓ Deployed" if agent["deployed"] else "Available"
|
|
261
349
|
|
|
262
350
|
print(
|
|
263
|
-
f"{i:<
|
|
351
|
+
f"{i:<{widths['#']}} "
|
|
352
|
+
f"{agent_id:<{widths['Agent ID']}} "
|
|
353
|
+
f"{name:<{widths['Name']}} "
|
|
354
|
+
f"{source_label:<{widths['Source']}} "
|
|
355
|
+
f"{status:<{widths['Status']}}"
|
|
264
356
|
)
|
|
265
357
|
|
|
266
|
-
#
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
358
|
+
# Build menu choices with arrow-key navigation
|
|
359
|
+
menu_choices = []
|
|
360
|
+
|
|
361
|
+
# Add agent viewing options (1-N)
|
|
362
|
+
for i, agent in enumerate(all_agents, 1):
|
|
363
|
+
menu_choices.append(f"{i}. View agent: {agent['agent_id']}")
|
|
364
|
+
|
|
365
|
+
# Add action options
|
|
366
|
+
menu_choices.append(f"{len(all_agents) + 1}. Deploy agent")
|
|
367
|
+
menu_choices.append(f"{len(all_agents) + 2}. Create new agent")
|
|
368
|
+
menu_choices.append(f"{len(all_agents) + 3}. Delete agent(s)")
|
|
369
|
+
menu_choices.append(f"{len(all_agents) + 4}. Import agents")
|
|
370
|
+
menu_choices.append(f"{len(all_agents) + 5}. Export all agents")
|
|
371
|
+
|
|
272
372
|
if self.discovery_enabled:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
373
|
+
menu_choices.append(
|
|
374
|
+
f"{len(all_agents) + 6}. Browse & filter agents"
|
|
375
|
+
)
|
|
376
|
+
menu_choices.append(f"{len(all_agents) + 7}. Deploy preset")
|
|
377
|
+
menu_choices.append(f"{len(all_agents) + 8}. Manage agent sources")
|
|
378
|
+
menu_choices.append(f"{len(all_agents) + 9}. Exit")
|
|
379
|
+
exit_num = len(all_agents) + 9
|
|
278
380
|
else:
|
|
279
|
-
|
|
280
|
-
|
|
381
|
+
menu_choices.append(f"{len(all_agents) + 6}. Exit")
|
|
382
|
+
exit_num = len(all_agents) + 6
|
|
281
383
|
|
|
282
|
-
choice =
|
|
384
|
+
choice = questionary.select(
|
|
385
|
+
"Agent Management Menu:",
|
|
386
|
+
choices=menu_choices,
|
|
387
|
+
style=QUESTIONARY_STYLE,
|
|
388
|
+
).ask()
|
|
283
389
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
390
|
+
if not choice: # User pressed Esc
|
|
391
|
+
return True, "Management menu exited"
|
|
392
|
+
|
|
393
|
+
# Parse choice number from "N. Description" format
|
|
394
|
+
choice_num = int(choice.split(".")[0])
|
|
289
395
|
|
|
290
396
|
if 1 <= choice_num <= len(all_agents):
|
|
291
397
|
# View agent details
|
|
@@ -324,9 +430,7 @@ class AgentWizard:
|
|
|
324
430
|
elif choice_num == len(all_agents) + 8 and self.discovery_enabled:
|
|
325
431
|
self._manage_sources_interactive()
|
|
326
432
|
continue
|
|
327
|
-
elif
|
|
328
|
-
choice_num == len(all_agents) + 6 and not self.discovery_enabled
|
|
329
|
-
):
|
|
433
|
+
elif choice_num == exit_num:
|
|
330
434
|
return True, "Management menu exited"
|
|
331
435
|
else:
|
|
332
436
|
print("❌ Invalid choice. Please try again.")
|
|
@@ -1073,8 +1177,11 @@ class AgentWizard:
|
|
|
1073
1177
|
Args:
|
|
1074
1178
|
available_agents: List of all available agents
|
|
1075
1179
|
"""
|
|
1076
|
-
# Filter to non-deployed agents
|
|
1077
|
-
|
|
1180
|
+
# Filter to non-deployed agents using improved detection (1M-502 Phase 1)
|
|
1181
|
+
# This checks both .claude-mpm/agents/ and .claude/agents/
|
|
1182
|
+
deployable = apply_all_filters(
|
|
1183
|
+
available_agents, filter_base=True, filter_deployed=True
|
|
1184
|
+
)
|
|
1078
1185
|
|
|
1079
1186
|
if not deployable:
|
|
1080
1187
|
print("\n✅ All agents are already deployed!")
|
|
@@ -1086,110 +1193,100 @@ class AgentWizard:
|
|
|
1086
1193
|
print("=" * 60)
|
|
1087
1194
|
print(f"\n{len(deployable)} agent(s) available to deploy:\n")
|
|
1088
1195
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
choice = input("\nEnter agent number (or 'c' to cancel): ").strip()
|
|
1096
|
-
if choice.lower() == "c":
|
|
1097
|
-
return
|
|
1098
|
-
|
|
1099
|
-
try:
|
|
1100
|
-
idx = int(choice) - 1
|
|
1101
|
-
if idx < 0 or idx >= len(deployable):
|
|
1102
|
-
print("❌ Invalid selection")
|
|
1103
|
-
input("\nPress Enter to continue...")
|
|
1104
|
-
return
|
|
1105
|
-
|
|
1106
|
-
agent = deployable[idx]
|
|
1196
|
+
# Build agent selection choices with arrow-key navigation
|
|
1197
|
+
agent_choices = [
|
|
1198
|
+
f"{i}. {agent['agent_id']} - {agent['description'][:60]}{'...' if len(agent['description']) > 60 else ''}"
|
|
1199
|
+
for i, agent in enumerate(deployable, 1)
|
|
1200
|
+
]
|
|
1107
1201
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1202
|
+
choice = questionary.select(
|
|
1203
|
+
"Select agent to deploy:", choices=agent_choices, style=QUESTIONARY_STYLE
|
|
1204
|
+
).ask()
|
|
1110
1205
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
from claude_mpm.services.agents.deployment.agent_template_builder import (
|
|
1114
|
-
AgentTemplateBuilder,
|
|
1115
|
-
)
|
|
1116
|
-
from claude_mpm.services.agents.deployment.agent_version_manager import (
|
|
1117
|
-
AgentVersionManager,
|
|
1118
|
-
)
|
|
1119
|
-
from claude_mpm.services.agents.deployment.deployment_results_manager import (
|
|
1120
|
-
DeploymentResultsManager,
|
|
1121
|
-
)
|
|
1122
|
-
from claude_mpm.services.agents.deployment.single_agent_deployer import (
|
|
1123
|
-
SingleAgentDeployer,
|
|
1124
|
-
)
|
|
1206
|
+
if not choice: # User pressed Esc
|
|
1207
|
+
return
|
|
1125
1208
|
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
results_manager = DeploymentResultsManager(self.logger)
|
|
1130
|
-
deployer = SingleAgentDeployer(
|
|
1131
|
-
template_builder=template_builder,
|
|
1132
|
-
version_manager=version_manager,
|
|
1133
|
-
results_manager=results_manager,
|
|
1134
|
-
logger=self.logger,
|
|
1135
|
-
)
|
|
1209
|
+
# Parse agent index from "N. agent_id - description" format
|
|
1210
|
+
idx = int(choice.split(".")[0]) - 1
|
|
1211
|
+
agent = deployable[idx]
|
|
1136
1212
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
target_dir = Path.cwd() / ".claude" / "agents"
|
|
1213
|
+
# Deploy agent using deployment service
|
|
1214
|
+
print(f"\n🚀 Deploying {agent['agent_id']}...")
|
|
1140
1215
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
for candidate in base_agent_candidates:
|
|
1156
|
-
if candidate.exists():
|
|
1157
|
-
base_agent_path = candidate
|
|
1158
|
-
break
|
|
1159
|
-
|
|
1160
|
-
if not base_agent_path:
|
|
1161
|
-
base_agent_path = base_agent_candidates[
|
|
1162
|
-
0
|
|
1163
|
-
] # Use default even if not exists
|
|
1216
|
+
try:
|
|
1217
|
+
# Use SingleAgentDeployer for deployment
|
|
1218
|
+
from claude_mpm.services.agents.deployment.agent_template_builder import (
|
|
1219
|
+
AgentTemplateBuilder,
|
|
1220
|
+
)
|
|
1221
|
+
from claude_mpm.services.agents.deployment.agent_version_manager import (
|
|
1222
|
+
AgentVersionManager,
|
|
1223
|
+
)
|
|
1224
|
+
from claude_mpm.services.agents.deployment.deployment_results_manager import (
|
|
1225
|
+
DeploymentResultsManager,
|
|
1226
|
+
)
|
|
1227
|
+
from claude_mpm.services.agents.deployment.single_agent_deployer import (
|
|
1228
|
+
SingleAgentDeployer,
|
|
1229
|
+
)
|
|
1164
1230
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1231
|
+
# Initialize deployment services
|
|
1232
|
+
template_builder = AgentTemplateBuilder()
|
|
1233
|
+
version_manager = AgentVersionManager()
|
|
1234
|
+
results_manager = DeploymentResultsManager(self.logger)
|
|
1235
|
+
deployer = SingleAgentDeployer(
|
|
1236
|
+
template_builder=template_builder,
|
|
1237
|
+
version_manager=version_manager,
|
|
1238
|
+
results_manager=results_manager,
|
|
1239
|
+
logger=self.logger,
|
|
1240
|
+
)
|
|
1174
1241
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1242
|
+
# Prepare deployment parameters
|
|
1243
|
+
template_path = Path(agent["path"])
|
|
1244
|
+
target_dir = Path.cwd() / ".claude" / "agents"
|
|
1245
|
+
|
|
1246
|
+
# Find base_agent.json in multiple possible locations
|
|
1247
|
+
base_agent_candidates = [
|
|
1248
|
+
Path.home()
|
|
1249
|
+
/ ".claude-mpm"
|
|
1250
|
+
/ "agents"
|
|
1251
|
+
/ "templates"
|
|
1252
|
+
/ "base_agent.json",
|
|
1253
|
+
Path.home() / ".claude-mpm" / "cache" / "base_agent.json",
|
|
1254
|
+
Path(__file__).parent.parent.parent
|
|
1255
|
+
/ "agents"
|
|
1256
|
+
/ "templates"
|
|
1257
|
+
/ "base_agent.json",
|
|
1258
|
+
]
|
|
1259
|
+
base_agent_path = None
|
|
1260
|
+
for candidate in base_agent_candidates:
|
|
1261
|
+
if candidate.exists():
|
|
1262
|
+
base_agent_path = candidate
|
|
1263
|
+
break
|
|
1179
1264
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1265
|
+
if not base_agent_path:
|
|
1266
|
+
base_agent_path = base_agent_candidates[
|
|
1267
|
+
0
|
|
1268
|
+
] # Use default even if not exists
|
|
1269
|
+
|
|
1270
|
+
# Deploy the agent
|
|
1271
|
+
success = deployer.deploy_agent(
|
|
1272
|
+
agent_name=agent["agent_id"],
|
|
1273
|
+
templates_dir=template_path.parent,
|
|
1274
|
+
target_dir=target_dir,
|
|
1275
|
+
base_agent_path=base_agent_path,
|
|
1276
|
+
force_rebuild=True,
|
|
1277
|
+
working_directory=Path.cwd(),
|
|
1278
|
+
)
|
|
1183
1279
|
|
|
1184
|
-
|
|
1280
|
+
if success:
|
|
1281
|
+
print(f"\n✅ Successfully deployed {agent['agent_id']}")
|
|
1282
|
+
else:
|
|
1283
|
+
print(f"\n❌ Failed to deploy {agent['agent_id']}")
|
|
1185
1284
|
|
|
1186
|
-
except ValueError:
|
|
1187
|
-
print("❌ Invalid selection")
|
|
1188
|
-
input("\nPress Enter to continue...")
|
|
1189
1285
|
except Exception as e:
|
|
1190
|
-
self.logger.error(f"Deployment
|
|
1191
|
-
print(f"\n❌
|
|
1192
|
-
|
|
1286
|
+
self.logger.error(f"Deployment failed: {e}", exc_info=True)
|
|
1287
|
+
print(f"\n❌ Deployment error: {e}")
|
|
1288
|
+
|
|
1289
|
+
input("\nPress Enter to continue...")
|
|
1193
1290
|
|
|
1194
1291
|
def _browse_agents_interactive(self):
|
|
1195
1292
|
"""Interactive agent browsing with filters."""
|
|
@@ -1203,24 +1300,37 @@ class AgentWizard:
|
|
|
1203
1300
|
print("🔍 Browse & Filter Agents")
|
|
1204
1301
|
print("=" * 60)
|
|
1205
1302
|
|
|
1206
|
-
# Show filter menu
|
|
1303
|
+
# Show filter menu with arrow-key navigation
|
|
1207
1304
|
print("\n[bold]Filter by:[/bold]")
|
|
1208
|
-
print(" [1] Category (engineer/backend, qa, ops, etc.)")
|
|
1209
|
-
print(" [2] Language (python, typescript, rust, etc.)")
|
|
1210
|
-
print(" [3] Framework (react, nextjs, flask, etc.)")
|
|
1211
|
-
print(" [4] Show all agents")
|
|
1212
|
-
print(" [b] Back to main menu")
|
|
1213
1305
|
|
|
1214
|
-
|
|
1306
|
+
filter_choices = [
|
|
1307
|
+
"1. Category (engineer/backend, qa, ops, etc.)",
|
|
1308
|
+
"2. Language (python, typescript, rust, etc.)",
|
|
1309
|
+
"3. Framework (react, nextjs, flask, etc.)",
|
|
1310
|
+
"4. Show all agents",
|
|
1311
|
+
"← Back to main menu",
|
|
1312
|
+
]
|
|
1313
|
+
|
|
1314
|
+
choice = questionary.select(
|
|
1315
|
+
"Browse & Filter Agents:",
|
|
1316
|
+
choices=filter_choices,
|
|
1317
|
+
style=QUESTIONARY_STYLE,
|
|
1318
|
+
).ask()
|
|
1319
|
+
|
|
1320
|
+
if not choice or "Back" in choice:
|
|
1321
|
+
break
|
|
1215
1322
|
|
|
1216
|
-
|
|
1323
|
+
# Parse choice number if it starts with a digit
|
|
1324
|
+
if choice[0].isdigit():
|
|
1325
|
+
choice_num = choice.split(".")[0]
|
|
1326
|
+
else:
|
|
1217
1327
|
break
|
|
1218
1328
|
|
|
1219
1329
|
filtered_agents = []
|
|
1220
1330
|
filter_description = ""
|
|
1221
1331
|
|
|
1222
|
-
if
|
|
1223
|
-
# Category filtering
|
|
1332
|
+
if choice_num == "1":
|
|
1333
|
+
# Category filtering with arrow-key navigation
|
|
1224
1334
|
categories = [
|
|
1225
1335
|
"engineer/backend",
|
|
1226
1336
|
"engineer/frontend",
|
|
@@ -1229,26 +1339,26 @@ class AgentWizard:
|
|
|
1229
1339
|
"documentation",
|
|
1230
1340
|
"universal",
|
|
1231
1341
|
]
|
|
1232
|
-
print("\n[bold]Available categories:[/bold]")
|
|
1233
|
-
for idx, cat in enumerate(categories, 1):
|
|
1234
|
-
print(f" {idx}. {cat}")
|
|
1235
1342
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
if a.get("category", "").startswith(category)
|
|
1244
|
-
]
|
|
1245
|
-
filter_description = f"Category: {category}"
|
|
1246
|
-
except (ValueError, IndexError):
|
|
1247
|
-
print("❌ Invalid selection")
|
|
1248
|
-
input("\nPress Enter to continue...")
|
|
1343
|
+
cat_choices = [f"{idx}. {cat}" for idx, cat in enumerate(categories, 1)]
|
|
1344
|
+
|
|
1345
|
+
cat_choice = questionary.select(
|
|
1346
|
+
"Select category:", choices=cat_choices, style=QUESTIONARY_STYLE
|
|
1347
|
+
).ask()
|
|
1348
|
+
|
|
1349
|
+
if not cat_choice: # User pressed Esc
|
|
1249
1350
|
continue
|
|
1250
1351
|
|
|
1251
|
-
|
|
1352
|
+
# Parse category from "N. category" format
|
|
1353
|
+
cat_idx = int(cat_choice.split(".")[0]) - 1
|
|
1354
|
+
category = categories[cat_idx]
|
|
1355
|
+
all_agents = self._merge_agent_sources()
|
|
1356
|
+
filtered_agents = [
|
|
1357
|
+
a for a in all_agents if a.get("category", "").startswith(category)
|
|
1358
|
+
]
|
|
1359
|
+
filter_description = f"Category: {category}"
|
|
1360
|
+
|
|
1361
|
+
elif choice_num == "2":
|
|
1252
1362
|
# Language filtering (using AUTO-DEPLOY-INDEX if available)
|
|
1253
1363
|
language = input(
|
|
1254
1364
|
"\nEnter language (python, typescript, rust, go, etc.): "
|
|
@@ -1294,7 +1404,7 @@ class AgentWizard:
|
|
|
1294
1404
|
input("\nPress Enter to continue...")
|
|
1295
1405
|
continue
|
|
1296
1406
|
|
|
1297
|
-
elif
|
|
1407
|
+
elif choice_num == "3":
|
|
1298
1408
|
# Framework filtering
|
|
1299
1409
|
framework = input(
|
|
1300
1410
|
"\nEnter framework (react, nextjs, flask, django, etc.): "
|
|
@@ -1337,7 +1447,7 @@ class AgentWizard:
|
|
|
1337
1447
|
input("\nPress Enter to continue...")
|
|
1338
1448
|
continue
|
|
1339
1449
|
|
|
1340
|
-
elif
|
|
1450
|
+
elif choice_num == "4":
|
|
1341
1451
|
# Show all agents
|
|
1342
1452
|
filtered_agents = self._merge_agent_sources()
|
|
1343
1453
|
filter_description = "All agents"
|
|
@@ -1407,26 +1517,28 @@ class AgentWizard:
|
|
|
1407
1517
|
input("\nPress Enter to continue...")
|
|
1408
1518
|
return
|
|
1409
1519
|
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
return
|
|
1520
|
+
# Build agent selection choices
|
|
1521
|
+
agent_choices = [
|
|
1522
|
+
f"{i}. {agent['agent_id']}" for i, agent in enumerate(agents, 1)
|
|
1523
|
+
]
|
|
1415
1524
|
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
print("❌ Invalid agent number")
|
|
1420
|
-
input("\nPress Enter to continue...")
|
|
1421
|
-
return
|
|
1525
|
+
agent_choice = questionary.select(
|
|
1526
|
+
"Select agent to deploy:", choices=agent_choices, style=QUESTIONARY_STYLE
|
|
1527
|
+
).ask()
|
|
1422
1528
|
|
|
1423
|
-
|
|
1529
|
+
if not agent_choice: # User pressed Esc
|
|
1530
|
+
return
|
|
1424
1531
|
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
print(f"\n🚀 Deploying {agent['agent_id']}...")
|
|
1532
|
+
# Parse agent index from "N. agent_id" format
|
|
1533
|
+
idx = int(agent_choice.split(".")[0]) - 1
|
|
1534
|
+
agent = agents[idx]
|
|
1429
1535
|
|
|
1536
|
+
if agent.get("deployed"):
|
|
1537
|
+
print(f"\n[yellow]{agent['agent_id']} is already deployed[/yellow]")
|
|
1538
|
+
else:
|
|
1539
|
+
print(f"\n🚀 Deploying {agent['agent_id']}...")
|
|
1540
|
+
|
|
1541
|
+
try:
|
|
1430
1542
|
from claude_mpm.services.agents.deployment.agent_template_builder import (
|
|
1431
1543
|
AgentTemplateBuilder,
|
|
1432
1544
|
)
|
|
@@ -1494,14 +1606,11 @@ class AgentWizard:
|
|
|
1494
1606
|
else:
|
|
1495
1607
|
print(f"[red]✗ Failed to deploy {agent['agent_id']}[/red]")
|
|
1496
1608
|
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
self.logger.error(f"Deployment error: {e}", exc_info=True)
|
|
1503
|
-
print(f"❌ Deployment error: {e}")
|
|
1504
|
-
input("\nPress Enter to continue...")
|
|
1609
|
+
except Exception as e:
|
|
1610
|
+
self.logger.error(f"Deployment error: {e}", exc_info=True)
|
|
1611
|
+
print(f"❌ Deployment error: {e}")
|
|
1612
|
+
|
|
1613
|
+
input("\nPress Enter to continue...")
|
|
1505
1614
|
|
|
1506
1615
|
def _view_from_filtered_list(self, agents: List[Dict[str, Any]]):
|
|
1507
1616
|
"""View details of an agent from filtered list.
|
|
@@ -1514,24 +1623,22 @@ class AgentWizard:
|
|
|
1514
1623
|
input("\nPress Enter to continue...")
|
|
1515
1624
|
return
|
|
1516
1625
|
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
return
|
|
1626
|
+
# Build agent selection choices
|
|
1627
|
+
agent_choices = [
|
|
1628
|
+
f"{i}. {agent['agent_id']}" for i, agent in enumerate(agents, 1)
|
|
1629
|
+
]
|
|
1522
1630
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
print("❌ Invalid agent number")
|
|
1527
|
-
input("\nPress Enter to continue...")
|
|
1528
|
-
return
|
|
1631
|
+
agent_choice = questionary.select(
|
|
1632
|
+
"Select agent to view:", choices=agent_choices, style=QUESTIONARY_STYLE
|
|
1633
|
+
).ask()
|
|
1529
1634
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1635
|
+
if not agent_choice: # User pressed Esc
|
|
1636
|
+
return
|
|
1637
|
+
|
|
1638
|
+
# Parse agent index from "N. agent_id" format
|
|
1639
|
+
idx = int(agent_choice.split(".")[0]) - 1
|
|
1640
|
+
agent = agents[idx]
|
|
1641
|
+
self._show_agent_details(agent)
|
|
1535
1642
|
|
|
1536
1643
|
def _deploy_preset_interactive(self):
|
|
1537
1644
|
"""Interactive preset deployment with preview and confirmation."""
|