attune-ai 2.0.0__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.
- attune/__init__.py +358 -0
- attune/adaptive/__init__.py +13 -0
- attune/adaptive/task_complexity.py +127 -0
- attune/agent_monitoring.py +414 -0
- attune/cache/__init__.py +117 -0
- attune/cache/base.py +166 -0
- attune/cache/dependency_manager.py +256 -0
- attune/cache/hash_only.py +251 -0
- attune/cache/hybrid.py +457 -0
- attune/cache/storage.py +285 -0
- attune/cache_monitor.py +356 -0
- attune/cache_stats.py +298 -0
- attune/cli/__init__.py +152 -0
- attune/cli/__main__.py +12 -0
- attune/cli/commands/__init__.py +1 -0
- attune/cli/commands/batch.py +264 -0
- attune/cli/commands/cache.py +248 -0
- attune/cli/commands/help.py +331 -0
- attune/cli/commands/info.py +140 -0
- attune/cli/commands/inspect.py +436 -0
- attune/cli/commands/inspection.py +57 -0
- attune/cli/commands/memory.py +48 -0
- attune/cli/commands/metrics.py +92 -0
- attune/cli/commands/orchestrate.py +184 -0
- attune/cli/commands/patterns.py +207 -0
- attune/cli/commands/profiling.py +202 -0
- attune/cli/commands/provider.py +98 -0
- attune/cli/commands/routing.py +285 -0
- attune/cli/commands/setup.py +96 -0
- attune/cli/commands/status.py +235 -0
- attune/cli/commands/sync.py +166 -0
- attune/cli/commands/tier.py +121 -0
- attune/cli/commands/utilities.py +114 -0
- attune/cli/commands/workflow.py +579 -0
- attune/cli/core.py +32 -0
- attune/cli/parsers/__init__.py +68 -0
- attune/cli/parsers/batch.py +118 -0
- attune/cli/parsers/cache.py +65 -0
- attune/cli/parsers/help.py +41 -0
- attune/cli/parsers/info.py +26 -0
- attune/cli/parsers/inspect.py +66 -0
- attune/cli/parsers/metrics.py +42 -0
- attune/cli/parsers/orchestrate.py +61 -0
- attune/cli/parsers/patterns.py +54 -0
- attune/cli/parsers/provider.py +40 -0
- attune/cli/parsers/routing.py +110 -0
- attune/cli/parsers/setup.py +42 -0
- attune/cli/parsers/status.py +47 -0
- attune/cli/parsers/sync.py +31 -0
- attune/cli/parsers/tier.py +33 -0
- attune/cli/parsers/workflow.py +77 -0
- attune/cli/utils/__init__.py +1 -0
- attune/cli/utils/data.py +242 -0
- attune/cli/utils/helpers.py +68 -0
- attune/cli_legacy.py +3957 -0
- attune/cli_minimal.py +1159 -0
- attune/cli_router.py +437 -0
- attune/cli_unified.py +814 -0
- attune/config/__init__.py +66 -0
- attune/config/xml_config.py +286 -0
- attune/config.py +545 -0
- attune/coordination.py +870 -0
- attune/core.py +1511 -0
- attune/core_modules/__init__.py +15 -0
- attune/cost_tracker.py +626 -0
- attune/dashboard/__init__.py +41 -0
- attune/dashboard/app.py +512 -0
- attune/dashboard/simple_server.py +435 -0
- attune/dashboard/standalone_server.py +547 -0
- attune/discovery.py +306 -0
- attune/emergence.py +306 -0
- attune/exceptions.py +123 -0
- attune/feedback_loops.py +373 -0
- attune/hot_reload/README.md +473 -0
- attune/hot_reload/__init__.py +62 -0
- attune/hot_reload/config.py +83 -0
- attune/hot_reload/integration.py +229 -0
- attune/hot_reload/reloader.py +298 -0
- attune/hot_reload/watcher.py +183 -0
- attune/hot_reload/websocket.py +177 -0
- attune/levels.py +577 -0
- attune/leverage_points.py +441 -0
- attune/logging_config.py +261 -0
- attune/mcp/__init__.py +10 -0
- attune/mcp/server.py +506 -0
- attune/memory/__init__.py +237 -0
- attune/memory/claude_memory.py +469 -0
- attune/memory/config.py +224 -0
- attune/memory/control_panel.py +1290 -0
- attune/memory/control_panel_support.py +145 -0
- attune/memory/cross_session.py +845 -0
- attune/memory/edges.py +179 -0
- attune/memory/encryption.py +159 -0
- attune/memory/file_session.py +770 -0
- attune/memory/graph.py +570 -0
- attune/memory/long_term.py +913 -0
- attune/memory/long_term_types.py +99 -0
- attune/memory/mixins/__init__.py +25 -0
- attune/memory/mixins/backend_init_mixin.py +249 -0
- attune/memory/mixins/capabilities_mixin.py +208 -0
- attune/memory/mixins/handoff_mixin.py +208 -0
- attune/memory/mixins/lifecycle_mixin.py +49 -0
- attune/memory/mixins/long_term_mixin.py +352 -0
- attune/memory/mixins/promotion_mixin.py +109 -0
- attune/memory/mixins/short_term_mixin.py +182 -0
- attune/memory/nodes.py +179 -0
- attune/memory/redis_bootstrap.py +540 -0
- attune/memory/security/__init__.py +31 -0
- attune/memory/security/audit_logger.py +932 -0
- attune/memory/security/pii_scrubber.py +640 -0
- attune/memory/security/secrets_detector.py +678 -0
- attune/memory/short_term.py +2192 -0
- attune/memory/simple_storage.py +302 -0
- attune/memory/storage/__init__.py +15 -0
- attune/memory/storage_backend.py +167 -0
- attune/memory/summary_index.py +583 -0
- attune/memory/types.py +446 -0
- attune/memory/unified.py +182 -0
- attune/meta_workflows/__init__.py +74 -0
- attune/meta_workflows/agent_creator.py +248 -0
- attune/meta_workflows/builtin_templates.py +567 -0
- attune/meta_workflows/cli_commands/__init__.py +56 -0
- attune/meta_workflows/cli_commands/agent_commands.py +321 -0
- attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
- attune/meta_workflows/cli_commands/config_commands.py +232 -0
- attune/meta_workflows/cli_commands/memory_commands.py +182 -0
- attune/meta_workflows/cli_commands/template_commands.py +354 -0
- attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
- attune/meta_workflows/cli_meta_workflows.py +59 -0
- attune/meta_workflows/form_engine.py +292 -0
- attune/meta_workflows/intent_detector.py +409 -0
- attune/meta_workflows/models.py +569 -0
- attune/meta_workflows/pattern_learner.py +738 -0
- attune/meta_workflows/plan_generator.py +384 -0
- attune/meta_workflows/session_context.py +397 -0
- attune/meta_workflows/template_registry.py +229 -0
- attune/meta_workflows/workflow.py +984 -0
- attune/metrics/__init__.py +12 -0
- attune/metrics/collector.py +31 -0
- attune/metrics/prompt_metrics.py +194 -0
- attune/models/__init__.py +172 -0
- attune/models/__main__.py +13 -0
- attune/models/adaptive_routing.py +437 -0
- attune/models/auth_cli.py +444 -0
- attune/models/auth_strategy.py +450 -0
- attune/models/cli.py +655 -0
- attune/models/empathy_executor.py +354 -0
- attune/models/executor.py +257 -0
- attune/models/fallback.py +762 -0
- attune/models/provider_config.py +282 -0
- attune/models/registry.py +472 -0
- attune/models/tasks.py +359 -0
- attune/models/telemetry/__init__.py +71 -0
- attune/models/telemetry/analytics.py +594 -0
- attune/models/telemetry/backend.py +196 -0
- attune/models/telemetry/data_models.py +431 -0
- attune/models/telemetry/storage.py +489 -0
- attune/models/token_estimator.py +420 -0
- attune/models/validation.py +280 -0
- attune/monitoring/__init__.py +52 -0
- attune/monitoring/alerts.py +946 -0
- attune/monitoring/alerts_cli.py +448 -0
- attune/monitoring/multi_backend.py +271 -0
- attune/monitoring/otel_backend.py +362 -0
- attune/optimization/__init__.py +19 -0
- attune/optimization/context_optimizer.py +272 -0
- attune/orchestration/__init__.py +67 -0
- attune/orchestration/agent_templates.py +707 -0
- attune/orchestration/config_store.py +499 -0
- attune/orchestration/execution_strategies.py +2111 -0
- attune/orchestration/meta_orchestrator.py +1168 -0
- attune/orchestration/pattern_learner.py +696 -0
- attune/orchestration/real_tools.py +931 -0
- attune/pattern_cache.py +187 -0
- attune/pattern_library.py +542 -0
- attune/patterns/debugging/all_patterns.json +81 -0
- attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
- attune/patterns/refactoring_memory.json +89 -0
- attune/persistence.py +564 -0
- attune/platform_utils.py +265 -0
- attune/plugins/__init__.py +28 -0
- attune/plugins/base.py +361 -0
- attune/plugins/registry.py +268 -0
- attune/project_index/__init__.py +32 -0
- attune/project_index/cli.py +335 -0
- attune/project_index/index.py +667 -0
- attune/project_index/models.py +504 -0
- attune/project_index/reports.py +474 -0
- attune/project_index/scanner.py +777 -0
- attune/project_index/scanner_parallel.py +291 -0
- attune/prompts/__init__.py +61 -0
- attune/prompts/config.py +77 -0
- attune/prompts/context.py +177 -0
- attune/prompts/parser.py +285 -0
- attune/prompts/registry.py +313 -0
- attune/prompts/templates.py +208 -0
- attune/redis_config.py +302 -0
- attune/redis_memory.py +799 -0
- attune/resilience/__init__.py +56 -0
- attune/resilience/circuit_breaker.py +256 -0
- attune/resilience/fallback.py +179 -0
- attune/resilience/health.py +300 -0
- attune/resilience/retry.py +209 -0
- attune/resilience/timeout.py +135 -0
- attune/routing/__init__.py +43 -0
- attune/routing/chain_executor.py +433 -0
- attune/routing/classifier.py +217 -0
- attune/routing/smart_router.py +234 -0
- attune/routing/workflow_registry.py +343 -0
- attune/scaffolding/README.md +589 -0
- attune/scaffolding/__init__.py +35 -0
- attune/scaffolding/__main__.py +14 -0
- attune/scaffolding/cli.py +240 -0
- attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
- attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
- attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
- attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
- attune/socratic/__init__.py +256 -0
- attune/socratic/ab_testing.py +958 -0
- attune/socratic/blueprint.py +533 -0
- attune/socratic/cli.py +703 -0
- attune/socratic/collaboration.py +1114 -0
- attune/socratic/domain_templates.py +924 -0
- attune/socratic/embeddings.py +738 -0
- attune/socratic/engine.py +794 -0
- attune/socratic/explainer.py +682 -0
- attune/socratic/feedback.py +772 -0
- attune/socratic/forms.py +629 -0
- attune/socratic/generator.py +732 -0
- attune/socratic/llm_analyzer.py +637 -0
- attune/socratic/mcp_server.py +702 -0
- attune/socratic/session.py +312 -0
- attune/socratic/storage.py +667 -0
- attune/socratic/success.py +730 -0
- attune/socratic/visual_editor.py +860 -0
- attune/socratic/web_ui.py +958 -0
- attune/telemetry/__init__.py +39 -0
- attune/telemetry/agent_coordination.py +475 -0
- attune/telemetry/agent_tracking.py +367 -0
- attune/telemetry/approval_gates.py +545 -0
- attune/telemetry/cli.py +1231 -0
- attune/telemetry/commands/__init__.py +14 -0
- attune/telemetry/commands/dashboard_commands.py +696 -0
- attune/telemetry/event_streaming.py +409 -0
- attune/telemetry/feedback_loop.py +567 -0
- attune/telemetry/usage_tracker.py +591 -0
- attune/templates.py +754 -0
- attune/test_generator/__init__.py +38 -0
- attune/test_generator/__main__.py +14 -0
- attune/test_generator/cli.py +234 -0
- attune/test_generator/generator.py +355 -0
- attune/test_generator/risk_analyzer.py +216 -0
- attune/test_generator/templates/unit_test.py.jinja2 +272 -0
- attune/tier_recommender.py +384 -0
- attune/tools.py +183 -0
- attune/trust/__init__.py +28 -0
- attune/trust/circuit_breaker.py +579 -0
- attune/trust_building.py +527 -0
- attune/validation/__init__.py +19 -0
- attune/validation/xml_validator.py +281 -0
- attune/vscode_bridge.py +173 -0
- attune/workflow_commands.py +780 -0
- attune/workflow_patterns/__init__.py +33 -0
- attune/workflow_patterns/behavior.py +249 -0
- attune/workflow_patterns/core.py +76 -0
- attune/workflow_patterns/output.py +99 -0
- attune/workflow_patterns/registry.py +255 -0
- attune/workflow_patterns/structural.py +288 -0
- attune/workflows/__init__.py +539 -0
- attune/workflows/autonomous_test_gen.py +1268 -0
- attune/workflows/base.py +2667 -0
- attune/workflows/batch_processing.py +342 -0
- attune/workflows/bug_predict.py +1084 -0
- attune/workflows/builder.py +273 -0
- attune/workflows/caching.py +253 -0
- attune/workflows/code_review.py +1048 -0
- attune/workflows/code_review_adapters.py +312 -0
- attune/workflows/code_review_pipeline.py +722 -0
- attune/workflows/config.py +645 -0
- attune/workflows/dependency_check.py +644 -0
- attune/workflows/document_gen/__init__.py +25 -0
- attune/workflows/document_gen/config.py +30 -0
- attune/workflows/document_gen/report_formatter.py +162 -0
- attune/workflows/document_gen/workflow.py +1426 -0
- attune/workflows/document_manager.py +216 -0
- attune/workflows/document_manager_README.md +134 -0
- attune/workflows/documentation_orchestrator.py +1205 -0
- attune/workflows/history.py +510 -0
- attune/workflows/keyboard_shortcuts/__init__.py +39 -0
- attune/workflows/keyboard_shortcuts/generators.py +391 -0
- attune/workflows/keyboard_shortcuts/parsers.py +416 -0
- attune/workflows/keyboard_shortcuts/prompts.py +295 -0
- attune/workflows/keyboard_shortcuts/schema.py +193 -0
- attune/workflows/keyboard_shortcuts/workflow.py +509 -0
- attune/workflows/llm_base.py +363 -0
- attune/workflows/manage_docs.py +87 -0
- attune/workflows/manage_docs_README.md +134 -0
- attune/workflows/manage_documentation.py +821 -0
- attune/workflows/new_sample_workflow1.py +149 -0
- attune/workflows/new_sample_workflow1_README.md +150 -0
- attune/workflows/orchestrated_health_check.py +849 -0
- attune/workflows/orchestrated_release_prep.py +600 -0
- attune/workflows/output.py +413 -0
- attune/workflows/perf_audit.py +863 -0
- attune/workflows/pr_review.py +762 -0
- attune/workflows/progress.py +785 -0
- attune/workflows/progress_server.py +322 -0
- attune/workflows/progressive/README 2.md +454 -0
- attune/workflows/progressive/README.md +454 -0
- attune/workflows/progressive/__init__.py +82 -0
- attune/workflows/progressive/cli.py +219 -0
- attune/workflows/progressive/core.py +488 -0
- attune/workflows/progressive/orchestrator.py +723 -0
- attune/workflows/progressive/reports.py +520 -0
- attune/workflows/progressive/telemetry.py +274 -0
- attune/workflows/progressive/test_gen.py +495 -0
- attune/workflows/progressive/workflow.py +589 -0
- attune/workflows/refactor_plan.py +694 -0
- attune/workflows/release_prep.py +895 -0
- attune/workflows/release_prep_crew.py +969 -0
- attune/workflows/research_synthesis.py +404 -0
- attune/workflows/routing.py +168 -0
- attune/workflows/secure_release.py +593 -0
- attune/workflows/security_adapters.py +297 -0
- attune/workflows/security_audit.py +1329 -0
- attune/workflows/security_audit_phase3.py +355 -0
- attune/workflows/seo_optimization.py +633 -0
- attune/workflows/step_config.py +234 -0
- attune/workflows/telemetry_mixin.py +269 -0
- attune/workflows/test5.py +125 -0
- attune/workflows/test5_README.md +158 -0
- attune/workflows/test_coverage_boost_crew.py +849 -0
- attune/workflows/test_gen/__init__.py +52 -0
- attune/workflows/test_gen/ast_analyzer.py +249 -0
- attune/workflows/test_gen/config.py +88 -0
- attune/workflows/test_gen/data_models.py +38 -0
- attune/workflows/test_gen/report_formatter.py +289 -0
- attune/workflows/test_gen/test_templates.py +381 -0
- attune/workflows/test_gen/workflow.py +655 -0
- attune/workflows/test_gen.py +54 -0
- attune/workflows/test_gen_behavioral.py +477 -0
- attune/workflows/test_gen_parallel.py +341 -0
- attune/workflows/test_lifecycle.py +526 -0
- attune/workflows/test_maintenance.py +627 -0
- attune/workflows/test_maintenance_cli.py +590 -0
- attune/workflows/test_maintenance_crew.py +840 -0
- attune/workflows/test_runner.py +622 -0
- attune/workflows/tier_tracking.py +531 -0
- attune/workflows/xml_enhanced_crew.py +285 -0
- attune_ai-2.0.0.dist-info/METADATA +1026 -0
- attune_ai-2.0.0.dist-info/RECORD +457 -0
- attune_ai-2.0.0.dist-info/WHEEL +5 -0
- attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
- attune_ai-2.0.0.dist-info/top_level.txt +5 -0
- attune_healthcare/__init__.py +13 -0
- attune_healthcare/monitors/__init__.py +9 -0
- attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
- attune_healthcare/monitors/monitoring/__init__.py +44 -0
- attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
- attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
- attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
- attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
- attune_llm/README.md +553 -0
- attune_llm/__init__.py +28 -0
- attune_llm/agent_factory/__init__.py +53 -0
- attune_llm/agent_factory/adapters/__init__.py +85 -0
- attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
- attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
- attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
- attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
- attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
- attune_llm/agent_factory/adapters/native.py +228 -0
- attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
- attune_llm/agent_factory/base.py +305 -0
- attune_llm/agent_factory/crews/__init__.py +67 -0
- attune_llm/agent_factory/crews/code_review.py +1113 -0
- attune_llm/agent_factory/crews/health_check.py +1262 -0
- attune_llm/agent_factory/crews/refactoring.py +1128 -0
- attune_llm/agent_factory/crews/security_audit.py +1018 -0
- attune_llm/agent_factory/decorators.py +287 -0
- attune_llm/agent_factory/factory.py +558 -0
- attune_llm/agent_factory/framework.py +193 -0
- attune_llm/agent_factory/memory_integration.py +328 -0
- attune_llm/agent_factory/resilient.py +320 -0
- attune_llm/agents_md/__init__.py +22 -0
- attune_llm/agents_md/loader.py +218 -0
- attune_llm/agents_md/parser.py +271 -0
- attune_llm/agents_md/registry.py +307 -0
- attune_llm/claude_memory.py +466 -0
- attune_llm/cli/__init__.py +8 -0
- attune_llm/cli/sync_claude.py +487 -0
- attune_llm/code_health.py +1313 -0
- attune_llm/commands/__init__.py +51 -0
- attune_llm/commands/context.py +375 -0
- attune_llm/commands/loader.py +301 -0
- attune_llm/commands/models.py +231 -0
- attune_llm/commands/parser.py +371 -0
- attune_llm/commands/registry.py +429 -0
- attune_llm/config/__init__.py +29 -0
- attune_llm/config/unified.py +291 -0
- attune_llm/context/__init__.py +22 -0
- attune_llm/context/compaction.py +455 -0
- attune_llm/context/manager.py +434 -0
- attune_llm/contextual_patterns.py +361 -0
- attune_llm/core.py +907 -0
- attune_llm/git_pattern_extractor.py +435 -0
- attune_llm/hooks/__init__.py +24 -0
- attune_llm/hooks/config.py +306 -0
- attune_llm/hooks/executor.py +289 -0
- attune_llm/hooks/registry.py +302 -0
- attune_llm/hooks/scripts/__init__.py +39 -0
- attune_llm/hooks/scripts/evaluate_session.py +201 -0
- attune_llm/hooks/scripts/first_time_init.py +285 -0
- attune_llm/hooks/scripts/pre_compact.py +207 -0
- attune_llm/hooks/scripts/session_end.py +183 -0
- attune_llm/hooks/scripts/session_start.py +163 -0
- attune_llm/hooks/scripts/suggest_compact.py +225 -0
- attune_llm/learning/__init__.py +30 -0
- attune_llm/learning/evaluator.py +438 -0
- attune_llm/learning/extractor.py +514 -0
- attune_llm/learning/storage.py +560 -0
- attune_llm/levels.py +227 -0
- attune_llm/pattern_confidence.py +414 -0
- attune_llm/pattern_resolver.py +272 -0
- attune_llm/pattern_summary.py +350 -0
- attune_llm/providers.py +967 -0
- attune_llm/routing/__init__.py +32 -0
- attune_llm/routing/model_router.py +362 -0
- attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
- attune_llm/security/PHASE2_COMPLETE.md +384 -0
- attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- attune_llm/security/QUICK_REFERENCE.md +316 -0
- attune_llm/security/README.md +262 -0
- attune_llm/security/__init__.py +62 -0
- attune_llm/security/audit_logger.py +929 -0
- attune_llm/security/audit_logger_example.py +152 -0
- attune_llm/security/pii_scrubber.py +640 -0
- attune_llm/security/secrets_detector.py +678 -0
- attune_llm/security/secrets_detector_example.py +304 -0
- attune_llm/security/secure_memdocs.py +1192 -0
- attune_llm/security/secure_memdocs_example.py +278 -0
- attune_llm/session_status.py +745 -0
- attune_llm/state.py +246 -0
- attune_llm/utils/__init__.py +5 -0
- attune_llm/utils/tokens.py +349 -0
- attune_software/SOFTWARE_PLUGIN_README.md +57 -0
- attune_software/__init__.py +13 -0
- attune_software/cli/__init__.py +120 -0
- attune_software/cli/inspect.py +362 -0
- attune_software/cli.py +574 -0
- attune_software/plugin.py +188 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
"""Orchestrated Release Preparation Workflow
|
|
2
|
+
|
|
3
|
+
Uses the meta-orchestration system to coordinate multiple validation agents
|
|
4
|
+
in parallel for comprehensive release readiness assessment.
|
|
5
|
+
|
|
6
|
+
This is the first production use case of the meta-orchestration system,
|
|
7
|
+
demonstrating parallel agent composition with quality gates.
|
|
8
|
+
|
|
9
|
+
Architecture:
|
|
10
|
+
- MetaOrchestrator analyzes task and selects agents
|
|
11
|
+
- ParallelStrategy runs validation agents simultaneously
|
|
12
|
+
- Quality gates enforce release standards
|
|
13
|
+
- Results aggregated into consolidated report
|
|
14
|
+
|
|
15
|
+
Agents:
|
|
16
|
+
- Security Auditor: Vulnerability scan and compliance check
|
|
17
|
+
- Test Coverage Analyzer: Gap analysis and coverage validation
|
|
18
|
+
- Code Quality Reviewer: Code review and best practices
|
|
19
|
+
- Documentation Writer: Documentation completeness check
|
|
20
|
+
|
|
21
|
+
Quality Gates:
|
|
22
|
+
- No critical security issues
|
|
23
|
+
- Test coverage ≥ 80%
|
|
24
|
+
- Code quality score ≥ 7
|
|
25
|
+
- Documentation coverage ≥ 100%
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
>>> workflow = OrchestCreatedReleasePrepWorkflow()
|
|
29
|
+
>>> result = await workflow.execute(path=".")
|
|
30
|
+
>>> print(result.approved)
|
|
31
|
+
True
|
|
32
|
+
|
|
33
|
+
Copyright 2025 Smart-AI-Memory
|
|
34
|
+
Licensed under Fair Source License 0.9
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
import asyncio
|
|
38
|
+
import logging
|
|
39
|
+
from dataclasses import dataclass, field
|
|
40
|
+
from datetime import datetime
|
|
41
|
+
from typing import Any
|
|
42
|
+
|
|
43
|
+
from ..orchestration.agent_templates import AgentTemplate, get_template
|
|
44
|
+
from ..orchestration.execution_strategies import ParallelStrategy, StrategyResult
|
|
45
|
+
from ..orchestration.meta_orchestrator import MetaOrchestrator
|
|
46
|
+
|
|
47
|
+
logger = logging.getLogger(__name__)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class QualityGate:
|
|
52
|
+
"""Quality gate threshold for release readiness.
|
|
53
|
+
|
|
54
|
+
Attributes:
|
|
55
|
+
name: Gate identifier (e.g., "security", "coverage")
|
|
56
|
+
threshold: Minimum acceptable value
|
|
57
|
+
actual: Actual measured value
|
|
58
|
+
passed: Whether gate passed
|
|
59
|
+
critical: Whether failure blocks release
|
|
60
|
+
message: Human-readable status message
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
name: str
|
|
64
|
+
threshold: float
|
|
65
|
+
actual: float = 0.0
|
|
66
|
+
passed: bool = False
|
|
67
|
+
critical: bool = True
|
|
68
|
+
message: str = ""
|
|
69
|
+
|
|
70
|
+
def __post_init__(self):
|
|
71
|
+
"""Validate and compute pass/fail status."""
|
|
72
|
+
if not self.name:
|
|
73
|
+
raise ValueError("name must be non-empty")
|
|
74
|
+
if self.threshold < 0:
|
|
75
|
+
raise ValueError("threshold must be non-negative")
|
|
76
|
+
|
|
77
|
+
# Note: passed field is computed externally based on gate semantics
|
|
78
|
+
# (some gates use >=, others use <=)
|
|
79
|
+
|
|
80
|
+
# Generate message if not provided
|
|
81
|
+
if not self.message:
|
|
82
|
+
status = "✅ PASS" if self.passed else "❌ FAIL"
|
|
83
|
+
self.message = (
|
|
84
|
+
f"{self.name}: {status} "
|
|
85
|
+
f"(actual: {self.actual:.1f}, threshold: {self.threshold:.1f})"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass
|
|
90
|
+
class ReleaseReadinessReport:
|
|
91
|
+
"""Consolidated release readiness assessment.
|
|
92
|
+
|
|
93
|
+
Attributes:
|
|
94
|
+
approved: Overall release approval status
|
|
95
|
+
confidence: Confidence level ("high", "medium", "low")
|
|
96
|
+
quality_gates: List of quality gate results
|
|
97
|
+
agent_results: Individual agent outputs
|
|
98
|
+
blockers: Critical issues blocking release
|
|
99
|
+
warnings: Non-critical issues to address
|
|
100
|
+
summary: Executive summary of readiness
|
|
101
|
+
timestamp: Report generation time
|
|
102
|
+
total_duration: Total execution time in seconds
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
approved: bool
|
|
106
|
+
confidence: str
|
|
107
|
+
quality_gates: list[QualityGate] = field(default_factory=list)
|
|
108
|
+
agent_results: dict[str, dict] = field(default_factory=dict)
|
|
109
|
+
blockers: list[str] = field(default_factory=list)
|
|
110
|
+
warnings: list[str] = field(default_factory=list)
|
|
111
|
+
summary: str = ""
|
|
112
|
+
timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
|
|
113
|
+
total_duration: float = 0.0
|
|
114
|
+
|
|
115
|
+
def to_dict(self) -> dict[str, Any]:
|
|
116
|
+
"""Convert report to dictionary format.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Dictionary representation suitable for JSON serialization
|
|
120
|
+
"""
|
|
121
|
+
return {
|
|
122
|
+
"approved": self.approved,
|
|
123
|
+
"confidence": self.confidence,
|
|
124
|
+
"quality_gates": [
|
|
125
|
+
{
|
|
126
|
+
"name": gate.name,
|
|
127
|
+
"threshold": gate.threshold,
|
|
128
|
+
"actual": gate.actual,
|
|
129
|
+
"passed": gate.passed,
|
|
130
|
+
"critical": gate.critical,
|
|
131
|
+
"message": gate.message,
|
|
132
|
+
}
|
|
133
|
+
for gate in self.quality_gates
|
|
134
|
+
],
|
|
135
|
+
"agent_results": self.agent_results,
|
|
136
|
+
"blockers": self.blockers,
|
|
137
|
+
"warnings": self.warnings,
|
|
138
|
+
"summary": self.summary,
|
|
139
|
+
"timestamp": self.timestamp,
|
|
140
|
+
"total_duration": self.total_duration,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
def format_console_output(self) -> str:
|
|
144
|
+
"""Format report for console display.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Human-readable formatted report
|
|
148
|
+
"""
|
|
149
|
+
lines = []
|
|
150
|
+
|
|
151
|
+
# Header
|
|
152
|
+
lines.append("=" * 70)
|
|
153
|
+
lines.append("RELEASE READINESS REPORT (Meta-Orchestrated)")
|
|
154
|
+
lines.append("=" * 70)
|
|
155
|
+
lines.append("")
|
|
156
|
+
|
|
157
|
+
# Status
|
|
158
|
+
status_icon = "✅" if self.approved else "❌"
|
|
159
|
+
lines.append(
|
|
160
|
+
f"Status: {status_icon} {'READY FOR RELEASE' if self.approved else 'NOT READY'}"
|
|
161
|
+
)
|
|
162
|
+
lines.append(f"Confidence: {self.confidence.upper()}")
|
|
163
|
+
lines.append(f"Generated: {self.timestamp}")
|
|
164
|
+
lines.append(f"Duration: {self.total_duration:.2f}s")
|
|
165
|
+
lines.append("")
|
|
166
|
+
|
|
167
|
+
# Quality Gates
|
|
168
|
+
lines.append("-" * 70)
|
|
169
|
+
lines.append("QUALITY GATES")
|
|
170
|
+
lines.append("-" * 70)
|
|
171
|
+
for gate in self.quality_gates:
|
|
172
|
+
icon = "✅" if gate.passed else ("🔴" if gate.critical else "⚠️")
|
|
173
|
+
lines.append(f"{icon} {gate.message}")
|
|
174
|
+
lines.append("")
|
|
175
|
+
|
|
176
|
+
# Blockers
|
|
177
|
+
if self.blockers:
|
|
178
|
+
lines.append("-" * 70)
|
|
179
|
+
lines.append("🚫 RELEASE BLOCKERS")
|
|
180
|
+
lines.append("-" * 70)
|
|
181
|
+
for blocker in self.blockers:
|
|
182
|
+
lines.append(f" • {blocker}")
|
|
183
|
+
lines.append("")
|
|
184
|
+
|
|
185
|
+
# Warnings
|
|
186
|
+
if self.warnings:
|
|
187
|
+
lines.append("-" * 70)
|
|
188
|
+
lines.append("⚠️ WARNINGS")
|
|
189
|
+
lines.append("-" * 70)
|
|
190
|
+
for warning in self.warnings:
|
|
191
|
+
lines.append(f" • {warning}")
|
|
192
|
+
lines.append("")
|
|
193
|
+
|
|
194
|
+
# Summary
|
|
195
|
+
if self.summary:
|
|
196
|
+
lines.append("-" * 70)
|
|
197
|
+
lines.append("EXECUTIVE SUMMARY")
|
|
198
|
+
lines.append("-" * 70)
|
|
199
|
+
lines.append(self.summary)
|
|
200
|
+
lines.append("")
|
|
201
|
+
|
|
202
|
+
# Agent Results Summary
|
|
203
|
+
lines.append("-" * 70)
|
|
204
|
+
lines.append(f"AGENTS EXECUTED ({len(self.agent_results)})")
|
|
205
|
+
lines.append("-" * 70)
|
|
206
|
+
for agent_id, result in self.agent_results.items():
|
|
207
|
+
success = result.get("success", False)
|
|
208
|
+
icon = "✅" if success else "❌"
|
|
209
|
+
duration = result.get("duration", 0.0)
|
|
210
|
+
lines.append(f"{icon} {agent_id}: {duration:.2f}s")
|
|
211
|
+
lines.append("")
|
|
212
|
+
|
|
213
|
+
lines.append("=" * 70)
|
|
214
|
+
|
|
215
|
+
return "\n".join(lines)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class OrchestratedReleasePrepWorkflow:
|
|
219
|
+
"""Release preparation workflow using meta-orchestration.
|
|
220
|
+
|
|
221
|
+
This workflow demonstrates the meta-orchestration system's capabilities
|
|
222
|
+
by coordinating multiple validation agents in parallel to assess release
|
|
223
|
+
readiness.
|
|
224
|
+
|
|
225
|
+
The workflow:
|
|
226
|
+
1. Uses MetaOrchestrator to analyze task and select agents
|
|
227
|
+
2. Executes agents in parallel using ParallelStrategy
|
|
228
|
+
3. Aggregates results and enforces quality gates
|
|
229
|
+
4. Produces consolidated release readiness report
|
|
230
|
+
|
|
231
|
+
Quality Gates:
|
|
232
|
+
- no_critical_security_issues: No critical vulnerabilities
|
|
233
|
+
- min_test_coverage: Test coverage ≥ 80%
|
|
234
|
+
- min_code_quality: Quality score ≥ 7
|
|
235
|
+
- complete_documentation: All public APIs documented
|
|
236
|
+
|
|
237
|
+
Example:
|
|
238
|
+
>>> workflow = OrchestratedReleasePrepWorkflow()
|
|
239
|
+
>>> report = await workflow.execute(path=".")
|
|
240
|
+
>>> if report.approved:
|
|
241
|
+
... print("Ready for release!")
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
# Default quality gate thresholds
|
|
245
|
+
DEFAULT_QUALITY_GATES = {
|
|
246
|
+
"min_coverage": 80.0,
|
|
247
|
+
"min_quality_score": 7.0,
|
|
248
|
+
"max_critical_issues": 0.0,
|
|
249
|
+
"min_doc_coverage": 100.0,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
def __init__(
|
|
253
|
+
self,
|
|
254
|
+
quality_gates: dict[str, float] | None = None,
|
|
255
|
+
agent_ids: list[str] | None = None,
|
|
256
|
+
**kwargs, # Absorb extra CLI parameters (provider, enable_tier_fallback, etc.)
|
|
257
|
+
):
|
|
258
|
+
"""Initialize orchestrated release prep workflow.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
quality_gates: Custom quality gate thresholds
|
|
262
|
+
agent_ids: Specific agent IDs to use (defaults to domain defaults)
|
|
263
|
+
**kwargs: Extra parameters (ignored, for CLI compatibility)
|
|
264
|
+
|
|
265
|
+
Raises:
|
|
266
|
+
ValueError: If quality gates are invalid
|
|
267
|
+
"""
|
|
268
|
+
self.quality_gates = {**self.DEFAULT_QUALITY_GATES}
|
|
269
|
+
if quality_gates:
|
|
270
|
+
self.quality_gates.update(quality_gates)
|
|
271
|
+
|
|
272
|
+
# Validate quality gates
|
|
273
|
+
for name, threshold in self.quality_gates.items():
|
|
274
|
+
if not isinstance(threshold, int | float):
|
|
275
|
+
raise ValueError(f"Quality gate '{name}' must be numeric")
|
|
276
|
+
if threshold < 0:
|
|
277
|
+
raise ValueError(f"Quality gate '{name}' must be non-negative")
|
|
278
|
+
|
|
279
|
+
self.orchestrator = MetaOrchestrator()
|
|
280
|
+
# Use default agents if none specified
|
|
281
|
+
self.agent_ids = agent_ids or [
|
|
282
|
+
"security_auditor",
|
|
283
|
+
"test_coverage_analyzer",
|
|
284
|
+
"code_reviewer",
|
|
285
|
+
"documentation_writer",
|
|
286
|
+
]
|
|
287
|
+
|
|
288
|
+
logger.info(
|
|
289
|
+
f"OrchestratedReleasePrepWorkflow initialized with gates: {self.quality_gates}, "
|
|
290
|
+
f"agents: {self.agent_ids}"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
async def execute(
|
|
294
|
+
self,
|
|
295
|
+
path: str = ".",
|
|
296
|
+
context: dict[str, Any] | None = None,
|
|
297
|
+
**kwargs, # Absorb extra parameters from VSCode/CLI (target, etc.)
|
|
298
|
+
) -> ReleaseReadinessReport:
|
|
299
|
+
"""Execute release preparation workflow.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
path: Path to codebase to analyze (default: ".")
|
|
303
|
+
context: Additional context for agents
|
|
304
|
+
**kwargs: Extra parameters (ignored, for VSCode/CLI compatibility)
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
ReleaseReadinessReport with consolidated results
|
|
308
|
+
|
|
309
|
+
Raises:
|
|
310
|
+
ValueError: If path is invalid
|
|
311
|
+
"""
|
|
312
|
+
# Map 'target' to 'path' for VSCode compatibility
|
|
313
|
+
if "target" in kwargs and path == ".":
|
|
314
|
+
path = kwargs["target"]
|
|
315
|
+
if not path or not isinstance(path, str):
|
|
316
|
+
raise ValueError("path must be a non-empty string")
|
|
317
|
+
|
|
318
|
+
logger.info(f"Starting orchestrated release prep for: {path}")
|
|
319
|
+
start_time = asyncio.get_event_loop().time()
|
|
320
|
+
|
|
321
|
+
# Prepare context
|
|
322
|
+
full_context = {
|
|
323
|
+
"path": path,
|
|
324
|
+
"quality_gates": self.quality_gates,
|
|
325
|
+
**(context or {}),
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
# Step 1: Analyze task and compose agents
|
|
329
|
+
task = (
|
|
330
|
+
"Prepare for release: validate security, test coverage, code quality, and documentation"
|
|
331
|
+
)
|
|
332
|
+
execution_plan = self.orchestrator.analyze_and_compose(task, full_context)
|
|
333
|
+
|
|
334
|
+
logger.info(
|
|
335
|
+
f"Execution plan: {len(execution_plan.agents)} agents, "
|
|
336
|
+
f"strategy={execution_plan.strategy.value}"
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
# Override agents if specific IDs provided
|
|
340
|
+
if self.agent_ids:
|
|
341
|
+
agents = []
|
|
342
|
+
for agent_id in self.agent_ids:
|
|
343
|
+
template = get_template(agent_id)
|
|
344
|
+
if template:
|
|
345
|
+
agents.append(template)
|
|
346
|
+
else:
|
|
347
|
+
logger.warning(f"Agent template not found: {agent_id}")
|
|
348
|
+
|
|
349
|
+
if not agents:
|
|
350
|
+
raise ValueError(f"No valid agents found from: {self.agent_ids}")
|
|
351
|
+
|
|
352
|
+
execution_plan.agents = agents
|
|
353
|
+
|
|
354
|
+
# Step 2: Execute agents in parallel
|
|
355
|
+
strategy = ParallelStrategy()
|
|
356
|
+
strategy_result = await strategy.execute(execution_plan.agents, full_context)
|
|
357
|
+
|
|
358
|
+
# Step 3: Process results and evaluate quality gates
|
|
359
|
+
report = await self._create_report(strategy_result, execution_plan.agents, full_context)
|
|
360
|
+
|
|
361
|
+
# Set duration
|
|
362
|
+
end_time = asyncio.get_event_loop().time()
|
|
363
|
+
report.total_duration = end_time - start_time
|
|
364
|
+
|
|
365
|
+
logger.info(
|
|
366
|
+
f"Release prep completed: approved={report.approved}, "
|
|
367
|
+
f"duration={report.total_duration:.2f}s"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
return report
|
|
371
|
+
|
|
372
|
+
async def _create_report(
|
|
373
|
+
self,
|
|
374
|
+
strategy_result: StrategyResult,
|
|
375
|
+
agents: list[AgentTemplate],
|
|
376
|
+
context: dict[str, Any],
|
|
377
|
+
) -> ReleaseReadinessReport:
|
|
378
|
+
"""Create consolidated release readiness report.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
strategy_result: Results from parallel execution
|
|
382
|
+
agents: Agents that were executed
|
|
383
|
+
context: Execution context
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
ReleaseReadinessReport with all findings
|
|
387
|
+
"""
|
|
388
|
+
# Extract agent results
|
|
389
|
+
agent_results: dict[str, dict] = {}
|
|
390
|
+
for result in strategy_result.outputs:
|
|
391
|
+
agent_results[result.agent_id] = {
|
|
392
|
+
"success": result.success,
|
|
393
|
+
"output": result.output,
|
|
394
|
+
"confidence": result.confidence,
|
|
395
|
+
"duration": result.duration_seconds,
|
|
396
|
+
"error": result.error,
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
# Evaluate quality gates
|
|
400
|
+
quality_gates = self._evaluate_quality_gates(agent_results)
|
|
401
|
+
|
|
402
|
+
# Identify blockers and warnings
|
|
403
|
+
blockers, warnings = self._identify_issues(quality_gates, agent_results)
|
|
404
|
+
|
|
405
|
+
# Determine approval
|
|
406
|
+
critical_failures = [g for g in quality_gates if g.critical and not g.passed]
|
|
407
|
+
approved = len(critical_failures) == 0 and len(blockers) == 0
|
|
408
|
+
|
|
409
|
+
# Determine confidence
|
|
410
|
+
if approved and len(warnings) == 0:
|
|
411
|
+
confidence = "high"
|
|
412
|
+
elif approved:
|
|
413
|
+
confidence = "medium"
|
|
414
|
+
else:
|
|
415
|
+
confidence = "low"
|
|
416
|
+
|
|
417
|
+
# Generate summary
|
|
418
|
+
summary = self._generate_summary(approved, quality_gates, agent_results)
|
|
419
|
+
|
|
420
|
+
return ReleaseReadinessReport(
|
|
421
|
+
approved=approved,
|
|
422
|
+
confidence=confidence,
|
|
423
|
+
quality_gates=quality_gates,
|
|
424
|
+
agent_results=agent_results,
|
|
425
|
+
blockers=blockers,
|
|
426
|
+
warnings=warnings,
|
|
427
|
+
summary=summary,
|
|
428
|
+
total_duration=strategy_result.total_duration,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
def _evaluate_quality_gates(self, agent_results: dict[str, dict]) -> list[QualityGate]:
|
|
432
|
+
"""Evaluate all quality gates based on agent results.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
agent_results: Results from all agents
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
List of QualityGate results
|
|
439
|
+
"""
|
|
440
|
+
gates = []
|
|
441
|
+
|
|
442
|
+
# Security gate: no critical issues
|
|
443
|
+
security_result = agent_results.get("security_auditor", {}).get("output", {})
|
|
444
|
+
critical_issues = security_result.get("critical_issues", 0)
|
|
445
|
+
|
|
446
|
+
gates.append(
|
|
447
|
+
QualityGate(
|
|
448
|
+
name="Security",
|
|
449
|
+
threshold=self.quality_gates["max_critical_issues"],
|
|
450
|
+
actual=float(critical_issues),
|
|
451
|
+
critical=True,
|
|
452
|
+
passed=critical_issues <= self.quality_gates["max_critical_issues"],
|
|
453
|
+
)
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
# Coverage gate: minimum test coverage
|
|
457
|
+
coverage_result = agent_results.get("test_coverage_analyzer", {}).get("output", {})
|
|
458
|
+
coverage_percent = coverage_result.get("coverage_percent", 0.0)
|
|
459
|
+
|
|
460
|
+
gates.append(
|
|
461
|
+
QualityGate(
|
|
462
|
+
name="Test Coverage",
|
|
463
|
+
threshold=self.quality_gates["min_coverage"],
|
|
464
|
+
actual=coverage_percent,
|
|
465
|
+
passed=coverage_percent >= self.quality_gates["min_coverage"],
|
|
466
|
+
critical=True,
|
|
467
|
+
)
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Quality gate: minimum code quality score
|
|
471
|
+
quality_result = agent_results.get("code_reviewer", {}).get("output", {})
|
|
472
|
+
quality_score = quality_result.get("quality_score", 0.0)
|
|
473
|
+
|
|
474
|
+
gates.append(
|
|
475
|
+
QualityGate(
|
|
476
|
+
name="Code Quality",
|
|
477
|
+
threshold=self.quality_gates["min_quality_score"],
|
|
478
|
+
actual=quality_score,
|
|
479
|
+
passed=quality_score >= self.quality_gates["min_quality_score"],
|
|
480
|
+
critical=True,
|
|
481
|
+
)
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
# Documentation gate: completeness
|
|
485
|
+
docs_result = agent_results.get("documentation_writer", {}).get("output", {})
|
|
486
|
+
doc_coverage = docs_result.get("coverage_percent", 0.0)
|
|
487
|
+
|
|
488
|
+
gates.append(
|
|
489
|
+
QualityGate(
|
|
490
|
+
name="Documentation",
|
|
491
|
+
threshold=self.quality_gates["min_doc_coverage"],
|
|
492
|
+
actual=doc_coverage,
|
|
493
|
+
passed=doc_coverage >= self.quality_gates["min_doc_coverage"],
|
|
494
|
+
critical=False, # Non-critical - warning only
|
|
495
|
+
)
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
return gates
|
|
499
|
+
|
|
500
|
+
def _identify_issues(
|
|
501
|
+
self, quality_gates: list[QualityGate], agent_results: dict[str, dict]
|
|
502
|
+
) -> tuple[list[str], list[str]]:
|
|
503
|
+
"""Identify blockers and warnings from quality gates and agent results.
|
|
504
|
+
|
|
505
|
+
Args:
|
|
506
|
+
quality_gates: Evaluated quality gates
|
|
507
|
+
agent_results: Agent execution results
|
|
508
|
+
|
|
509
|
+
Returns:
|
|
510
|
+
Tuple of (blockers, warnings)
|
|
511
|
+
"""
|
|
512
|
+
blockers = []
|
|
513
|
+
warnings = []
|
|
514
|
+
|
|
515
|
+
# Check quality gates
|
|
516
|
+
for gate in quality_gates:
|
|
517
|
+
if not gate.passed:
|
|
518
|
+
if gate.critical:
|
|
519
|
+
blockers.append(f"{gate.name} failed: {gate.message}")
|
|
520
|
+
else:
|
|
521
|
+
warnings.append(f"{gate.name} below threshold: {gate.message}")
|
|
522
|
+
|
|
523
|
+
# Check agent errors
|
|
524
|
+
for agent_id, result in agent_results.items():
|
|
525
|
+
if not result["success"]:
|
|
526
|
+
error = result.get("error", "Unknown error")
|
|
527
|
+
blockers.append(f"Agent {agent_id} failed: {error}")
|
|
528
|
+
|
|
529
|
+
return blockers, warnings
|
|
530
|
+
|
|
531
|
+
def _generate_summary(
|
|
532
|
+
self,
|
|
533
|
+
approved: bool,
|
|
534
|
+
quality_gates: list[QualityGate],
|
|
535
|
+
agent_results: dict[str, dict],
|
|
536
|
+
) -> str:
|
|
537
|
+
"""Generate executive summary of release readiness.
|
|
538
|
+
|
|
539
|
+
Args:
|
|
540
|
+
approved: Overall approval status
|
|
541
|
+
quality_gates: Quality gate results
|
|
542
|
+
agent_results: Agent execution results
|
|
543
|
+
|
|
544
|
+
Returns:
|
|
545
|
+
Executive summary text
|
|
546
|
+
"""
|
|
547
|
+
lines = []
|
|
548
|
+
|
|
549
|
+
if approved:
|
|
550
|
+
lines.append("✅ RELEASE APPROVED")
|
|
551
|
+
lines.append("")
|
|
552
|
+
lines.append("All quality gates passed. The codebase is ready for release.")
|
|
553
|
+
else:
|
|
554
|
+
lines.append("❌ RELEASE NOT APPROVED")
|
|
555
|
+
lines.append("")
|
|
556
|
+
lines.append("Critical quality gates failed. Address blockers before release.")
|
|
557
|
+
|
|
558
|
+
lines.append("")
|
|
559
|
+
lines.append("Quality Gate Summary:")
|
|
560
|
+
|
|
561
|
+
passed_count = sum(1 for g in quality_gates if g.passed)
|
|
562
|
+
total_count = len(quality_gates)
|
|
563
|
+
lines.append(f" Passed: {passed_count}/{total_count}")
|
|
564
|
+
|
|
565
|
+
failed_gates = [g for g in quality_gates if not g.passed]
|
|
566
|
+
if failed_gates:
|
|
567
|
+
lines.append(" Failed:")
|
|
568
|
+
for gate in failed_gates:
|
|
569
|
+
lines.append(f" • {gate.name}: {gate.actual:.1f} < {gate.threshold:.1f}")
|
|
570
|
+
|
|
571
|
+
lines.append("")
|
|
572
|
+
lines.append(f"Agents Executed: {len(agent_results)}")
|
|
573
|
+
|
|
574
|
+
successful_agents = sum(1 for r in agent_results.values() if r["success"])
|
|
575
|
+
lines.append(f" Successful: {successful_agents}/{len(agent_results)}")
|
|
576
|
+
|
|
577
|
+
return "\n".join(lines)
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
async def main():
|
|
581
|
+
"""CLI entry point for orchestrated release preparation."""
|
|
582
|
+
import sys
|
|
583
|
+
|
|
584
|
+
workflow = OrchestratedReleasePrepWorkflow()
|
|
585
|
+
|
|
586
|
+
# Get path from args or use current directory
|
|
587
|
+
path = sys.argv[1] if len(sys.argv) > 1 else "."
|
|
588
|
+
|
|
589
|
+
# Execute workflow
|
|
590
|
+
report = await workflow.execute(path=path)
|
|
591
|
+
|
|
592
|
+
# Print formatted report
|
|
593
|
+
print(report.format_console_output())
|
|
594
|
+
|
|
595
|
+
# Exit with appropriate code
|
|
596
|
+
sys.exit(0 if report.approved else 1)
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
if __name__ == "__main__":
|
|
600
|
+
asyncio.run(main())
|