claude-mpm 4.13.2__py3-none-any.whl → 4.18.2__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/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +48 -17
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +227 -8
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/agentic-coder-optimizer.json +9 -2
- claude_mpm/agents/templates/api_qa.json +7 -1
- claude_mpm/agents/templates/clerk-ops.json +8 -1
- claude_mpm/agents/templates/code_analyzer.json +4 -1
- claude_mpm/agents/templates/dart_engineer.json +11 -1
- claude_mpm/agents/templates/data_engineer.json +11 -1
- claude_mpm/agents/templates/documentation.json +6 -1
- claude_mpm/agents/templates/engineer.json +18 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +8 -1
- claude_mpm/agents/templates/golang_engineer.json +11 -1
- claude_mpm/agents/templates/java_engineer.json +12 -2
- claude_mpm/agents/templates/local_ops_agent.json +1217 -6
- claude_mpm/agents/templates/nextjs_engineer.json +11 -1
- claude_mpm/agents/templates/ops.json +8 -1
- claude_mpm/agents/templates/php-engineer.json +11 -1
- claude_mpm/agents/templates/project_organizer.json +10 -3
- claude_mpm/agents/templates/prompt-engineer.json +5 -1
- claude_mpm/agents/templates/python_engineer.json +11 -1
- claude_mpm/agents/templates/qa.json +7 -1
- claude_mpm/agents/templates/react_engineer.json +11 -1
- claude_mpm/agents/templates/refactoring_engineer.json +8 -1
- claude_mpm/agents/templates/research.json +4 -1
- claude_mpm/agents/templates/ruby-engineer.json +11 -1
- claude_mpm/agents/templates/rust_engineer.json +11 -1
- claude_mpm/agents/templates/security.json +6 -1
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +6 -1
- claude_mpm/agents/templates/typescript_engineer.json +11 -1
- claude_mpm/agents/templates/vercel_ops_agent.json +8 -1
- claude_mpm/agents/templates/version_control.json +8 -1
- claude_mpm/agents/templates/web_qa.json +7 -1
- claude_mpm/agents/templates/web_ui.json +11 -1
- claude_mpm/cli/__init__.py +34 -706
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +204 -148
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +7 -9
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +294 -1788
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +39 -25
- claude_mpm/cli/commands/mpm_init_handler.py +8 -3
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/base_parser.py +98 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/auto_config_manager.py +10 -11
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/interfaces/__init__.py +74 -2
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/models/__init__.py +33 -0
- claude_mpm/services/core/models/agent_config.py +12 -28
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +36 -31
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +71 -24
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/memory_hook_service.py +4 -1
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +117 -8
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +238 -174
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.13.2.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
"""Startup configuration and service management for configure command.
|
|
2
|
+
|
|
3
|
+
This module handles all startup-related configuration including:
|
|
4
|
+
- Hook service configuration
|
|
5
|
+
- MCP service configuration
|
|
6
|
+
- System agent configuration
|
|
7
|
+
- Background service orchestration
|
|
8
|
+
- Startup configuration persistence
|
|
9
|
+
|
|
10
|
+
WHY: Startup configuration requires orchestrating multiple services (MCP, hooks, agents)
|
|
11
|
+
and needs a dedicated manager to handle the complexity of service dependencies and
|
|
12
|
+
configuration persistence.
|
|
13
|
+
|
|
14
|
+
DESIGN DECISIONS:
|
|
15
|
+
- Separate startup concerns from main configure command
|
|
16
|
+
- Use Config system for persistence
|
|
17
|
+
- Integrate with MCPConfigManager for service discovery
|
|
18
|
+
- Support interactive and batch operations
|
|
19
|
+
- Handle disabled_agents list (NEW LOGIC: track disabled, not enabled)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import logging
|
|
23
|
+
import os
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Dict
|
|
26
|
+
|
|
27
|
+
from rich.box import ROUNDED
|
|
28
|
+
from rich.console import Console
|
|
29
|
+
from rich.prompt import Confirm, Prompt
|
|
30
|
+
from rich.table import Table
|
|
31
|
+
from rich.text import Text
|
|
32
|
+
|
|
33
|
+
from ...core.config import Config
|
|
34
|
+
from ...services.mcp_config_manager import MCPConfigManager
|
|
35
|
+
from .agent_state_manager import SimpleAgentManager
|
|
36
|
+
from .configure_validators import parse_id_selection
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class StartupManager:
|
|
40
|
+
"""Manage startup configuration and background services.
|
|
41
|
+
|
|
42
|
+
This manager handles:
|
|
43
|
+
- Loading and saving startup configuration
|
|
44
|
+
- Configuring hook services (enable/disable)
|
|
45
|
+
- Configuring MCP services (enable/disable)
|
|
46
|
+
- Configuring system agents
|
|
47
|
+
- Managing all background services
|
|
48
|
+
- Interactive startup configuration interface
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
agent_manager: SimpleAgentManager,
|
|
54
|
+
console: Console,
|
|
55
|
+
current_scope: str,
|
|
56
|
+
project_dir: Path,
|
|
57
|
+
display_header_callback: callable,
|
|
58
|
+
):
|
|
59
|
+
"""Initialize startup manager.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
agent_manager: Agent state manager for agent discovery/management
|
|
63
|
+
console: Rich console for output
|
|
64
|
+
current_scope: Configuration scope ('project' or 'user')
|
|
65
|
+
project_dir: Path to project directory
|
|
66
|
+
display_header_callback: Callback to display header in interactive mode
|
|
67
|
+
"""
|
|
68
|
+
self.agent_manager = agent_manager
|
|
69
|
+
self.console = console
|
|
70
|
+
self.current_scope = current_scope
|
|
71
|
+
self.project_dir = project_dir
|
|
72
|
+
self.display_header = display_header_callback
|
|
73
|
+
|
|
74
|
+
def manage_startup_configuration(self) -> bool:
|
|
75
|
+
"""Manage startup configuration for MCP services and agents.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
bool: True if user saved and wants to proceed to startup, False otherwise
|
|
79
|
+
"""
|
|
80
|
+
# Temporarily suppress INFO logging during Config initialization
|
|
81
|
+
root_logger = logging.getLogger("claude_mpm")
|
|
82
|
+
original_level = root_logger.level
|
|
83
|
+
root_logger.setLevel(logging.WARNING)
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
# Load current configuration ONCE at the start
|
|
87
|
+
config = Config()
|
|
88
|
+
startup_config = self.load_startup_configuration(config)
|
|
89
|
+
finally:
|
|
90
|
+
# Restore original logging level
|
|
91
|
+
root_logger.setLevel(original_level)
|
|
92
|
+
|
|
93
|
+
proceed_to_startup = False
|
|
94
|
+
while True:
|
|
95
|
+
self.console.clear()
|
|
96
|
+
self.display_header()
|
|
97
|
+
|
|
98
|
+
self.console.print("[bold]Startup Configuration Management[/bold]\n")
|
|
99
|
+
self.console.print(
|
|
100
|
+
"[dim]Configure which MCP services, hook services, and system agents "
|
|
101
|
+
"are enabled when Claude MPM starts.[/dim]\n"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Display current configuration (using in-memory state)
|
|
105
|
+
self.display_startup_configuration(startup_config)
|
|
106
|
+
|
|
107
|
+
# Show menu options
|
|
108
|
+
self.console.print("\n[bold]Options:[/bold]")
|
|
109
|
+
self.console.print(" [cyan]1[/cyan] - Configure MCP Services")
|
|
110
|
+
self.console.print(" [cyan]2[/cyan] - Configure Hook Services")
|
|
111
|
+
self.console.print(" [cyan]3[/cyan] - Configure System Agents")
|
|
112
|
+
self.console.print(" [cyan]4[/cyan] - Enable All")
|
|
113
|
+
self.console.print(" [cyan]5[/cyan] - Disable All")
|
|
114
|
+
self.console.print(" [cyan]6[/cyan] - Reset to Defaults")
|
|
115
|
+
self.console.print(
|
|
116
|
+
" [cyan]s[/cyan] - Save configuration and start claude-mpm"
|
|
117
|
+
)
|
|
118
|
+
self.console.print(" [cyan]b[/cyan] - Cancel and return without saving")
|
|
119
|
+
self.console.print()
|
|
120
|
+
|
|
121
|
+
choice = Prompt.ask("[bold cyan]Select an option[/bold cyan]", default="s")
|
|
122
|
+
|
|
123
|
+
if choice == "b":
|
|
124
|
+
break
|
|
125
|
+
if choice == "1":
|
|
126
|
+
self.configure_mcp_services(startup_config, config)
|
|
127
|
+
elif choice == "2":
|
|
128
|
+
self.configure_hook_services(startup_config, config)
|
|
129
|
+
elif choice == "3":
|
|
130
|
+
self.configure_system_agents(startup_config, config)
|
|
131
|
+
elif choice == "4":
|
|
132
|
+
self.enable_all_services(startup_config, config)
|
|
133
|
+
elif choice == "5":
|
|
134
|
+
self.disable_all_services(startup_config, config)
|
|
135
|
+
elif choice == "6":
|
|
136
|
+
self.reset_to_defaults(startup_config, config)
|
|
137
|
+
elif choice == "s":
|
|
138
|
+
# Save and exit if successful
|
|
139
|
+
if self.save_startup_configuration(startup_config, config):
|
|
140
|
+
proceed_to_startup = True
|
|
141
|
+
break
|
|
142
|
+
else:
|
|
143
|
+
self.console.print("[red]Invalid choice.[/red]")
|
|
144
|
+
Prompt.ask("Press Enter to continue")
|
|
145
|
+
|
|
146
|
+
return proceed_to_startup
|
|
147
|
+
|
|
148
|
+
def load_startup_configuration(self, config: Config) -> Dict:
|
|
149
|
+
"""Load current startup configuration from config."""
|
|
150
|
+
startup_config = config.get("startup", {})
|
|
151
|
+
|
|
152
|
+
# Ensure all required sections exist
|
|
153
|
+
if "enabled_mcp_services" not in startup_config:
|
|
154
|
+
# Get available MCP services from MCPConfigManager
|
|
155
|
+
mcp_manager = MCPConfigManager()
|
|
156
|
+
available_services = list(mcp_manager.STATIC_MCP_CONFIGS.keys())
|
|
157
|
+
startup_config["enabled_mcp_services"] = available_services.copy()
|
|
158
|
+
|
|
159
|
+
if "enabled_hook_services" not in startup_config:
|
|
160
|
+
# Default hook services (health-monitor enabled by default)
|
|
161
|
+
startup_config["enabled_hook_services"] = [
|
|
162
|
+
"monitor",
|
|
163
|
+
"dashboard",
|
|
164
|
+
"response-logger",
|
|
165
|
+
"health-monitor",
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
if "disabled_agents" not in startup_config:
|
|
169
|
+
# NEW LOGIC: Track DISABLED agents instead of enabled
|
|
170
|
+
# By default, NO agents are disabled (all agents enabled)
|
|
171
|
+
startup_config["disabled_agents"] = []
|
|
172
|
+
|
|
173
|
+
return startup_config
|
|
174
|
+
|
|
175
|
+
def display_startup_configuration(self, startup_config: Dict) -> None:
|
|
176
|
+
"""Display current startup configuration in a table."""
|
|
177
|
+
table = Table(
|
|
178
|
+
title="Current Startup Configuration", box=ROUNDED, show_lines=True
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
table.add_column("Category", style="bold blue", width=20)
|
|
182
|
+
table.add_column("Enabled Services", style="", width=50)
|
|
183
|
+
table.add_column("Count", style="dim", width=10)
|
|
184
|
+
|
|
185
|
+
# MCP Services
|
|
186
|
+
mcp_services = startup_config.get("enabled_mcp_services", [])
|
|
187
|
+
mcp_display = ", ".join(mcp_services[:3]) + (
|
|
188
|
+
"..." if len(mcp_services) > 3 else ""
|
|
189
|
+
)
|
|
190
|
+
table.add_row(
|
|
191
|
+
"MCP Services",
|
|
192
|
+
mcp_display if mcp_services else "[dim]None[/dim]",
|
|
193
|
+
str(len(mcp_services)),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# Hook Services
|
|
197
|
+
hook_services = startup_config.get("enabled_hook_services", [])
|
|
198
|
+
hook_display = ", ".join(hook_services[:3]) + (
|
|
199
|
+
"..." if len(hook_services) > 3 else ""
|
|
200
|
+
)
|
|
201
|
+
table.add_row(
|
|
202
|
+
"Hook Services",
|
|
203
|
+
hook_display if hook_services else "[dim]None[/dim]",
|
|
204
|
+
str(len(hook_services)),
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# System Agents - show count of ENABLED agents (total - disabled)
|
|
208
|
+
all_agents = self.agent_manager.discover_agents() if self.agent_manager else []
|
|
209
|
+
disabled_agents = startup_config.get("disabled_agents", [])
|
|
210
|
+
enabled_count = len(all_agents) - len(disabled_agents)
|
|
211
|
+
|
|
212
|
+
# Show first few enabled agent names
|
|
213
|
+
enabled_names = [a.name for a in all_agents if a.name not in disabled_agents]
|
|
214
|
+
agent_display = ", ".join(enabled_names[:3]) + (
|
|
215
|
+
"..." if len(enabled_names) > 3 else ""
|
|
216
|
+
)
|
|
217
|
+
table.add_row(
|
|
218
|
+
"System Agents",
|
|
219
|
+
agent_display if enabled_names else "[dim]All Disabled[/dim]",
|
|
220
|
+
f"{enabled_count}/{len(all_agents)}",
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
self.console.print(table)
|
|
224
|
+
|
|
225
|
+
def configure_mcp_services(self, startup_config: Dict, config: Config) -> None:
|
|
226
|
+
"""Configure which MCP services to enable at startup."""
|
|
227
|
+
self.console.clear()
|
|
228
|
+
self.display_header()
|
|
229
|
+
self.console.print("[bold]Configure MCP Services[/bold]\n")
|
|
230
|
+
|
|
231
|
+
# Get available MCP services
|
|
232
|
+
mcp_manager = MCPConfigManager()
|
|
233
|
+
available_services = list(mcp_manager.STATIC_MCP_CONFIGS.keys())
|
|
234
|
+
enabled_services = set(startup_config.get("enabled_mcp_services", []))
|
|
235
|
+
|
|
236
|
+
# Display services with checkboxes
|
|
237
|
+
table = Table(box=ROUNDED, show_lines=True)
|
|
238
|
+
table.add_column("ID", style="dim", width=5)
|
|
239
|
+
table.add_column("Service", style="bold blue", width=25)
|
|
240
|
+
table.add_column("Status", width=15)
|
|
241
|
+
table.add_column("Description", style="", width=45)
|
|
242
|
+
|
|
243
|
+
service_descriptions = {
|
|
244
|
+
"kuzu-memory": "Graph-based memory system for agents",
|
|
245
|
+
"mcp-ticketer": "Ticket and issue tracking integration",
|
|
246
|
+
"mcp-browser": "Browser automation and web scraping",
|
|
247
|
+
"mcp-vector-search": "Semantic code search capabilities",
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
for idx, service in enumerate(available_services, 1):
|
|
251
|
+
status = (
|
|
252
|
+
"[green]✓ Enabled[/green]"
|
|
253
|
+
if service in enabled_services
|
|
254
|
+
else "[red]✗ Disabled[/red]"
|
|
255
|
+
)
|
|
256
|
+
description = service_descriptions.get(service, "MCP service")
|
|
257
|
+
table.add_row(str(idx), service, status, description)
|
|
258
|
+
|
|
259
|
+
self.console.print(table)
|
|
260
|
+
self.console.print("\n[bold]Commands:[/bold]")
|
|
261
|
+
self.console.print(" Enter service IDs to toggle (e.g., '1,3' or '1-4')")
|
|
262
|
+
|
|
263
|
+
text_a = Text(" ")
|
|
264
|
+
text_a.append("[a]", style="bold blue")
|
|
265
|
+
text_a.append(" Enable all")
|
|
266
|
+
self.console.print(text_a)
|
|
267
|
+
|
|
268
|
+
text_n = Text(" ")
|
|
269
|
+
text_n.append("[n]", style="bold blue")
|
|
270
|
+
text_n.append(" Disable all")
|
|
271
|
+
self.console.print(text_n)
|
|
272
|
+
|
|
273
|
+
text_b = Text(" ")
|
|
274
|
+
text_b.append("[b]", style="bold blue")
|
|
275
|
+
text_b.append(" Back to previous menu")
|
|
276
|
+
self.console.print(text_b)
|
|
277
|
+
|
|
278
|
+
self.console.print()
|
|
279
|
+
|
|
280
|
+
choice = Prompt.ask("[bold cyan]Toggle services[/bold cyan]", default="b")
|
|
281
|
+
|
|
282
|
+
if choice == "b":
|
|
283
|
+
return
|
|
284
|
+
if choice == "a":
|
|
285
|
+
startup_config["enabled_mcp_services"] = available_services.copy()
|
|
286
|
+
self.console.print("[green]All MCP services enabled![/green]")
|
|
287
|
+
elif choice == "n":
|
|
288
|
+
startup_config["enabled_mcp_services"] = []
|
|
289
|
+
self.console.print("[green]All MCP services disabled![/green]")
|
|
290
|
+
else:
|
|
291
|
+
# Parse service IDs
|
|
292
|
+
try:
|
|
293
|
+
selected_ids = parse_id_selection(choice, len(available_services))
|
|
294
|
+
for idx in selected_ids:
|
|
295
|
+
service = available_services[idx - 1]
|
|
296
|
+
if service in enabled_services:
|
|
297
|
+
enabled_services.remove(service)
|
|
298
|
+
self.console.print(f"[red]Disabled {service}[/red]")
|
|
299
|
+
else:
|
|
300
|
+
enabled_services.add(service)
|
|
301
|
+
self.console.print(f"[green]Enabled {service}[/green]")
|
|
302
|
+
startup_config["enabled_mcp_services"] = list(enabled_services)
|
|
303
|
+
except (ValueError, IndexError) as e:
|
|
304
|
+
self.console.print(f"[red]Invalid selection: {e}[/red]")
|
|
305
|
+
|
|
306
|
+
Prompt.ask("Press Enter to continue")
|
|
307
|
+
|
|
308
|
+
def configure_hook_services(self, startup_config: Dict, config: Config) -> None:
|
|
309
|
+
"""Configure which hook services to enable at startup."""
|
|
310
|
+
self.console.clear()
|
|
311
|
+
self.display_header()
|
|
312
|
+
self.console.print("[bold]Configure Hook Services[/bold]\n")
|
|
313
|
+
|
|
314
|
+
# Available hook services
|
|
315
|
+
available_services = [
|
|
316
|
+
("monitor", "Real-time event monitoring server (SocketIO)"),
|
|
317
|
+
("dashboard", "Web-based dashboard interface"),
|
|
318
|
+
("response-logger", "Agent response logging"),
|
|
319
|
+
("health-monitor", "Service health and recovery monitoring"),
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
enabled_services = set(startup_config.get("enabled_hook_services", []))
|
|
323
|
+
|
|
324
|
+
# Display services with checkboxes
|
|
325
|
+
table = Table(box=ROUNDED, show_lines=True)
|
|
326
|
+
table.add_column("ID", style="dim", width=5)
|
|
327
|
+
table.add_column("Service", style="bold blue", width=25)
|
|
328
|
+
table.add_column("Status", width=15)
|
|
329
|
+
table.add_column("Description", style="", width=45)
|
|
330
|
+
|
|
331
|
+
for idx, (service, description) in enumerate(available_services, 1):
|
|
332
|
+
status = (
|
|
333
|
+
"[green]✓ Enabled[/green]"
|
|
334
|
+
if service in enabled_services
|
|
335
|
+
else "[red]✗ Disabled[/red]"
|
|
336
|
+
)
|
|
337
|
+
table.add_row(str(idx), service, status, description)
|
|
338
|
+
|
|
339
|
+
self.console.print(table)
|
|
340
|
+
self.console.print("\n[bold]Commands:[/bold]")
|
|
341
|
+
self.console.print(" Enter service IDs to toggle (e.g., '1,3' or '1-4')")
|
|
342
|
+
|
|
343
|
+
text_a = Text(" ")
|
|
344
|
+
text_a.append("[a]", style="bold blue")
|
|
345
|
+
text_a.append(" Enable all")
|
|
346
|
+
self.console.print(text_a)
|
|
347
|
+
|
|
348
|
+
text_n = Text(" ")
|
|
349
|
+
text_n.append("[n]", style="bold blue")
|
|
350
|
+
text_n.append(" Disable all")
|
|
351
|
+
self.console.print(text_n)
|
|
352
|
+
|
|
353
|
+
text_b = Text(" ")
|
|
354
|
+
text_b.append("[b]", style="bold blue")
|
|
355
|
+
text_b.append(" Back to previous menu")
|
|
356
|
+
self.console.print(text_b)
|
|
357
|
+
|
|
358
|
+
self.console.print()
|
|
359
|
+
|
|
360
|
+
choice = Prompt.ask("[bold cyan]Toggle services[/bold cyan]", default="b")
|
|
361
|
+
|
|
362
|
+
if choice == "b":
|
|
363
|
+
return
|
|
364
|
+
if choice == "a":
|
|
365
|
+
startup_config["enabled_hook_services"] = [s[0] for s in available_services]
|
|
366
|
+
self.console.print("[green]All hook services enabled![/green]")
|
|
367
|
+
elif choice == "n":
|
|
368
|
+
startup_config["enabled_hook_services"] = []
|
|
369
|
+
self.console.print("[green]All hook services disabled![/green]")
|
|
370
|
+
else:
|
|
371
|
+
# Parse service IDs
|
|
372
|
+
try:
|
|
373
|
+
selected_ids = parse_id_selection(choice, len(available_services))
|
|
374
|
+
for idx in selected_ids:
|
|
375
|
+
service = available_services[idx - 1][0]
|
|
376
|
+
if service in enabled_services:
|
|
377
|
+
enabled_services.remove(service)
|
|
378
|
+
self.console.print(f"[red]Disabled {service}[/red]")
|
|
379
|
+
else:
|
|
380
|
+
enabled_services.add(service)
|
|
381
|
+
self.console.print(f"[green]Enabled {service}[/green]")
|
|
382
|
+
startup_config["enabled_hook_services"] = list(enabled_services)
|
|
383
|
+
except (ValueError, IndexError) as e:
|
|
384
|
+
self.console.print(f"[red]Invalid selection: {e}[/red]")
|
|
385
|
+
|
|
386
|
+
Prompt.ask("Press Enter to continue")
|
|
387
|
+
|
|
388
|
+
def configure_system_agents(self, startup_config: Dict, config: Config) -> None:
|
|
389
|
+
"""Configure which system agents to deploy at startup.
|
|
390
|
+
|
|
391
|
+
NEW LOGIC: Uses disabled_agents list. All agents from templates are enabled by default.
|
|
392
|
+
"""
|
|
393
|
+
while True:
|
|
394
|
+
self.console.clear()
|
|
395
|
+
self.display_header()
|
|
396
|
+
self.console.print("[bold]Configure System Agents[/bold]\n")
|
|
397
|
+
self.console.print(
|
|
398
|
+
"[dim]All agents discovered from templates are enabled by default. "
|
|
399
|
+
"Mark agents as disabled to prevent deployment.[/dim]\n"
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
# Discover available agents from template files
|
|
403
|
+
agents = self.agent_manager.discover_agents()
|
|
404
|
+
disabled_agents = set(startup_config.get("disabled_agents", []))
|
|
405
|
+
|
|
406
|
+
# Display agents with checkboxes
|
|
407
|
+
table = Table(box=ROUNDED, show_lines=True)
|
|
408
|
+
table.add_column("ID", style="dim", width=5)
|
|
409
|
+
table.add_column("Agent", style="bold blue", width=25)
|
|
410
|
+
table.add_column("Status", width=15)
|
|
411
|
+
table.add_column("Description", style="bold", width=45)
|
|
412
|
+
|
|
413
|
+
for idx, agent in enumerate(agents, 1):
|
|
414
|
+
# Agent is ENABLED if NOT in disabled list
|
|
415
|
+
is_enabled = agent.name not in disabled_agents
|
|
416
|
+
status = (
|
|
417
|
+
"[green]✓ Enabled[/green]"
|
|
418
|
+
if is_enabled
|
|
419
|
+
else "[red]✗ Disabled[/red]"
|
|
420
|
+
)
|
|
421
|
+
# Format description with bright styling
|
|
422
|
+
if len(agent.description) > 42:
|
|
423
|
+
desc_display = (
|
|
424
|
+
f"[cyan]{agent.description[:42]}[/cyan][dim]...[/dim]"
|
|
425
|
+
)
|
|
426
|
+
else:
|
|
427
|
+
desc_display = f"[cyan]{agent.description}[/cyan]"
|
|
428
|
+
table.add_row(str(idx), agent.name, status, desc_display)
|
|
429
|
+
|
|
430
|
+
self.console.print(table)
|
|
431
|
+
self.console.print("\n[bold]Commands:[/bold]")
|
|
432
|
+
self.console.print(" Enter agent IDs to toggle (e.g., '1,3' or '1-4')")
|
|
433
|
+
self.console.print(" [cyan]a[/cyan] - Enable all (clear disabled list)")
|
|
434
|
+
self.console.print(" [cyan]n[/cyan] - Disable all")
|
|
435
|
+
self.console.print(" [cyan]b[/cyan] - Back to previous menu")
|
|
436
|
+
self.console.print()
|
|
437
|
+
|
|
438
|
+
choice = Prompt.ask("[bold cyan]Select option[/bold cyan]", default="b")
|
|
439
|
+
|
|
440
|
+
if choice == "b":
|
|
441
|
+
return
|
|
442
|
+
if choice == "a":
|
|
443
|
+
# Enable all = empty disabled list
|
|
444
|
+
startup_config["disabled_agents"] = []
|
|
445
|
+
self.console.print("[green]All agents enabled![/green]")
|
|
446
|
+
Prompt.ask("Press Enter to continue")
|
|
447
|
+
elif choice == "n":
|
|
448
|
+
# Disable all = all agents in disabled list
|
|
449
|
+
startup_config["disabled_agents"] = [agent.name for agent in agents]
|
|
450
|
+
self.console.print("[green]All agents disabled![/green]")
|
|
451
|
+
Prompt.ask("Press Enter to continue")
|
|
452
|
+
else:
|
|
453
|
+
# Parse agent IDs
|
|
454
|
+
try:
|
|
455
|
+
selected_ids = parse_id_selection(choice, len(agents))
|
|
456
|
+
for idx in selected_ids:
|
|
457
|
+
agent = agents[idx - 1]
|
|
458
|
+
if agent.name in disabled_agents:
|
|
459
|
+
# Currently disabled, enable it (remove from disabled list)
|
|
460
|
+
disabled_agents.remove(agent.name)
|
|
461
|
+
self.console.print(f"[green]Enabled {agent.name}[/green]")
|
|
462
|
+
else:
|
|
463
|
+
# Currently enabled, disable it (add to disabled list)
|
|
464
|
+
disabled_agents.add(agent.name)
|
|
465
|
+
self.console.print(f"[red]Disabled {agent.name}[/red]")
|
|
466
|
+
startup_config["disabled_agents"] = list(disabled_agents)
|
|
467
|
+
# Refresh the display to show updated status immediately
|
|
468
|
+
except (ValueError, IndexError) as e:
|
|
469
|
+
self.console.print(f"[red]Invalid selection: {e}[/red]")
|
|
470
|
+
Prompt.ask("Press Enter to continue")
|
|
471
|
+
|
|
472
|
+
def enable_all_services(self, startup_config: Dict, config: Config) -> None:
|
|
473
|
+
"""Enable all services and agents."""
|
|
474
|
+
if Confirm.ask("[yellow]Enable ALL services and agents?[/yellow]"):
|
|
475
|
+
# Enable all MCP services
|
|
476
|
+
mcp_manager = MCPConfigManager()
|
|
477
|
+
startup_config["enabled_mcp_services"] = list(
|
|
478
|
+
mcp_manager.STATIC_MCP_CONFIGS.keys()
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
# Enable all hook services
|
|
482
|
+
startup_config["enabled_hook_services"] = [
|
|
483
|
+
"monitor",
|
|
484
|
+
"dashboard",
|
|
485
|
+
"response-logger",
|
|
486
|
+
"health-monitor",
|
|
487
|
+
]
|
|
488
|
+
|
|
489
|
+
# Enable all agents (empty disabled list)
|
|
490
|
+
startup_config["disabled_agents"] = []
|
|
491
|
+
|
|
492
|
+
self.console.print("[green]All services and agents enabled![/green]")
|
|
493
|
+
Prompt.ask("Press Enter to continue")
|
|
494
|
+
|
|
495
|
+
def disable_all_services(self, startup_config: Dict, config: Config) -> None:
|
|
496
|
+
"""Disable all services and agents."""
|
|
497
|
+
if Confirm.ask("[yellow]Disable ALL services and agents?[/yellow]"):
|
|
498
|
+
startup_config["enabled_mcp_services"] = []
|
|
499
|
+
startup_config["enabled_hook_services"] = []
|
|
500
|
+
# Disable all agents = add all to disabled list
|
|
501
|
+
agents = self.agent_manager.discover_agents()
|
|
502
|
+
startup_config["disabled_agents"] = [agent.name for agent in agents]
|
|
503
|
+
|
|
504
|
+
self.console.print("[green]All services and agents disabled![/green]")
|
|
505
|
+
self.console.print(
|
|
506
|
+
"[yellow]Note: You may need to enable at least some services for Claude MPM to function properly.[/yellow]"
|
|
507
|
+
)
|
|
508
|
+
Prompt.ask("Press Enter to continue")
|
|
509
|
+
|
|
510
|
+
def reset_to_defaults(self, startup_config: Dict, config: Config) -> None:
|
|
511
|
+
"""Reset startup configuration to defaults."""
|
|
512
|
+
if Confirm.ask("[yellow]Reset startup configuration to defaults?[/yellow]"):
|
|
513
|
+
# Reset to default values
|
|
514
|
+
mcp_manager = MCPConfigManager()
|
|
515
|
+
startup_config["enabled_mcp_services"] = list(
|
|
516
|
+
mcp_manager.STATIC_MCP_CONFIGS.keys()
|
|
517
|
+
)
|
|
518
|
+
startup_config["enabled_hook_services"] = [
|
|
519
|
+
"monitor",
|
|
520
|
+
"dashboard",
|
|
521
|
+
"response-logger",
|
|
522
|
+
"health-monitor",
|
|
523
|
+
]
|
|
524
|
+
# Default: All agents enabled (empty disabled list)
|
|
525
|
+
startup_config["disabled_agents"] = []
|
|
526
|
+
|
|
527
|
+
self.console.print(
|
|
528
|
+
"[green]Startup configuration reset to defaults![/green]"
|
|
529
|
+
)
|
|
530
|
+
Prompt.ask("Press Enter to continue")
|
|
531
|
+
|
|
532
|
+
def save_startup_configuration(self, startup_config: Dict, config: Config) -> bool:
|
|
533
|
+
"""Save startup configuration to config file and return whether to proceed to startup.
|
|
534
|
+
|
|
535
|
+
Returns:
|
|
536
|
+
bool: True if should proceed to startup, False to continue in menu
|
|
537
|
+
"""
|
|
538
|
+
try:
|
|
539
|
+
# Update the startup configuration
|
|
540
|
+
config.set("startup", startup_config)
|
|
541
|
+
|
|
542
|
+
# IMPORTANT: Also update agent_deployment.disabled_agents so the deployment
|
|
543
|
+
# system actually uses the configured disabled agents list
|
|
544
|
+
config.set(
|
|
545
|
+
"agent_deployment.disabled_agents",
|
|
546
|
+
startup_config.get("disabled_agents", []),
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
# Determine config file path
|
|
550
|
+
if self.current_scope == "project":
|
|
551
|
+
config_file = self.project_dir / ".claude-mpm" / "configuration.yaml"
|
|
552
|
+
else:
|
|
553
|
+
config_file = Path.home() / ".claude-mpm" / "configuration.yaml"
|
|
554
|
+
|
|
555
|
+
# Ensure directory exists
|
|
556
|
+
config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
557
|
+
|
|
558
|
+
# Temporarily suppress INFO logging to avoid duplicate save messages
|
|
559
|
+
root_logger = logging.getLogger("claude_mpm")
|
|
560
|
+
original_level = root_logger.level
|
|
561
|
+
root_logger.setLevel(logging.WARNING)
|
|
562
|
+
|
|
563
|
+
try:
|
|
564
|
+
# Save configuration (this will log at INFO level which we've suppressed)
|
|
565
|
+
config.save(config_file, format="yaml")
|
|
566
|
+
finally:
|
|
567
|
+
# Restore original logging level
|
|
568
|
+
root_logger.setLevel(original_level)
|
|
569
|
+
|
|
570
|
+
self.console.print(
|
|
571
|
+
f"[green]✓ Startup configuration saved to {config_file}[/green]"
|
|
572
|
+
)
|
|
573
|
+
self.console.print(
|
|
574
|
+
"\n[cyan]Applying configuration and launching Claude MPM...[/cyan]\n"
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
# Launch claude-mpm run command to get full startup cycle
|
|
578
|
+
# This ensures:
|
|
579
|
+
# 1. Configuration is loaded
|
|
580
|
+
# 2. Enabled agents are deployed
|
|
581
|
+
# 3. Disabled agents are removed from .claude/agents/
|
|
582
|
+
# 4. MCP services and hooks are started
|
|
583
|
+
try:
|
|
584
|
+
# Use execvp to replace the current process with claude-mpm run
|
|
585
|
+
# This ensures a clean transition from configurator to Claude MPM
|
|
586
|
+
os.execvp("claude-mpm", ["claude-mpm", "run"])
|
|
587
|
+
except Exception as e:
|
|
588
|
+
self.console.print(
|
|
589
|
+
f"[yellow]Could not launch Claude MPM automatically: {e}[/yellow]"
|
|
590
|
+
)
|
|
591
|
+
self.console.print(
|
|
592
|
+
"[cyan]Please run 'claude-mpm' manually to start.[/cyan]"
|
|
593
|
+
)
|
|
594
|
+
Prompt.ask("Press Enter to continue")
|
|
595
|
+
return True
|
|
596
|
+
|
|
597
|
+
# This line will never be reached if execvp succeeds
|
|
598
|
+
return True
|
|
599
|
+
|
|
600
|
+
except Exception as e:
|
|
601
|
+
self.console.print(f"[red]Error saving configuration: {e}[/red]")
|
|
602
|
+
Prompt.ask("Press Enter to continue")
|
|
603
|
+
return False
|
|
604
|
+
|
|
605
|
+
def save_all_configuration(self) -> bool:
|
|
606
|
+
"""Save all configuration changes across all contexts.
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
bool: True if all saves successful, False otherwise
|
|
610
|
+
"""
|
|
611
|
+
try:
|
|
612
|
+
# 1. Save any pending agent changes
|
|
613
|
+
if self.agent_manager and self.agent_manager.has_pending_changes():
|
|
614
|
+
self.agent_manager.commit_deferred_changes()
|
|
615
|
+
self.console.print("[green]✓ Agent changes saved[/green]")
|
|
616
|
+
|
|
617
|
+
# 2. Save configuration file
|
|
618
|
+
config = Config()
|
|
619
|
+
|
|
620
|
+
# Determine config file path based on scope
|
|
621
|
+
if self.current_scope == "project":
|
|
622
|
+
config_file = self.project_dir / ".claude-mpm" / "configuration.yaml"
|
|
623
|
+
else:
|
|
624
|
+
config_file = Path.home() / ".claude-mpm" / "configuration.yaml"
|
|
625
|
+
|
|
626
|
+
config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
627
|
+
|
|
628
|
+
# Save with suppressed logging to avoid duplicate messages
|
|
629
|
+
root_logger = logging.getLogger("claude_mpm")
|
|
630
|
+
original_level = root_logger.level
|
|
631
|
+
root_logger.setLevel(logging.WARNING)
|
|
632
|
+
|
|
633
|
+
try:
|
|
634
|
+
config.save(config_file, format="yaml")
|
|
635
|
+
finally:
|
|
636
|
+
root_logger.setLevel(original_level)
|
|
637
|
+
|
|
638
|
+
self.console.print(f"[green]✓ Configuration saved to {config_file}[/green]")
|
|
639
|
+
return True
|
|
640
|
+
|
|
641
|
+
except Exception as e:
|
|
642
|
+
self.console.print(f"[red]✗ Error saving configuration: {e}[/red]")
|
|
643
|
+
import traceback
|
|
644
|
+
|
|
645
|
+
traceback.print_exc()
|
|
646
|
+
return False
|