claude-mpm 4.7.4__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.
Files changed (308) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  4. claude_mpm/agents/BASE_PM.md +106 -1
  5. claude_mpm/agents/OUTPUT_STYLE.md +329 -11
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
  7. claude_mpm/agents/agent_loader.py +17 -5
  8. claude_mpm/agents/frontmatter_validator.py +284 -253
  9. claude_mpm/agents/templates/README.md +465 -0
  10. claude_mpm/agents/templates/agent-manager.json +4 -1
  11. claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
  12. claude_mpm/agents/templates/api_qa.json +11 -2
  13. claude_mpm/agents/templates/circuit_breakers.md +638 -0
  14. claude_mpm/agents/templates/clerk-ops.json +12 -2
  15. claude_mpm/agents/templates/code_analyzer.json +8 -2
  16. claude_mpm/agents/templates/content-agent.json +358 -0
  17. claude_mpm/agents/templates/dart_engineer.json +15 -2
  18. claude_mpm/agents/templates/data_engineer.json +15 -2
  19. claude_mpm/agents/templates/documentation.json +10 -2
  20. claude_mpm/agents/templates/engineer.json +21 -1
  21. claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
  22. claude_mpm/agents/templates/git_file_tracking.md +584 -0
  23. claude_mpm/agents/templates/golang_engineer.json +270 -0
  24. claude_mpm/agents/templates/imagemagick.json +4 -1
  25. claude_mpm/agents/templates/java_engineer.json +346 -0
  26. claude_mpm/agents/templates/local_ops_agent.json +1227 -6
  27. claude_mpm/agents/templates/memory_manager.json +4 -1
  28. claude_mpm/agents/templates/nextjs_engineer.json +141 -133
  29. claude_mpm/agents/templates/ops.json +12 -2
  30. claude_mpm/agents/templates/php-engineer.json +270 -174
  31. claude_mpm/agents/templates/pm_examples.md +474 -0
  32. claude_mpm/agents/templates/pm_red_flags.md +240 -0
  33. claude_mpm/agents/templates/product_owner.json +338 -0
  34. claude_mpm/agents/templates/project_organizer.json +14 -4
  35. claude_mpm/agents/templates/prompt-engineer.json +13 -2
  36. claude_mpm/agents/templates/python_engineer.json +174 -81
  37. claude_mpm/agents/templates/qa.json +11 -2
  38. claude_mpm/agents/templates/react_engineer.json +16 -3
  39. claude_mpm/agents/templates/refactoring_engineer.json +12 -2
  40. claude_mpm/agents/templates/research.json +34 -21
  41. claude_mpm/agents/templates/response_format.md +583 -0
  42. claude_mpm/agents/templates/ruby-engineer.json +129 -192
  43. claude_mpm/agents/templates/rust_engineer.json +270 -0
  44. claude_mpm/agents/templates/security.json +10 -2
  45. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  46. claude_mpm/agents/templates/ticketing.json +10 -2
  47. claude_mpm/agents/templates/typescript_engineer.json +116 -125
  48. claude_mpm/agents/templates/validation_templates.md +312 -0
  49. claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
  50. claude_mpm/agents/templates/version_control.json +12 -2
  51. claude_mpm/agents/templates/web_qa.json +11 -2
  52. claude_mpm/agents/templates/web_ui.json +15 -2
  53. claude_mpm/cli/__init__.py +34 -614
  54. claude_mpm/cli/commands/agent_manager.py +25 -12
  55. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  56. claude_mpm/cli/commands/agents.py +235 -148
  57. claude_mpm/cli/commands/agents_detect.py +380 -0
  58. claude_mpm/cli/commands/agents_recommend.py +309 -0
  59. claude_mpm/cli/commands/aggregate.py +7 -3
  60. claude_mpm/cli/commands/analyze.py +9 -4
  61. claude_mpm/cli/commands/analyze_code.py +7 -2
  62. claude_mpm/cli/commands/auto_configure.py +570 -0
  63. claude_mpm/cli/commands/config.py +47 -13
  64. claude_mpm/cli/commands/configure.py +419 -1571
  65. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  66. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  67. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  68. claude_mpm/cli/commands/configure_models.py +18 -0
  69. claude_mpm/cli/commands/configure_navigation.py +167 -0
  70. claude_mpm/cli/commands/configure_paths.py +104 -0
  71. claude_mpm/cli/commands/configure_persistence.py +254 -0
  72. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  73. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  74. claude_mpm/cli/commands/configure_validators.py +73 -0
  75. claude_mpm/cli/commands/local_deploy.py +537 -0
  76. claude_mpm/cli/commands/memory.py +54 -20
  77. claude_mpm/cli/commands/mpm_init.py +585 -196
  78. claude_mpm/cli/commands/mpm_init_handler.py +37 -3
  79. claude_mpm/cli/commands/search.py +170 -4
  80. claude_mpm/cli/commands/upgrade.py +152 -0
  81. claude_mpm/cli/executor.py +202 -0
  82. claude_mpm/cli/helpers.py +105 -0
  83. claude_mpm/cli/interactive/__init__.py +3 -0
  84. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  85. claude_mpm/cli/parsers/__init__.py +7 -1
  86. claude_mpm/cli/parsers/agents_parser.py +9 -0
  87. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  88. claude_mpm/cli/parsers/base_parser.py +110 -3
  89. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  90. claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
  91. claude_mpm/cli/shared/output_formatters.py +28 -19
  92. claude_mpm/cli/startup.py +481 -0
  93. claude_mpm/cli/utils.py +52 -1
  94. claude_mpm/commands/mpm-agents-detect.md +168 -0
  95. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  96. claude_mpm/commands/mpm-agents.md +75 -1
  97. claude_mpm/commands/mpm-auto-configure.md +217 -0
  98. claude_mpm/commands/mpm-help.md +163 -0
  99. claude_mpm/commands/mpm-init.md +148 -3
  100. claude_mpm/commands/mpm-version.md +113 -0
  101. claude_mpm/commands/mpm.md +1 -0
  102. claude_mpm/config/agent_config.py +2 -2
  103. claude_mpm/config/model_config.py +428 -0
  104. claude_mpm/constants.py +1 -0
  105. claude_mpm/core/base_service.py +13 -12
  106. claude_mpm/core/enums.py +452 -0
  107. claude_mpm/core/factories.py +1 -1
  108. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  109. claude_mpm/core/interactive_session.py +9 -3
  110. claude_mpm/core/log_manager.py +2 -0
  111. claude_mpm/core/logging_config.py +6 -2
  112. claude_mpm/core/oneshot_session.py +8 -4
  113. claude_mpm/core/optimized_agent_loader.py +3 -3
  114. claude_mpm/core/output_style_manager.py +12 -192
  115. claude_mpm/core/service_registry.py +5 -1
  116. claude_mpm/core/types.py +2 -9
  117. claude_mpm/core/typing_utils.py +7 -6
  118. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  119. claude_mpm/dashboard/templates/index.html +3 -41
  120. claude_mpm/hooks/__init__.py +20 -0
  121. claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
  122. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  123. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
  124. claude_mpm/hooks/failure_learning/__init__.py +60 -0
  125. claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
  126. claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
  127. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
  128. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  129. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  130. claude_mpm/hooks/kuzu_memory_hook.py +37 -12
  131. claude_mpm/hooks/kuzu_response_hook.py +183 -0
  132. claude_mpm/models/resume_log.py +340 -0
  133. claude_mpm/services/agents/__init__.py +18 -5
  134. claude_mpm/services/agents/auto_config_manager.py +796 -0
  135. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  136. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  137. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  138. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  139. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  140. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  141. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  142. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  143. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  144. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  145. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  146. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  147. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  148. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  149. claude_mpm/services/agents/local_template_manager.py +1 -1
  150. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  151. claude_mpm/services/agents/observers.py +547 -0
  152. claude_mpm/services/agents/recommender.py +568 -0
  153. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  154. claude_mpm/services/command_handler_service.py +11 -5
  155. claude_mpm/services/core/__init__.py +33 -1
  156. claude_mpm/services/core/interfaces/__init__.py +90 -3
  157. claude_mpm/services/core/interfaces/agent.py +184 -0
  158. claude_mpm/services/core/interfaces/health.py +172 -0
  159. claude_mpm/services/core/interfaces/model.py +281 -0
  160. claude_mpm/services/core/interfaces/process.py +372 -0
  161. claude_mpm/services/core/interfaces/project.py +121 -0
  162. claude_mpm/services/core/interfaces/restart.py +307 -0
  163. claude_mpm/services/core/interfaces/stability.py +260 -0
  164. claude_mpm/services/core/memory_manager.py +11 -24
  165. claude_mpm/services/core/models/__init__.py +79 -0
  166. claude_mpm/services/core/models/agent_config.py +381 -0
  167. claude_mpm/services/core/models/health.py +162 -0
  168. claude_mpm/services/core/models/process.py +235 -0
  169. claude_mpm/services/core/models/restart.py +302 -0
  170. claude_mpm/services/core/models/stability.py +264 -0
  171. claude_mpm/services/core/models/toolchain.py +306 -0
  172. claude_mpm/services/core/path_resolver.py +23 -7
  173. claude_mpm/services/diagnostics/__init__.py +2 -2
  174. claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
  175. claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
  176. claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
  177. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
  178. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  179. claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
  180. claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
  181. claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
  182. claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
  183. claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
  184. claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
  185. claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
  186. claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
  187. claude_mpm/services/diagnostics/models.py +19 -24
  188. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  189. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  190. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  191. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  192. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  193. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  194. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  195. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  196. claude_mpm/services/local_ops/__init__.py +163 -0
  197. claude_mpm/services/local_ops/crash_detector.py +257 -0
  198. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  199. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  200. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  201. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  202. claude_mpm/services/local_ops/health_manager.py +430 -0
  203. claude_mpm/services/local_ops/log_monitor.py +396 -0
  204. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  205. claude_mpm/services/local_ops/process_manager.py +595 -0
  206. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  207. claude_mpm/services/local_ops/restart_manager.py +401 -0
  208. claude_mpm/services/local_ops/restart_policy.py +387 -0
  209. claude_mpm/services/local_ops/state_manager.py +372 -0
  210. claude_mpm/services/local_ops/unified_manager.py +600 -0
  211. claude_mpm/services/mcp_config_manager.py +9 -4
  212. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  213. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  214. claude_mpm/services/mcp_gateway/main.py +30 -0
  215. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
  216. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
  217. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
  218. claude_mpm/services/mcp_service_verifier.py +1 -1
  219. claude_mpm/services/memory/failure_tracker.py +563 -0
  220. claude_mpm/services/memory_hook_service.py +165 -4
  221. claude_mpm/services/model/__init__.py +147 -0
  222. claude_mpm/services/model/base_provider.py +365 -0
  223. claude_mpm/services/model/claude_provider.py +412 -0
  224. claude_mpm/services/model/model_router.py +453 -0
  225. claude_mpm/services/model/ollama_provider.py +415 -0
  226. claude_mpm/services/monitor/daemon_manager.py +3 -2
  227. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  228. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  229. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  230. claude_mpm/services/monitor/server.py +2 -1
  231. claude_mpm/services/project/__init__.py +23 -0
  232. claude_mpm/services/project/detection_strategies.py +719 -0
  233. claude_mpm/services/project/toolchain_analyzer.py +581 -0
  234. claude_mpm/services/self_upgrade_service.py +342 -0
  235. claude_mpm/services/session_management_service.py +3 -2
  236. claude_mpm/services/session_manager.py +205 -1
  237. claude_mpm/services/shared/async_service_base.py +16 -27
  238. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  239. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  240. claude_mpm/services/socketio/handlers/hook.py +13 -2
  241. claude_mpm/services/socketio/handlers/registry.py +4 -2
  242. claude_mpm/services/socketio/server/main.py +10 -8
  243. claude_mpm/services/subprocess_launcher_service.py +14 -5
  244. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
  245. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  246. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  247. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
  248. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  249. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  250. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  251. claude_mpm/services/unified/deployment_strategies/local.py +6 -5
  252. claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
  253. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
  254. claude_mpm/services/unified/interfaces.py +3 -1
  255. claude_mpm/services/unified/unified_analyzer.py +14 -10
  256. claude_mpm/services/unified/unified_config.py +2 -1
  257. claude_mpm/services/unified/unified_deployment.py +9 -4
  258. claude_mpm/services/version_service.py +104 -1
  259. claude_mpm/skills/__init__.py +21 -0
  260. claude_mpm/skills/bundled/__init__.py +6 -0
  261. claude_mpm/skills/bundled/api-documentation.md +393 -0
  262. claude_mpm/skills/bundled/async-testing.md +571 -0
  263. claude_mpm/skills/bundled/code-review.md +143 -0
  264. claude_mpm/skills/bundled/database-migration.md +199 -0
  265. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  266. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  267. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  268. claude_mpm/skills/bundled/git-workflow.md +414 -0
  269. claude_mpm/skills/bundled/imagemagick.md +204 -0
  270. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  271. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  272. claude_mpm/skills/bundled/pdf.md +141 -0
  273. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  274. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  275. claude_mpm/skills/bundled/security-scanning.md +327 -0
  276. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  277. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  278. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  279. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  280. claude_mpm/skills/bundled/xlsx.md +157 -0
  281. claude_mpm/skills/registry.py +286 -0
  282. claude_mpm/skills/skill_manager.py +310 -0
  283. claude_mpm/storage/state_storage.py +15 -15
  284. claude_mpm/tools/code_tree_analyzer.py +177 -141
  285. claude_mpm/tools/code_tree_events.py +4 -2
  286. claude_mpm/utils/agent_dependency_loader.py +40 -20
  287. claude_mpm/utils/display_helper.py +260 -0
  288. claude_mpm/utils/git_analyzer.py +407 -0
  289. claude_mpm/utils/robust_installer.py +73 -19
  290. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
  291. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
  292. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  293. claude_mpm/dashboard/static/index-hub-backup.html +0 -713
  294. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  295. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  296. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  297. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  298. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  299. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  300. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  301. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  302. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  303. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  304. claude_mpm/services/project/analyzer_refactored.py +0 -450
  305. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
  306. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
  307. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
  308. {claude_mpm-4.7.4.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