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,796 @@
1
+ """
2
+ Auto-Configuration Manager Service for Claude MPM Framework
3
+ ===========================================================
4
+
5
+ WHY: Orchestrates the complete auto-configuration workflow from toolchain
6
+ analysis through agent deployment. Provides a single entry point for automated
7
+ project configuration with safety checks and rollback capabilities.
8
+
9
+ DESIGN DECISION: Implements the Facade pattern to simplify complex interactions
10
+ between ToolchainAnalyzer, AgentRecommender, and AgentDeployment services.
11
+ Uses Observer pattern for progress tracking and supports dry-run mode for
12
+ safe previewing.
13
+
14
+ Part of TSK-0054: Auto-Configuration Feature - Phase 4
15
+ """
16
+
17
+ import time
18
+ import traceback
19
+ from datetime import datetime, timezone
20
+ from pathlib import Path
21
+ from typing import Any, Dict, List, Optional
22
+
23
+ import yaml
24
+
25
+ from ...core.base_service import BaseService
26
+ from ...core.enums import OperationResult, ValidationSeverity
27
+ from ..core.interfaces.agent import IAgentRegistry, IAutoConfigManager
28
+ from ..core.models.agent_config import (
29
+ AgentRecommendation,
30
+ ConfigurationPreview,
31
+ ConfigurationResult,
32
+ ValidationIssue,
33
+ ValidationResult,
34
+ )
35
+ from ..core.models.toolchain import ToolchainAnalysis
36
+ from .observers import IDeploymentObserver, NullObserver
37
+ from .recommender import AgentRecommenderService
38
+
39
+
40
+ class AutoConfigManagerService(BaseService, IAutoConfigManager):
41
+ """
42
+ Service for automated agent configuration and deployment.
43
+
44
+ This service orchestrates:
45
+ 1. Toolchain analysis to understand project technology stack
46
+ 2. Agent recommendations based on detected toolchain
47
+ 3. Configuration validation with comprehensive checks
48
+ 4. User confirmation (optional) before deployment
49
+ 5. Agent deployment with progress tracking
50
+ 6. Rollback on failure to maintain consistency
51
+ 7. Configuration persistence for future reference
52
+
53
+ Safety Features:
54
+ - Minimum confidence threshold (default 0.8)
55
+ - Dry-run mode for preview without changes
56
+ - Validation gates to block invalid configurations
57
+ - Rollback capability for failed deployments
58
+ - User confirmation for destructive operations
59
+
60
+ Performance:
61
+ - Complete workflow: <30 seconds for typical projects
62
+ - Validation: <1 second
63
+ - Preview generation: <5 seconds
64
+ - Uses caching where applicable
65
+ """
66
+
67
+ def __init__(
68
+ self,
69
+ toolchain_analyzer: Optional[Any] = None,
70
+ agent_recommender: Optional[AgentRecommenderService] = None,
71
+ agent_registry: Optional[IAgentRegistry] = None,
72
+ agent_deployment: Optional[Any] = None,
73
+ config: Optional[Dict[str, Any]] = None,
74
+ container: Optional[Any] = None,
75
+ ):
76
+ """
77
+ Initialize the Auto-Configuration Manager Service.
78
+
79
+ Args:
80
+ toolchain_analyzer: Service for analyzing project toolchains
81
+ agent_recommender: Service for recommending agents
82
+ agent_registry: Service for agent discovery and metadata
83
+ agent_deployment: Service for deploying agents
84
+ config: Optional configuration dictionary
85
+ container: Optional service container for dependency injection
86
+ """
87
+ super().__init__(
88
+ name="AutoConfigManagerService",
89
+ config=config,
90
+ enable_enhanced_features=False,
91
+ container=container,
92
+ )
93
+
94
+ # Store service dependencies
95
+ self._toolchain_analyzer = toolchain_analyzer
96
+ self._agent_recommender = agent_recommender
97
+ self._agent_registry = agent_registry
98
+ self._agent_deployment = agent_deployment
99
+
100
+ # Configuration settings
101
+ self._min_confidence_default = 0.8
102
+ self._max_rollback_attempts = 3
103
+ self._deployment_timeout_seconds = 300 # 5 minutes
104
+ self._config_file_name = "auto-config.yaml"
105
+
106
+ self.logger.info("AutoConfigManagerService initialized")
107
+
108
+ async def _initialize(self) -> None:
109
+ """Initialize the service (required by BaseService)."""
110
+ # Lazy initialization of dependencies if needed
111
+ if self._toolchain_analyzer is None:
112
+ try:
113
+ from ..project.toolchain_analyzer import ToolchainAnalyzerService
114
+
115
+ self._toolchain_analyzer = ToolchainAnalyzerService()
116
+ self.logger.info("Initialized ToolchainAnalyzerService")
117
+ except Exception as e:
118
+ self.logger.warning(
119
+ f"Failed to initialize ToolchainAnalyzerService: {e}"
120
+ )
121
+
122
+ if self._agent_recommender is None:
123
+ try:
124
+ self._agent_recommender = AgentRecommenderService()
125
+ self.logger.info("Initialized AgentRecommenderService")
126
+ except Exception as e:
127
+ self.logger.warning(
128
+ f"Failed to initialize AgentRecommenderService: {e}"
129
+ )
130
+
131
+ async def _cleanup(self) -> None:
132
+ """Cleanup service resources (required by BaseService)."""
133
+ # Clear any cached data
134
+
135
+ async def auto_configure(
136
+ self,
137
+ project_path: Path,
138
+ confirmation_required: bool = True,
139
+ dry_run: bool = False,
140
+ min_confidence: float = 0.8,
141
+ observer: Optional[IDeploymentObserver] = None,
142
+ ) -> ConfigurationResult:
143
+ """
144
+ Perform automated agent configuration.
145
+
146
+ Complete end-to-end configuration workflow:
147
+ 1. Analyze project toolchain
148
+ 2. Generate agent recommendations
149
+ 3. Validate proposed configuration
150
+ 4. Request user confirmation (if required)
151
+ 5. Deploy approved agents
152
+ 6. Verify deployment success
153
+
154
+ Args:
155
+ project_path: Path to the project root directory
156
+ confirmation_required: Whether to require user approval before deployment
157
+ dry_run: If True, preview only without deploying
158
+ min_confidence: Minimum confidence score for recommendations (0.0-1.0)
159
+ observer: Optional observer for progress tracking
160
+
161
+ Returns:
162
+ ConfigurationResult: Complete configuration results including
163
+ deployed agents, validation results, and any errors
164
+
165
+ Raises:
166
+ FileNotFoundError: If project_path does not exist
167
+ PermissionError: If unable to write to project directory
168
+ ValueError: If min_confidence is invalid
169
+ """
170
+ # Validate inputs
171
+ if not project_path.exists():
172
+ raise FileNotFoundError(f"Project path does not exist: {project_path}")
173
+ if not project_path.is_dir():
174
+ raise ValueError(f"Project path is not a directory: {project_path}")
175
+ if not (0.0 <= min_confidence <= 1.0):
176
+ raise ValueError(
177
+ f"min_confidence must be between 0.0 and 1.0, got {min_confidence}"
178
+ )
179
+
180
+ # Use NullObserver if none provided
181
+ if observer is None:
182
+ observer = NullObserver()
183
+
184
+ start_time = time.time()
185
+ self.logger.info(
186
+ f"Starting auto-configuration for project: {project_path} "
187
+ f"(dry_run={dry_run}, min_confidence={min_confidence})"
188
+ )
189
+
190
+ try:
191
+ # Step 1: Analyze toolchain
192
+ analysis_start = time.time()
193
+ observer.on_analysis_started(str(project_path))
194
+
195
+ toolchain = await self._analyze_toolchain(project_path)
196
+ analysis_duration = (time.time() - analysis_start) * 1000
197
+
198
+ observer.on_analysis_completed(toolchain, analysis_duration)
199
+ self.logger.info(
200
+ f"Toolchain analysis complete: {toolchain.primary_language} "
201
+ f"with {len(toolchain.frameworks)} frameworks"
202
+ )
203
+
204
+ # Step 2: Generate recommendations
205
+ rec_start = time.time()
206
+ observer.on_recommendation_started()
207
+
208
+ recommendations = await self._generate_recommendations(
209
+ toolchain, min_confidence
210
+ )
211
+ rec_duration = (time.time() - rec_start) * 1000
212
+
213
+ observer.on_recommendation_completed(recommendations, rec_duration)
214
+ self.logger.info(f"Generated {len(recommendations)} agent recommendations")
215
+
216
+ if not recommendations:
217
+ return ConfigurationResult(
218
+ status=OperationResult.SUCCESS,
219
+ message="No agents recommended for this project configuration",
220
+ recommendations=recommendations,
221
+ metadata={
222
+ "duration_ms": (time.time() - start_time) * 1000,
223
+ "dry_run": dry_run,
224
+ },
225
+ )
226
+
227
+ # Step 3: Validate configuration
228
+ observer.on_validation_started()
229
+
230
+ validation_result = self.validate_configuration(recommendations)
231
+
232
+ observer.on_validation_completed(
233
+ validation_result.is_valid,
234
+ validation_result.error_count,
235
+ validation_result.warning_count,
236
+ )
237
+
238
+ if not validation_result.is_valid:
239
+ self.logger.error(
240
+ f"Validation failed with {validation_result.error_count} errors"
241
+ )
242
+ return ConfigurationResult(
243
+ status=OperationResult.ERROR,
244
+ validation_errors=[
245
+ issue.message for issue in validation_result.errors
246
+ ],
247
+ validation_warnings=[
248
+ issue.message for issue in validation_result.warnings
249
+ ],
250
+ recommendations=recommendations,
251
+ message="Configuration validation failed",
252
+ metadata={
253
+ "duration_ms": (time.time() - start_time) * 1000,
254
+ "dry_run": dry_run,
255
+ },
256
+ )
257
+
258
+ # Step 4: Handle dry-run
259
+ if dry_run:
260
+ self.logger.info("Dry-run mode: skipping deployment")
261
+ return ConfigurationResult(
262
+ status=OperationResult.SUCCESS,
263
+ validation_warnings=[
264
+ issue.message for issue in validation_result.warnings
265
+ ],
266
+ recommendations=recommendations,
267
+ message=f"Dry-run complete: would deploy {len(recommendations)} agents",
268
+ metadata={
269
+ "duration_ms": (time.time() - start_time) * 1000,
270
+ "dry_run": True,
271
+ },
272
+ )
273
+
274
+ # Step 5: User confirmation
275
+ if confirmation_required:
276
+ confirmed = await self._request_confirmation(
277
+ recommendations, validation_result
278
+ )
279
+ if not confirmed:
280
+ self.logger.info("User cancelled auto-configuration")
281
+ return ConfigurationResult(
282
+ status=OperationResult.CANCELLED,
283
+ recommendations=recommendations,
284
+ message="Auto-configuration cancelled by user",
285
+ metadata={
286
+ "duration_ms": (time.time() - start_time) * 1000,
287
+ "dry_run": dry_run,
288
+ },
289
+ )
290
+
291
+ # Step 6: Deploy agents
292
+ deploy_start = time.time()
293
+ observer.on_deployment_started(len(recommendations))
294
+
295
+ deployed_agents, failed_agents = await self._deploy_agents(
296
+ project_path, recommendations, observer
297
+ )
298
+ deploy_duration = (time.time() - deploy_start) * 1000
299
+
300
+ observer.on_deployment_completed(
301
+ len(deployed_agents), len(failed_agents), deploy_duration
302
+ )
303
+
304
+ # Step 7: Handle deployment failures
305
+ if failed_agents:
306
+ self.logger.warning(
307
+ f"Deployment completed with {len(failed_agents)} failures"
308
+ )
309
+
310
+ # Attempt rollback
311
+ if deployed_agents:
312
+ observer.on_rollback_started(deployed_agents)
313
+ rollback_success = await self._rollback_deployment(
314
+ project_path, deployed_agents
315
+ )
316
+ observer.on_rollback_completed(rollback_success)
317
+
318
+ return ConfigurationResult(
319
+ status=(
320
+ OperationResult.WARNING
321
+ if deployed_agents
322
+ else OperationResult.FAILED
323
+ ),
324
+ deployed_agents=deployed_agents,
325
+ failed_agents=failed_agents,
326
+ validation_warnings=[
327
+ issue.message for issue in validation_result.warnings
328
+ ],
329
+ recommendations=recommendations,
330
+ message=f"Deployment completed with issues: {len(deployed_agents)} succeeded, {len(failed_agents)} failed",
331
+ metadata={
332
+ "duration_ms": (time.time() - start_time) * 1000,
333
+ "dry_run": dry_run,
334
+ "rollback_attempted": len(deployed_agents) > 0,
335
+ },
336
+ )
337
+
338
+ # Step 8: Save configuration
339
+ await self._save_configuration(project_path, toolchain, recommendations)
340
+
341
+ # Success!
342
+ total_duration = (time.time() - start_time) * 1000
343
+ self.logger.info(
344
+ f"Auto-configuration completed successfully in {total_duration:.0f}ms: "
345
+ f"deployed {len(deployed_agents)} agents"
346
+ )
347
+
348
+ return ConfigurationResult(
349
+ status=OperationResult.SUCCESS,
350
+ deployed_agents=deployed_agents,
351
+ validation_warnings=[
352
+ issue.message for issue in validation_result.warnings
353
+ ],
354
+ recommendations=recommendations,
355
+ message=f"Successfully configured {len(deployed_agents)} agents",
356
+ metadata={
357
+ "duration_ms": total_duration,
358
+ "dry_run": dry_run,
359
+ },
360
+ )
361
+
362
+ except Exception as e:
363
+ self.logger.error(f"Auto-configuration failed: {e}", exc_info=True)
364
+ observer.on_error("auto-configuration", str(e), e)
365
+
366
+ return ConfigurationResult(
367
+ status=OperationResult.FAILED,
368
+ message=f"Auto-configuration failed: {e}",
369
+ metadata={
370
+ "duration_ms": (time.time() - start_time) * 1000,
371
+ "dry_run": dry_run,
372
+ "error": str(e),
373
+ "traceback": traceback.format_exc(),
374
+ },
375
+ )
376
+
377
+ def validate_configuration(
378
+ self, recommendations: List[AgentRecommendation]
379
+ ) -> ValidationResult:
380
+ """
381
+ Validate proposed configuration before deployment.
382
+
383
+ Performs comprehensive validation:
384
+ - Checks for agent existence
385
+ - Verifies no conflicts (multiple agents for same role)
386
+ - Validates minimum confidence threshold
387
+ - Checks deployment prerequisites
388
+ - Warns about unmatched toolchains
389
+
390
+ Args:
391
+ recommendations: List of agent recommendations to validate
392
+
393
+ Returns:
394
+ ValidationResult: Validation result with any warnings or errors
395
+
396
+ Raises:
397
+ ValueError: If recommendations list is empty or invalid
398
+ """
399
+ if not recommendations:
400
+ raise ValueError("Cannot validate empty recommendations list")
401
+
402
+ issues: List[ValidationIssue] = []
403
+ validated_agents: List[str] = []
404
+
405
+ # Track agent roles to detect conflicts
406
+ role_agents: Dict[str, List[str]] = {}
407
+
408
+ for recommendation in recommendations:
409
+ agent_id = recommendation.agent_id
410
+ validated_agents.append(agent_id)
411
+
412
+ # Check 1: Agent existence
413
+ if self._agent_registry:
414
+ try:
415
+ # Try to get agent metadata to verify it exists
416
+ agent = self._agent_registry.get_agent(agent_id)
417
+ if agent is None:
418
+ issues.append(
419
+ ValidationIssue(
420
+ severity=ValidationSeverity.ERROR,
421
+ message=f"Agent '{agent_id}' does not exist",
422
+ agent_id=agent_id,
423
+ suggested_fix="Remove this recommendation or ensure agent is installed",
424
+ )
425
+ )
426
+ continue
427
+ except Exception as e:
428
+ issues.append(
429
+ ValidationIssue(
430
+ severity=ValidationSeverity.WARNING,
431
+ message=f"Could not verify agent '{agent_id}': {e}",
432
+ agent_id=agent_id,
433
+ )
434
+ )
435
+
436
+ # Check 2: Confidence threshold
437
+ if recommendation.confidence_score < 0.5:
438
+ issues.append(
439
+ ValidationIssue(
440
+ severity=ValidationSeverity.WARNING,
441
+ message=f"Low confidence score ({recommendation.confidence_score:.2f}) for agent '{agent_id}'",
442
+ agent_id=agent_id,
443
+ suggested_fix="Consider reviewing agent capabilities or adjusting threshold",
444
+ )
445
+ )
446
+ elif recommendation.confidence_score < 0.7:
447
+ issues.append(
448
+ ValidationIssue(
449
+ severity=ValidationSeverity.INFO,
450
+ message=f"Moderate confidence score ({recommendation.confidence_score:.2f}) for agent '{agent_id}'",
451
+ agent_id=agent_id,
452
+ )
453
+ )
454
+
455
+ # Check 3: Track roles for conflict detection
456
+ if recommendation.capabilities:
457
+ for spec in recommendation.capabilities.specializations:
458
+ role = spec.value
459
+ if role not in role_agents:
460
+ role_agents[role] = []
461
+ role_agents[role].append(agent_id)
462
+
463
+ # Check 4: Recommendation concerns
464
+ if recommendation.has_concerns:
465
+ for concern in recommendation.concerns:
466
+ issues.append(
467
+ ValidationIssue(
468
+ severity=ValidationSeverity.INFO,
469
+ message=f"Concern for '{agent_id}': {concern}",
470
+ agent_id=agent_id,
471
+ )
472
+ )
473
+
474
+ # Check 5: Role conflicts (multiple agents for same role)
475
+ for role, agents in role_agents.items():
476
+ if len(agents) > 1:
477
+ issues.append(
478
+ ValidationIssue(
479
+ severity=ValidationSeverity.WARNING,
480
+ message=f"Multiple agents ({', '.join(agents)}) recommended for role '{role}'",
481
+ suggested_fix="Consider selecting the highest confidence agent for this role",
482
+ )
483
+ )
484
+
485
+ # Determine if validation passes (no errors)
486
+ is_valid = not any(
487
+ issue.severity == ValidationSeverity.ERROR for issue in issues
488
+ )
489
+
490
+ self.logger.info(
491
+ f"Validation complete: {len(validated_agents)} agents, "
492
+ f"{len([i for i in issues if i.severity == ValidationSeverity.ERROR])} errors, "
493
+ f"{len([i for i in issues if i.severity == ValidationSeverity.WARNING])} warnings"
494
+ )
495
+
496
+ return ValidationResult(
497
+ is_valid=is_valid,
498
+ issues=issues,
499
+ validated_agents=validated_agents,
500
+ metadata={"validation_timestamp": datetime.now(timezone.utc).isoformat()},
501
+ )
502
+
503
+ def preview_configuration(
504
+ self, project_path: Path, min_confidence: float = 0.8
505
+ ) -> ConfigurationPreview:
506
+ """
507
+ Preview what would be configured without applying changes.
508
+
509
+ Performs analysis and recommendation without making any changes:
510
+ - Analyzes project toolchain
511
+ - Generates recommendations
512
+ - Validates configuration
513
+ - Returns preview of what would be deployed
514
+
515
+ Args:
516
+ project_path: Path to the project root directory
517
+ min_confidence: Minimum confidence score for recommendations
518
+
519
+ Returns:
520
+ ConfigurationPreview: Preview of configuration that would be applied
521
+
522
+ Raises:
523
+ FileNotFoundError: If project_path does not exist
524
+ """
525
+ if not project_path.exists():
526
+ raise FileNotFoundError(f"Project path does not exist: {project_path}")
527
+
528
+ self.logger.info(f"Generating configuration preview for: {project_path}")
529
+
530
+ try:
531
+ # Run analysis and recommendations synchronously for preview
532
+ import asyncio
533
+
534
+ loop = asyncio.get_event_loop()
535
+
536
+ # Analyze toolchain
537
+ if asyncio.iscoroutinefunction(self._analyze_toolchain):
538
+ toolchain = loop.run_until_complete(
539
+ self._analyze_toolchain(project_path)
540
+ )
541
+ else:
542
+ toolchain = self._analyze_toolchain(project_path)
543
+
544
+ # Generate recommendations
545
+ if asyncio.iscoroutinefunction(self._generate_recommendations):
546
+ recommendations = loop.run_until_complete(
547
+ self._generate_recommendations(toolchain, min_confidence)
548
+ )
549
+ else:
550
+ recommendations = self._generate_recommendations(
551
+ toolchain, min_confidence
552
+ )
553
+
554
+ # Validate configuration
555
+ validation_result = self.validate_configuration(recommendations)
556
+
557
+ # Estimate deployment time (5 seconds per agent)
558
+ estimated_time = len(recommendations) * 5.0
559
+
560
+ # Determine what would be deployed
561
+ would_deploy = [
562
+ rec.agent_id
563
+ for rec in recommendations
564
+ if rec.confidence_score >= min_confidence
565
+ ]
566
+ would_skip = [
567
+ rec.agent_id
568
+ for rec in recommendations
569
+ if rec.confidence_score < min_confidence
570
+ ]
571
+
572
+ preview = ConfigurationPreview(
573
+ recommendations=recommendations,
574
+ validation_result=validation_result,
575
+ estimated_deployment_time=estimated_time,
576
+ would_deploy=would_deploy,
577
+ would_skip=would_skip,
578
+ requires_confirmation=True,
579
+ metadata={
580
+ "preview_timestamp": datetime.now(timezone.utc).isoformat(),
581
+ "toolchain_summary": {
582
+ "primary_language": toolchain.primary_language,
583
+ "frameworks": [fw.name for fw in toolchain.frameworks],
584
+ "deployment_target": (
585
+ toolchain.deployment_target.platform
586
+ if toolchain.deployment_target
587
+ else None
588
+ ),
589
+ },
590
+ },
591
+ )
592
+
593
+ self.logger.info(
594
+ f"Preview generated: {preview.deployment_count} agents would be deployed"
595
+ )
596
+ return preview
597
+
598
+ except Exception as e:
599
+ self.logger.error(f"Failed to generate preview: {e}", exc_info=True)
600
+ raise
601
+
602
+ # Private helper methods
603
+
604
+ async def _analyze_toolchain(self, project_path: Path) -> ToolchainAnalysis:
605
+ """Analyze project toolchain."""
606
+ if self._toolchain_analyzer is None:
607
+ raise RuntimeError("ToolchainAnalyzer not initialized")
608
+
609
+ return self._toolchain_analyzer.analyze_toolchain(project_path)
610
+
611
+ async def _generate_recommendations(
612
+ self, toolchain: ToolchainAnalysis, min_confidence: float
613
+ ) -> List[AgentRecommendation]:
614
+ """Generate agent recommendations."""
615
+ if self._agent_recommender is None:
616
+ raise RuntimeError("AgentRecommender not initialized")
617
+
618
+ constraints = {"min_confidence": min_confidence}
619
+ return self._agent_recommender.recommend_agents(toolchain, constraints)
620
+
621
+ async def _request_confirmation(
622
+ self, recommendations: List[AgentRecommendation], validation: ValidationResult
623
+ ) -> bool:
624
+ """
625
+ Request user confirmation before deployment.
626
+
627
+ TODO: Implement interactive confirmation dialog.
628
+ For now, returns True (auto-approve) to enable testing.
629
+
630
+ Args:
631
+ recommendations: List of recommended agents
632
+ validation: Validation results
633
+
634
+ Returns:
635
+ bool: True if user confirms, False otherwise
636
+ """
637
+ # TODO: Implement interactive confirmation
638
+ # For now, auto-approve if validation passed
639
+ return validation.is_valid
640
+
641
+ async def _deploy_agents(
642
+ self,
643
+ project_path: Path,
644
+ recommendations: List[AgentRecommendation],
645
+ observer: IDeploymentObserver,
646
+ ) -> tuple[List[str], List[str]]:
647
+ """
648
+ Deploy recommended agents.
649
+
650
+ Args:
651
+ project_path: Project root directory
652
+ recommendations: List of recommendations to deploy
653
+ observer: Observer for progress tracking
654
+
655
+ Returns:
656
+ Tuple of (deployed_agent_ids, failed_agent_ids)
657
+ """
658
+ deployed = []
659
+ failed = []
660
+
661
+ # Sort recommendations by deployment priority
662
+ sorted_recs = sorted(recommendations, key=lambda r: r.deployment_priority)
663
+
664
+ for index, recommendation in enumerate(sorted_recs, 1):
665
+ agent_id = recommendation.agent_id
666
+ agent_name = recommendation.agent_name
667
+
668
+ try:
669
+ observer.on_agent_deployment_started(
670
+ agent_id, agent_name, index, len(sorted_recs)
671
+ )
672
+
673
+ # TODO: Integrate with actual AgentDeploymentService
674
+ # For now, simulate deployment
675
+ await self._deploy_single_agent(agent_id, project_path)
676
+
677
+ observer.on_agent_deployment_completed(
678
+ agent_id, agent_name, success=True
679
+ )
680
+ deployed.append(agent_id)
681
+ self.logger.debug(f"Successfully deployed agent: {agent_id}")
682
+
683
+ except Exception as e:
684
+ self.logger.error(
685
+ f"Failed to deploy agent '{agent_id}': {e}", exc_info=True
686
+ )
687
+ observer.on_agent_deployment_completed(
688
+ agent_id, agent_name, success=False, error=str(e)
689
+ )
690
+ failed.append(agent_id)
691
+
692
+ return deployed, failed
693
+
694
+ async def _deploy_single_agent(self, agent_id: str, project_path: Path) -> None:
695
+ """
696
+ Deploy a single agent.
697
+
698
+ TODO: Integrate with AgentDeploymentService.
699
+
700
+ Args:
701
+ agent_id: Agent identifier
702
+ project_path: Project root directory
703
+
704
+ Raises:
705
+ Exception: If deployment fails
706
+ """
707
+ # TODO: Implement actual deployment logic
708
+ # For now, simulate deployment with a small delay
709
+ import asyncio
710
+
711
+ await asyncio.sleep(0.1)
712
+
713
+ # Placeholder: will integrate with AgentDeploymentService
714
+ self.logger.debug(f"Deployed agent {agent_id} to {project_path}")
715
+
716
+ async def _rollback_deployment(
717
+ self, project_path: Path, deployed_agents: List[str]
718
+ ) -> bool:
719
+ """
720
+ Rollback deployed agents after failure.
721
+
722
+ Args:
723
+ project_path: Project root directory
724
+ deployed_agents: List of agent IDs to rollback
725
+
726
+ Returns:
727
+ bool: True if rollback succeeded, False otherwise
728
+ """
729
+ self.logger.warning(f"Rolling back {len(deployed_agents)} deployed agents")
730
+
731
+ try:
732
+ # TODO: Implement actual rollback logic
733
+ # For now, log the rollback attempt
734
+ for agent_id in deployed_agents:
735
+ self.logger.info(f"Rolling back agent: {agent_id}")
736
+
737
+ return True
738
+
739
+ except Exception as e:
740
+ self.logger.error(f"Rollback failed: {e}", exc_info=True)
741
+ return False
742
+
743
+ async def _save_configuration(
744
+ self,
745
+ project_path: Path,
746
+ toolchain: ToolchainAnalysis,
747
+ recommendations: List[AgentRecommendation],
748
+ ) -> None:
749
+ """
750
+ Save auto-configuration metadata to project.
751
+
752
+ Args:
753
+ project_path: Project root directory
754
+ toolchain: Toolchain analysis results
755
+ recommendations: Agent recommendations that were deployed
756
+ """
757
+ config_dir = project_path / ".claude-mpm"
758
+ config_dir.mkdir(exist_ok=True)
759
+
760
+ config_file = config_dir / self._config_file_name
761
+
762
+ config_data = {
763
+ "auto_config": {
764
+ "enabled": True,
765
+ "last_run": datetime.now(timezone.utc).isoformat(),
766
+ "toolchain_snapshot": {
767
+ "primary_language": toolchain.primary_language,
768
+ "frameworks": [fw.name for fw in toolchain.frameworks],
769
+ "deployment_targets": (
770
+ [toolchain.deployment_target.platform]
771
+ if toolchain.deployment_target
772
+ else []
773
+ ),
774
+ },
775
+ "deployed_agents": [
776
+ {
777
+ "agent_id": rec.agent_id,
778
+ "agent_name": rec.agent_name,
779
+ "confidence": rec.confidence_score,
780
+ "deployed_at": datetime.now(timezone.utc).isoformat(),
781
+ }
782
+ for rec in recommendations
783
+ ],
784
+ "user_overrides": {"disabled_agents": [], "custom_agents": []},
785
+ }
786
+ }
787
+
788
+ try:
789
+ with config_file.open("w", encoding="utf-8") as f:
790
+ yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)
791
+
792
+ self.logger.info(f"Saved auto-configuration to: {config_file}")
793
+
794
+ except Exception as e:
795
+ self.logger.error(f"Failed to save configuration: {e}", exc_info=True)
796
+ # Don't raise - configuration save is non-critical