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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +106 -1
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/agent-manager.json +4 -1
- claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
- claude_mpm/agents/templates/api_qa.json +11 -2
- claude_mpm/agents/templates/circuit_breakers.md +638 -0
- claude_mpm/agents/templates/clerk-ops.json +12 -2
- claude_mpm/agents/templates/code_analyzer.json +8 -2
- claude_mpm/agents/templates/content-agent.json +358 -0
- claude_mpm/agents/templates/dart_engineer.json +15 -2
- claude_mpm/agents/templates/data_engineer.json +15 -2
- claude_mpm/agents/templates/documentation.json +10 -2
- claude_mpm/agents/templates/engineer.json +21 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
- claude_mpm/agents/templates/git_file_tracking.md +584 -0
- claude_mpm/agents/templates/golang_engineer.json +270 -0
- claude_mpm/agents/templates/imagemagick.json +4 -1
- claude_mpm/agents/templates/java_engineer.json +346 -0
- claude_mpm/agents/templates/local_ops_agent.json +1227 -6
- claude_mpm/agents/templates/memory_manager.json +4 -1
- claude_mpm/agents/templates/nextjs_engineer.json +141 -133
- claude_mpm/agents/templates/ops.json +12 -2
- claude_mpm/agents/templates/php-engineer.json +270 -174
- claude_mpm/agents/templates/pm_examples.md +474 -0
- claude_mpm/agents/templates/pm_red_flags.md +240 -0
- claude_mpm/agents/templates/product_owner.json +338 -0
- claude_mpm/agents/templates/project_organizer.json +14 -4
- claude_mpm/agents/templates/prompt-engineer.json +13 -2
- claude_mpm/agents/templates/python_engineer.json +174 -81
- claude_mpm/agents/templates/qa.json +11 -2
- claude_mpm/agents/templates/react_engineer.json +16 -3
- claude_mpm/agents/templates/refactoring_engineer.json +12 -2
- claude_mpm/agents/templates/research.json +34 -21
- claude_mpm/agents/templates/response_format.md +583 -0
- claude_mpm/agents/templates/ruby-engineer.json +129 -192
- claude_mpm/agents/templates/rust_engineer.json +270 -0
- claude_mpm/agents/templates/security.json +10 -2
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +10 -2
- claude_mpm/agents/templates/typescript_engineer.json +116 -125
- claude_mpm/agents/templates/validation_templates.md +312 -0
- claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
- claude_mpm/agents/templates/version_control.json +12 -2
- claude_mpm/agents/templates/web_qa.json +11 -2
- claude_mpm/agents/templates/web_ui.json +15 -2
- claude_mpm/cli/__init__.py +34 -614
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +235 -148
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +570 -0
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +419 -1571
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +585 -196
- claude_mpm/cli/commands/mpm_init_handler.py +37 -3
- claude_mpm/cli/commands/search.py +170 -4
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agents_parser.py +9 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +110 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-agents-detect.md +168 -0
- claude_mpm/commands/mpm-agents-recommend.md +214 -0
- claude_mpm/commands/mpm-agents.md +75 -1
- claude_mpm/commands/mpm-auto-configure.md +217 -0
- claude_mpm/commands/mpm-help.md +163 -0
- claude_mpm/commands/mpm-init.md +148 -3
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/log_manager.py +2 -0
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/__init__.py +20 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
- claude_mpm/hooks/failure_learning/__init__.py +60 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +37 -12
- claude_mpm/hooks/kuzu_response_hook.py +183 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +568 -0
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/interfaces/__init__.py +90 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/memory_manager.py +11 -24
- claude_mpm/services/core/models/__init__.py +79 -0
- claude_mpm/services/core/models/agent_config.py +381 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/main.py +30 -0
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/failure_tracker.py +563 -0
- claude_mpm/services/memory_hook_service.py +165 -4
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/toolchain_analyzer.py +581 -0
- claude_mpm/services/self_upgrade_service.py +342 -0
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/storage/state_storage.py +15 -15
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +40 -20
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/robust_installer.py +73 -19
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/index-hub-backup.html +0 -713
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {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)
|