tapps-agents 3.6.0__py3-none-any.whl → 3.6.1__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.
- tapps_agents/__init__.py +2 -2
- tapps_agents/agents/__init__.py +22 -22
- tapps_agents/agents/analyst/__init__.py +5 -5
- tapps_agents/agents/architect/__init__.py +5 -5
- tapps_agents/agents/architect/agent.py +1033 -1033
- tapps_agents/agents/architect/pattern_detector.py +75 -75
- tapps_agents/agents/cleanup/__init__.py +7 -7
- tapps_agents/agents/cleanup/agent.py +445 -445
- tapps_agents/agents/debugger/__init__.py +7 -7
- tapps_agents/agents/debugger/agent.py +310 -310
- tapps_agents/agents/debugger/error_analyzer.py +437 -437
- tapps_agents/agents/designer/__init__.py +5 -5
- tapps_agents/agents/designer/agent.py +786 -786
- tapps_agents/agents/designer/visual_designer.py +638 -638
- tapps_agents/agents/documenter/__init__.py +7 -7
- tapps_agents/agents/documenter/agent.py +531 -531
- tapps_agents/agents/documenter/doc_generator.py +472 -472
- tapps_agents/agents/documenter/doc_validator.py +393 -393
- tapps_agents/agents/documenter/framework_doc_updater.py +493 -493
- tapps_agents/agents/enhancer/__init__.py +7 -7
- tapps_agents/agents/evaluator/__init__.py +7 -7
- tapps_agents/agents/evaluator/agent.py +443 -443
- tapps_agents/agents/evaluator/priority_evaluator.py +641 -641
- tapps_agents/agents/evaluator/quality_analyzer.py +147 -147
- tapps_agents/agents/evaluator/report_generator.py +344 -344
- tapps_agents/agents/evaluator/usage_analyzer.py +192 -192
- tapps_agents/agents/evaluator/workflow_analyzer.py +189 -189
- tapps_agents/agents/implementer/__init__.py +7 -7
- tapps_agents/agents/implementer/agent.py +798 -798
- tapps_agents/agents/implementer/auto_fix.py +1119 -1119
- tapps_agents/agents/implementer/code_generator.py +73 -73
- tapps_agents/agents/improver/__init__.py +1 -1
- tapps_agents/agents/improver/agent.py +753 -753
- tapps_agents/agents/ops/__init__.py +1 -1
- tapps_agents/agents/ops/agent.py +619 -619
- tapps_agents/agents/ops/dependency_analyzer.py +600 -600
- tapps_agents/agents/orchestrator/__init__.py +5 -5
- tapps_agents/agents/orchestrator/agent.py +522 -522
- tapps_agents/agents/planner/__init__.py +7 -7
- tapps_agents/agents/planner/agent.py +1127 -1127
- tapps_agents/agents/reviewer/__init__.py +24 -24
- tapps_agents/agents/reviewer/agent.py +3513 -3513
- tapps_agents/agents/reviewer/aggregator.py +213 -213
- tapps_agents/agents/reviewer/batch_review.py +448 -448
- tapps_agents/agents/reviewer/cache.py +443 -443
- tapps_agents/agents/reviewer/context7_enhancer.py +630 -630
- tapps_agents/agents/reviewer/context_detector.py +203 -203
- tapps_agents/agents/reviewer/docker_compose_validator.py +158 -158
- tapps_agents/agents/reviewer/dockerfile_validator.py +176 -176
- tapps_agents/agents/reviewer/error_handling.py +126 -126
- tapps_agents/agents/reviewer/feedback_generator.py +490 -490
- tapps_agents/agents/reviewer/influxdb_validator.py +316 -316
- tapps_agents/agents/reviewer/issue_tracking.py +169 -169
- tapps_agents/agents/reviewer/library_detector.py +295 -295
- tapps_agents/agents/reviewer/library_patterns.py +268 -268
- tapps_agents/agents/reviewer/maintainability_scorer.py +593 -593
- tapps_agents/agents/reviewer/metric_strategies.py +276 -276
- tapps_agents/agents/reviewer/mqtt_validator.py +160 -160
- tapps_agents/agents/reviewer/output_enhancer.py +105 -105
- tapps_agents/agents/reviewer/pattern_detector.py +241 -241
- tapps_agents/agents/reviewer/performance_scorer.py +357 -357
- tapps_agents/agents/reviewer/phased_review.py +516 -516
- tapps_agents/agents/reviewer/progressive_review.py +435 -435
- tapps_agents/agents/reviewer/react_scorer.py +331 -331
- tapps_agents/agents/reviewer/score_constants.py +228 -228
- tapps_agents/agents/reviewer/score_validator.py +507 -507
- tapps_agents/agents/reviewer/scorer_registry.py +373 -373
- tapps_agents/agents/reviewer/service_discovery.py +534 -534
- tapps_agents/agents/reviewer/tools/parallel_executor.py +581 -581
- tapps_agents/agents/reviewer/tools/ruff_grouping.py +250 -250
- tapps_agents/agents/reviewer/tools/scoped_mypy.py +284 -284
- tapps_agents/agents/reviewer/typescript_scorer.py +1142 -1142
- tapps_agents/agents/reviewer/validation.py +208 -208
- tapps_agents/agents/reviewer/websocket_validator.py +132 -132
- tapps_agents/agents/tester/__init__.py +7 -7
- tapps_agents/agents/tester/accessibility_auditor.py +309 -309
- tapps_agents/agents/tester/agent.py +1080 -1080
- tapps_agents/agents/tester/batch_generator.py +54 -54
- tapps_agents/agents/tester/context_learner.py +51 -51
- tapps_agents/agents/tester/coverage_analyzer.py +386 -386
- tapps_agents/agents/tester/coverage_test_generator.py +290 -290
- tapps_agents/agents/tester/debug_enhancer.py +238 -238
- tapps_agents/agents/tester/device_emulator.py +241 -241
- tapps_agents/agents/tester/integration_generator.py +62 -62
- tapps_agents/agents/tester/network_recorder.py +300 -300
- tapps_agents/agents/tester/performance_monitor.py +320 -320
- tapps_agents/agents/tester/test_fixer.py +316 -316
- tapps_agents/agents/tester/test_generator.py +632 -632
- tapps_agents/agents/tester/trace_manager.py +234 -234
- tapps_agents/agents/tester/visual_regression.py +291 -291
- tapps_agents/analysis/pattern_detector.py +36 -36
- tapps_agents/beads/hydration.py +213 -213
- tapps_agents/beads/parse.py +32 -32
- tapps_agents/beads/specs.py +206 -206
- tapps_agents/cli/__init__.py +9 -9
- tapps_agents/cli/__main__.py +8 -8
- tapps_agents/cli/base.py +478 -478
- tapps_agents/cli/command_classifier.py +72 -72
- tapps_agents/cli/commands/__init__.py +2 -2
- tapps_agents/cli/commands/analyst.py +173 -173
- tapps_agents/cli/commands/architect.py +109 -109
- tapps_agents/cli/commands/cleanup_agent.py +92 -92
- tapps_agents/cli/commands/common.py +126 -126
- tapps_agents/cli/commands/debugger.py +90 -90
- tapps_agents/cli/commands/designer.py +112 -112
- tapps_agents/cli/commands/documenter.py +136 -136
- tapps_agents/cli/commands/enhancer.py +110 -110
- tapps_agents/cli/commands/evaluator.py +255 -255
- tapps_agents/cli/commands/implementer.py +301 -301
- tapps_agents/cli/commands/improver.py +91 -91
- tapps_agents/cli/commands/knowledge.py +111 -111
- tapps_agents/cli/commands/learning.py +172 -172
- tapps_agents/cli/commands/observability.py +283 -283
- tapps_agents/cli/commands/ops.py +135 -135
- tapps_agents/cli/commands/orchestrator.py +116 -116
- tapps_agents/cli/commands/planner.py +237 -237
- tapps_agents/cli/commands/reviewer.py +1872 -1872
- tapps_agents/cli/commands/status.py +285 -285
- tapps_agents/cli/commands/task.py +227 -227
- tapps_agents/cli/commands/tester.py +191 -191
- tapps_agents/cli/feedback.py +936 -936
- tapps_agents/cli/formatters.py +608 -608
- tapps_agents/cli/help/__init__.py +7 -7
- tapps_agents/cli/help/static_help.py +425 -425
- tapps_agents/cli/network_detection.py +110 -110
- tapps_agents/cli/output_compactor.py +274 -274
- tapps_agents/cli/parsers/__init__.py +2 -2
- tapps_agents/cli/parsers/analyst.py +186 -186
- tapps_agents/cli/parsers/architect.py +167 -167
- tapps_agents/cli/parsers/cleanup_agent.py +228 -228
- tapps_agents/cli/parsers/debugger.py +116 -116
- tapps_agents/cli/parsers/designer.py +182 -182
- tapps_agents/cli/parsers/documenter.py +134 -134
- tapps_agents/cli/parsers/enhancer.py +113 -113
- tapps_agents/cli/parsers/evaluator.py +213 -213
- tapps_agents/cli/parsers/implementer.py +168 -168
- tapps_agents/cli/parsers/improver.py +132 -132
- tapps_agents/cli/parsers/ops.py +159 -159
- tapps_agents/cli/parsers/orchestrator.py +98 -98
- tapps_agents/cli/parsers/planner.py +145 -145
- tapps_agents/cli/parsers/reviewer.py +462 -462
- tapps_agents/cli/parsers/tester.py +124 -124
- tapps_agents/cli/progress_heartbeat.py +254 -254
- tapps_agents/cli/streaming_progress.py +336 -336
- tapps_agents/cli/utils/__init__.py +6 -6
- tapps_agents/cli/utils/agent_lifecycle.py +48 -48
- tapps_agents/cli/utils/error_formatter.py +82 -82
- tapps_agents/cli/utils/error_recovery.py +188 -188
- tapps_agents/cli/utils/output_handler.py +59 -59
- tapps_agents/cli/utils/prompt_enhancer.py +319 -319
- tapps_agents/cli/validators/__init__.py +9 -9
- tapps_agents/cli/validators/command_validator.py +81 -81
- tapps_agents/context7/__init__.py +112 -112
- tapps_agents/context7/agent_integration.py +869 -869
- tapps_agents/context7/analytics.py +382 -382
- tapps_agents/context7/analytics_dashboard.py +299 -299
- tapps_agents/context7/async_cache.py +681 -681
- tapps_agents/context7/backup_client.py +958 -958
- tapps_agents/context7/cache_locking.py +194 -194
- tapps_agents/context7/cache_metadata.py +214 -214
- tapps_agents/context7/cache_prewarm.py +488 -488
- tapps_agents/context7/cache_structure.py +168 -168
- tapps_agents/context7/cache_warming.py +604 -604
- tapps_agents/context7/circuit_breaker.py +376 -376
- tapps_agents/context7/cleanup.py +461 -461
- tapps_agents/context7/commands.py +858 -858
- tapps_agents/context7/credential_validation.py +276 -276
- tapps_agents/context7/cross_reference_resolver.py +168 -168
- tapps_agents/context7/cross_references.py +424 -424
- tapps_agents/context7/doc_manager.py +225 -225
- tapps_agents/context7/fuzzy_matcher.py +369 -369
- tapps_agents/context7/kb_cache.py +404 -404
- tapps_agents/context7/language_detector.py +219 -219
- tapps_agents/context7/library_detector.py +725 -725
- tapps_agents/context7/lookup.py +738 -738
- tapps_agents/context7/metadata.py +258 -258
- tapps_agents/context7/refresh_queue.py +300 -300
- tapps_agents/context7/security.py +373 -373
- tapps_agents/context7/staleness_policies.py +278 -278
- tapps_agents/context7/tiles_integration.py +47 -47
- tapps_agents/continuous_bug_fix/__init__.py +20 -20
- tapps_agents/continuous_bug_fix/bug_finder.py +306 -306
- tapps_agents/continuous_bug_fix/bug_fix_coordinator.py +177 -177
- tapps_agents/continuous_bug_fix/commit_manager.py +178 -178
- tapps_agents/continuous_bug_fix/continuous_bug_fixer.py +322 -322
- tapps_agents/continuous_bug_fix/proactive_bug_finder.py +285 -285
- tapps_agents/core/__init__.py +298 -298
- tapps_agents/core/adaptive_cache_config.py +432 -432
- tapps_agents/core/agent_base.py +647 -647
- tapps_agents/core/agent_cache.py +466 -466
- tapps_agents/core/agent_learning.py +1865 -1865
- tapps_agents/core/analytics_dashboard.py +563 -563
- tapps_agents/core/analytics_enhancements.py +597 -597
- tapps_agents/core/anonymization.py +274 -274
- tapps_agents/core/ast_parser.py +228 -228
- tapps_agents/core/async_file_ops.py +402 -402
- tapps_agents/core/best_practice_consultant.py +299 -299
- tapps_agents/core/brownfield_analyzer.py +299 -299
- tapps_agents/core/brownfield_review.py +541 -541
- tapps_agents/core/browser_controller.py +513 -513
- tapps_agents/core/capability_registry.py +418 -418
- tapps_agents/core/change_impact_analyzer.py +190 -190
- tapps_agents/core/checkpoint_manager.py +377 -377
- tapps_agents/core/code_generator.py +329 -329
- tapps_agents/core/code_validator.py +276 -276
- tapps_agents/core/command_registry.py +327 -327
- tapps_agents/core/context_gathering/__init__.py +2 -2
- tapps_agents/core/context_gathering/repository_explorer.py +28 -28
- tapps_agents/core/context_intelligence/__init__.py +2 -2
- tapps_agents/core/context_intelligence/relevance_scorer.py +24 -24
- tapps_agents/core/context_intelligence/token_budget_manager.py +27 -27
- tapps_agents/core/context_manager.py +240 -240
- tapps_agents/core/cursor_feedback_monitor.py +146 -146
- tapps_agents/core/cursor_verification.py +290 -290
- tapps_agents/core/customization_loader.py +280 -280
- tapps_agents/core/customization_schema.py +260 -260
- tapps_agents/core/customization_template.py +238 -238
- tapps_agents/core/debug_logger.py +124 -124
- tapps_agents/core/design_validator.py +298 -298
- tapps_agents/core/diagram_generator.py +226 -226
- tapps_agents/core/docker_utils.py +232 -232
- tapps_agents/core/document_generator.py +617 -617
- tapps_agents/core/domain_detector.py +30 -30
- tapps_agents/core/error_envelope.py +454 -454
- tapps_agents/core/error_handler.py +270 -270
- tapps_agents/core/estimation_tracker.py +189 -189
- tapps_agents/core/eval_prompt_engine.py +116 -116
- tapps_agents/core/evaluation_base.py +119 -119
- tapps_agents/core/evaluation_models.py +320 -320
- tapps_agents/core/evaluation_orchestrator.py +225 -225
- tapps_agents/core/evaluators/__init__.py +7 -7
- tapps_agents/core/evaluators/architectural_evaluator.py +205 -205
- tapps_agents/core/evaluators/behavioral_evaluator.py +160 -160
- tapps_agents/core/evaluators/performance_profile_evaluator.py +160 -160
- tapps_agents/core/evaluators/security_posture_evaluator.py +148 -148
- tapps_agents/core/evaluators/spec_compliance_evaluator.py +181 -181
- tapps_agents/core/exceptions.py +107 -107
- tapps_agents/core/expert_config_generator.py +293 -293
- tapps_agents/core/export_schema.py +202 -202
- tapps_agents/core/external_feedback_models.py +102 -102
- tapps_agents/core/external_feedback_storage.py +213 -213
- tapps_agents/core/fallback_strategy.py +314 -314
- tapps_agents/core/feedback_analyzer.py +162 -162
- tapps_agents/core/feedback_collector.py +178 -178
- tapps_agents/core/git_operations.py +445 -445
- tapps_agents/core/hardware_profiler.py +151 -151
- tapps_agents/core/instructions.py +324 -324
- tapps_agents/core/io_guardrails.py +69 -69
- tapps_agents/core/issue_manifest.py +249 -249
- tapps_agents/core/issue_schema.py +139 -139
- tapps_agents/core/json_utils.py +128 -128
- tapps_agents/core/knowledge_graph.py +446 -446
- tapps_agents/core/language_detector.py +296 -296
- tapps_agents/core/learning_confidence.py +242 -242
- tapps_agents/core/learning_dashboard.py +246 -246
- tapps_agents/core/learning_decision.py +384 -384
- tapps_agents/core/learning_explainability.py +578 -578
- tapps_agents/core/learning_export.py +287 -287
- tapps_agents/core/learning_integration.py +228 -228
- tapps_agents/core/llm_behavior.py +232 -232
- tapps_agents/core/long_duration_support.py +786 -786
- tapps_agents/core/mcp_setup.py +106 -106
- tapps_agents/core/memory_integration.py +396 -396
- tapps_agents/core/meta_learning.py +666 -666
- tapps_agents/core/module_path_sanitizer.py +199 -199
- tapps_agents/core/multi_agent_orchestrator.py +382 -382
- tapps_agents/core/network_errors.py +125 -125
- tapps_agents/core/nfr_validator.py +336 -336
- tapps_agents/core/offline_mode.py +158 -158
- tapps_agents/core/output_contracts.py +300 -300
- tapps_agents/core/output_formatter.py +300 -300
- tapps_agents/core/path_normalizer.py +174 -174
- tapps_agents/core/path_validator.py +322 -322
- tapps_agents/core/pattern_library.py +250 -250
- tapps_agents/core/performance_benchmark.py +301 -301
- tapps_agents/core/performance_monitor.py +184 -184
- tapps_agents/core/playwright_mcp_controller.py +771 -771
- tapps_agents/core/policy_loader.py +135 -135
- tapps_agents/core/progress.py +166 -166
- tapps_agents/core/project_profile.py +354 -354
- tapps_agents/core/project_type_detector.py +454 -454
- tapps_agents/core/prompt_base.py +223 -223
- tapps_agents/core/prompt_learning/__init__.py +2 -2
- tapps_agents/core/prompt_learning/learning_loop.py +24 -24
- tapps_agents/core/prompt_learning/project_prompt_store.py +25 -25
- tapps_agents/core/prompt_learning/skills_prompt_analyzer.py +35 -35
- tapps_agents/core/prompt_optimization/__init__.py +6 -6
- tapps_agents/core/prompt_optimization/ab_tester.py +114 -114
- tapps_agents/core/prompt_optimization/correlation_analyzer.py +160 -160
- tapps_agents/core/prompt_optimization/progressive_refiner.py +129 -129
- tapps_agents/core/prompt_optimization/prompt_library.py +37 -37
- tapps_agents/core/requirements_evaluator.py +431 -431
- tapps_agents/core/resource_aware_executor.py +449 -449
- tapps_agents/core/resource_monitor.py +343 -343
- tapps_agents/core/resume_handler.py +298 -298
- tapps_agents/core/retry_handler.py +197 -197
- tapps_agents/core/review_checklists.py +479 -479
- tapps_agents/core/role_loader.py +201 -201
- tapps_agents/core/role_template_loader.py +201 -201
- tapps_agents/core/runtime_mode.py +60 -60
- tapps_agents/core/security_scanner.py +342 -342
- tapps_agents/core/skill_agent_registry.py +194 -194
- tapps_agents/core/skill_integration.py +208 -208
- tapps_agents/core/skill_loader.py +492 -492
- tapps_agents/core/skill_template.py +341 -341
- tapps_agents/core/skill_validator.py +478 -478
- tapps_agents/core/stack_analyzer.py +35 -35
- tapps_agents/core/startup.py +174 -174
- tapps_agents/core/storage_manager.py +397 -397
- tapps_agents/core/storage_models.py +166 -166
- tapps_agents/core/story_evaluator.py +410 -410
- tapps_agents/core/subprocess_utils.py +170 -170
- tapps_agents/core/task_duration.py +296 -296
- tapps_agents/core/task_memory.py +582 -582
- tapps_agents/core/task_state.py +226 -226
- tapps_agents/core/tech_stack_priorities.py +208 -208
- tapps_agents/core/temp_directory.py +194 -194
- tapps_agents/core/template_merger.py +600 -600
- tapps_agents/core/template_selector.py +280 -280
- tapps_agents/core/test_generator.py +286 -286
- tapps_agents/core/tiered_context.py +253 -253
- tapps_agents/core/token_monitor.py +345 -345
- tapps_agents/core/traceability.py +254 -254
- tapps_agents/core/trajectory_tracker.py +50 -50
- tapps_agents/core/unicode_safe.py +143 -143
- tapps_agents/core/unified_cache_config.py +170 -170
- tapps_agents/core/unified_state.py +324 -324
- tapps_agents/core/validate_cursor_setup.py +237 -237
- tapps_agents/core/validation_registry.py +136 -136
- tapps_agents/core/validators/__init__.py +4 -4
- tapps_agents/core/validators/python_validator.py +87 -87
- tapps_agents/core/verification_agent.py +90 -90
- tapps_agents/core/visual_feedback.py +644 -644
- tapps_agents/core/workflow_validator.py +197 -197
- tapps_agents/core/worktree.py +367 -367
- tapps_agents/docker/__init__.py +10 -10
- tapps_agents/docker/analyzer.py +186 -186
- tapps_agents/docker/debugger.py +229 -229
- tapps_agents/docker/error_patterns.py +216 -216
- tapps_agents/epic/__init__.py +22 -22
- tapps_agents/epic/beads_sync.py +115 -115
- tapps_agents/epic/markdown_sync.py +105 -105
- tapps_agents/epic/models.py +96 -96
- tapps_agents/experts/__init__.py +163 -163
- tapps_agents/experts/agent_integration.py +243 -243
- tapps_agents/experts/auto_generator.py +331 -331
- tapps_agents/experts/base_expert.py +536 -536
- tapps_agents/experts/builtin_registry.py +261 -261
- tapps_agents/experts/business_metrics.py +565 -565
- tapps_agents/experts/cache.py +266 -266
- tapps_agents/experts/confidence_breakdown.py +306 -306
- tapps_agents/experts/confidence_calculator.py +336 -336
- tapps_agents/experts/confidence_metrics.py +236 -236
- tapps_agents/experts/domain_config.py +311 -311
- tapps_agents/experts/domain_detector.py +550 -550
- tapps_agents/experts/domain_utils.py +84 -84
- tapps_agents/experts/expert_config.py +113 -113
- tapps_agents/experts/expert_engine.py +465 -465
- tapps_agents/experts/expert_registry.py +744 -744
- tapps_agents/experts/expert_synthesizer.py +70 -70
- tapps_agents/experts/governance.py +197 -197
- tapps_agents/experts/history_logger.py +312 -312
- tapps_agents/experts/knowledge/README.md +180 -180
- tapps_agents/experts/knowledge/accessibility/accessible-forms.md +331 -331
- tapps_agents/experts/knowledge/accessibility/aria-patterns.md +344 -344
- tapps_agents/experts/knowledge/accessibility/color-contrast.md +285 -285
- tapps_agents/experts/knowledge/accessibility/keyboard-navigation.md +332 -332
- tapps_agents/experts/knowledge/accessibility/screen-readers.md +282 -282
- tapps_agents/experts/knowledge/accessibility/semantic-html.md +355 -355
- tapps_agents/experts/knowledge/accessibility/testing-accessibility.md +369 -369
- tapps_agents/experts/knowledge/accessibility/wcag-2.1.md +296 -296
- tapps_agents/experts/knowledge/accessibility/wcag-2.2.md +211 -211
- tapps_agents/experts/knowledge/agent-learning/best-practices.md +715 -715
- tapps_agents/experts/knowledge/agent-learning/pattern-extraction.md +282 -282
- tapps_agents/experts/knowledge/agent-learning/prompt-optimization.md +320 -320
- tapps_agents/experts/knowledge/ai-frameworks/model-optimization.md +90 -90
- tapps_agents/experts/knowledge/ai-frameworks/openvino-patterns.md +260 -260
- tapps_agents/experts/knowledge/api-design-integration/api-gateway-patterns.md +309 -309
- tapps_agents/experts/knowledge/api-design-integration/api-security-patterns.md +521 -521
- tapps_agents/experts/knowledge/api-design-integration/api-versioning.md +421 -421
- tapps_agents/experts/knowledge/api-design-integration/async-protocol-patterns.md +61 -61
- tapps_agents/experts/knowledge/api-design-integration/contract-testing.md +221 -221
- tapps_agents/experts/knowledge/api-design-integration/external-api-integration.md +489 -489
- tapps_agents/experts/knowledge/api-design-integration/fastapi-patterns.md +360 -360
- tapps_agents/experts/knowledge/api-design-integration/fastapi-testing.md +262 -262
- tapps_agents/experts/knowledge/api-design-integration/graphql-patterns.md +582 -582
- tapps_agents/experts/knowledge/api-design-integration/grpc-best-practices.md +499 -499
- tapps_agents/experts/knowledge/api-design-integration/mqtt-patterns.md +455 -455
- tapps_agents/experts/knowledge/api-design-integration/rate-limiting.md +507 -507
- tapps_agents/experts/knowledge/api-design-integration/restful-api-design.md +618 -618
- tapps_agents/experts/knowledge/api-design-integration/websocket-patterns.md +480 -480
- tapps_agents/experts/knowledge/cloud-infrastructure/cloud-native-patterns.md +175 -175
- tapps_agents/experts/knowledge/cloud-infrastructure/container-health-checks.md +261 -261
- tapps_agents/experts/knowledge/cloud-infrastructure/containerization.md +222 -222
- tapps_agents/experts/knowledge/cloud-infrastructure/cost-optimization.md +122 -122
- tapps_agents/experts/knowledge/cloud-infrastructure/disaster-recovery.md +153 -153
- tapps_agents/experts/knowledge/cloud-infrastructure/dockerfile-patterns.md +285 -285
- tapps_agents/experts/knowledge/cloud-infrastructure/infrastructure-as-code.md +187 -187
- tapps_agents/experts/knowledge/cloud-infrastructure/kubernetes-patterns.md +253 -253
- tapps_agents/experts/knowledge/cloud-infrastructure/multi-cloud-strategies.md +155 -155
- tapps_agents/experts/knowledge/cloud-infrastructure/serverless-architecture.md +200 -200
- tapps_agents/experts/knowledge/code-quality-analysis/README.md +16 -16
- tapps_agents/experts/knowledge/code-quality-analysis/code-metrics.md +137 -137
- tapps_agents/experts/knowledge/code-quality-analysis/complexity-analysis.md +181 -181
- tapps_agents/experts/knowledge/code-quality-analysis/technical-debt-patterns.md +191 -191
- tapps_agents/experts/knowledge/data-privacy-compliance/anonymization.md +313 -313
- tapps_agents/experts/knowledge/data-privacy-compliance/ccpa.md +255 -255
- tapps_agents/experts/knowledge/data-privacy-compliance/consent-management.md +282 -282
- tapps_agents/experts/knowledge/data-privacy-compliance/data-minimization.md +275 -275
- tapps_agents/experts/knowledge/data-privacy-compliance/data-retention.md +297 -297
- tapps_agents/experts/knowledge/data-privacy-compliance/data-subject-rights.md +383 -383
- tapps_agents/experts/knowledge/data-privacy-compliance/encryption-privacy.md +285 -285
- tapps_agents/experts/knowledge/data-privacy-compliance/gdpr.md +344 -344
- tapps_agents/experts/knowledge/data-privacy-compliance/hipaa.md +385 -385
- tapps_agents/experts/knowledge/data-privacy-compliance/privacy-by-design.md +280 -280
- tapps_agents/experts/knowledge/database-data-management/acid-vs-cap.md +164 -164
- tapps_agents/experts/knowledge/database-data-management/backup-and-recovery.md +182 -182
- tapps_agents/experts/knowledge/database-data-management/data-modeling.md +172 -172
- tapps_agents/experts/knowledge/database-data-management/database-design.md +187 -187
- tapps_agents/experts/knowledge/database-data-management/flux-query-optimization.md +342 -342
- tapps_agents/experts/knowledge/database-data-management/influxdb-connection-patterns.md +432 -432
- tapps_agents/experts/knowledge/database-data-management/influxdb-patterns.md +442 -442
- tapps_agents/experts/knowledge/database-data-management/migration-strategies.md +216 -216
- tapps_agents/experts/knowledge/database-data-management/nosql-patterns.md +259 -259
- tapps_agents/experts/knowledge/database-data-management/scalability-patterns.md +184 -184
- tapps_agents/experts/knowledge/database-data-management/sql-optimization.md +175 -175
- tapps_agents/experts/knowledge/database-data-management/time-series-modeling.md +444 -444
- tapps_agents/experts/knowledge/development-workflow/README.md +16 -16
- tapps_agents/experts/knowledge/development-workflow/automation-best-practices.md +216 -216
- tapps_agents/experts/knowledge/development-workflow/build-strategies.md +198 -198
- tapps_agents/experts/knowledge/development-workflow/deployment-patterns.md +205 -205
- tapps_agents/experts/knowledge/development-workflow/git-workflows.md +205 -205
- tapps_agents/experts/knowledge/documentation-knowledge-management/README.md +16 -16
- tapps_agents/experts/knowledge/documentation-knowledge-management/api-documentation-patterns.md +231 -231
- tapps_agents/experts/knowledge/documentation-knowledge-management/documentation-standards.md +191 -191
- tapps_agents/experts/knowledge/documentation-knowledge-management/knowledge-management.md +171 -171
- tapps_agents/experts/knowledge/documentation-knowledge-management/technical-writing-guide.md +192 -192
- tapps_agents/experts/knowledge/observability-monitoring/alerting-patterns.md +461 -461
- tapps_agents/experts/knowledge/observability-monitoring/apm-tools.md +459 -459
- tapps_agents/experts/knowledge/observability-monitoring/distributed-tracing.md +367 -367
- tapps_agents/experts/knowledge/observability-monitoring/logging-strategies.md +478 -478
- tapps_agents/experts/knowledge/observability-monitoring/metrics-and-monitoring.md +510 -510
- tapps_agents/experts/knowledge/observability-monitoring/observability-best-practices.md +492 -492
- tapps_agents/experts/knowledge/observability-monitoring/open-telemetry.md +573 -573
- tapps_agents/experts/knowledge/observability-monitoring/slo-sli-sla.md +419 -419
- tapps_agents/experts/knowledge/performance/anti-patterns.md +284 -284
- tapps_agents/experts/knowledge/performance/api-performance.md +256 -256
- tapps_agents/experts/knowledge/performance/caching.md +327 -327
- tapps_agents/experts/knowledge/performance/database-performance.md +252 -252
- tapps_agents/experts/knowledge/performance/optimization-patterns.md +327 -327
- tapps_agents/experts/knowledge/performance/profiling.md +297 -297
- tapps_agents/experts/knowledge/performance/resource-management.md +293 -293
- tapps_agents/experts/knowledge/performance/scalability.md +306 -306
- tapps_agents/experts/knowledge/security/owasp-top10.md +209 -209
- tapps_agents/experts/knowledge/security/secure-coding-practices.md +207 -207
- tapps_agents/experts/knowledge/security/threat-modeling.md +220 -220
- tapps_agents/experts/knowledge/security/vulnerability-patterns.md +342 -342
- tapps_agents/experts/knowledge/software-architecture/docker-compose-patterns.md +314 -314
- tapps_agents/experts/knowledge/software-architecture/microservices-patterns.md +379 -379
- tapps_agents/experts/knowledge/software-architecture/service-communication.md +316 -316
- tapps_agents/experts/knowledge/testing/best-practices.md +310 -310
- tapps_agents/experts/knowledge/testing/coverage-analysis.md +293 -293
- tapps_agents/experts/knowledge/testing/mocking.md +256 -256
- tapps_agents/experts/knowledge/testing/test-automation.md +276 -276
- tapps_agents/experts/knowledge/testing/test-data.md +271 -271
- tapps_agents/experts/knowledge/testing/test-design-patterns.md +280 -280
- tapps_agents/experts/knowledge/testing/test-maintenance.md +236 -236
- tapps_agents/experts/knowledge/testing/test-strategies.md +311 -311
- tapps_agents/experts/knowledge/user-experience/information-architecture.md +325 -325
- tapps_agents/experts/knowledge/user-experience/interaction-design.md +363 -363
- tapps_agents/experts/knowledge/user-experience/prototyping.md +293 -293
- tapps_agents/experts/knowledge/user-experience/usability-heuristics.md +337 -337
- tapps_agents/experts/knowledge/user-experience/usability-testing.md +311 -311
- tapps_agents/experts/knowledge/user-experience/user-journeys.md +296 -296
- tapps_agents/experts/knowledge/user-experience/user-research.md +373 -373
- tapps_agents/experts/knowledge/user-experience/ux-principles.md +340 -340
- tapps_agents/experts/knowledge_freshness.py +321 -321
- tapps_agents/experts/knowledge_ingestion.py +438 -438
- tapps_agents/experts/knowledge_need_detector.py +93 -93
- tapps_agents/experts/knowledge_validator.py +382 -382
- tapps_agents/experts/observability.py +440 -440
- tapps_agents/experts/passive_notifier.py +238 -238
- tapps_agents/experts/proactive_orchestrator.py +32 -32
- tapps_agents/experts/rag_chunker.py +205 -205
- tapps_agents/experts/rag_embedder.py +152 -152
- tapps_agents/experts/rag_evaluation.py +299 -299
- tapps_agents/experts/rag_index.py +303 -303
- tapps_agents/experts/rag_metrics.py +293 -293
- tapps_agents/experts/rag_safety.py +263 -263
- tapps_agents/experts/report_generator.py +296 -296
- tapps_agents/experts/setup_wizard.py +441 -441
- tapps_agents/experts/simple_rag.py +431 -431
- tapps_agents/experts/vector_rag.py +354 -354
- tapps_agents/experts/weight_distributor.py +304 -304
- tapps_agents/health/__init__.py +24 -24
- tapps_agents/health/base.py +75 -75
- tapps_agents/health/checks/__init__.py +22 -22
- tapps_agents/health/checks/automation.py +127 -127
- tapps_agents/health/checks/context7_cache.py +210 -210
- tapps_agents/health/checks/environment.py +116 -116
- tapps_agents/health/checks/execution.py +170 -170
- tapps_agents/health/checks/knowledge_base.py +187 -187
- tapps_agents/health/checks/outcomes.backup_20260204_064058.py +324 -0
- tapps_agents/health/checks/outcomes.backup_20260204_064256.py +324 -0
- tapps_agents/health/checks/outcomes.backup_20260204_064600.py +324 -0
- tapps_agents/health/checks/outcomes.py +324 -324
- tapps_agents/health/collector.py +280 -280
- tapps_agents/health/dashboard.py +137 -137
- tapps_agents/health/metrics.py +151 -151
- tapps_agents/health/registry.py +166 -166
- tapps_agents/hooks/__init__.py +33 -33
- tapps_agents/hooks/config.py +140 -140
- tapps_agents/hooks/events.py +135 -135
- tapps_agents/hooks/executor.py +128 -128
- tapps_agents/hooks/manager.py +143 -143
- tapps_agents/integration/__init__.py +8 -8
- tapps_agents/integration/service_integrator.py +121 -121
- tapps_agents/integrations/__init__.py +10 -10
- tapps_agents/integrations/clawdbot.py +525 -525
- tapps_agents/integrations/memory_bridge.py +356 -356
- tapps_agents/mcp/__init__.py +18 -18
- tapps_agents/mcp/gateway.py +112 -112
- tapps_agents/mcp/servers/__init__.py +13 -13
- tapps_agents/mcp/servers/analysis.py +204 -204
- tapps_agents/mcp/servers/context7.py +198 -198
- tapps_agents/mcp/servers/filesystem.py +218 -218
- tapps_agents/mcp/servers/git.py +201 -201
- tapps_agents/mcp/tool_registry.py +115 -115
- tapps_agents/quality/__init__.py +54 -54
- tapps_agents/quality/coverage_analyzer.py +379 -379
- tapps_agents/quality/enforcement.py +82 -82
- tapps_agents/quality/gates/__init__.py +37 -37
- tapps_agents/quality/gates/approval_gate.py +255 -255
- tapps_agents/quality/gates/base.py +84 -84
- tapps_agents/quality/gates/exceptions.py +43 -43
- tapps_agents/quality/gates/policy_gate.py +195 -195
- tapps_agents/quality/gates/registry.py +239 -239
- tapps_agents/quality/gates/security_gate.py +156 -156
- tapps_agents/quality/quality_gates.py +369 -369
- tapps_agents/quality/secret_scanner.py +335 -335
- tapps_agents/resources/__init__.py +5 -0
- tapps_agents/resources/claude/__init__.py +1 -0
- tapps_agents/resources/claude/commands/README.md +156 -0
- tapps_agents/resources/claude/commands/__init__.py +1 -0
- tapps_agents/resources/claude/commands/build-fix.md +22 -0
- tapps_agents/resources/claude/commands/build.md +77 -0
- tapps_agents/resources/claude/commands/debug.md +53 -0
- tapps_agents/resources/claude/commands/design.md +68 -0
- tapps_agents/resources/claude/commands/docs.md +53 -0
- tapps_agents/resources/claude/commands/e2e.md +22 -0
- tapps_agents/resources/claude/commands/fix.md +54 -0
- tapps_agents/resources/claude/commands/implement.md +53 -0
- tapps_agents/resources/claude/commands/improve.md +53 -0
- tapps_agents/resources/claude/commands/library-docs.md +64 -0
- tapps_agents/resources/claude/commands/lint.md +52 -0
- tapps_agents/resources/claude/commands/plan.md +65 -0
- tapps_agents/resources/claude/commands/refactor-clean.md +21 -0
- tapps_agents/resources/claude/commands/refactor.md +55 -0
- tapps_agents/resources/claude/commands/review.md +67 -0
- tapps_agents/resources/claude/commands/score.md +60 -0
- tapps_agents/resources/claude/commands/security-review.md +22 -0
- tapps_agents/resources/claude/commands/security-scan.md +54 -0
- tapps_agents/resources/claude/commands/tdd.md +24 -0
- tapps_agents/resources/claude/commands/test-coverage.md +21 -0
- tapps_agents/resources/claude/commands/test.md +54 -0
- tapps_agents/resources/claude/commands/update-codemaps.md +20 -0
- tapps_agents/resources/claude/commands/update-docs.md +21 -0
- tapps_agents/resources/claude/skills/__init__.py +1 -0
- tapps_agents/resources/claude/skills/analyst/SKILL.md +272 -0
- tapps_agents/resources/claude/skills/analyst/__init__.py +1 -0
- tapps_agents/resources/claude/skills/architect/SKILL.md +282 -0
- tapps_agents/resources/claude/skills/architect/__init__.py +1 -0
- tapps_agents/resources/claude/skills/backend-patterns/SKILL.md +30 -0
- tapps_agents/resources/claude/skills/backend-patterns/__init__.py +1 -0
- tapps_agents/resources/claude/skills/coding-standards/SKILL.md +29 -0
- tapps_agents/resources/claude/skills/coding-standards/__init__.py +1 -0
- tapps_agents/resources/claude/skills/debugger/SKILL.md +203 -0
- tapps_agents/resources/claude/skills/debugger/__init__.py +1 -0
- tapps_agents/resources/claude/skills/designer/SKILL.md +243 -0
- tapps_agents/resources/claude/skills/designer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/documenter/SKILL.md +252 -0
- tapps_agents/resources/claude/skills/documenter/__init__.py +1 -0
- tapps_agents/resources/claude/skills/enhancer/SKILL.md +307 -0
- tapps_agents/resources/claude/skills/enhancer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/evaluator/SKILL.md +204 -0
- tapps_agents/resources/claude/skills/evaluator/__init__.py +1 -0
- tapps_agents/resources/claude/skills/frontend-patterns/SKILL.md +29 -0
- tapps_agents/resources/claude/skills/frontend-patterns/__init__.py +1 -0
- tapps_agents/resources/claude/skills/implementer/SKILL.md +188 -0
- tapps_agents/resources/claude/skills/implementer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/improver/SKILL.md +218 -0
- tapps_agents/resources/claude/skills/improver/__init__.py +1 -0
- tapps_agents/resources/claude/skills/ops/SKILL.md +281 -0
- tapps_agents/resources/claude/skills/ops/__init__.py +1 -0
- tapps_agents/resources/claude/skills/orchestrator/SKILL.md +390 -0
- tapps_agents/resources/claude/skills/orchestrator/__init__.py +1 -0
- tapps_agents/resources/claude/skills/planner/SKILL.md +254 -0
- tapps_agents/resources/claude/skills/planner/__init__.py +1 -0
- tapps_agents/resources/claude/skills/reviewer/SKILL.md +434 -0
- tapps_agents/resources/claude/skills/reviewer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/security-review/SKILL.md +31 -0
- tapps_agents/resources/claude/skills/security-review/__init__.py +1 -0
- tapps_agents/resources/claude/skills/simple-mode/SKILL.md +695 -0
- tapps_agents/resources/claude/skills/simple-mode/__init__.py +1 -0
- tapps_agents/resources/claude/skills/tester/SKILL.md +219 -0
- tapps_agents/resources/claude/skills/tester/__init__.py +1 -0
- tapps_agents/resources/cursor/.cursorignore +35 -0
- tapps_agents/resources/cursor/__init__.py +1 -0
- tapps_agents/resources/cursor/commands/__init__.py +1 -0
- tapps_agents/resources/cursor/commands/build-fix.md +11 -0
- tapps_agents/resources/cursor/commands/build.md +11 -0
- tapps_agents/resources/cursor/commands/e2e.md +11 -0
- tapps_agents/resources/cursor/commands/fix.md +11 -0
- tapps_agents/resources/cursor/commands/refactor-clean.md +11 -0
- tapps_agents/resources/cursor/commands/review.md +11 -0
- tapps_agents/resources/cursor/commands/security-review.md +11 -0
- tapps_agents/resources/cursor/commands/tdd.md +11 -0
- tapps_agents/resources/cursor/commands/test-coverage.md +11 -0
- tapps_agents/resources/cursor/commands/test.md +11 -0
- tapps_agents/resources/cursor/commands/update-codemaps.md +10 -0
- tapps_agents/resources/cursor/commands/update-docs.md +11 -0
- tapps_agents/resources/cursor/rules/__init__.py +1 -0
- tapps_agents/resources/cursor/rules/agent-capabilities.mdc +687 -0
- tapps_agents/resources/cursor/rules/coding-style.mdc +31 -0
- tapps_agents/resources/cursor/rules/command-reference.mdc +2081 -0
- tapps_agents/resources/cursor/rules/cursor-mode-usage.mdc +125 -0
- tapps_agents/resources/cursor/rules/git-workflow.mdc +29 -0
- tapps_agents/resources/cursor/rules/performance.mdc +29 -0
- tapps_agents/resources/cursor/rules/project-context.mdc +163 -0
- tapps_agents/resources/cursor/rules/project-profiling.mdc +197 -0
- tapps_agents/resources/cursor/rules/quick-reference.mdc +630 -0
- tapps_agents/resources/cursor/rules/security.mdc +32 -0
- tapps_agents/resources/cursor/rules/simple-mode.mdc +500 -0
- tapps_agents/resources/cursor/rules/testing.mdc +31 -0
- tapps_agents/resources/cursor/rules/when-to-use.mdc +156 -0
- tapps_agents/resources/cursor/rules/workflow-presets.mdc +179 -0
- tapps_agents/resources/customizations/__init__.py +1 -0
- tapps_agents/resources/customizations/example-custom.yaml +83 -0
- tapps_agents/resources/hooks/__init__.py +1 -0
- tapps_agents/resources/hooks/templates/README.md +5 -0
- tapps_agents/resources/hooks/templates/__init__.py +1 -0
- tapps_agents/resources/hooks/templates/add-project-context.yaml +8 -0
- tapps_agents/resources/hooks/templates/auto-format-js.yaml +10 -0
- tapps_agents/resources/hooks/templates/auto-format-python.yaml +10 -0
- tapps_agents/resources/hooks/templates/git-commit-check.yaml +7 -0
- tapps_agents/resources/hooks/templates/notify-on-complete.yaml +8 -0
- tapps_agents/resources/hooks/templates/quality-gate.yaml +8 -0
- tapps_agents/resources/hooks/templates/security-scan-on-edit.yaml +10 -0
- tapps_agents/resources/hooks/templates/session-end-log.yaml +7 -0
- tapps_agents/resources/hooks/templates/show-beads-ready.yaml +8 -0
- tapps_agents/resources/hooks/templates/test-on-edit.yaml +10 -0
- tapps_agents/resources/hooks/templates/update-docs-on-complete.yaml +8 -0
- tapps_agents/resources/hooks/templates/user-prompt-log.yaml +7 -0
- tapps_agents/resources/scripts/__init__.py +1 -0
- tapps_agents/resources/scripts/set_bd_path.ps1 +51 -0
- tapps_agents/resources/workflows/__init__.py +1 -0
- tapps_agents/resources/workflows/presets/__init__.py +1 -0
- tapps_agents/resources/workflows/presets/brownfield-analysis.yaml +235 -0
- tapps_agents/resources/workflows/presets/fix.yaml +78 -0
- tapps_agents/resources/workflows/presets/full-sdlc.yaml +122 -0
- tapps_agents/resources/workflows/presets/quality.yaml +82 -0
- tapps_agents/resources/workflows/presets/rapid-dev.yaml +84 -0
- tapps_agents/session/__init__.py +19 -19
- tapps_agents/session/manager.py +256 -256
- tapps_agents/simple_mode/__init__.py +66 -66
- tapps_agents/simple_mode/agent_contracts.py +357 -357
- tapps_agents/simple_mode/beads_hooks.py +151 -151
- tapps_agents/simple_mode/code_snippet_handler.py +382 -382
- tapps_agents/simple_mode/documentation_manager.py +395 -395
- tapps_agents/simple_mode/documentation_reader.py +187 -187
- tapps_agents/simple_mode/file_inference.py +292 -292
- tapps_agents/simple_mode/framework_change_detector.py +268 -268
- tapps_agents/simple_mode/intent_parser.py +510 -510
- tapps_agents/simple_mode/learning_progression.py +358 -358
- tapps_agents/simple_mode/nl_handler.py +700 -700
- tapps_agents/simple_mode/onboarding.py +253 -253
- tapps_agents/simple_mode/orchestrators/__init__.py +38 -38
- tapps_agents/simple_mode/orchestrators/breakdown_orchestrator.py +49 -49
- tapps_agents/simple_mode/orchestrators/brownfield_orchestrator.py +135 -135
- tapps_agents/simple_mode/orchestrators/deliverable_checklist.py +349 -349
- tapps_agents/simple_mode/orchestrators/enhance_orchestrator.py +53 -53
- tapps_agents/simple_mode/orchestrators/epic_orchestrator.py +122 -122
- tapps_agents/simple_mode/orchestrators/explore_orchestrator.py +184 -184
- tapps_agents/simple_mode/orchestrators/plan_analysis_orchestrator.py +206 -206
- tapps_agents/simple_mode/orchestrators/pr_orchestrator.py +237 -237
- tapps_agents/simple_mode/orchestrators/refactor_orchestrator.py +222 -222
- tapps_agents/simple_mode/orchestrators/requirements_tracer.py +262 -262
- tapps_agents/simple_mode/orchestrators/resume_orchestrator.py +210 -210
- tapps_agents/simple_mode/orchestrators/review_orchestrator.py +161 -161
- tapps_agents/simple_mode/orchestrators/test_orchestrator.py +82 -82
- tapps_agents/simple_mode/output_aggregator.py +340 -340
- tapps_agents/simple_mode/result_formatters.py +598 -598
- tapps_agents/simple_mode/step_dependencies.py +382 -382
- tapps_agents/simple_mode/step_results.py +276 -276
- tapps_agents/simple_mode/streaming.py +388 -388
- tapps_agents/simple_mode/variations.py +129 -129
- tapps_agents/simple_mode/visual_feedback.py +238 -238
- tapps_agents/simple_mode/zero_config.py +274 -274
- tapps_agents/suggestions/__init__.py +8 -8
- tapps_agents/suggestions/inline_suggester.py +52 -52
- tapps_agents/templates/__init__.py +8 -8
- tapps_agents/templates/microservice_generator.py +274 -274
- tapps_agents/utils/env_validator.py +291 -291
- tapps_agents/workflow/__init__.py +171 -171
- tapps_agents/workflow/acceptance_verifier.py +132 -132
- tapps_agents/workflow/agent_handlers/__init__.py +41 -41
- tapps_agents/workflow/agent_handlers/analyst_handler.py +75 -75
- tapps_agents/workflow/agent_handlers/architect_handler.py +107 -107
- tapps_agents/workflow/agent_handlers/base.py +84 -84
- tapps_agents/workflow/agent_handlers/debugger_handler.py +100 -100
- tapps_agents/workflow/agent_handlers/designer_handler.py +110 -110
- tapps_agents/workflow/agent_handlers/documenter_handler.py +94 -94
- tapps_agents/workflow/agent_handlers/implementer_handler.py +235 -235
- tapps_agents/workflow/agent_handlers/ops_handler.py +62 -62
- tapps_agents/workflow/agent_handlers/orchestrator_handler.py +43 -43
- tapps_agents/workflow/agent_handlers/planner_handler.py +98 -98
- tapps_agents/workflow/agent_handlers/registry.py +119 -119
- tapps_agents/workflow/agent_handlers/reviewer_handler.py +119 -119
- tapps_agents/workflow/agent_handlers/tester_handler.py +69 -69
- tapps_agents/workflow/analytics_accessor.py +337 -337
- tapps_agents/workflow/analytics_alerts.py +416 -416
- tapps_agents/workflow/analytics_dashboard_cursor.py +281 -281
- tapps_agents/workflow/analytics_dual_write.py +103 -103
- tapps_agents/workflow/analytics_integration.py +119 -119
- tapps_agents/workflow/analytics_query_parser.py +278 -278
- tapps_agents/workflow/analytics_visualizer.py +259 -259
- tapps_agents/workflow/artifact_helper.py +204 -204
- tapps_agents/workflow/audit_logger.py +263 -263
- tapps_agents/workflow/auto_execution_config.py +340 -340
- tapps_agents/workflow/auto_progression.py +586 -586
- tapps_agents/workflow/branch_cleanup.py +349 -349
- tapps_agents/workflow/checkpoint.py +256 -256
- tapps_agents/workflow/checkpoint_manager.py +178 -178
- tapps_agents/workflow/code_artifact.py +179 -179
- tapps_agents/workflow/common_enums.py +96 -96
- tapps_agents/workflow/confirmation_handler.py +130 -130
- tapps_agents/workflow/context_analyzer.py +222 -222
- tapps_agents/workflow/context_artifact.py +230 -230
- tapps_agents/workflow/cursor_chat.py +94 -94
- tapps_agents/workflow/cursor_skill_helper.py +516 -516
- tapps_agents/workflow/dependency_resolver.py +244 -244
- tapps_agents/workflow/design_artifact.py +156 -156
- tapps_agents/workflow/detector.py +751 -751
- tapps_agents/workflow/direct_execution_fallback.py +301 -301
- tapps_agents/workflow/docs_artifact.py +168 -168
- tapps_agents/workflow/enforcer.py +389 -389
- tapps_agents/workflow/enhancement_artifact.py +142 -142
- tapps_agents/workflow/error_recovery.py +806 -806
- tapps_agents/workflow/event_bus.py +183 -183
- tapps_agents/workflow/event_log.py +612 -612
- tapps_agents/workflow/events.py +63 -63
- tapps_agents/workflow/exceptions.py +43 -43
- tapps_agents/workflow/execution_graph.py +498 -498
- tapps_agents/workflow/execution_plan.py +126 -126
- tapps_agents/workflow/file_utils.py +186 -186
- tapps_agents/workflow/gate_evaluator.py +182 -182
- tapps_agents/workflow/gate_integration.py +200 -200
- tapps_agents/workflow/graph_visualizer.py +130 -130
- tapps_agents/workflow/health_checker.py +206 -206
- tapps_agents/workflow/logging_helper.py +243 -243
- tapps_agents/workflow/manifest.py +582 -582
- tapps_agents/workflow/marker_writer.py +250 -250
- tapps_agents/workflow/messaging.py +325 -325
- tapps_agents/workflow/metadata_models.py +91 -91
- tapps_agents/workflow/metrics_integration.py +226 -226
- tapps_agents/workflow/migration_utils.py +116 -116
- tapps_agents/workflow/models.py +148 -148
- tapps_agents/workflow/nlp_config.py +198 -198
- tapps_agents/workflow/nlp_error_handler.py +207 -207
- tapps_agents/workflow/nlp_executor.py +163 -163
- tapps_agents/workflow/nlp_parser.py +528 -528
- tapps_agents/workflow/observability_dashboard.py +451 -451
- tapps_agents/workflow/observer.py +170 -170
- tapps_agents/workflow/ops_artifact.py +257 -257
- tapps_agents/workflow/output_passing.py +214 -214
- tapps_agents/workflow/parallel_executor.py +463 -463
- tapps_agents/workflow/planning_artifact.py +179 -179
- tapps_agents/workflow/preset_loader.py +285 -285
- tapps_agents/workflow/preset_recommender.py +270 -270
- tapps_agents/workflow/progress_logger.py +145 -145
- tapps_agents/workflow/progress_manager.py +303 -303
- tapps_agents/workflow/progress_monitor.py +186 -186
- tapps_agents/workflow/progress_updates.py +423 -423
- tapps_agents/workflow/quality_artifact.py +158 -158
- tapps_agents/workflow/quality_loopback.py +101 -101
- tapps_agents/workflow/recommender.py +387 -387
- tapps_agents/workflow/remediation_loop.py +166 -166
- tapps_agents/workflow/result_aggregator.py +300 -300
- tapps_agents/workflow/review_artifact.py +185 -185
- tapps_agents/workflow/schema_validator.py +522 -522
- tapps_agents/workflow/session_handoff.py +178 -178
- tapps_agents/workflow/skill_invoker.py +648 -648
- tapps_agents/workflow/state_manager.py +756 -756
- tapps_agents/workflow/state_persistence_config.py +331 -331
- tapps_agents/workflow/status_monitor.py +449 -449
- tapps_agents/workflow/step_checkpoint.py +314 -314
- tapps_agents/workflow/step_details.py +201 -201
- tapps_agents/workflow/story_models.py +147 -147
- tapps_agents/workflow/streaming.py +416 -416
- tapps_agents/workflow/suggestion_engine.py +552 -552
- tapps_agents/workflow/testing_artifact.py +186 -186
- tapps_agents/workflow/timeline.py +158 -158
- tapps_agents/workflow/token_integration.py +209 -209
- tapps_agents/workflow/validation.py +217 -217
- tapps_agents/workflow/visual_feedback.py +391 -391
- tapps_agents/workflow/workflow_chain.py +95 -95
- tapps_agents/workflow/workflow_summary.py +219 -219
- tapps_agents/workflow/worktree_manager.py +724 -724
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/METADATA +672 -672
- tapps_agents-3.6.1.dist-info/RECORD +883 -0
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/licenses/LICENSE +22 -22
- tapps_agents-3.6.0.dist-info/RECORD +0 -758
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/WHEEL +0 -0
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/top_level.txt +0 -0
|
@@ -1,600 +1,600 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Tech Stack Template Merging Module
|
|
3
|
-
|
|
4
|
-
Merges stack-specific templates with default configuration, handling
|
|
5
|
-
deep merging, variable expansion, conditional blocks, and user overrides.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import json
|
|
9
|
-
import logging
|
|
10
|
-
import re
|
|
11
|
-
from dataclasses import dataclass, field
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import Any
|
|
14
|
-
|
|
15
|
-
import yaml
|
|
16
|
-
|
|
17
|
-
logger = logging.getLogger(__name__)
|
|
18
|
-
|
|
19
|
-
# Variable pattern: {{variable.name}} or {{variable.nested.name}}
|
|
20
|
-
VARIABLE_PATTERN = re.compile(r"\{\{([a-zA-Z0-9_.]+)\}\}")
|
|
21
|
-
|
|
22
|
-
# Conditional block patterns: {{#if var}}...{{/if}} and {{#if var}}...{{#else}}...{{/if}}
|
|
23
|
-
CONDITIONAL_IF_PATTERN = re.compile(r"\{\{#if\s+([a-zA-Z0-9_.]+)\}\}")
|
|
24
|
-
CONDITIONAL_ELSE_PATTERN = re.compile(r"\{\{#else\}\}")
|
|
25
|
-
CONDITIONAL_ENDIF_PATTERN = re.compile(r"\{\{/if\}\}")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclass
|
|
29
|
-
class ConditionalTrace:
|
|
30
|
-
"""Trace information for conditional block evaluation."""
|
|
31
|
-
|
|
32
|
-
condition: str
|
|
33
|
-
variable_path: str
|
|
34
|
-
variable_value: Any
|
|
35
|
-
evaluated: bool
|
|
36
|
-
reason: str
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@dataclass
|
|
40
|
-
class TemplateTrace:
|
|
41
|
-
"""Trace information for template rendering."""
|
|
42
|
-
|
|
43
|
-
template_path: str | None = None
|
|
44
|
-
variables_used: dict[str, Any] = field(default_factory=dict)
|
|
45
|
-
conditionals_evaluated: list[ConditionalTrace] = field(default_factory=list)
|
|
46
|
-
variable_expansions: dict[str, str] = field(default_factory=dict)
|
|
47
|
-
|
|
48
|
-
def to_dict(self) -> dict[str, Any]:
|
|
49
|
-
"""Convert trace to dictionary for JSON serialization."""
|
|
50
|
-
return {
|
|
51
|
-
"template_path": self.template_path,
|
|
52
|
-
"variables_used": self.variables_used,
|
|
53
|
-
"conditionals_evaluated": [
|
|
54
|
-
{
|
|
55
|
-
"condition": c.condition,
|
|
56
|
-
"variable_path": c.variable_path,
|
|
57
|
-
"variable_value": str(c.variable_value),
|
|
58
|
-
"evaluated": c.evaluated,
|
|
59
|
-
"reason": c.reason,
|
|
60
|
-
}
|
|
61
|
-
for c in self.conditionals_evaluated
|
|
62
|
-
],
|
|
63
|
-
"variable_expansions": self.variable_expansions,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
def to_json(self) -> str:
|
|
67
|
-
"""Convert trace to JSON string."""
|
|
68
|
-
return json.dumps(self.to_dict(), indent=2)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def deep_merge_dict(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
|
|
72
|
-
"""
|
|
73
|
-
Deep merge two dictionaries, with override taking precedence for conflicts.
|
|
74
|
-
|
|
75
|
-
For nested dictionaries, recursively merges. For lists, override replaces base.
|
|
76
|
-
For scalar values, override replaces base.
|
|
77
|
-
|
|
78
|
-
Args:
|
|
79
|
-
base: Base dictionary (defaults)
|
|
80
|
-
override: Override dictionary (template values)
|
|
81
|
-
|
|
82
|
-
Returns:
|
|
83
|
-
Merged dictionary
|
|
84
|
-
|
|
85
|
-
Examples:
|
|
86
|
-
>>> base = {"a": 1, "b": {"c": 2}}
|
|
87
|
-
>>> override = {"b": {"d": 3}, "e": 4}
|
|
88
|
-
>>> deep_merge_dict(base, override)
|
|
89
|
-
{'a': 1, 'b': {'c': 2, 'd': 3}, 'e': 4}
|
|
90
|
-
"""
|
|
91
|
-
result = base.copy()
|
|
92
|
-
|
|
93
|
-
for key, value in override.items():
|
|
94
|
-
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
|
95
|
-
# Recursively merge nested dictionaries
|
|
96
|
-
result[key] = deep_merge_dict(result[key], value)
|
|
97
|
-
else:
|
|
98
|
-
# Override replaces base (for scalars, lists, and non-dict types)
|
|
99
|
-
result[key] = value
|
|
100
|
-
|
|
101
|
-
return result
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def expand_variables(
|
|
105
|
-
value: Any,
|
|
106
|
-
variables: dict[str, Any],
|
|
107
|
-
context: dict[str, Any] | None = None,
|
|
108
|
-
trace: TemplateTrace | None = None,
|
|
109
|
-
) -> Any:
|
|
110
|
-
"""
|
|
111
|
-
Expand template variables in a value.
|
|
112
|
-
|
|
113
|
-
Supports variable expansion in strings and nested structures.
|
|
114
|
-
Variables use {{variable.name}} syntax.
|
|
115
|
-
|
|
116
|
-
Args:
|
|
117
|
-
value: Value that may contain variables
|
|
118
|
-
variables: Dictionary of variable values
|
|
119
|
-
context: Additional context for variable resolution (optional)
|
|
120
|
-
trace: Optional trace object to record expansions (optional)
|
|
121
|
-
|
|
122
|
-
Returns:
|
|
123
|
-
Value with variables expanded
|
|
124
|
-
|
|
125
|
-
Examples:
|
|
126
|
-
>>> expand_variables("Hello {{name}}", {"name": "World"})
|
|
127
|
-
'Hello World'
|
|
128
|
-
>>> expand_variables({"path": "{{project.root}}/src"}, {"project": {"root": "/app"}})
|
|
129
|
-
{'path': '/app/src'}
|
|
130
|
-
"""
|
|
131
|
-
if context is None:
|
|
132
|
-
context = {}
|
|
133
|
-
|
|
134
|
-
# Combine variables and context
|
|
135
|
-
all_vars = {**variables, **context}
|
|
136
|
-
|
|
137
|
-
if isinstance(value, str):
|
|
138
|
-
# Expand variables in string
|
|
139
|
-
def replace_var(match):
|
|
140
|
-
var_path = match.group(1)
|
|
141
|
-
resolved = _resolve_variable(var_path, all_vars)
|
|
142
|
-
if trace and var_path not in trace.variable_expansions:
|
|
143
|
-
trace.variable_expansions[var_path] = resolved
|
|
144
|
-
return resolved
|
|
145
|
-
|
|
146
|
-
return VARIABLE_PATTERN.sub(replace_var, value)
|
|
147
|
-
|
|
148
|
-
elif isinstance(value, dict):
|
|
149
|
-
# Recursively expand variables in dictionary
|
|
150
|
-
return {k: expand_variables(v, variables, context, trace) for k, v in value.items()}
|
|
151
|
-
|
|
152
|
-
elif isinstance(value, list):
|
|
153
|
-
# Recursively expand variables in list
|
|
154
|
-
return [expand_variables(item, variables, context, trace) for item in value]
|
|
155
|
-
|
|
156
|
-
else:
|
|
157
|
-
# Scalar value, return as-is
|
|
158
|
-
return value
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def _resolve_variable(var_path: str, variables: dict[str, Any]) -> str:
|
|
162
|
-
"""
|
|
163
|
-
Resolve a variable path (e.g., "project.name") from variables dictionary.
|
|
164
|
-
|
|
165
|
-
Args:
|
|
166
|
-
var_path: Dot-separated variable path
|
|
167
|
-
variables: Dictionary of variables
|
|
168
|
-
|
|
169
|
-
Returns:
|
|
170
|
-
Resolved value as string, or original {{var_path}} if not found
|
|
171
|
-
"""
|
|
172
|
-
parts = var_path.split(".")
|
|
173
|
-
current = variables
|
|
174
|
-
|
|
175
|
-
try:
|
|
176
|
-
for part in parts:
|
|
177
|
-
if isinstance(current, dict):
|
|
178
|
-
current = current.get(part)
|
|
179
|
-
if current is None:
|
|
180
|
-
# Variable not found, return original
|
|
181
|
-
return f"{{{{{var_path}}}}}"
|
|
182
|
-
else:
|
|
183
|
-
# Can't traverse further
|
|
184
|
-
return f"{{{{{var_path}}}}}"
|
|
185
|
-
|
|
186
|
-
# Convert to string
|
|
187
|
-
if current is None:
|
|
188
|
-
return f"{{{{{var_path}}}}}"
|
|
189
|
-
|
|
190
|
-
return str(current)
|
|
191
|
-
|
|
192
|
-
except (AttributeError, TypeError):
|
|
193
|
-
# Error during traversal, return original
|
|
194
|
-
return f"{{{{{var_path}}}}}"
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def _resolve_variable_value(var_path: str, variables: dict[str, Any]) -> Any:
|
|
198
|
-
"""
|
|
199
|
-
Resolve a variable path and return the actual value (not string).
|
|
200
|
-
|
|
201
|
-
Args:
|
|
202
|
-
var_path: Dot-separated variable path
|
|
203
|
-
variables: Dictionary of variables
|
|
204
|
-
|
|
205
|
-
Returns:
|
|
206
|
-
Resolved value (any type) or None if not found
|
|
207
|
-
"""
|
|
208
|
-
parts = var_path.split(".")
|
|
209
|
-
current = variables
|
|
210
|
-
|
|
211
|
-
try:
|
|
212
|
-
for part in parts:
|
|
213
|
-
if isinstance(current, dict):
|
|
214
|
-
current = current.get(part)
|
|
215
|
-
if current is None:
|
|
216
|
-
return None
|
|
217
|
-
else:
|
|
218
|
-
return None
|
|
219
|
-
|
|
220
|
-
return current
|
|
221
|
-
|
|
222
|
-
except (AttributeError, TypeError):
|
|
223
|
-
return None
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
def _evaluate_condition(var_path: str, variables: dict[str, Any]) -> tuple[bool, Any, str]:
|
|
227
|
-
"""
|
|
228
|
-
Safely evaluate a conditional variable.
|
|
229
|
-
|
|
230
|
-
Safe evaluation rules:
|
|
231
|
-
- Variable must exist in allowlisted variables
|
|
232
|
-
- Only checks presence/truthiness (no arbitrary expressions)
|
|
233
|
-
- Missing variables evaluate to False
|
|
234
|
-
|
|
235
|
-
Args:
|
|
236
|
-
var_path: Variable path to evaluate
|
|
237
|
-
variables: Dictionary of variables
|
|
238
|
-
|
|
239
|
-
Returns:
|
|
240
|
-
Tuple of (evaluated, value, reason) where:
|
|
241
|
-
- evaluated: Boolean result
|
|
242
|
-
- value: Variable value (for trace)
|
|
243
|
-
- reason: Human-readable reason
|
|
244
|
-
"""
|
|
245
|
-
value = _resolve_variable_value(var_path, variables)
|
|
246
|
-
|
|
247
|
-
if value is None:
|
|
248
|
-
return (False, None, f"Variable '{var_path}' not found - evaluating to False")
|
|
249
|
-
|
|
250
|
-
# Safe truthiness check (no arbitrary code execution)
|
|
251
|
-
if isinstance(value, bool):
|
|
252
|
-
evaluated = value
|
|
253
|
-
reason = f"Variable '{var_path}' is boolean: {value}"
|
|
254
|
-
elif isinstance(value, (str, list, dict)):
|
|
255
|
-
evaluated = bool(value) # Non-empty string/list/dict is truthy
|
|
256
|
-
reason = f"Variable '{var_path}' is {'non-empty' if value else 'empty'}"
|
|
257
|
-
elif isinstance(value, (int, float)):
|
|
258
|
-
evaluated = value != 0
|
|
259
|
-
reason = f"Variable '{var_path}' is numeric: {value} (non-zero is truthy)"
|
|
260
|
-
else:
|
|
261
|
-
evaluated = bool(value)
|
|
262
|
-
reason = f"Variable '{var_path}' evaluated to {evaluated}"
|
|
263
|
-
|
|
264
|
-
return (evaluated, value, reason)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def _process_conditional_blocks(
|
|
268
|
-
content: str,
|
|
269
|
-
variables: dict[str, Any],
|
|
270
|
-
trace: TemplateTrace | None = None,
|
|
271
|
-
) -> str:
|
|
272
|
-
"""
|
|
273
|
-
Process conditional blocks in YAML content string.
|
|
274
|
-
|
|
275
|
-
Supports syntax:
|
|
276
|
-
- {{#if variable.path}}...{{/if}}
|
|
277
|
-
- {{#if variable.path}}...{{#else}}...{{/if}}
|
|
278
|
-
|
|
279
|
-
Args:
|
|
280
|
-
content: YAML content string with conditional blocks
|
|
281
|
-
variables: Variables for conditional evaluation
|
|
282
|
-
trace: Optional trace object to record evaluations
|
|
283
|
-
|
|
284
|
-
Returns:
|
|
285
|
-
Content with conditionals processed
|
|
286
|
-
"""
|
|
287
|
-
result = []
|
|
288
|
-
i = 0
|
|
289
|
-
|
|
290
|
-
while i < len(content):
|
|
291
|
-
# Look for {{#if ...}}
|
|
292
|
-
if_match = CONDITIONAL_IF_PATTERN.search(content, i)
|
|
293
|
-
if not if_match:
|
|
294
|
-
# No more conditionals, append rest of content
|
|
295
|
-
result.append(content[i:])
|
|
296
|
-
break
|
|
297
|
-
|
|
298
|
-
# Append content before conditional
|
|
299
|
-
result.append(content[i : if_match.start()])
|
|
300
|
-
|
|
301
|
-
# Extract variable path from {{#if var.path}}
|
|
302
|
-
var_path = if_match.group(1)
|
|
303
|
-
|
|
304
|
-
# Find matching {{/if}}
|
|
305
|
-
endif_pos = if_match.end()
|
|
306
|
-
depth = 1
|
|
307
|
-
else_pos = None
|
|
308
|
-
endif_match = None
|
|
309
|
-
|
|
310
|
-
while endif_pos < len(content) and depth > 0:
|
|
311
|
-
# Check for {{#else}}
|
|
312
|
-
else_match = CONDITIONAL_ELSE_PATTERN.search(content, endif_pos)
|
|
313
|
-
if else_match and depth == 1 and else_pos is None:
|
|
314
|
-
else_pos = else_match.start()
|
|
315
|
-
endif_pos = else_match.end()
|
|
316
|
-
continue
|
|
317
|
-
|
|
318
|
-
# Check for {{/if}}
|
|
319
|
-
endif_match = CONDITIONAL_ENDIF_PATTERN.search(content, endif_pos)
|
|
320
|
-
if endif_match:
|
|
321
|
-
if depth == 1:
|
|
322
|
-
# Found matching endif - break and process
|
|
323
|
-
break
|
|
324
|
-
else:
|
|
325
|
-
# Nested conditional (not supported, but handle gracefully)
|
|
326
|
-
depth -= 1
|
|
327
|
-
endif_pos = endif_match.end()
|
|
328
|
-
continue
|
|
329
|
-
|
|
330
|
-
# Check for nested {{#if}}
|
|
331
|
-
nested_if = CONDITIONAL_IF_PATTERN.search(content, endif_pos)
|
|
332
|
-
if nested_if:
|
|
333
|
-
depth += 1
|
|
334
|
-
endif_pos = nested_if.end()
|
|
335
|
-
continue
|
|
336
|
-
|
|
337
|
-
# No match found, break
|
|
338
|
-
break
|
|
339
|
-
|
|
340
|
-
# Check if we successfully found matching endif
|
|
341
|
-
if endif_match is None or depth != 1:
|
|
342
|
-
# No matching {{/if}} found, treat as literal text
|
|
343
|
-
result.append(content[if_match.start() : if_match.end()])
|
|
344
|
-
i = if_match.end()
|
|
345
|
-
continue
|
|
346
|
-
|
|
347
|
-
# Extract true and false branches
|
|
348
|
-
if else_pos is not None:
|
|
349
|
-
true_branch = content[if_match.end() : else_pos]
|
|
350
|
-
# Find the else pattern again to get its end position
|
|
351
|
-
else_match = CONDITIONAL_ELSE_PATTERN.search(content, else_pos)
|
|
352
|
-
if else_match is None:
|
|
353
|
-
# Should not happen if logic is correct, but handle defensively
|
|
354
|
-
true_branch = content[if_match.end() : endif_match.start()]
|
|
355
|
-
false_branch = ""
|
|
356
|
-
else:
|
|
357
|
-
false_branch = content[else_match.end() : endif_match.start()]
|
|
358
|
-
else:
|
|
359
|
-
true_branch = content[if_match.end() : endif_match.start()]
|
|
360
|
-
false_branch = ""
|
|
361
|
-
|
|
362
|
-
# Evaluate condition
|
|
363
|
-
evaluated, value, reason = _evaluate_condition(var_path, variables)
|
|
364
|
-
|
|
365
|
-
# Record in trace if provided
|
|
366
|
-
if trace:
|
|
367
|
-
trace.conditionals_evaluated.append(
|
|
368
|
-
ConditionalTrace(
|
|
369
|
-
condition=f"{{{{#if {var_path}}}}}",
|
|
370
|
-
variable_path=var_path,
|
|
371
|
-
variable_value=value,
|
|
372
|
-
evaluated=evaluated,
|
|
373
|
-
reason=reason,
|
|
374
|
-
)
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
# Append appropriate branch
|
|
378
|
-
if evaluated:
|
|
379
|
-
result.append(true_branch)
|
|
380
|
-
else:
|
|
381
|
-
result.append(false_branch)
|
|
382
|
-
|
|
383
|
-
i = endif_match.end()
|
|
384
|
-
|
|
385
|
-
return "".join(result)
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
def load_template(
|
|
389
|
-
template_path: Path,
|
|
390
|
-
variables: dict[str, Any] | None = None,
|
|
391
|
-
trace: TemplateTrace | None = None,
|
|
392
|
-
) -> dict[str, Any]:
|
|
393
|
-
"""
|
|
394
|
-
Load a template YAML file and process conditional blocks.
|
|
395
|
-
|
|
396
|
-
Args:
|
|
397
|
-
template_path: Path to template YAML file
|
|
398
|
-
variables: Variables for conditional evaluation (optional)
|
|
399
|
-
trace: Optional trace object to record processing (optional)
|
|
400
|
-
|
|
401
|
-
Returns:
|
|
402
|
-
Template dictionary with conditionals processed
|
|
403
|
-
|
|
404
|
-
Raises:
|
|
405
|
-
FileNotFoundError: If template file doesn't exist
|
|
406
|
-
yaml.YAMLError: If template is invalid YAML
|
|
407
|
-
"""
|
|
408
|
-
if not template_path.exists():
|
|
409
|
-
raise FileNotFoundError(f"Template file not found: {template_path}")
|
|
410
|
-
|
|
411
|
-
try:
|
|
412
|
-
content = template_path.read_text(encoding="utf-8")
|
|
413
|
-
|
|
414
|
-
# Process conditional blocks if variables provided
|
|
415
|
-
if variables:
|
|
416
|
-
content = _process_conditional_blocks(content, variables, trace)
|
|
417
|
-
if trace:
|
|
418
|
-
trace.template_path = str(template_path)
|
|
419
|
-
trace.variables_used = variables.copy()
|
|
420
|
-
|
|
421
|
-
template = yaml.safe_load(content)
|
|
422
|
-
if template is None:
|
|
423
|
-
return {}
|
|
424
|
-
return template
|
|
425
|
-
except yaml.YAMLError as e:
|
|
426
|
-
raise yaml.YAMLError(f"Invalid YAML in template {template_path}: {e}") from e
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
def merge_template_with_config(
|
|
430
|
-
template: dict[str, Any],
|
|
431
|
-
default_config: dict[str, Any],
|
|
432
|
-
user_config: dict[str, Any] | None = None,
|
|
433
|
-
variables: dict[str, Any] | None = None,
|
|
434
|
-
trace: TemplateTrace | None = None,
|
|
435
|
-
) -> dict[str, Any]:
|
|
436
|
-
"""
|
|
437
|
-
Merge template with default config and user overrides.
|
|
438
|
-
|
|
439
|
-
Merge order (precedence from lowest to highest):
|
|
440
|
-
1. Default config (base)
|
|
441
|
-
2. Template values (override defaults)
|
|
442
|
-
3. User config (override template and defaults)
|
|
443
|
-
|
|
444
|
-
Variables are expanded in template before merging.
|
|
445
|
-
Conditional blocks are processed during template loading.
|
|
446
|
-
|
|
447
|
-
Args:
|
|
448
|
-
template: Template dictionary (conditionals already processed)
|
|
449
|
-
default_config: Default configuration dictionary
|
|
450
|
-
user_config: User override configuration (optional)
|
|
451
|
-
variables: Variables for template expansion (optional)
|
|
452
|
-
trace: Optional trace object to record processing (optional)
|
|
453
|
-
|
|
454
|
-
Returns:
|
|
455
|
-
Merged configuration dictionary
|
|
456
|
-
|
|
457
|
-
Examples:
|
|
458
|
-
>>> template = {"agent_config": {"reviewer": {"quality_threshold": 75.0}}}
|
|
459
|
-
>>> default = {"agent_config": {"reviewer": {"quality_threshold": 70.0}}}
|
|
460
|
-
>>> merge_template_with_config(template, default)
|
|
461
|
-
{'agent_config': {'reviewer': {'quality_threshold': 75.0}}}
|
|
462
|
-
"""
|
|
463
|
-
# Expand variables in template if variables provided
|
|
464
|
-
if variables:
|
|
465
|
-
template = expand_variables(template, variables, trace=trace)
|
|
466
|
-
if trace:
|
|
467
|
-
# Record variable expansions
|
|
468
|
-
for key, value in template.items():
|
|
469
|
-
if isinstance(value, str) and "{{" in value:
|
|
470
|
-
trace.variable_expansions[key] = value
|
|
471
|
-
|
|
472
|
-
# Merge order: default -> template -> user
|
|
473
|
-
merged = deep_merge_dict(default_config, template)
|
|
474
|
-
|
|
475
|
-
if user_config:
|
|
476
|
-
merged = deep_merge_dict(merged, user_config)
|
|
477
|
-
|
|
478
|
-
return merged
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
def build_template_variables(
|
|
482
|
-
project_root: Path,
|
|
483
|
-
tech_stack: dict[str, Any] | None = None,
|
|
484
|
-
project_name: str | None = None,
|
|
485
|
-
) -> dict[str, Any]:
|
|
486
|
-
"""
|
|
487
|
-
Build variables dictionary for template expansion.
|
|
488
|
-
|
|
489
|
-
Args:
|
|
490
|
-
project_root: Project root directory
|
|
491
|
-
tech_stack: Detected tech stack (optional)
|
|
492
|
-
project_name: Project name (optional)
|
|
493
|
-
|
|
494
|
-
Returns:
|
|
495
|
-
Variables dictionary for template expansion
|
|
496
|
-
"""
|
|
497
|
-
variables: dict[str, Any] = {
|
|
498
|
-
"project": {
|
|
499
|
-
"root": str(project_root),
|
|
500
|
-
"name": project_name or project_root.name,
|
|
501
|
-
},
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if tech_stack:
|
|
505
|
-
variables["tech_stack"] = {
|
|
506
|
-
"frameworks": tech_stack.get("frameworks", []),
|
|
507
|
-
"languages": tech_stack.get("languages", []),
|
|
508
|
-
"libraries": tech_stack.get("libraries", []),
|
|
509
|
-
"package_managers": tech_stack.get("package_managers", []),
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
return variables
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
def apply_template_to_config(
|
|
516
|
-
template_path: Path | None,
|
|
517
|
-
default_config: dict[str, Any],
|
|
518
|
-
user_config: dict[str, Any] | None = None,
|
|
519
|
-
project_root: Path | None = None,
|
|
520
|
-
tech_stack: dict[str, Any] | None = None,
|
|
521
|
-
project_name: str | None = None,
|
|
522
|
-
enable_trace: bool = False,
|
|
523
|
-
trace_output_path: Path | None = None,
|
|
524
|
-
) -> tuple[dict[str, Any], TemplateTrace | None]:
|
|
525
|
-
"""
|
|
526
|
-
Apply a template to configuration (main entry point).
|
|
527
|
-
|
|
528
|
-
This function:
|
|
529
|
-
1. Loads the template (if provided)
|
|
530
|
-
2. Builds template variables
|
|
531
|
-
3. Processes conditional blocks in template
|
|
532
|
-
4. Expands variables in template
|
|
533
|
-
5. Merges template with defaults and user config
|
|
534
|
-
6. Optionally generates trace output
|
|
535
|
-
|
|
536
|
-
Args:
|
|
537
|
-
template_path: Path to template file (None = no template)
|
|
538
|
-
default_config: Default configuration
|
|
539
|
-
user_config: User override configuration (optional)
|
|
540
|
-
project_root: Project root directory (optional)
|
|
541
|
-
tech_stack: Detected tech stack (optional)
|
|
542
|
-
project_name: Project name (optional)
|
|
543
|
-
enable_trace: Whether to generate trace output (default: False)
|
|
544
|
-
trace_output_path: Path to save trace JSON file (optional)
|
|
545
|
-
|
|
546
|
-
Returns:
|
|
547
|
-
Tuple of (merged_config, trace) where:
|
|
548
|
-
- merged_config: Merged configuration dictionary
|
|
549
|
-
- trace: TemplateTrace object (None if tracing disabled)
|
|
550
|
-
|
|
551
|
-
Examples:
|
|
552
|
-
>>> default = {"agent_config": {"reviewer": {"quality_threshold": 70.0}}}
|
|
553
|
-
>>> template_path = Path("templates/tech_stacks/fastapi.yaml")
|
|
554
|
-
>>> config, trace = apply_template_to_config(template_path, default)
|
|
555
|
-
# Returns config with FastAPI-specific overrides and trace info
|
|
556
|
-
"""
|
|
557
|
-
trace = TemplateTrace() if enable_trace else None
|
|
558
|
-
|
|
559
|
-
# If no template, just merge defaults with user config
|
|
560
|
-
if template_path is None or not template_path.exists():
|
|
561
|
-
if user_config:
|
|
562
|
-
return (deep_merge_dict(default_config, user_config), trace)
|
|
563
|
-
return (default_config.copy(), trace)
|
|
564
|
-
|
|
565
|
-
# Build variables for expansion (needed for conditionals)
|
|
566
|
-
if project_root is None:
|
|
567
|
-
project_root = Path.cwd()
|
|
568
|
-
|
|
569
|
-
variables = build_template_variables(project_root, tech_stack, project_name)
|
|
570
|
-
|
|
571
|
-
# Load template with conditional processing
|
|
572
|
-
try:
|
|
573
|
-
template = load_template(template_path, variables, trace)
|
|
574
|
-
except (FileNotFoundError, yaml.YAMLError) as e:
|
|
575
|
-
logger.warning(f"Failed to load template {template_path}: {e}")
|
|
576
|
-
# Fallback to defaults + user config
|
|
577
|
-
if user_config:
|
|
578
|
-
return (deep_merge_dict(default_config, user_config), trace)
|
|
579
|
-
return (default_config.copy(), trace)
|
|
580
|
-
|
|
581
|
-
# Merge template with configs
|
|
582
|
-
merged = merge_template_with_config(
|
|
583
|
-
template,
|
|
584
|
-
default_config,
|
|
585
|
-
user_config,
|
|
586
|
-
variables,
|
|
587
|
-
trace,
|
|
588
|
-
)
|
|
589
|
-
|
|
590
|
-
# Save trace if requested
|
|
591
|
-
if trace and trace_output_path:
|
|
592
|
-
try:
|
|
593
|
-
trace_output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
594
|
-
trace_output_path.write_text(trace.to_json(), encoding="utf-8")
|
|
595
|
-
logger.info(f"Template trace saved to {trace_output_path}")
|
|
596
|
-
except Exception as e:
|
|
597
|
-
logger.warning(f"Failed to save trace to {trace_output_path}: {e}")
|
|
598
|
-
|
|
599
|
-
return (merged, trace)
|
|
600
|
-
|
|
1
|
+
"""
|
|
2
|
+
Tech Stack Template Merging Module
|
|
3
|
+
|
|
4
|
+
Merges stack-specific templates with default configuration, handling
|
|
5
|
+
deep merging, variable expansion, conditional blocks, and user overrides.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
import re
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import yaml
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
# Variable pattern: {{variable.name}} or {{variable.nested.name}}
|
|
20
|
+
VARIABLE_PATTERN = re.compile(r"\{\{([a-zA-Z0-9_.]+)\}\}")
|
|
21
|
+
|
|
22
|
+
# Conditional block patterns: {{#if var}}...{{/if}} and {{#if var}}...{{#else}}...{{/if}}
|
|
23
|
+
CONDITIONAL_IF_PATTERN = re.compile(r"\{\{#if\s+([a-zA-Z0-9_.]+)\}\}")
|
|
24
|
+
CONDITIONAL_ELSE_PATTERN = re.compile(r"\{\{#else\}\}")
|
|
25
|
+
CONDITIONAL_ENDIF_PATTERN = re.compile(r"\{\{/if\}\}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class ConditionalTrace:
|
|
30
|
+
"""Trace information for conditional block evaluation."""
|
|
31
|
+
|
|
32
|
+
condition: str
|
|
33
|
+
variable_path: str
|
|
34
|
+
variable_value: Any
|
|
35
|
+
evaluated: bool
|
|
36
|
+
reason: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class TemplateTrace:
|
|
41
|
+
"""Trace information for template rendering."""
|
|
42
|
+
|
|
43
|
+
template_path: str | None = None
|
|
44
|
+
variables_used: dict[str, Any] = field(default_factory=dict)
|
|
45
|
+
conditionals_evaluated: list[ConditionalTrace] = field(default_factory=list)
|
|
46
|
+
variable_expansions: dict[str, str] = field(default_factory=dict)
|
|
47
|
+
|
|
48
|
+
def to_dict(self) -> dict[str, Any]:
|
|
49
|
+
"""Convert trace to dictionary for JSON serialization."""
|
|
50
|
+
return {
|
|
51
|
+
"template_path": self.template_path,
|
|
52
|
+
"variables_used": self.variables_used,
|
|
53
|
+
"conditionals_evaluated": [
|
|
54
|
+
{
|
|
55
|
+
"condition": c.condition,
|
|
56
|
+
"variable_path": c.variable_path,
|
|
57
|
+
"variable_value": str(c.variable_value),
|
|
58
|
+
"evaluated": c.evaluated,
|
|
59
|
+
"reason": c.reason,
|
|
60
|
+
}
|
|
61
|
+
for c in self.conditionals_evaluated
|
|
62
|
+
],
|
|
63
|
+
"variable_expansions": self.variable_expansions,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def to_json(self) -> str:
|
|
67
|
+
"""Convert trace to JSON string."""
|
|
68
|
+
return json.dumps(self.to_dict(), indent=2)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def deep_merge_dict(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
|
|
72
|
+
"""
|
|
73
|
+
Deep merge two dictionaries, with override taking precedence for conflicts.
|
|
74
|
+
|
|
75
|
+
For nested dictionaries, recursively merges. For lists, override replaces base.
|
|
76
|
+
For scalar values, override replaces base.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
base: Base dictionary (defaults)
|
|
80
|
+
override: Override dictionary (template values)
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Merged dictionary
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
>>> base = {"a": 1, "b": {"c": 2}}
|
|
87
|
+
>>> override = {"b": {"d": 3}, "e": 4}
|
|
88
|
+
>>> deep_merge_dict(base, override)
|
|
89
|
+
{'a': 1, 'b': {'c': 2, 'd': 3}, 'e': 4}
|
|
90
|
+
"""
|
|
91
|
+
result = base.copy()
|
|
92
|
+
|
|
93
|
+
for key, value in override.items():
|
|
94
|
+
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
|
95
|
+
# Recursively merge nested dictionaries
|
|
96
|
+
result[key] = deep_merge_dict(result[key], value)
|
|
97
|
+
else:
|
|
98
|
+
# Override replaces base (for scalars, lists, and non-dict types)
|
|
99
|
+
result[key] = value
|
|
100
|
+
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def expand_variables(
|
|
105
|
+
value: Any,
|
|
106
|
+
variables: dict[str, Any],
|
|
107
|
+
context: dict[str, Any] | None = None,
|
|
108
|
+
trace: TemplateTrace | None = None,
|
|
109
|
+
) -> Any:
|
|
110
|
+
"""
|
|
111
|
+
Expand template variables in a value.
|
|
112
|
+
|
|
113
|
+
Supports variable expansion in strings and nested structures.
|
|
114
|
+
Variables use {{variable.name}} syntax.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
value: Value that may contain variables
|
|
118
|
+
variables: Dictionary of variable values
|
|
119
|
+
context: Additional context for variable resolution (optional)
|
|
120
|
+
trace: Optional trace object to record expansions (optional)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Value with variables expanded
|
|
124
|
+
|
|
125
|
+
Examples:
|
|
126
|
+
>>> expand_variables("Hello {{name}}", {"name": "World"})
|
|
127
|
+
'Hello World'
|
|
128
|
+
>>> expand_variables({"path": "{{project.root}}/src"}, {"project": {"root": "/app"}})
|
|
129
|
+
{'path': '/app/src'}
|
|
130
|
+
"""
|
|
131
|
+
if context is None:
|
|
132
|
+
context = {}
|
|
133
|
+
|
|
134
|
+
# Combine variables and context
|
|
135
|
+
all_vars = {**variables, **context}
|
|
136
|
+
|
|
137
|
+
if isinstance(value, str):
|
|
138
|
+
# Expand variables in string
|
|
139
|
+
def replace_var(match):
|
|
140
|
+
var_path = match.group(1)
|
|
141
|
+
resolved = _resolve_variable(var_path, all_vars)
|
|
142
|
+
if trace and var_path not in trace.variable_expansions:
|
|
143
|
+
trace.variable_expansions[var_path] = resolved
|
|
144
|
+
return resolved
|
|
145
|
+
|
|
146
|
+
return VARIABLE_PATTERN.sub(replace_var, value)
|
|
147
|
+
|
|
148
|
+
elif isinstance(value, dict):
|
|
149
|
+
# Recursively expand variables in dictionary
|
|
150
|
+
return {k: expand_variables(v, variables, context, trace) for k, v in value.items()}
|
|
151
|
+
|
|
152
|
+
elif isinstance(value, list):
|
|
153
|
+
# Recursively expand variables in list
|
|
154
|
+
return [expand_variables(item, variables, context, trace) for item in value]
|
|
155
|
+
|
|
156
|
+
else:
|
|
157
|
+
# Scalar value, return as-is
|
|
158
|
+
return value
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _resolve_variable(var_path: str, variables: dict[str, Any]) -> str:
|
|
162
|
+
"""
|
|
163
|
+
Resolve a variable path (e.g., "project.name") from variables dictionary.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
var_path: Dot-separated variable path
|
|
167
|
+
variables: Dictionary of variables
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Resolved value as string, or original {{var_path}} if not found
|
|
171
|
+
"""
|
|
172
|
+
parts = var_path.split(".")
|
|
173
|
+
current = variables
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
for part in parts:
|
|
177
|
+
if isinstance(current, dict):
|
|
178
|
+
current = current.get(part)
|
|
179
|
+
if current is None:
|
|
180
|
+
# Variable not found, return original
|
|
181
|
+
return f"{{{{{var_path}}}}}"
|
|
182
|
+
else:
|
|
183
|
+
# Can't traverse further
|
|
184
|
+
return f"{{{{{var_path}}}}}"
|
|
185
|
+
|
|
186
|
+
# Convert to string
|
|
187
|
+
if current is None:
|
|
188
|
+
return f"{{{{{var_path}}}}}"
|
|
189
|
+
|
|
190
|
+
return str(current)
|
|
191
|
+
|
|
192
|
+
except (AttributeError, TypeError):
|
|
193
|
+
# Error during traversal, return original
|
|
194
|
+
return f"{{{{{var_path}}}}}"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _resolve_variable_value(var_path: str, variables: dict[str, Any]) -> Any:
|
|
198
|
+
"""
|
|
199
|
+
Resolve a variable path and return the actual value (not string).
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
var_path: Dot-separated variable path
|
|
203
|
+
variables: Dictionary of variables
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Resolved value (any type) or None if not found
|
|
207
|
+
"""
|
|
208
|
+
parts = var_path.split(".")
|
|
209
|
+
current = variables
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
for part in parts:
|
|
213
|
+
if isinstance(current, dict):
|
|
214
|
+
current = current.get(part)
|
|
215
|
+
if current is None:
|
|
216
|
+
return None
|
|
217
|
+
else:
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
return current
|
|
221
|
+
|
|
222
|
+
except (AttributeError, TypeError):
|
|
223
|
+
return None
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _evaluate_condition(var_path: str, variables: dict[str, Any]) -> tuple[bool, Any, str]:
|
|
227
|
+
"""
|
|
228
|
+
Safely evaluate a conditional variable.
|
|
229
|
+
|
|
230
|
+
Safe evaluation rules:
|
|
231
|
+
- Variable must exist in allowlisted variables
|
|
232
|
+
- Only checks presence/truthiness (no arbitrary expressions)
|
|
233
|
+
- Missing variables evaluate to False
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
var_path: Variable path to evaluate
|
|
237
|
+
variables: Dictionary of variables
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Tuple of (evaluated, value, reason) where:
|
|
241
|
+
- evaluated: Boolean result
|
|
242
|
+
- value: Variable value (for trace)
|
|
243
|
+
- reason: Human-readable reason
|
|
244
|
+
"""
|
|
245
|
+
value = _resolve_variable_value(var_path, variables)
|
|
246
|
+
|
|
247
|
+
if value is None:
|
|
248
|
+
return (False, None, f"Variable '{var_path}' not found - evaluating to False")
|
|
249
|
+
|
|
250
|
+
# Safe truthiness check (no arbitrary code execution)
|
|
251
|
+
if isinstance(value, bool):
|
|
252
|
+
evaluated = value
|
|
253
|
+
reason = f"Variable '{var_path}' is boolean: {value}"
|
|
254
|
+
elif isinstance(value, (str, list, dict)):
|
|
255
|
+
evaluated = bool(value) # Non-empty string/list/dict is truthy
|
|
256
|
+
reason = f"Variable '{var_path}' is {'non-empty' if value else 'empty'}"
|
|
257
|
+
elif isinstance(value, (int, float)):
|
|
258
|
+
evaluated = value != 0
|
|
259
|
+
reason = f"Variable '{var_path}' is numeric: {value} (non-zero is truthy)"
|
|
260
|
+
else:
|
|
261
|
+
evaluated = bool(value)
|
|
262
|
+
reason = f"Variable '{var_path}' evaluated to {evaluated}"
|
|
263
|
+
|
|
264
|
+
return (evaluated, value, reason)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _process_conditional_blocks(
|
|
268
|
+
content: str,
|
|
269
|
+
variables: dict[str, Any],
|
|
270
|
+
trace: TemplateTrace | None = None,
|
|
271
|
+
) -> str:
|
|
272
|
+
"""
|
|
273
|
+
Process conditional blocks in YAML content string.
|
|
274
|
+
|
|
275
|
+
Supports syntax:
|
|
276
|
+
- {{#if variable.path}}...{{/if}}
|
|
277
|
+
- {{#if variable.path}}...{{#else}}...{{/if}}
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
content: YAML content string with conditional blocks
|
|
281
|
+
variables: Variables for conditional evaluation
|
|
282
|
+
trace: Optional trace object to record evaluations
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
Content with conditionals processed
|
|
286
|
+
"""
|
|
287
|
+
result = []
|
|
288
|
+
i = 0
|
|
289
|
+
|
|
290
|
+
while i < len(content):
|
|
291
|
+
# Look for {{#if ...}}
|
|
292
|
+
if_match = CONDITIONAL_IF_PATTERN.search(content, i)
|
|
293
|
+
if not if_match:
|
|
294
|
+
# No more conditionals, append rest of content
|
|
295
|
+
result.append(content[i:])
|
|
296
|
+
break
|
|
297
|
+
|
|
298
|
+
# Append content before conditional
|
|
299
|
+
result.append(content[i : if_match.start()])
|
|
300
|
+
|
|
301
|
+
# Extract variable path from {{#if var.path}}
|
|
302
|
+
var_path = if_match.group(1)
|
|
303
|
+
|
|
304
|
+
# Find matching {{/if}}
|
|
305
|
+
endif_pos = if_match.end()
|
|
306
|
+
depth = 1
|
|
307
|
+
else_pos = None
|
|
308
|
+
endif_match = None
|
|
309
|
+
|
|
310
|
+
while endif_pos < len(content) and depth > 0:
|
|
311
|
+
# Check for {{#else}}
|
|
312
|
+
else_match = CONDITIONAL_ELSE_PATTERN.search(content, endif_pos)
|
|
313
|
+
if else_match and depth == 1 and else_pos is None:
|
|
314
|
+
else_pos = else_match.start()
|
|
315
|
+
endif_pos = else_match.end()
|
|
316
|
+
continue
|
|
317
|
+
|
|
318
|
+
# Check for {{/if}}
|
|
319
|
+
endif_match = CONDITIONAL_ENDIF_PATTERN.search(content, endif_pos)
|
|
320
|
+
if endif_match:
|
|
321
|
+
if depth == 1:
|
|
322
|
+
# Found matching endif - break and process
|
|
323
|
+
break
|
|
324
|
+
else:
|
|
325
|
+
# Nested conditional (not supported, but handle gracefully)
|
|
326
|
+
depth -= 1
|
|
327
|
+
endif_pos = endif_match.end()
|
|
328
|
+
continue
|
|
329
|
+
|
|
330
|
+
# Check for nested {{#if}}
|
|
331
|
+
nested_if = CONDITIONAL_IF_PATTERN.search(content, endif_pos)
|
|
332
|
+
if nested_if:
|
|
333
|
+
depth += 1
|
|
334
|
+
endif_pos = nested_if.end()
|
|
335
|
+
continue
|
|
336
|
+
|
|
337
|
+
# No match found, break
|
|
338
|
+
break
|
|
339
|
+
|
|
340
|
+
# Check if we successfully found matching endif
|
|
341
|
+
if endif_match is None or depth != 1:
|
|
342
|
+
# No matching {{/if}} found, treat as literal text
|
|
343
|
+
result.append(content[if_match.start() : if_match.end()])
|
|
344
|
+
i = if_match.end()
|
|
345
|
+
continue
|
|
346
|
+
|
|
347
|
+
# Extract true and false branches
|
|
348
|
+
if else_pos is not None:
|
|
349
|
+
true_branch = content[if_match.end() : else_pos]
|
|
350
|
+
# Find the else pattern again to get its end position
|
|
351
|
+
else_match = CONDITIONAL_ELSE_PATTERN.search(content, else_pos)
|
|
352
|
+
if else_match is None:
|
|
353
|
+
# Should not happen if logic is correct, but handle defensively
|
|
354
|
+
true_branch = content[if_match.end() : endif_match.start()]
|
|
355
|
+
false_branch = ""
|
|
356
|
+
else:
|
|
357
|
+
false_branch = content[else_match.end() : endif_match.start()]
|
|
358
|
+
else:
|
|
359
|
+
true_branch = content[if_match.end() : endif_match.start()]
|
|
360
|
+
false_branch = ""
|
|
361
|
+
|
|
362
|
+
# Evaluate condition
|
|
363
|
+
evaluated, value, reason = _evaluate_condition(var_path, variables)
|
|
364
|
+
|
|
365
|
+
# Record in trace if provided
|
|
366
|
+
if trace:
|
|
367
|
+
trace.conditionals_evaluated.append(
|
|
368
|
+
ConditionalTrace(
|
|
369
|
+
condition=f"{{{{#if {var_path}}}}}",
|
|
370
|
+
variable_path=var_path,
|
|
371
|
+
variable_value=value,
|
|
372
|
+
evaluated=evaluated,
|
|
373
|
+
reason=reason,
|
|
374
|
+
)
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
# Append appropriate branch
|
|
378
|
+
if evaluated:
|
|
379
|
+
result.append(true_branch)
|
|
380
|
+
else:
|
|
381
|
+
result.append(false_branch)
|
|
382
|
+
|
|
383
|
+
i = endif_match.end()
|
|
384
|
+
|
|
385
|
+
return "".join(result)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def load_template(
|
|
389
|
+
template_path: Path,
|
|
390
|
+
variables: dict[str, Any] | None = None,
|
|
391
|
+
trace: TemplateTrace | None = None,
|
|
392
|
+
) -> dict[str, Any]:
|
|
393
|
+
"""
|
|
394
|
+
Load a template YAML file and process conditional blocks.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
template_path: Path to template YAML file
|
|
398
|
+
variables: Variables for conditional evaluation (optional)
|
|
399
|
+
trace: Optional trace object to record processing (optional)
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Template dictionary with conditionals processed
|
|
403
|
+
|
|
404
|
+
Raises:
|
|
405
|
+
FileNotFoundError: If template file doesn't exist
|
|
406
|
+
yaml.YAMLError: If template is invalid YAML
|
|
407
|
+
"""
|
|
408
|
+
if not template_path.exists():
|
|
409
|
+
raise FileNotFoundError(f"Template file not found: {template_path}")
|
|
410
|
+
|
|
411
|
+
try:
|
|
412
|
+
content = template_path.read_text(encoding="utf-8")
|
|
413
|
+
|
|
414
|
+
# Process conditional blocks if variables provided
|
|
415
|
+
if variables:
|
|
416
|
+
content = _process_conditional_blocks(content, variables, trace)
|
|
417
|
+
if trace:
|
|
418
|
+
trace.template_path = str(template_path)
|
|
419
|
+
trace.variables_used = variables.copy()
|
|
420
|
+
|
|
421
|
+
template = yaml.safe_load(content)
|
|
422
|
+
if template is None:
|
|
423
|
+
return {}
|
|
424
|
+
return template
|
|
425
|
+
except yaml.YAMLError as e:
|
|
426
|
+
raise yaml.YAMLError(f"Invalid YAML in template {template_path}: {e}") from e
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def merge_template_with_config(
|
|
430
|
+
template: dict[str, Any],
|
|
431
|
+
default_config: dict[str, Any],
|
|
432
|
+
user_config: dict[str, Any] | None = None,
|
|
433
|
+
variables: dict[str, Any] | None = None,
|
|
434
|
+
trace: TemplateTrace | None = None,
|
|
435
|
+
) -> dict[str, Any]:
|
|
436
|
+
"""
|
|
437
|
+
Merge template with default config and user overrides.
|
|
438
|
+
|
|
439
|
+
Merge order (precedence from lowest to highest):
|
|
440
|
+
1. Default config (base)
|
|
441
|
+
2. Template values (override defaults)
|
|
442
|
+
3. User config (override template and defaults)
|
|
443
|
+
|
|
444
|
+
Variables are expanded in template before merging.
|
|
445
|
+
Conditional blocks are processed during template loading.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
template: Template dictionary (conditionals already processed)
|
|
449
|
+
default_config: Default configuration dictionary
|
|
450
|
+
user_config: User override configuration (optional)
|
|
451
|
+
variables: Variables for template expansion (optional)
|
|
452
|
+
trace: Optional trace object to record processing (optional)
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
Merged configuration dictionary
|
|
456
|
+
|
|
457
|
+
Examples:
|
|
458
|
+
>>> template = {"agent_config": {"reviewer": {"quality_threshold": 75.0}}}
|
|
459
|
+
>>> default = {"agent_config": {"reviewer": {"quality_threshold": 70.0}}}
|
|
460
|
+
>>> merge_template_with_config(template, default)
|
|
461
|
+
{'agent_config': {'reviewer': {'quality_threshold': 75.0}}}
|
|
462
|
+
"""
|
|
463
|
+
# Expand variables in template if variables provided
|
|
464
|
+
if variables:
|
|
465
|
+
template = expand_variables(template, variables, trace=trace)
|
|
466
|
+
if trace:
|
|
467
|
+
# Record variable expansions
|
|
468
|
+
for key, value in template.items():
|
|
469
|
+
if isinstance(value, str) and "{{" in value:
|
|
470
|
+
trace.variable_expansions[key] = value
|
|
471
|
+
|
|
472
|
+
# Merge order: default -> template -> user
|
|
473
|
+
merged = deep_merge_dict(default_config, template)
|
|
474
|
+
|
|
475
|
+
if user_config:
|
|
476
|
+
merged = deep_merge_dict(merged, user_config)
|
|
477
|
+
|
|
478
|
+
return merged
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def build_template_variables(
|
|
482
|
+
project_root: Path,
|
|
483
|
+
tech_stack: dict[str, Any] | None = None,
|
|
484
|
+
project_name: str | None = None,
|
|
485
|
+
) -> dict[str, Any]:
|
|
486
|
+
"""
|
|
487
|
+
Build variables dictionary for template expansion.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
project_root: Project root directory
|
|
491
|
+
tech_stack: Detected tech stack (optional)
|
|
492
|
+
project_name: Project name (optional)
|
|
493
|
+
|
|
494
|
+
Returns:
|
|
495
|
+
Variables dictionary for template expansion
|
|
496
|
+
"""
|
|
497
|
+
variables: dict[str, Any] = {
|
|
498
|
+
"project": {
|
|
499
|
+
"root": str(project_root),
|
|
500
|
+
"name": project_name or project_root.name,
|
|
501
|
+
},
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if tech_stack:
|
|
505
|
+
variables["tech_stack"] = {
|
|
506
|
+
"frameworks": tech_stack.get("frameworks", []),
|
|
507
|
+
"languages": tech_stack.get("languages", []),
|
|
508
|
+
"libraries": tech_stack.get("libraries", []),
|
|
509
|
+
"package_managers": tech_stack.get("package_managers", []),
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return variables
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def apply_template_to_config(
|
|
516
|
+
template_path: Path | None,
|
|
517
|
+
default_config: dict[str, Any],
|
|
518
|
+
user_config: dict[str, Any] | None = None,
|
|
519
|
+
project_root: Path | None = None,
|
|
520
|
+
tech_stack: dict[str, Any] | None = None,
|
|
521
|
+
project_name: str | None = None,
|
|
522
|
+
enable_trace: bool = False,
|
|
523
|
+
trace_output_path: Path | None = None,
|
|
524
|
+
) -> tuple[dict[str, Any], TemplateTrace | None]:
|
|
525
|
+
"""
|
|
526
|
+
Apply a template to configuration (main entry point).
|
|
527
|
+
|
|
528
|
+
This function:
|
|
529
|
+
1. Loads the template (if provided)
|
|
530
|
+
2. Builds template variables
|
|
531
|
+
3. Processes conditional blocks in template
|
|
532
|
+
4. Expands variables in template
|
|
533
|
+
5. Merges template with defaults and user config
|
|
534
|
+
6. Optionally generates trace output
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
template_path: Path to template file (None = no template)
|
|
538
|
+
default_config: Default configuration
|
|
539
|
+
user_config: User override configuration (optional)
|
|
540
|
+
project_root: Project root directory (optional)
|
|
541
|
+
tech_stack: Detected tech stack (optional)
|
|
542
|
+
project_name: Project name (optional)
|
|
543
|
+
enable_trace: Whether to generate trace output (default: False)
|
|
544
|
+
trace_output_path: Path to save trace JSON file (optional)
|
|
545
|
+
|
|
546
|
+
Returns:
|
|
547
|
+
Tuple of (merged_config, trace) where:
|
|
548
|
+
- merged_config: Merged configuration dictionary
|
|
549
|
+
- trace: TemplateTrace object (None if tracing disabled)
|
|
550
|
+
|
|
551
|
+
Examples:
|
|
552
|
+
>>> default = {"agent_config": {"reviewer": {"quality_threshold": 70.0}}}
|
|
553
|
+
>>> template_path = Path("templates/tech_stacks/fastapi.yaml")
|
|
554
|
+
>>> config, trace = apply_template_to_config(template_path, default)
|
|
555
|
+
# Returns config with FastAPI-specific overrides and trace info
|
|
556
|
+
"""
|
|
557
|
+
trace = TemplateTrace() if enable_trace else None
|
|
558
|
+
|
|
559
|
+
# If no template, just merge defaults with user config
|
|
560
|
+
if template_path is None or not template_path.exists():
|
|
561
|
+
if user_config:
|
|
562
|
+
return (deep_merge_dict(default_config, user_config), trace)
|
|
563
|
+
return (default_config.copy(), trace)
|
|
564
|
+
|
|
565
|
+
# Build variables for expansion (needed for conditionals)
|
|
566
|
+
if project_root is None:
|
|
567
|
+
project_root = Path.cwd()
|
|
568
|
+
|
|
569
|
+
variables = build_template_variables(project_root, tech_stack, project_name)
|
|
570
|
+
|
|
571
|
+
# Load template with conditional processing
|
|
572
|
+
try:
|
|
573
|
+
template = load_template(template_path, variables, trace)
|
|
574
|
+
except (FileNotFoundError, yaml.YAMLError) as e:
|
|
575
|
+
logger.warning(f"Failed to load template {template_path}: {e}")
|
|
576
|
+
# Fallback to defaults + user config
|
|
577
|
+
if user_config:
|
|
578
|
+
return (deep_merge_dict(default_config, user_config), trace)
|
|
579
|
+
return (default_config.copy(), trace)
|
|
580
|
+
|
|
581
|
+
# Merge template with configs
|
|
582
|
+
merged = merge_template_with_config(
|
|
583
|
+
template,
|
|
584
|
+
default_config,
|
|
585
|
+
user_config,
|
|
586
|
+
variables,
|
|
587
|
+
trace,
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
# Save trace if requested
|
|
591
|
+
if trace and trace_output_path:
|
|
592
|
+
try:
|
|
593
|
+
trace_output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
594
|
+
trace_output_path.write_text(trace.to_json(), encoding="utf-8")
|
|
595
|
+
logger.info(f"Template trace saved to {trace_output_path}")
|
|
596
|
+
except Exception as e:
|
|
597
|
+
logger.warning(f"Failed to save trace to {trace_output_path}: {e}")
|
|
598
|
+
|
|
599
|
+
return (merged, trace)
|
|
600
|
+
|