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,547 @@
1
+ """
2
+ Observer Pattern for Auto-Configuration Progress Tracking
3
+ =========================================================
4
+
5
+ WHY: Auto-configuration involves multiple steps (analysis, recommendation,
6
+ deployment) that can take significant time. Observers enable real-time
7
+ progress tracking and user feedback.
8
+
9
+ DESIGN DECISION: Observer pattern allows decoupling of progress notification
10
+ from core business logic. Multiple observers can be attached for different
11
+ output targets (console, file, network).
12
+
13
+ Part of TSK-0054: Auto-Configuration Feature - Phase 4
14
+ """
15
+
16
+ from abc import ABC, abstractmethod
17
+ from typing import List, Optional
18
+
19
+ from ..core.models.agent_config import AgentRecommendation
20
+ from ..core.models.toolchain import ToolchainAnalysis
21
+
22
+
23
+ class IDeploymentObserver(ABC):
24
+ """
25
+ Observer interface for deployment events.
26
+
27
+ WHY: Standardizes the observer interface to enable multiple observer
28
+ implementations (console, GUI, logging, metrics) that all receive
29
+ the same event notifications.
30
+
31
+ DESIGN DECISION: Separate methods for each event type enable fine-grained
32
+ control over which events observers handle. All methods are optional
33
+ (have default implementations) to simplify observer creation.
34
+ """
35
+
36
+ @abstractmethod
37
+ def on_analysis_started(self, project_path: str) -> None:
38
+ """
39
+ Called when toolchain analysis starts.
40
+
41
+ Args:
42
+ project_path: Path to the project being analyzed
43
+ """
44
+
45
+ @abstractmethod
46
+ def on_analysis_completed(
47
+ self, toolchain: ToolchainAnalysis, duration_ms: float
48
+ ) -> None:
49
+ """
50
+ Called when toolchain analysis completes.
51
+
52
+ Args:
53
+ toolchain: Complete toolchain analysis result
54
+ duration_ms: Analysis duration in milliseconds
55
+ """
56
+
57
+ @abstractmethod
58
+ def on_recommendation_started(self) -> None:
59
+ """Called when agent recommendation starts."""
60
+
61
+ @abstractmethod
62
+ def on_recommendation_completed(
63
+ self, recommendations: List[AgentRecommendation], duration_ms: float
64
+ ) -> None:
65
+ """
66
+ Called when agent recommendation completes.
67
+
68
+ Args:
69
+ recommendations: List of agent recommendations
70
+ duration_ms: Recommendation duration in milliseconds
71
+ """
72
+
73
+ @abstractmethod
74
+ def on_validation_started(self) -> None:
75
+ """Called when configuration validation starts."""
76
+
77
+ @abstractmethod
78
+ def on_validation_completed(
79
+ self, is_valid: bool, error_count: int, warning_count: int
80
+ ) -> None:
81
+ """
82
+ Called when configuration validation completes.
83
+
84
+ Args:
85
+ is_valid: Whether validation passed
86
+ error_count: Number of validation errors
87
+ warning_count: Number of validation warnings
88
+ """
89
+
90
+ @abstractmethod
91
+ def on_deployment_started(self, total_agents: int) -> None:
92
+ """
93
+ Called when deployment of agents starts.
94
+
95
+ Args:
96
+ total_agents: Total number of agents to deploy
97
+ """
98
+
99
+ @abstractmethod
100
+ def on_agent_deployment_started(
101
+ self, agent_id: str, agent_name: str, index: int, total: int
102
+ ) -> None:
103
+ """
104
+ Called when deployment of a specific agent starts.
105
+
106
+ Args:
107
+ agent_id: Agent identifier
108
+ agent_name: Human-readable agent name
109
+ index: Current agent index (1-based)
110
+ total: Total number of agents being deployed
111
+ """
112
+
113
+ @abstractmethod
114
+ def on_agent_deployment_progress(
115
+ self, agent_id: str, progress: int, message: str = ""
116
+ ) -> None:
117
+ """
118
+ Called to report progress of agent deployment.
119
+
120
+ Args:
121
+ agent_id: Agent identifier
122
+ progress: Progress percentage (0-100)
123
+ message: Optional progress message
124
+ """
125
+
126
+ @abstractmethod
127
+ def on_agent_deployment_completed(
128
+ self, agent_id: str, agent_name: str, success: bool, error: Optional[str] = None
129
+ ) -> None:
130
+ """
131
+ Called when deployment of a specific agent completes.
132
+
133
+ Args:
134
+ agent_id: Agent identifier
135
+ agent_name: Human-readable agent name
136
+ success: Whether deployment succeeded
137
+ error: Error message if deployment failed
138
+ """
139
+
140
+ @abstractmethod
141
+ def on_deployment_completed(
142
+ self, success_count: int, failure_count: int, duration_ms: float
143
+ ) -> None:
144
+ """
145
+ Called when all agent deployments complete.
146
+
147
+ Args:
148
+ success_count: Number of successfully deployed agents
149
+ failure_count: Number of failed deployments
150
+ duration_ms: Total deployment duration in milliseconds
151
+ """
152
+
153
+ @abstractmethod
154
+ def on_rollback_started(self, agent_ids: List[str]) -> None:
155
+ """
156
+ Called when rollback of failed deployments starts.
157
+
158
+ Args:
159
+ agent_ids: List of agent IDs to roll back
160
+ """
161
+
162
+ @abstractmethod
163
+ def on_rollback_completed(self, success: bool) -> None:
164
+ """
165
+ Called when rollback completes.
166
+
167
+ Args:
168
+ success: Whether rollback succeeded
169
+ """
170
+
171
+ @abstractmethod
172
+ def on_error(
173
+ self, phase: str, error_message: str, exception: Optional[Exception] = None
174
+ ) -> None:
175
+ """
176
+ Called when an error occurs during auto-configuration.
177
+
178
+ Args:
179
+ phase: Phase where error occurred (analysis, recommendation, deployment)
180
+ error_message: Human-readable error message
181
+ exception: Optional exception object
182
+ """
183
+
184
+
185
+ class NullObserver(IDeploymentObserver):
186
+ """
187
+ Null Object pattern implementation of observer.
188
+
189
+ WHY: Provides a no-op observer to simplify code when no observer is needed.
190
+ Eliminates need for null checks before calling observer methods.
191
+
192
+ DESIGN DECISION: All methods do nothing, making this a safe default observer.
193
+ """
194
+
195
+ def on_analysis_started(self, project_path: str) -> None:
196
+ pass
197
+
198
+ def on_analysis_completed(
199
+ self, toolchain: ToolchainAnalysis, duration_ms: float
200
+ ) -> None:
201
+ pass
202
+
203
+ def on_recommendation_started(self) -> None:
204
+ pass
205
+
206
+ def on_recommendation_completed(
207
+ self, recommendations: List[AgentRecommendation], duration_ms: float
208
+ ) -> None:
209
+ pass
210
+
211
+ def on_validation_started(self) -> None:
212
+ pass
213
+
214
+ def on_validation_completed(
215
+ self, is_valid: bool, error_count: int, warning_count: int
216
+ ) -> None:
217
+ pass
218
+
219
+ def on_deployment_started(self, total_agents: int) -> None:
220
+ pass
221
+
222
+ def on_agent_deployment_started(
223
+ self, agent_id: str, agent_name: str, index: int, total: int
224
+ ) -> None:
225
+ pass
226
+
227
+ def on_agent_deployment_progress(
228
+ self, agent_id: str, progress: int, message: str = ""
229
+ ) -> None:
230
+ pass
231
+
232
+ def on_agent_deployment_completed(
233
+ self, agent_id: str, agent_name: str, success: bool, error: Optional[str] = None
234
+ ) -> None:
235
+ pass
236
+
237
+ def on_deployment_completed(
238
+ self, success_count: int, failure_count: int, duration_ms: float
239
+ ) -> None:
240
+ pass
241
+
242
+ def on_rollback_started(self, agent_ids: List[str]) -> None:
243
+ pass
244
+
245
+ def on_rollback_completed(self, success: bool) -> None:
246
+ pass
247
+
248
+ def on_error(
249
+ self, phase: str, error_message: str, exception: Optional[Exception] = None
250
+ ) -> None:
251
+ pass
252
+
253
+
254
+ class ConsoleProgressObserver(IDeploymentObserver):
255
+ """
256
+ Console-based progress observer with rich terminal output.
257
+
258
+ WHY: Provides user-friendly progress feedback during auto-configuration.
259
+ Uses rich library for enhanced terminal output with colors and progress bars.
260
+
261
+ DESIGN DECISION: Conditionally imports rich library to avoid hard dependency.
262
+ Falls back to simple print statements if rich is not available.
263
+ """
264
+
265
+ def __init__(self, use_rich: bool = True):
266
+ """
267
+ Initialize console observer.
268
+
269
+ Args:
270
+ use_rich: Whether to use rich library for enhanced output
271
+ """
272
+ self.use_rich = use_rich
273
+ self._rich_available = False
274
+ self._console = None
275
+ self._progress = None
276
+ self._task_id = None
277
+
278
+ if self.use_rich:
279
+ try:
280
+ from rich.console import Console
281
+ from rich.progress import (
282
+ BarColumn,
283
+ Progress,
284
+ SpinnerColumn,
285
+ TextColumn,
286
+ TimeRemainingColumn,
287
+ )
288
+
289
+ self._Console = Console
290
+ self._Progress = Progress
291
+ self._SpinnerColumn = SpinnerColumn
292
+ self._TextColumn = TextColumn
293
+ self._BarColumn = BarColumn
294
+ self._TimeRemainingColumn = TimeRemainingColumn
295
+ self._rich_available = True
296
+ self._console = Console()
297
+ except ImportError:
298
+ self._rich_available = False
299
+
300
+ def _print(self, message: str, style: str = "") -> None:
301
+ """
302
+ Print message with optional styling.
303
+
304
+ Args:
305
+ message: Message to print
306
+ style: Rich style string (e.g., "bold green", "red")
307
+ """
308
+ if self._rich_available and self._console:
309
+ self._console.print(message, style=style)
310
+ else:
311
+ print(message)
312
+
313
+ def on_analysis_started(self, project_path: str) -> None:
314
+ """Called when toolchain analysis starts."""
315
+ self._print(f"\n🔍 Analyzing project toolchain: {project_path}", "bold cyan")
316
+
317
+ def on_analysis_completed(
318
+ self, toolchain: ToolchainAnalysis, duration_ms: float
319
+ ) -> None:
320
+ """Called when toolchain analysis completes."""
321
+ self._print(
322
+ f"✓ Analysis complete ({duration_ms:.0f}ms): "
323
+ f"{toolchain.primary_language} with {len(toolchain.frameworks)} frameworks",
324
+ "bold green",
325
+ )
326
+
327
+ def on_recommendation_started(self) -> None:
328
+ """Called when agent recommendation starts."""
329
+ self._print("\n🤖 Generating agent recommendations...", "bold cyan")
330
+
331
+ def on_recommendation_completed(
332
+ self, recommendations: List[AgentRecommendation], duration_ms: float
333
+ ) -> None:
334
+ """Called when agent recommendation completes."""
335
+ high_conf = sum(1 for r in recommendations if r.is_high_confidence)
336
+ self._print(
337
+ f"✓ Generated {len(recommendations)} recommendations ({duration_ms:.0f}ms): "
338
+ f"{high_conf} high confidence",
339
+ "bold green",
340
+ )
341
+
342
+ def on_validation_started(self) -> None:
343
+ """Called when configuration validation starts."""
344
+ self._print("\n✓ Validating configuration...", "bold cyan")
345
+
346
+ def on_validation_completed(
347
+ self, is_valid: bool, error_count: int, warning_count: int
348
+ ) -> None:
349
+ """Called when configuration validation completes."""
350
+ if is_valid:
351
+ self._print(
352
+ f"✓ Validation passed ({warning_count} warnings)",
353
+ "bold green",
354
+ )
355
+ else:
356
+ self._print(
357
+ f"✗ Validation failed: {error_count} errors, {warning_count} warnings",
358
+ "bold red",
359
+ )
360
+
361
+ def on_deployment_started(self, total_agents: int) -> None:
362
+ """Called when deployment of agents starts."""
363
+ self._print(f"\n🚀 Deploying {total_agents} agents...", "bold cyan")
364
+
365
+ def on_agent_deployment_started(
366
+ self, agent_id: str, agent_name: str, index: int, total: int
367
+ ) -> None:
368
+ """Called when deployment of a specific agent starts."""
369
+ self._print(f" [{index}/{total}] Deploying {agent_name}...", "cyan")
370
+
371
+ def on_agent_deployment_progress(
372
+ self, agent_id: str, progress: int, message: str = ""
373
+ ) -> None:
374
+ """Called to report progress of agent deployment."""
375
+ # Progress updates are too noisy for console, skip them
376
+
377
+ def on_agent_deployment_completed(
378
+ self, agent_id: str, agent_name: str, success: bool, error: Optional[str] = None
379
+ ) -> None:
380
+ """Called when deployment of a specific agent completes."""
381
+ if success:
382
+ self._print(f" ✓ {agent_name} deployed successfully", "green")
383
+ else:
384
+ error_msg = f": {error}" if error else ""
385
+ self._print(f" ✗ {agent_name} deployment failed{error_msg}", "red")
386
+
387
+ def on_deployment_completed(
388
+ self, success_count: int, failure_count: int, duration_ms: float
389
+ ) -> None:
390
+ """Called when all agent deployments complete."""
391
+ if failure_count == 0:
392
+ self._print(
393
+ f"\n✓ All {success_count} agents deployed successfully ({duration_ms / 1000:.1f}s)",
394
+ "bold green",
395
+ )
396
+ else:
397
+ self._print(
398
+ f"\n⚠ Deployment completed with issues: "
399
+ f"{success_count} succeeded, {failure_count} failed ({duration_ms / 1000:.1f}s)",
400
+ "bold yellow",
401
+ )
402
+
403
+ def on_rollback_started(self, agent_ids: List[str]) -> None:
404
+ """Called when rollback of failed deployments starts."""
405
+ self._print(f"\n⏪ Rolling back {len(agent_ids)} agents...", "bold yellow")
406
+
407
+ def on_rollback_completed(self, success: bool) -> None:
408
+ """Called when rollback completes."""
409
+ if success:
410
+ self._print("✓ Rollback completed successfully", "green")
411
+ else:
412
+ self._print("✗ Rollback failed", "red")
413
+
414
+ def on_error(
415
+ self, phase: str, error_message: str, exception: Optional[Exception] = None
416
+ ) -> None:
417
+ """Called when an error occurs during auto-configuration."""
418
+ self._print(f"\n✗ Error in {phase}: {error_message}", "bold red")
419
+ if exception:
420
+ self._print(f" Exception: {type(exception).__name__}: {exception}", "red")
421
+
422
+
423
+ class CompositeObserver(IDeploymentObserver):
424
+ """
425
+ Composite observer that broadcasts events to multiple observers.
426
+
427
+ WHY: Enables simultaneous notification of multiple observers (e.g., console
428
+ output + file logging + metrics collection) without coupling.
429
+
430
+ DESIGN DECISION: Implements observer pattern by delegating all events to
431
+ registered observers. Catches and logs exceptions from individual observers
432
+ to prevent one failing observer from breaking others.
433
+ """
434
+
435
+ def __init__(self, observers: Optional[List[IDeploymentObserver]] = None):
436
+ """
437
+ Initialize composite observer.
438
+
439
+ Args:
440
+ observers: List of observers to notify
441
+ """
442
+ self._observers: List[IDeploymentObserver] = observers or []
443
+
444
+ def add_observer(self, observer: IDeploymentObserver) -> None:
445
+ """
446
+ Add an observer to the composite.
447
+
448
+ Args:
449
+ observer: Observer to add
450
+ """
451
+ if observer not in self._observers:
452
+ self._observers.append(observer)
453
+
454
+ def remove_observer(self, observer: IDeploymentObserver) -> None:
455
+ """
456
+ Remove an observer from the composite.
457
+
458
+ Args:
459
+ observer: Observer to remove
460
+ """
461
+ if observer in self._observers:
462
+ self._observers.remove(observer)
463
+
464
+ def _notify_all(self, method_name: str, *args, **kwargs) -> None:
465
+ """
466
+ Notify all observers by calling method on each.
467
+
468
+ Args:
469
+ method_name: Name of the observer method to call
470
+ *args: Positional arguments to pass
471
+ **kwargs: Keyword arguments to pass
472
+ """
473
+ for observer in self._observers:
474
+ try:
475
+ method = getattr(observer, method_name)
476
+ method(*args, **kwargs)
477
+ except Exception as e:
478
+ # Log but don't re-raise to prevent one observer from breaking others
479
+ print(
480
+ f"Error in observer {observer.__class__.__name__}.{method_name}: {e}"
481
+ )
482
+
483
+ def on_analysis_started(self, project_path: str) -> None:
484
+ self._notify_all("on_analysis_started", project_path)
485
+
486
+ def on_analysis_completed(
487
+ self, toolchain: ToolchainAnalysis, duration_ms: float
488
+ ) -> None:
489
+ self._notify_all("on_analysis_completed", toolchain, duration_ms)
490
+
491
+ def on_recommendation_started(self) -> None:
492
+ self._notify_all("on_recommendation_started")
493
+
494
+ def on_recommendation_completed(
495
+ self, recommendations: List[AgentRecommendation], duration_ms: float
496
+ ) -> None:
497
+ self._notify_all("on_recommendation_completed", recommendations, duration_ms)
498
+
499
+ def on_validation_started(self) -> None:
500
+ self._notify_all("on_validation_started")
501
+
502
+ def on_validation_completed(
503
+ self, is_valid: bool, error_count: int, warning_count: int
504
+ ) -> None:
505
+ self._notify_all(
506
+ "on_validation_completed", is_valid, error_count, warning_count
507
+ )
508
+
509
+ def on_deployment_started(self, total_agents: int) -> None:
510
+ self._notify_all("on_deployment_started", total_agents)
511
+
512
+ def on_agent_deployment_started(
513
+ self, agent_id: str, agent_name: str, index: int, total: int
514
+ ) -> None:
515
+ self._notify_all(
516
+ "on_agent_deployment_started", agent_id, agent_name, index, total
517
+ )
518
+
519
+ def on_agent_deployment_progress(
520
+ self, agent_id: str, progress: int, message: str = ""
521
+ ) -> None:
522
+ self._notify_all("on_agent_deployment_progress", agent_id, progress, message)
523
+
524
+ def on_agent_deployment_completed(
525
+ self, agent_id: str, agent_name: str, success: bool, error: Optional[str] = None
526
+ ) -> None:
527
+ self._notify_all(
528
+ "on_agent_deployment_completed", agent_id, agent_name, success, error
529
+ )
530
+
531
+ def on_deployment_completed(
532
+ self, success_count: int, failure_count: int, duration_ms: float
533
+ ) -> None:
534
+ self._notify_all(
535
+ "on_deployment_completed", success_count, failure_count, duration_ms
536
+ )
537
+
538
+ def on_rollback_started(self, agent_ids: List[str]) -> None:
539
+ self._notify_all("on_rollback_started", agent_ids)
540
+
541
+ def on_rollback_completed(self, success: bool) -> None:
542
+ self._notify_all("on_rollback_completed", success)
543
+
544
+ def on_error(
545
+ self, phase: str, error_message: str, exception: Optional[Exception] = None
546
+ ) -> None:
547
+ self._notify_all("on_error", phase, error_message, exception)