@agentic-qe/v3 3.0.0-alpha.6 → 3.0.0-alpha.8
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.
- package/assets/agents/v3/subagents/v3-qe-code-reviewer.md +339 -0
- package/assets/agents/v3/subagents/v3-qe-integration-reviewer.md +344 -0
- package/assets/agents/v3/subagents/v3-qe-performance-reviewer.md +351 -0
- package/assets/agents/v3/subagents/v3-qe-security-reviewer.md +374 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-green.md +334 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-red.md +329 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-refactor.md +361 -0
- package/assets/agents/v3/v3-qe-accessibility-auditor.md +266 -0
- package/assets/agents/v3/v3-qe-bdd-generator.md +279 -0
- package/assets/agents/v3/v3-qe-chaos-engineer.md +265 -0
- package/assets/agents/v3/v3-qe-code-complexity.md +298 -0
- package/assets/agents/v3/v3-qe-code-intelligence.md +262 -0
- package/assets/agents/v3/v3-qe-contract-validator.md +267 -0
- package/assets/agents/v3/v3-qe-coverage-specialist.md +227 -0
- package/assets/agents/v3/v3-qe-defect-predictor.md +251 -0
- package/assets/agents/v3/v3-qe-dependency-mapper.md +277 -0
- package/assets/agents/v3/v3-qe-deployment-advisor.md +275 -0
- package/assets/agents/v3/v3-qe-flaky-hunter.md +248 -0
- package/assets/agents/v3/v3-qe-fleet-commander.md +293 -0
- package/assets/agents/v3/v3-qe-gap-detector.md +260 -0
- package/assets/agents/v3/v3-qe-graphql-tester.md +308 -0
- package/assets/agents/v3/v3-qe-impact-analyzer.md +299 -0
- package/assets/agents/v3/v3-qe-integration-tester.md +238 -0
- package/assets/agents/v3/v3-qe-kg-builder.md +273 -0
- package/assets/agents/v3/v3-qe-learning-coordinator.md +226 -0
- package/assets/agents/v3/v3-qe-load-tester.md +280 -0
- package/assets/agents/v3/v3-qe-metrics-optimizer.md +300 -0
- package/assets/agents/v3/v3-qe-mutation-tester.md +301 -0
- package/assets/agents/v3/v3-qe-parallel-executor.md +240 -0
- package/assets/agents/v3/v3-qe-pattern-learner.md +271 -0
- package/assets/agents/v3/v3-qe-performance-tester.md +262 -0
- package/assets/agents/v3/v3-qe-property-tester.md +247 -0
- package/assets/agents/v3/v3-qe-quality-gate.md +218 -0
- package/assets/agents/v3/v3-qe-queen-coordinator.md +214 -0
- package/assets/agents/v3/v3-qe-qx-partner.md +313 -0
- package/assets/agents/v3/v3-qe-regression-analyzer.md +322 -0
- package/assets/agents/v3/v3-qe-requirements-validator.md +360 -0
- package/assets/agents/v3/v3-qe-responsive-tester.md +311 -0
- package/assets/agents/v3/v3-qe-retry-handler.md +256 -0
- package/assets/agents/v3/v3-qe-risk-assessor.md +273 -0
- package/assets/agents/v3/v3-qe-root-cause-analyzer.md +286 -0
- package/assets/agents/v3/v3-qe-security-auditor.md +299 -0
- package/assets/agents/v3/v3-qe-security-scanner.md +235 -0
- package/assets/agents/v3/v3-qe-tdd-specialist.md +239 -0
- package/assets/agents/v3/v3-qe-test-architect.md +233 -0
- package/assets/agents/v3/v3-qe-transfer-specialist.md +295 -0
- package/assets/agents/v3/v3-qe-visual-tester.md +232 -0
- package/assets/skills/accessibility-testing/SKILL.md +216 -0
- package/assets/skills/agentdb-advanced/SKILL.md +550 -0
- package/assets/skills/agentdb-learning/SKILL.md +545 -0
- package/assets/skills/agentdb-memory-patterns/SKILL.md +339 -0
- package/assets/skills/agentdb-optimization/SKILL.md +509 -0
- package/assets/skills/agentdb-vector-search/SKILL.md +339 -0
- package/assets/skills/agentic-jujutsu/SKILL.md +645 -0
- package/assets/skills/agentic-quality-engineering/SKILL.md +335 -0
- package/assets/skills/api-testing-patterns/SKILL.md +294 -0
- package/assets/skills/aqe-v2-v3-migration/skill.md +322 -0
- package/assets/skills/brutal-honesty-review/README.md +218 -0
- package/assets/skills/brutal-honesty-review/SKILL.md +235 -0
- package/assets/skills/brutal-honesty-review/resources/assessment-rubrics.md +295 -0
- package/assets/skills/brutal-honesty-review/resources/review-template.md +102 -0
- package/assets/skills/brutal-honesty-review/scripts/assess-code.sh +179 -0
- package/assets/skills/brutal-honesty-review/scripts/assess-tests.sh +223 -0
- package/assets/skills/bug-reporting-excellence/SKILL.md +225 -0
- package/assets/skills/chaos-engineering-resilience/SKILL.md +158 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/README.md +304 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/SKILL.md +315 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/microservice-pipeline.md +239 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/mobile-pipeline.md +375 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/monolith-pipeline.md +268 -0
- package/assets/skills/code-review-quality/SKILL.md +227 -0
- package/assets/skills/compatibility-testing/SKILL.md +205 -0
- package/assets/skills/compliance-testing/SKILL.md +225 -0
- package/assets/skills/consultancy-practices/SKILL.md +202 -0
- package/assets/skills/context-driven-testing/SKILL.md +196 -0
- package/assets/skills/contract-testing/SKILL.md +222 -0
- package/assets/skills/database-testing/SKILL.md +244 -0
- package/assets/skills/exploratory-testing-advanced/SKILL.md +201 -0
- package/assets/skills/flow-nexus-neural/SKILL.md +738 -0
- package/assets/skills/flow-nexus-platform/SKILL.md +1157 -0
- package/assets/skills/flow-nexus-swarm/SKILL.md +610 -0
- package/assets/skills/github-code-review/SKILL.md +1140 -0
- package/assets/skills/github-multi-repo/SKILL.md +874 -0
- package/assets/skills/github-project-management/SKILL.md +1277 -0
- package/assets/skills/github-release-management/SKILL.md +1081 -0
- package/assets/skills/github-workflow-automation/SKILL.md +1065 -0
- package/assets/skills/hive-mind-advanced/SKILL.md +712 -0
- package/assets/skills/holistic-testing-pact/SKILL.md +171 -0
- package/assets/skills/hooks-automation/SKILL.md +1201 -0
- package/assets/skills/localization-testing/SKILL.md +221 -0
- package/assets/skills/mobile-testing/SKILL.md +219 -0
- package/assets/skills/mutation-testing/SKILL.md +229 -0
- package/assets/skills/n8n-expression-testing/SKILL.md +434 -0
- package/assets/skills/n8n-integration-testing-patterns/SKILL.md +540 -0
- package/assets/skills/n8n-security-testing/SKILL.md +599 -0
- package/assets/skills/n8n-trigger-testing-strategies/SKILL.md +541 -0
- package/assets/skills/n8n-workflow-testing-fundamentals/SKILL.md +447 -0
- package/assets/skills/pair-programming/SKILL.md +1202 -0
- package/assets/skills/performance-analysis/SKILL.md +563 -0
- package/assets/skills/performance-testing/SKILL.md +310 -0
- package/assets/skills/quality-metrics/SKILL.md +225 -0
- package/assets/skills/reasoningbank-agentdb/SKILL.md +446 -0
- package/assets/skills/reasoningbank-intelligence/SKILL.md +201 -0
- package/assets/skills/refactoring-patterns/SKILL.md +205 -0
- package/assets/skills/regression-testing/SKILL.md +227 -0
- package/assets/skills/risk-based-testing/SKILL.md +206 -0
- package/assets/skills/security-testing/SKILL.md +306 -0
- package/assets/skills/sherlock-review/SKILL.md +250 -0
- package/assets/skills/shift-left-testing/SKILL.md +225 -0
- package/assets/skills/shift-right-testing/SKILL.md +227 -0
- package/assets/skills/six-thinking-hats/README.md +190 -0
- package/assets/skills/six-thinking-hats/SKILL.md +280 -0
- package/assets/skills/six-thinking-hats/resources/examples/api-testing-example.md +345 -0
- package/assets/skills/six-thinking-hats/resources/templates/solo-session-template.md +167 -0
- package/assets/skills/six-thinking-hats/resources/templates/team-session-template.md +336 -0
- package/assets/skills/skill-builder/SKILL.md +910 -0
- package/assets/skills/sparc-methodology/SKILL.md +1115 -0
- package/assets/skills/stream-chain/SKILL.md +563 -0
- package/assets/skills/swarm-advanced/SKILL.md +973 -0
- package/assets/skills/swarm-orchestration/SKILL.md +179 -0
- package/assets/skills/tdd-london-chicago/SKILL.md +244 -0
- package/assets/skills/technical-writing/SKILL.md +178 -0
- package/assets/skills/test-automation-strategy/SKILL.md +230 -0
- package/assets/skills/test-data-management/SKILL.md +270 -0
- package/assets/skills/test-design-techniques/SKILL.md +244 -0
- package/assets/skills/test-environment-management/SKILL.md +243 -0
- package/assets/skills/test-reporting-analytics/SKILL.md +214 -0
- package/assets/skills/testability-scoring/README.md +71 -0
- package/assets/skills/testability-scoring/SKILL.md +346 -0
- package/assets/skills/testability-scoring/resources/templates/config.template.js +84 -0
- package/assets/skills/testability-scoring/resources/templates/testability-scoring.spec.template.js +532 -0
- package/assets/skills/testability-scoring/scripts/generate-html-report.js +1007 -0
- package/assets/skills/testability-scoring/scripts/run-assessment.sh +70 -0
- package/assets/skills/v3-qe-chaos-resilience/SKILL.md +238 -0
- package/assets/skills/v3-qe-code-intelligence/SKILL.md +209 -0
- package/assets/skills/v3-qe-contract-testing/SKILL.md +218 -0
- package/assets/skills/v3-qe-coverage-analysis/SKILL.md +187 -0
- package/assets/skills/v3-qe-defect-intelligence/SKILL.md +205 -0
- package/assets/skills/v3-qe-learning-optimization/SKILL.md +238 -0
- package/assets/skills/v3-qe-quality-assessment/SKILL.md +213 -0
- package/assets/skills/v3-qe-requirements-validation/SKILL.md +248 -0
- package/assets/skills/v3-qe-test-execution/SKILL.md +182 -0
- package/assets/skills/v3-qe-test-generation/SKILL.md +141 -0
- package/assets/skills/v3-qe-visual-accessibility/SKILL.md +242 -0
- package/assets/skills/verification-quality/SKILL.md +649 -0
- package/assets/skills/visual-testing-advanced/SKILL.md +219 -0
- package/assets/skills/xp-practices/SKILL.md +229 -0
- package/dist/cli/bundle.js +23 -13
- package/dist/init/agents-installer.js +4 -4
- package/dist/init/agents-installer.js.map +1 -1
- package/dist/init/init-wizard.d.ts.map +1 -1
- package/dist/init/init-wizard.js +15 -5
- package/dist/init/init-wizard.js.map +1 -1
- package/dist/init/skills-installer.js +4 -4
- package/dist/init/skills-installer.js.map +1 -1
- package/package.json +7 -1
- package/docs/analysis/V3-INIT-REQUIREMENTS-ANALYSIS.md +0 -352
- package/implementation/README.md +0 -90
- package/implementation/adrs/ADR-030-coherence-gated-quality-gates.md +0 -312
- package/implementation/adrs/ADR-031-strange-loop-self-awareness.md +0 -484
- package/implementation/adrs/ADR-032-time-crystal-scheduling.md +0 -530
- package/implementation/adrs/ADR-033-early-exit-testing.md +0 -634
- package/implementation/adrs/ADR-034-neural-topology-optimizer.md +0 -589
- package/implementation/adrs/ADR-035-causal-discovery.md +0 -610
- package/implementation/adrs/ADR-036-result-persistence.md +0 -326
- package/implementation/adrs/ADR-037-v3-qe-agent-naming.md +0 -105
- package/implementation/adrs/ADR-038-v3-qe-memory-unification.md +0 -154
- package/implementation/adrs/ADR-039-v3-qe-mcp-optimization.md +0 -179
- package/implementation/adrs/ADR-040-v3-qe-agentic-flow-integration.md +0 -240
- package/implementation/adrs/ADR-041-v3-qe-cli-enhancement.md +0 -296
- package/implementation/adrs/ADR-042-v3-qe-token-tracking-integration.md +0 -517
- package/implementation/adrs/v3-adrs.md +0 -2783
- package/implementation/planning/AQE-V3-MASTER-PLAN.md +0 -815
- package/security-scan-report-2026-01-11.md +0 -410
- package/security-verification-report-2026-01-11.md +0 -278
- package/src/benchmarks/performance-benchmarks.ts +0 -646
- package/src/benchmarks/run-benchmarks.ts +0 -324
- package/src/causal-discovery/causal-graph.ts +0 -450
- package/src/causal-discovery/discovery-engine.ts +0 -438
- package/src/causal-discovery/index.ts +0 -117
- package/src/causal-discovery/types.ts +0 -456
- package/src/causal-discovery/weight-matrix.ts +0 -453
- package/src/cli/commands/qe-tools.ts +0 -634
- package/src/cli/index.ts +0 -1976
- package/src/compatibility/agent-mapper.ts +0 -291
- package/src/compatibility/cli-adapter.ts +0 -277
- package/src/compatibility/config-migrator.ts +0 -334
- package/src/compatibility/index.ts +0 -112
- package/src/compatibility/mcp-adapter.ts +0 -248
- package/src/compatibility/types.ts +0 -156
- package/src/coordination/claims/claim-repository.ts +0 -636
- package/src/coordination/claims/claim-service.ts +0 -675
- package/src/coordination/claims/handoff-manager.ts +0 -535
- package/src/coordination/claims/index.ts +0 -276
- package/src/coordination/claims/interfaces.ts +0 -687
- package/src/coordination/claims/work-stealing.ts +0 -436
- package/src/coordination/cross-domain-router.ts +0 -492
- package/src/coordination/index.ts +0 -127
- package/src/coordination/interfaces.ts +0 -691
- package/src/coordination/protocol-executor.ts +0 -760
- package/src/coordination/protocols/code-intelligence-index.ts +0 -855
- package/src/coordination/protocols/defect-investigation.ts +0 -1184
- package/src/coordination/protocols/index.ts +0 -11
- package/src/coordination/protocols/learning-consolidation.ts +0 -1181
- package/src/coordination/protocols/morning-sync.ts +0 -1055
- package/src/coordination/protocols/quality-gate.ts +0 -1566
- package/src/coordination/protocols/security-audit.ts +0 -1587
- package/src/coordination/queen-coordinator.ts +0 -1176
- package/src/coordination/result-saver.ts +0 -780
- package/src/coordination/task-executor.ts +0 -1146
- package/src/coordination/workflow-orchestrator.ts +0 -1917
- package/src/domains/chaos-resilience/coordinator.ts +0 -1032
- package/src/domains/chaos-resilience/index.ts +0 -143
- package/src/domains/chaos-resilience/interfaces.ts +0 -659
- package/src/domains/chaos-resilience/plugin.ts +0 -691
- package/src/domains/chaos-resilience/services/chaos-engineer.ts +0 -1097
- package/src/domains/chaos-resilience/services/index.ts +0 -19
- package/src/domains/chaos-resilience/services/load-tester.ts +0 -799
- package/src/domains/chaos-resilience/services/performance-profiler.ts +0 -792
- package/src/domains/code-intelligence/coordinator.ts +0 -631
- package/src/domains/code-intelligence/index.ts +0 -86
- package/src/domains/code-intelligence/interfaces.ts +0 -162
- package/src/domains/code-intelligence/plugin.ts +0 -451
- package/src/domains/code-intelligence/services/impact-analyzer.ts +0 -567
- package/src/domains/code-intelligence/services/index.ts +0 -26
- package/src/domains/code-intelligence/services/knowledge-graph.ts +0 -1067
- package/src/domains/code-intelligence/services/semantic-analyzer.ts +0 -901
- package/src/domains/contract-testing/coordinator.ts +0 -1038
- package/src/domains/contract-testing/index.ts +0 -122
- package/src/domains/contract-testing/interfaces.ts +0 -458
- package/src/domains/contract-testing/plugin.ts +0 -746
- package/src/domains/contract-testing/services/api-compatibility.ts +0 -748
- package/src/domains/contract-testing/services/contract-validator.ts +0 -1700
- package/src/domains/contract-testing/services/index.ts +0 -19
- package/src/domains/contract-testing/services/schema-validator.ts +0 -1102
- package/src/domains/coverage-analysis/coordinator.ts +0 -485
- package/src/domains/coverage-analysis/index.ts +0 -114
- package/src/domains/coverage-analysis/interfaces.ts +0 -142
- package/src/domains/coverage-analysis/plugin.ts +0 -172
- package/src/domains/coverage-analysis/services/coverage-analyzer.ts +0 -449
- package/src/domains/coverage-analysis/services/coverage-embedder.ts +0 -733
- package/src/domains/coverage-analysis/services/coverage-parser.ts +0 -753
- package/src/domains/coverage-analysis/services/gap-detector.ts +0 -592
- package/src/domains/coverage-analysis/services/hnsw-index.ts +0 -728
- package/src/domains/coverage-analysis/services/index.ts +0 -61
- package/src/domains/coverage-analysis/services/risk-scorer.ts +0 -540
- package/src/domains/coverage-analysis/services/sublinear-analyzer.ts +0 -747
- package/src/domains/defect-intelligence/coordinator.ts +0 -635
- package/src/domains/defect-intelligence/index.ts +0 -83
- package/src/domains/defect-intelligence/interfaces.ts +0 -152
- package/src/domains/defect-intelligence/plugin.ts +0 -483
- package/src/domains/defect-intelligence/services/causal-root-cause-analyzer.ts +0 -494
- package/src/domains/defect-intelligence/services/defect-predictor.ts +0 -852
- package/src/domains/defect-intelligence/services/index.ts +0 -37
- package/src/domains/defect-intelligence/services/pattern-learner.ts +0 -738
- package/src/domains/defect-intelligence/services/root-cause-analyzer.ts +0 -637
- package/src/domains/domain-interface.ts +0 -77
- package/src/domains/index.ts +0 -23
- package/src/domains/learning-optimization/coordinator.ts +0 -1215
- package/src/domains/learning-optimization/index.ts +0 -127
- package/src/domains/learning-optimization/interfaces.ts +0 -570
- package/src/domains/learning-optimization/plugin.ts +0 -851
- package/src/domains/learning-optimization/services/index.ts +0 -29
- package/src/domains/learning-optimization/services/learning-coordinator.ts +0 -972
- package/src/domains/learning-optimization/services/metrics-optimizer.ts +0 -915
- package/src/domains/learning-optimization/services/production-intel.ts +0 -971
- package/src/domains/learning-optimization/services/transfer-specialist.ts +0 -723
- package/src/domains/quality-assessment/coherence/gate-controller.ts +0 -549
- package/src/domains/quality-assessment/coherence/index.ts +0 -211
- package/src/domains/quality-assessment/coherence/lambda-calculator.ts +0 -384
- package/src/domains/quality-assessment/coherence/partition-detector.ts +0 -469
- package/src/domains/quality-assessment/coherence/types.ts +0 -384
- package/src/domains/quality-assessment/coordinator.ts +0 -605
- package/src/domains/quality-assessment/index.ts +0 -97
- package/src/domains/quality-assessment/interfaces.ts +0 -152
- package/src/domains/quality-assessment/plugin.ts +0 -496
- package/src/domains/quality-assessment/services/coherence-gate.ts +0 -358
- package/src/domains/quality-assessment/services/deployment-advisor.ts +0 -571
- package/src/domains/quality-assessment/services/index.ts +0 -34
- package/src/domains/quality-assessment/services/quality-analyzer.ts +0 -670
- package/src/domains/quality-assessment/services/quality-gate.ts +0 -384
- package/src/domains/requirements-validation/coordinator.ts +0 -812
- package/src/domains/requirements-validation/index.ts +0 -92
- package/src/domains/requirements-validation/interfaces.ts +0 -303
- package/src/domains/requirements-validation/plugin.ts +0 -576
- package/src/domains/requirements-validation/services/bdd-scenario-writer.ts +0 -676
- package/src/domains/requirements-validation/services/index.ts +0 -20
- package/src/domains/requirements-validation/services/requirements-validator.ts +0 -559
- package/src/domains/requirements-validation/services/testability-scorer.ts +0 -639
- package/src/domains/security-compliance/coordinator.ts +0 -757
- package/src/domains/security-compliance/index.ts +0 -120
- package/src/domains/security-compliance/interfaces.ts +0 -434
- package/src/domains/security-compliance/plugin.ts +0 -509
- package/src/domains/security-compliance/services/compliance-validator.ts +0 -1226
- package/src/domains/security-compliance/services/index.ts +0 -31
- package/src/domains/security-compliance/services/security-auditor.ts +0 -2227
- package/src/domains/security-compliance/services/security-scanner.ts +0 -2354
- package/src/domains/security-compliance/services/semgrep-integration.ts +0 -289
- package/src/domains/test-execution/coordinator.ts +0 -426
- package/src/domains/test-execution/index.ts +0 -76
- package/src/domains/test-execution/interfaces.ts +0 -119
- package/src/domains/test-execution/plugin.ts +0 -208
- package/src/domains/test-execution/services/flaky-detector.ts +0 -1240
- package/src/domains/test-execution/services/index.ts +0 -8
- package/src/domains/test-execution/services/retry-handler.ts +0 -820
- package/src/domains/test-execution/services/test-executor.ts +0 -885
- package/src/domains/test-generation/coordinator.ts +0 -656
- package/src/domains/test-generation/index.ts +0 -77
- package/src/domains/test-generation/interfaces.ts +0 -118
- package/src/domains/test-generation/plugin.ts +0 -397
- package/src/domains/test-generation/services/index.ts +0 -23
- package/src/domains/test-generation/services/pattern-matcher.ts +0 -1725
- package/src/domains/test-generation/services/test-generator.ts +0 -2750
- package/src/domains/visual-accessibility/coordinator.ts +0 -860
- package/src/domains/visual-accessibility/index.ts +0 -116
- package/src/domains/visual-accessibility/interfaces.ts +0 -435
- package/src/domains/visual-accessibility/plugin.ts +0 -568
- package/src/domains/visual-accessibility/services/accessibility-tester.ts +0 -982
- package/src/domains/visual-accessibility/services/axe-core-audit.ts +0 -630
- package/src/domains/visual-accessibility/services/index.ts +0 -28
- package/src/domains/visual-accessibility/services/responsive-tester.ts +0 -934
- package/src/domains/visual-accessibility/services/visual-tester.ts +0 -458
- package/src/early-exit/early-exit-controller.ts +0 -490
- package/src/early-exit/early-exit-decision.ts +0 -391
- package/src/early-exit/index.ts +0 -115
- package/src/early-exit/quality-signal.ts +0 -389
- package/src/early-exit/speculative-executor.ts +0 -505
- package/src/early-exit/types.ts +0 -407
- package/src/feedback/coverage-learner.ts +0 -456
- package/src/feedback/feedback-loop.ts +0 -426
- package/src/feedback/index.ts +0 -72
- package/src/feedback/pattern-promotion.ts +0 -373
- package/src/feedback/quality-score-calculator.ts +0 -334
- package/src/feedback/test-outcome-tracker.ts +0 -450
- package/src/feedback/types.ts +0 -497
- package/src/index.ts +0 -224
- package/src/init/agents-installer.ts +0 -536
- package/src/init/index.ts +0 -80
- package/src/init/init-wizard.ts +0 -1061
- package/src/init/project-analyzer.ts +0 -696
- package/src/init/self-configurator.ts +0 -488
- package/src/init/skills-installer.ts +0 -467
- package/src/init/types.ts +0 -432
- package/src/integrations/ruvector/ast-complexity.ts +0 -470
- package/src/integrations/ruvector/coverage-router.ts +0 -594
- package/src/integrations/ruvector/diff-risk-classifier.ts +0 -759
- package/src/integrations/ruvector/fallback.ts +0 -942
- package/src/integrations/ruvector/graph-boundaries.ts +0 -809
- package/src/integrations/ruvector/index.ts +0 -363
- package/src/integrations/ruvector/interfaces.ts +0 -609
- package/src/integrations/ruvector/q-learning-router.ts +0 -550
- package/src/kernel/agent-coordinator.ts +0 -165
- package/src/kernel/agentdb-backend.ts +0 -504
- package/src/kernel/event-bus.ts +0 -129
- package/src/kernel/hybrid-backend.ts +0 -538
- package/src/kernel/index.ts +0 -28
- package/src/kernel/interfaces.ts +0 -257
- package/src/kernel/kernel.ts +0 -285
- package/src/kernel/memory-backend.ts +0 -169
- package/src/kernel/memory-factory.ts +0 -293
- package/src/kernel/plugin-loader.ts +0 -179
- package/src/learning/index.ts +0 -219
- package/src/learning/pattern-store.ts +0 -990
- package/src/learning/qe-guidance.ts +0 -832
- package/src/learning/qe-hooks.ts +0 -644
- package/src/learning/qe-patterns.ts +0 -449
- package/src/learning/qe-reasoning-bank.ts +0 -951
- package/src/learning/real-embeddings.ts +0 -277
- package/src/learning/real-qe-reasoning-bank.ts +0 -833
- package/src/learning/sqlite-persistence.ts +0 -554
- package/src/mcp/entry.ts +0 -59
- package/src/mcp/handlers/agent-handlers.ts +0 -285
- package/src/mcp/handlers/core-handlers.ts +0 -317
- package/src/mcp/handlers/domain-handlers.ts +0 -1444
- package/src/mcp/handlers/index.ts +0 -57
- package/src/mcp/handlers/memory-handlers.ts +0 -338
- package/src/mcp/handlers/task-handlers.ts +0 -363
- package/src/mcp/index.ts +0 -30
- package/src/mcp/metrics/index.ts +0 -14
- package/src/mcp/metrics/metrics-collector.ts +0 -503
- package/src/mcp/protocol-server.ts +0 -752
- package/src/mcp/security/cve-prevention.ts +0 -742
- package/src/mcp/security/index.ts +0 -356
- package/src/mcp/security/oauth21-provider.ts +0 -821
- package/src/mcp/security/rate-limiter.ts +0 -615
- package/src/mcp/security/sampling-server.ts +0 -662
- package/src/mcp/security/schema-validator.ts +0 -855
- package/src/mcp/server.ts +0 -657
- package/src/mcp/tool-registry.ts +0 -391
- package/src/mcp/tools/base.ts +0 -399
- package/src/mcp/tools/chaos-resilience/inject.ts +0 -699
- package/src/mcp/tools/code-intelligence/analyze.ts +0 -745
- package/src/mcp/tools/contract-testing/validate.ts +0 -708
- package/src/mcp/tools/coverage-analysis/index.ts +0 -770
- package/src/mcp/tools/defect-intelligence/predict.ts +0 -466
- package/src/mcp/tools/index.ts +0 -214
- package/src/mcp/tools/learning-optimization/optimize.ts +0 -772
- package/src/mcp/tools/quality-assessment/evaluate.ts +0 -385
- package/src/mcp/tools/registry.ts +0 -248
- package/src/mcp/tools/requirements-validation/validate.ts +0 -394
- package/src/mcp/tools/security-compliance/scan.ts +0 -365
- package/src/mcp/tools/test-execution/execute.ts +0 -291
- package/src/mcp/tools/test-generation/generate.ts +0 -544
- package/src/mcp/tools/visual-accessibility/index.ts +0 -791
- package/src/mcp/transport/index.ts +0 -31
- package/src/mcp/transport/stdio.ts +0 -318
- package/src/mcp/types.ts +0 -543
- package/src/neural-optimizer/index.ts +0 -111
- package/src/neural-optimizer/replay-buffer.ts +0 -455
- package/src/neural-optimizer/swarm-topology.ts +0 -508
- package/src/neural-optimizer/topology-optimizer.ts +0 -828
- package/src/neural-optimizer/types.ts +0 -481
- package/src/neural-optimizer/value-network.ts +0 -351
- package/src/optimization/auto-tuner.ts +0 -817
- package/src/optimization/index.ts +0 -77
- package/src/optimization/metric-collectors.ts +0 -474
- package/src/optimization/qe-workers.ts +0 -704
- package/src/optimization/tuning-algorithm.ts +0 -401
- package/src/optimization/types.ts +0 -314
- package/src/routing/index.ts +0 -51
- package/src/routing/qe-agent-registry.ts +0 -963
- package/src/routing/qe-task-router.ts +0 -564
- package/src/routing/routing-feedback.ts +0 -365
- package/src/routing/types.ts +0 -406
- package/src/shared/embeddings/embedding-cache.ts +0 -157
- package/src/shared/embeddings/index.ts +0 -50
- package/src/shared/embeddings/nomic-embedder.ts +0 -404
- package/src/shared/embeddings/ollama-client.ts +0 -195
- package/src/shared/embeddings/types.ts +0 -147
- package/src/shared/entities/agent.ts +0 -141
- package/src/shared/entities/base-entity.ts +0 -79
- package/src/shared/entities/index.ts +0 -6
- package/src/shared/events/domain-events.ts +0 -259
- package/src/shared/events/index.ts +0 -5
- package/src/shared/git/git-analyzer.ts +0 -656
- package/src/shared/git/index.ts +0 -11
- package/src/shared/http/http-client.ts +0 -420
- package/src/shared/http/index.ts +0 -13
- package/src/shared/index.ts +0 -41
- package/src/shared/io/file-reader.ts +0 -525
- package/src/shared/io/index.ts +0 -25
- package/src/shared/llm/cache.ts +0 -473
- package/src/shared/llm/circuit-breaker.ts +0 -369
- package/src/shared/llm/cost-tracker.ts +0 -460
- package/src/shared/llm/index.ts +0 -140
- package/src/shared/llm/interfaces.ts +0 -629
- package/src/shared/llm/provider-manager.ts +0 -685
- package/src/shared/llm/providers/claude.ts +0 -524
- package/src/shared/llm/providers/index.ts +0 -8
- package/src/shared/llm/providers/ollama.ts +0 -575
- package/src/shared/llm/providers/openai.ts +0 -609
- package/src/shared/metrics/code-metrics.ts +0 -520
- package/src/shared/metrics/index.ts +0 -23
- package/src/shared/metrics/system-metrics.ts +0 -353
- package/src/shared/parsers/index.ts +0 -6
- package/src/shared/parsers/typescript-parser.ts +0 -841
- package/src/shared/security/compliance-patterns.ts +0 -666
- package/src/shared/security/index.ts +0 -30
- package/src/shared/security/osv-client.ts +0 -468
- package/src/shared/types/index.ts +0 -150
- package/src/shared/value-objects/index.ts +0 -273
- package/src/strange-loop/healing-controller.ts +0 -833
- package/src/strange-loop/index.ts +0 -104
- package/src/strange-loop/self-model.ts +0 -494
- package/src/strange-loop/strange-loop.ts +0 -446
- package/src/strange-loop/swarm-observer.ts +0 -448
- package/src/strange-loop/topology-analyzer.ts +0 -565
- package/src/strange-loop/types.ts +0 -640
- package/src/time-crystal/default-phases.ts +0 -520
- package/src/time-crystal/index.ts +0 -164
- package/src/time-crystal/oscillator.ts +0 -425
- package/src/time-crystal/phase-executor.ts +0 -521
- package/src/time-crystal/scheduler.ts +0 -1025
- package/src/time-crystal/test-runner.ts +0 -787
- package/src/time-crystal/types.ts +0 -421
- package/src/workers/base-worker.ts +0 -304
- package/src/workers/daemon.ts +0 -264
- package/src/workers/index.ts +0 -119
- package/src/workers/interfaces.ts +0 -393
- package/src/workers/worker-manager.ts +0 -424
- package/src/workers/workers/compliance-checker.ts +0 -445
- package/src/workers/workers/coverage-tracker.ts +0 -344
- package/src/workers/workers/defect-predictor.ts +0 -375
- package/src/workers/workers/flaky-detector.ts +0 -390
- package/src/workers/workers/index.ts +0 -17
- package/src/workers/workers/learning-consolidation.ts +0 -442
- package/src/workers/workers/performance-baseline.ts +0 -434
- package/src/workers/workers/quality-gate.ts +0 -419
- package/src/workers/workers/regression-monitor.ts +0 -357
- package/src/workers/workers/security-scan.ts +0 -349
- package/src/workers/workers/test-health.ts +0 -359
- package/tests/integration/code-intelligence/knowledge-graph-real.test.ts +0 -540
- package/tests/integration/coordination/cross-domain-router.test.ts +0 -403
- package/tests/integration/coordination/protocol-executor.test.ts +0 -454
- package/tests/integration/coordination/workflow-orchestrator.test.ts +0 -418
- package/tests/integration/feedback/feedback-loop-integration.test.ts +0 -560
- package/tests/integration/migration/v2-to-v3-migration.test.ts +0 -471
- package/tests/integration/parsers/typescript-parser.test.ts +0 -463
- package/tests/integration/security/vulnerability-detection.test.ts +0 -628
- package/tests/integration/test-execution/coordinator.test.ts +0 -410
- package/tests/integration/test-generation/coordinator.test.ts +0 -361
- package/tests/mocks/index.ts +0 -228
- package/tests/time-crystal/default-phases.test.ts +0 -476
- package/tests/time-crystal/oscillator.test.ts +0 -541
- package/tests/time-crystal/phase-executor.test.ts +0 -653
- package/tests/time-crystal/scheduler.test.ts +0 -626
- package/tests/time-crystal/test-runner.test.ts +0 -594
- package/tests/unit/causal-discovery/causal-graph.test.ts +0 -504
- package/tests/unit/causal-discovery/causal-root-cause-analyzer.test.ts +0 -347
- package/tests/unit/causal-discovery/discovery-engine.test.ts +0 -435
- package/tests/unit/causal-discovery/weight-matrix.test.ts +0 -328
- package/tests/unit/cli/cli.test.ts +0 -341
- package/tests/unit/cli/commands.test.ts +0 -414
- package/tests/unit/cli/init-command.test.ts +0 -274
- package/tests/unit/cli/migrate-command.test.ts +0 -396
- package/tests/unit/coordination/claims/claim-service.test.ts +0 -949
- package/tests/unit/coordination/claims/handoff-manager.test.ts +0 -773
- package/tests/unit/coordination/claims/work-stealing.test.ts +0 -492
- package/tests/unit/coordination/queen-coordinator.test.ts +0 -966
- package/tests/unit/coordination/result-saver.test.ts +0 -653
- package/tests/unit/coordination/task-executor.test.ts +0 -810
- package/tests/unit/domains/chaos-resilience/chaos-engineer.test.ts +0 -484
- package/tests/unit/domains/chaos-resilience/load-tester.test.ts +0 -559
- package/tests/unit/domains/chaos-resilience/performance-profiler.test.ts +0 -490
- package/tests/unit/domains/code-intelligence/impact-analyzer.test.ts +0 -560
- package/tests/unit/domains/code-intelligence/knowledge-graph.test.ts +0 -460
- package/tests/unit/domains/code-intelligence/semantic-analyzer.test.ts +0 -584
- package/tests/unit/domains/contract-testing/api-compatibility.test.ts +0 -483
- package/tests/unit/domains/contract-testing/contract-validator.test.ts +0 -370
- package/tests/unit/domains/contract-testing/schema-validator.test.ts +0 -610
- package/tests/unit/domains/coverage-analysis/coverage-embedder.test.ts +0 -298
- package/tests/unit/domains/coverage-analysis/hnsw-index.test.ts +0 -292
- package/tests/unit/domains/coverage-analysis/sublinear-analyzer.test.ts +0 -506
- package/tests/unit/domains/defect-intelligence/defect-predictor.test.ts +0 -370
- package/tests/unit/domains/defect-intelligence/pattern-learner.test.ts +0 -546
- package/tests/unit/domains/defect-intelligence/root-cause-analyzer.test.ts +0 -534
- package/tests/unit/domains/learning-optimization/learning-coordinator.test.ts +0 -541
- package/tests/unit/domains/learning-optimization/metrics-optimizer.test.ts +0 -552
- package/tests/unit/domains/learning-optimization/production-intel.test.ts +0 -589
- package/tests/unit/domains/learning-optimization/transfer-specialist.test.ts +0 -453
- package/tests/unit/domains/quality-assessment/coherence-gate.test.ts +0 -1006
- package/tests/unit/domains/quality-assessment/deployment-advisor.test.ts +0 -515
- package/tests/unit/domains/quality-assessment/quality-analyzer.test.ts +0 -401
- package/tests/unit/domains/quality-assessment/quality-gate.test.ts +0 -324
- package/tests/unit/domains/requirements-validation/bdd-scenario-writer.test.ts +0 -479
- package/tests/unit/domains/requirements-validation/requirements-validator.test.ts +0 -452
- package/tests/unit/domains/requirements-validation/testability-scorer.test.ts +0 -505
- package/tests/unit/domains/security-compliance/compliance-validator.test.ts +0 -500
- package/tests/unit/domains/security-compliance/security-auditor.test.ts +0 -498
- package/tests/unit/domains/security-compliance/security-scanner.test.ts +0 -412
- package/tests/unit/domains/visual-accessibility/accessibility-tester.test.ts +0 -432
- package/tests/unit/domains/visual-accessibility/responsive-tester.test.ts +0 -506
- package/tests/unit/domains/visual-accessibility/visual-tester.test.ts +0 -412
- package/tests/unit/early-exit/early-exit-controller.test.ts +0 -548
- package/tests/unit/early-exit/early-exit-decision.test.ts +0 -617
- package/tests/unit/early-exit/index.test.ts +0 -254
- package/tests/unit/early-exit/quality-signal.test.ts +0 -589
- package/tests/unit/early-exit/speculative-executor.test.ts +0 -453
- package/tests/unit/feedback/coverage-learner.test.ts +0 -288
- package/tests/unit/feedback/feedback-loop.test.ts +0 -458
- package/tests/unit/feedback/pattern-promotion.test.ts +0 -390
- package/tests/unit/feedback/quality-score-calculator.test.ts +0 -364
- package/tests/unit/feedback/test-outcome-tracker.test.ts +0 -243
- package/tests/unit/init/init-wizard.test.ts +0 -881
- package/tests/unit/init/project-analyzer.test.ts +0 -807
- package/tests/unit/init/self-configurator.test.ts +0 -493
- package/tests/unit/integrations/ruvector/ast-complexity.test.ts +0 -240
- package/tests/unit/integrations/ruvector/coverage-router.test.ts +0 -366
- package/tests/unit/integrations/ruvector/diff-risk-classifier.test.ts +0 -340
- package/tests/unit/integrations/ruvector/graph-boundaries.test.ts +0 -355
- package/tests/unit/integrations/ruvector/q-learning-router.test.ts +0 -314
- package/tests/unit/kernel/agent-coordinator.test.ts +0 -220
- package/tests/unit/kernel/event-bus.test.ts +0 -197
- package/tests/unit/learning/qe-reasoning-bank.test.ts +0 -666
- package/tests/unit/learning/real-qe-reasoning-bank.benchmark.test.ts +0 -415
- package/tests/unit/mcp/mcp-server.test.ts +0 -544
- package/tests/unit/mcp/metrics/metrics-collector.test.ts +0 -340
- package/tests/unit/mcp/security/cve-prevention.test.ts +0 -512
- package/tests/unit/mcp/security/oauth21-provider.test.ts +0 -624
- package/tests/unit/mcp/security/rate-limiter.test.ts +0 -410
- package/tests/unit/mcp/security/sampling-server.test.ts +0 -420
- package/tests/unit/mcp/security/schema-validator.test.ts +0 -494
- package/tests/unit/mcp/tools/base.test.ts +0 -336
- package/tests/unit/mcp/tools/domain-tools.test.ts +0 -759
- package/tests/unit/mcp/tools/registry.test.ts +0 -240
- package/tests/unit/neural-optimizer/replay-buffer.test.ts +0 -403
- package/tests/unit/neural-optimizer/swarm-topology.test.ts +0 -473
- package/tests/unit/neural-optimizer/topology-optimizer.test.ts +0 -595
- package/tests/unit/neural-optimizer/value-network.test.ts +0 -343
- package/tests/unit/optimization/auto-tuner.test.ts +0 -506
- package/tests/unit/optimization/metric-collectors.test.ts +0 -352
- package/tests/unit/optimization/qe-workers.test.ts +0 -407
- package/tests/unit/optimization/tuning-algorithm.test.ts +0 -467
- package/tests/unit/routing/qe-agent-registry.test.ts +0 -229
- package/tests/unit/routing/qe-task-router.test.ts +0 -390
- package/tests/unit/routing/routing-feedback.test.ts +0 -339
- package/tests/unit/shared/embeddings/nomic-embedder.test.ts +0 -419
- package/tests/unit/shared/http/http-client.test.ts +0 -719
- package/tests/unit/shared/io/file-reader.test.ts +0 -511
- package/tests/unit/shared/llm/cache.test.ts +0 -391
- package/tests/unit/shared/llm/circuit-breaker.test.ts +0 -293
- package/tests/unit/shared/llm/cost-tracker.test.ts +0 -431
- package/tests/unit/shared/llm/provider-manager.test.ts +0 -550
- package/tests/unit/shared/llm/providers.test.ts +0 -532
- package/tests/unit/shared/parsers/typescript-parser.test.ts +0 -693
- package/tests/unit/shared/value-objects.test.ts +0 -184
- package/tests/unit/strange-loop/strange-loop.test.ts +0 -1170
- package/tests/unit/workers/base-worker.test.ts +0 -341
- package/tests/unit/workers/daemon.test.ts +0 -291
- package/tests/unit/workers/worker-manager.test.ts +0 -284
- package/tsconfig.json +0 -32
- package/vitest.config.ts +0 -27
|
@@ -1,1097 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agentic QE v3 - Chaos Engineering Service
|
|
3
|
-
* Implements IChaosEngineeringService for fault injection and experiment execution
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Result, ok, err } from '../../../shared/types';
|
|
7
|
-
import { HttpClient } from '../../../shared/http';
|
|
8
|
-
import {
|
|
9
|
-
SystemMetricsCollector,
|
|
10
|
-
getSystemMetricsCollector,
|
|
11
|
-
} from '../../../shared/metrics';
|
|
12
|
-
import { MemoryBackend } from '../../../kernel/interfaces';
|
|
13
|
-
import {
|
|
14
|
-
ChaosExperiment,
|
|
15
|
-
ExperimentResult,
|
|
16
|
-
ExperimentStatus,
|
|
17
|
-
SteadyStateDefinition,
|
|
18
|
-
SteadyStateProbe,
|
|
19
|
-
FaultInjection,
|
|
20
|
-
FaultResult,
|
|
21
|
-
FaultType,
|
|
22
|
-
MetricSnapshot,
|
|
23
|
-
Incident,
|
|
24
|
-
IChaosEngineeringService,
|
|
25
|
-
} from '../interfaces';
|
|
26
|
-
import * as net from 'net';
|
|
27
|
-
import { execFile } from 'child_process';
|
|
28
|
-
import { validateCommand } from '../../../mcp/security/cve-prevention';
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Configuration for the chaos engineer service
|
|
32
|
-
*/
|
|
33
|
-
export interface ChaosEngineerConfig {
|
|
34
|
-
defaultTimeout: number;
|
|
35
|
-
maxConcurrentFaults: number;
|
|
36
|
-
enableDryRun: boolean;
|
|
37
|
-
safetyCheckInterval: number;
|
|
38
|
-
autoRollbackOnFailure: boolean;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const DEFAULT_CONFIG: ChaosEngineerConfig = {
|
|
42
|
-
defaultTimeout: 60000, // 60 seconds
|
|
43
|
-
maxConcurrentFaults: 3,
|
|
44
|
-
enableDryRun: true,
|
|
45
|
-
safetyCheckInterval: 5000, // 5 seconds
|
|
46
|
-
autoRollbackOnFailure: true,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Mutable version of ExperimentResult for internal tracking
|
|
51
|
-
*/
|
|
52
|
-
interface MutableExperimentResult {
|
|
53
|
-
experimentId: string;
|
|
54
|
-
status: ExperimentStatus;
|
|
55
|
-
startTime: Date;
|
|
56
|
-
endTime?: Date;
|
|
57
|
-
hypothesisValidated: boolean;
|
|
58
|
-
steadyStateVerified: boolean;
|
|
59
|
-
faultResults: FaultResult[];
|
|
60
|
-
metrics: MetricSnapshot[];
|
|
61
|
-
incidents: Incident[];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Internal type for tracking experiment execution
|
|
66
|
-
*/
|
|
67
|
-
interface ExperimentExecution {
|
|
68
|
-
experimentId: string;
|
|
69
|
-
startTime: Date;
|
|
70
|
-
result: MutableExperimentResult;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Chaos Engineering Service Implementation
|
|
75
|
-
* Manages chaos experiments, fault injection, and steady state verification
|
|
76
|
-
*/
|
|
77
|
-
export class ChaosEngineerService implements IChaosEngineeringService {
|
|
78
|
-
private readonly config: ChaosEngineerConfig;
|
|
79
|
-
private readonly activeExperiments: Map<string, ExperimentExecution> = new Map();
|
|
80
|
-
private readonly activeFaults: Map<string, FaultInjection> = new Map();
|
|
81
|
-
private readonly httpClient: HttpClient;
|
|
82
|
-
private readonly metricsCollector: SystemMetricsCollector;
|
|
83
|
-
private readonly stressWorkers: Map<string, NodeJS.Timeout | number[]> = new Map();
|
|
84
|
-
|
|
85
|
-
constructor(
|
|
86
|
-
private readonly memory: MemoryBackend,
|
|
87
|
-
config: Partial<ChaosEngineerConfig> = {}
|
|
88
|
-
) {
|
|
89
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
90
|
-
this.httpClient = new HttpClient();
|
|
91
|
-
this.metricsCollector = getSystemMetricsCollector();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Create a new chaos experiment
|
|
96
|
-
*/
|
|
97
|
-
async createExperiment(experiment: ChaosExperiment): Promise<Result<string>> {
|
|
98
|
-
try {
|
|
99
|
-
// Validate experiment configuration
|
|
100
|
-
const validationResult = this.validateExperiment(experiment);
|
|
101
|
-
if (!validationResult.success) {
|
|
102
|
-
return err(validationResult.error);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Store experiment
|
|
106
|
-
await this.memory.set(
|
|
107
|
-
`chaos:experiments:${experiment.id}`,
|
|
108
|
-
experiment,
|
|
109
|
-
{ namespace: 'chaos-resilience', persist: true }
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
return ok(experiment.id);
|
|
113
|
-
} catch (error) {
|
|
114
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Run a chaos experiment
|
|
120
|
-
*/
|
|
121
|
-
async runExperiment(experimentId: string): Promise<Result<ExperimentResult>> {
|
|
122
|
-
try {
|
|
123
|
-
// Load experiment
|
|
124
|
-
const experiment = await this.memory.get<ChaosExperiment>(
|
|
125
|
-
`chaos:experiments:${experimentId}`
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
if (!experiment) {
|
|
129
|
-
return err(new Error(`Experiment not found: ${experimentId}`));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Check if experiment is already running
|
|
133
|
-
if (this.activeExperiments.has(experimentId)) {
|
|
134
|
-
return err(new Error(`Experiment ${experimentId} is already running`));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Create experiment execution
|
|
138
|
-
const execution = this.createExecution(experiment);
|
|
139
|
-
this.activeExperiments.set(experimentId, execution);
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
// Phase 1: Verify initial steady state
|
|
143
|
-
const steadyStateResult = await this.verifySteadyState(experiment.steadyState);
|
|
144
|
-
if (!steadyStateResult.success || !steadyStateResult.value) {
|
|
145
|
-
execution.result.steadyStateVerified = false;
|
|
146
|
-
execution.result.status = 'failed';
|
|
147
|
-
execution.result.incidents.push({
|
|
148
|
-
type: 'error',
|
|
149
|
-
severity: 'high',
|
|
150
|
-
message: 'Initial steady state verification failed',
|
|
151
|
-
timestamp: new Date(),
|
|
152
|
-
resolved: false,
|
|
153
|
-
});
|
|
154
|
-
return ok(this.finalizeExecution(execution));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
execution.result.steadyStateVerified = true;
|
|
158
|
-
|
|
159
|
-
// Phase 2: Inject faults
|
|
160
|
-
for (const fault of experiment.faults) {
|
|
161
|
-
const faultResult = await this.injectFault(fault);
|
|
162
|
-
if (faultResult.success) {
|
|
163
|
-
execution.result.faultResults.push(faultResult.value);
|
|
164
|
-
} else {
|
|
165
|
-
execution.result.faultResults.push({
|
|
166
|
-
faultId: fault.id,
|
|
167
|
-
injected: false,
|
|
168
|
-
duration: 0,
|
|
169
|
-
affectedTargets: 0,
|
|
170
|
-
errors: [faultResult.error.message],
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Phase 3: Monitor and collect metrics
|
|
176
|
-
await this.collectMetricsDuringExperiment(execution, experiment);
|
|
177
|
-
|
|
178
|
-
// Phase 4: Verify final steady state
|
|
179
|
-
const finalSteadyState = await this.verifySteadyState(experiment.steadyState);
|
|
180
|
-
const finalSteadyStateValue = finalSteadyState.success ? finalSteadyState.value : false;
|
|
181
|
-
|
|
182
|
-
// Phase 5: Validate hypothesis
|
|
183
|
-
execution.result.hypothesisValidated = this.validateHypothesis(
|
|
184
|
-
experiment.hypothesis,
|
|
185
|
-
execution.result.metrics
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
// Determine final status
|
|
189
|
-
execution.result.status = this.determineExperimentStatus(execution, finalSteadyStateValue);
|
|
190
|
-
|
|
191
|
-
// Phase 6: Clean up faults
|
|
192
|
-
for (const fault of experiment.faults) {
|
|
193
|
-
await this.removeFault(fault.id);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return ok(this.finalizeExecution(execution));
|
|
197
|
-
} catch (error) {
|
|
198
|
-
// Handle unexpected errors
|
|
199
|
-
execution.result.status = 'failed';
|
|
200
|
-
execution.result.incidents.push({
|
|
201
|
-
type: 'error',
|
|
202
|
-
severity: 'critical',
|
|
203
|
-
message: error instanceof Error ? error.message : String(error),
|
|
204
|
-
timestamp: new Date(),
|
|
205
|
-
resolved: false,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Attempt rollback
|
|
209
|
-
if (this.config.autoRollbackOnFailure) {
|
|
210
|
-
await this.rollbackExperiment(experiment);
|
|
211
|
-
execution.result.status = 'rolled-back';
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return ok(this.finalizeExecution(execution));
|
|
215
|
-
} finally {
|
|
216
|
-
this.activeExperiments.delete(experimentId);
|
|
217
|
-
}
|
|
218
|
-
} catch (error) {
|
|
219
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Abort a running experiment
|
|
225
|
-
*/
|
|
226
|
-
async abortExperiment(experimentId: string, reason: string): Promise<Result<void>> {
|
|
227
|
-
try {
|
|
228
|
-
const execution = this.activeExperiments.get(experimentId);
|
|
229
|
-
if (!execution) {
|
|
230
|
-
return err(new Error(`No active experiment found: ${experimentId}`));
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
execution.result.status = 'aborted';
|
|
234
|
-
execution.result.incidents.push({
|
|
235
|
-
type: 'alert',
|
|
236
|
-
severity: 'medium',
|
|
237
|
-
message: `Experiment aborted: ${reason}`,
|
|
238
|
-
timestamp: new Date(),
|
|
239
|
-
resolved: true,
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Remove all active faults for this experiment
|
|
243
|
-
const experiment = await this.memory.get<ChaosExperiment>(
|
|
244
|
-
`chaos:experiments:${experimentId}`
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
if (experiment) {
|
|
248
|
-
for (const fault of experiment.faults) {
|
|
249
|
-
await this.removeFault(fault.id);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return ok(undefined);
|
|
254
|
-
} catch (error) {
|
|
255
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Verify steady state conditions
|
|
261
|
-
*/
|
|
262
|
-
async verifySteadyState(definition: SteadyStateDefinition): Promise<Result<boolean>> {
|
|
263
|
-
try {
|
|
264
|
-
const probeResults: boolean[] = [];
|
|
265
|
-
|
|
266
|
-
for (const probe of definition.probes) {
|
|
267
|
-
const result = await this.executeProbe(probe);
|
|
268
|
-
probeResults.push(result);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// All probes must pass
|
|
272
|
-
const allPassed = probeResults.every((r) => r);
|
|
273
|
-
|
|
274
|
-
return ok(allPassed);
|
|
275
|
-
} catch (error) {
|
|
276
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Inject a single fault
|
|
282
|
-
*/
|
|
283
|
-
async injectFault(fault: FaultInjection): Promise<Result<FaultResult>> {
|
|
284
|
-
try {
|
|
285
|
-
// Check concurrent fault limit
|
|
286
|
-
if (this.activeFaults.size >= this.config.maxConcurrentFaults) {
|
|
287
|
-
return err(new Error(`Maximum concurrent faults (${this.config.maxConcurrentFaults}) reached`));
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Validate fault configuration
|
|
291
|
-
const validationResult = this.validateFault(fault);
|
|
292
|
-
if (!validationResult.success) {
|
|
293
|
-
return err(validationResult.error);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const startTime = Date.now();
|
|
297
|
-
|
|
298
|
-
// Apply probability check
|
|
299
|
-
if (fault.probability !== undefined && Math.random() > fault.probability) {
|
|
300
|
-
return ok({
|
|
301
|
-
faultId: fault.id,
|
|
302
|
-
injected: false,
|
|
303
|
-
duration: 0,
|
|
304
|
-
affectedTargets: 0,
|
|
305
|
-
errors: ['Skipped due to probability check'],
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Inject fault based on type
|
|
310
|
-
const injectionResult = await this.performFaultInjection(fault);
|
|
311
|
-
|
|
312
|
-
if (injectionResult.success) {
|
|
313
|
-
this.activeFaults.set(fault.id, fault);
|
|
314
|
-
|
|
315
|
-
// Schedule automatic removal if duration is specified
|
|
316
|
-
if (fault.duration > 0) {
|
|
317
|
-
setTimeout(() => {
|
|
318
|
-
this.removeFault(fault.id);
|
|
319
|
-
}, fault.duration);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return ok({
|
|
323
|
-
faultId: fault.id,
|
|
324
|
-
injected: true,
|
|
325
|
-
duration: Date.now() - startTime,
|
|
326
|
-
affectedTargets: injectionResult.value,
|
|
327
|
-
errors: [],
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return ok({
|
|
332
|
-
faultId: fault.id,
|
|
333
|
-
injected: false,
|
|
334
|
-
duration: Date.now() - startTime,
|
|
335
|
-
affectedTargets: 0,
|
|
336
|
-
errors: [injectionResult.error.message],
|
|
337
|
-
});
|
|
338
|
-
} catch (error) {
|
|
339
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Remove an injected fault
|
|
345
|
-
*/
|
|
346
|
-
async removeFault(faultId: string): Promise<Result<void>> {
|
|
347
|
-
try {
|
|
348
|
-
const fault = this.activeFaults.get(faultId);
|
|
349
|
-
if (!fault) {
|
|
350
|
-
return ok(undefined); // Already removed
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Remove fault based on type
|
|
354
|
-
await this.performFaultRemoval(fault);
|
|
355
|
-
|
|
356
|
-
this.activeFaults.delete(faultId);
|
|
357
|
-
|
|
358
|
-
return ok(undefined);
|
|
359
|
-
} catch (error) {
|
|
360
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// ============================================================================
|
|
365
|
-
// Private Helper Methods
|
|
366
|
-
// ============================================================================
|
|
367
|
-
|
|
368
|
-
private validateExperiment(experiment: ChaosExperiment): Result<void> {
|
|
369
|
-
if (!experiment.id) {
|
|
370
|
-
return err(new Error('Experiment ID is required'));
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (!experiment.name) {
|
|
374
|
-
return err(new Error('Experiment name is required'));
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (!experiment.hypothesis) {
|
|
378
|
-
return err(new Error('Experiment hypothesis is required'));
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (!experiment.steadyState || experiment.steadyState.probes.length === 0) {
|
|
382
|
-
return err(new Error('At least one steady state probe is required'));
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (!experiment.faults || experiment.faults.length === 0) {
|
|
386
|
-
return err(new Error('At least one fault injection is required'));
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (!experiment.rollbackPlan) {
|
|
390
|
-
return err(new Error('Rollback plan is required'));
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Validate blast radius
|
|
394
|
-
if (experiment.blastRadius.excludeProduction === false) {
|
|
395
|
-
// Additional checks for production experiments
|
|
396
|
-
if (!experiment.rollbackPlan.automatic) {
|
|
397
|
-
return err(new Error('Production experiments require automatic rollback'));
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return ok(undefined);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
private validateFault(fault: FaultInjection): Result<void> {
|
|
405
|
-
if (!fault.id) {
|
|
406
|
-
return err(new Error('Fault ID is required'));
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (!fault.type) {
|
|
410
|
-
return err(new Error('Fault type is required'));
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (!fault.target) {
|
|
414
|
-
return err(new Error('Fault target is required'));
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (fault.duration < 0) {
|
|
418
|
-
return err(new Error('Fault duration must be non-negative'));
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (fault.probability !== undefined && (fault.probability < 0 || fault.probability > 1)) {
|
|
422
|
-
return err(new Error('Fault probability must be between 0 and 1'));
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
return ok(undefined);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
private createExecution(experiment: ChaosExperiment): ExperimentExecution {
|
|
429
|
-
return {
|
|
430
|
-
experimentId: experiment.id,
|
|
431
|
-
startTime: new Date(),
|
|
432
|
-
result: {
|
|
433
|
-
experimentId: experiment.id,
|
|
434
|
-
status: 'running',
|
|
435
|
-
startTime: new Date(),
|
|
436
|
-
hypothesisValidated: false,
|
|
437
|
-
steadyStateVerified: false,
|
|
438
|
-
faultResults: [],
|
|
439
|
-
metrics: [],
|
|
440
|
-
incidents: [],
|
|
441
|
-
},
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
private finalizeExecution(execution: ExperimentExecution): ExperimentResult {
|
|
446
|
-
execution.result.endTime = new Date();
|
|
447
|
-
|
|
448
|
-
// Convert mutable result to readonly ExperimentResult
|
|
449
|
-
const result: ExperimentResult = {
|
|
450
|
-
experimentId: execution.result.experimentId,
|
|
451
|
-
status: execution.result.status,
|
|
452
|
-
startTime: execution.result.startTime,
|
|
453
|
-
endTime: execution.result.endTime,
|
|
454
|
-
hypothesisValidated: execution.result.hypothesisValidated,
|
|
455
|
-
steadyStateVerified: execution.result.steadyStateVerified,
|
|
456
|
-
faultResults: execution.result.faultResults,
|
|
457
|
-
metrics: execution.result.metrics,
|
|
458
|
-
incidents: execution.result.incidents,
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
// Store result in memory
|
|
462
|
-
this.memory.set(
|
|
463
|
-
`chaos:results:${execution.experimentId}:${Date.now()}`,
|
|
464
|
-
result,
|
|
465
|
-
{ namespace: 'chaos-resilience', persist: true }
|
|
466
|
-
);
|
|
467
|
-
|
|
468
|
-
return result;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
private async executeProbe(probe: SteadyStateProbe): Promise<boolean> {
|
|
472
|
-
try {
|
|
473
|
-
// Execute the appropriate probe type based on configuration
|
|
474
|
-
switch (probe.type) {
|
|
475
|
-
case 'http':
|
|
476
|
-
return await this.executeHttpProbe(probe);
|
|
477
|
-
case 'tcp':
|
|
478
|
-
return await this.executeTcpProbe(probe);
|
|
479
|
-
case 'command':
|
|
480
|
-
return await this.executeCommandProbe(probe);
|
|
481
|
-
case 'metric':
|
|
482
|
-
return await this.executeMetricProbe(probe);
|
|
483
|
-
default:
|
|
484
|
-
return false;
|
|
485
|
-
}
|
|
486
|
-
} catch {
|
|
487
|
-
return false;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
private async executeHttpProbe(probe: SteadyStateProbe): Promise<boolean> {
|
|
492
|
-
try {
|
|
493
|
-
const result = await this.httpClient.get(probe.target, {
|
|
494
|
-
timeout: probe.timeout ?? 5000,
|
|
495
|
-
retries: 1,
|
|
496
|
-
circuitBreaker: false,
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
if (!result.success) {
|
|
500
|
-
console.log(`HTTP probe failed: ${probe.name} -> ${result.error.message}`);
|
|
501
|
-
return false;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
const response = result.value;
|
|
505
|
-
|
|
506
|
-
// Check expected status if specified
|
|
507
|
-
if (probe.expectedStatus !== undefined) {
|
|
508
|
-
const passed = response.status === probe.expectedStatus;
|
|
509
|
-
if (!passed) {
|
|
510
|
-
console.log(`HTTP probe ${probe.name}: expected status ${probe.expectedStatus}, got ${response.status}`);
|
|
511
|
-
}
|
|
512
|
-
return passed;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Default: any 2xx status is success
|
|
516
|
-
return response.ok;
|
|
517
|
-
} catch (error) {
|
|
518
|
-
console.log(`HTTP probe error: ${probe.name} -> ${error instanceof Error ? error.message : String(error)}`);
|
|
519
|
-
return false;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
private async executeTcpProbe(probe: SteadyStateProbe): Promise<boolean> {
|
|
524
|
-
return new Promise((resolve) => {
|
|
525
|
-
try {
|
|
526
|
-
// Parse target as host:port
|
|
527
|
-
const [host, portStr] = probe.target.split(':');
|
|
528
|
-
const port = parseInt(portStr, 10);
|
|
529
|
-
|
|
530
|
-
if (!host || isNaN(port)) {
|
|
531
|
-
console.log(`TCP probe invalid target: ${probe.target} (expected host:port)`);
|
|
532
|
-
resolve(false);
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
const timeout = probe.timeout ?? 5000;
|
|
537
|
-
const socket = new net.Socket();
|
|
538
|
-
|
|
539
|
-
const timer = setTimeout(() => {
|
|
540
|
-
socket.destroy();
|
|
541
|
-
console.log(`TCP probe timeout: ${probe.name} -> ${probe.target}`);
|
|
542
|
-
resolve(false);
|
|
543
|
-
}, timeout);
|
|
544
|
-
|
|
545
|
-
socket.connect(port, host, () => {
|
|
546
|
-
clearTimeout(timer);
|
|
547
|
-
socket.destroy();
|
|
548
|
-
resolve(true);
|
|
549
|
-
});
|
|
550
|
-
|
|
551
|
-
socket.on('error', (err) => {
|
|
552
|
-
clearTimeout(timer);
|
|
553
|
-
socket.destroy();
|
|
554
|
-
console.log(`TCP probe error: ${probe.name} -> ${err.message}`);
|
|
555
|
-
resolve(false);
|
|
556
|
-
});
|
|
557
|
-
} catch (error) {
|
|
558
|
-
console.log(`TCP probe exception: ${probe.name} -> ${error instanceof Error ? error.message : String(error)}`);
|
|
559
|
-
resolve(false);
|
|
560
|
-
}
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Allowed commands for chaos probes (security whitelist)
|
|
566
|
-
*/
|
|
567
|
-
private static readonly ALLOWED_PROBE_COMMANDS = [
|
|
568
|
-
'curl', 'wget', // Health check endpoints
|
|
569
|
-
'nc', 'netcat', // Network connectivity
|
|
570
|
-
'ping', // Network reachability
|
|
571
|
-
'nslookup', 'dig', // DNS checks
|
|
572
|
-
'ps', 'pgrep', // Process checks
|
|
573
|
-
'cat', 'head', 'tail', // File content checks
|
|
574
|
-
'ls', 'stat', // File system checks
|
|
575
|
-
'echo', // Simple output
|
|
576
|
-
'test', '[', // Conditional checks
|
|
577
|
-
'node', 'npm', // Node.js checks
|
|
578
|
-
];
|
|
579
|
-
|
|
580
|
-
private async executeCommandProbe(probe: SteadyStateProbe): Promise<boolean> {
|
|
581
|
-
return new Promise((resolve) => {
|
|
582
|
-
const timeout = probe.timeout ?? 10000;
|
|
583
|
-
|
|
584
|
-
// Validate command against whitelist to prevent injection (CWE-78)
|
|
585
|
-
const validation = validateCommand(probe.target, ChaosEngineerService.ALLOWED_PROBE_COMMANDS);
|
|
586
|
-
if (!validation.valid) {
|
|
587
|
-
console.log(`Command probe ${probe.name} blocked: ${validation.error}`);
|
|
588
|
-
console.log(`Blocked patterns: ${validation.blockedPatterns?.join(', ') || 'none'}`);
|
|
589
|
-
resolve(false);
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// Parse command into executable and arguments
|
|
594
|
-
const sanitizedCommand = validation.sanitizedCommand || probe.target;
|
|
595
|
-
const parts = sanitizedCommand.trim().split(/\s+/);
|
|
596
|
-
const executable = parts[0];
|
|
597
|
-
const args = parts.slice(1);
|
|
598
|
-
|
|
599
|
-
// Use execFile instead of exec to avoid shell interpretation
|
|
600
|
-
execFile(executable, args, { timeout }, (error, stdout, _stderr) => {
|
|
601
|
-
if (error) {
|
|
602
|
-
console.log(`Command probe failed: ${probe.name} -> ${error.message}`);
|
|
603
|
-
resolve(false);
|
|
604
|
-
return;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
// Check expected output if specified
|
|
608
|
-
if (probe.expectedOutput !== undefined) {
|
|
609
|
-
const passed = stdout.trim().includes(probe.expectedOutput);
|
|
610
|
-
if (!passed) {
|
|
611
|
-
console.log(`Command probe ${probe.name}: output did not contain expected value`);
|
|
612
|
-
}
|
|
613
|
-
resolve(passed);
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// Default: exit code 0 is success (no error)
|
|
618
|
-
resolve(true);
|
|
619
|
-
});
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
private async executeMetricProbe(probe: SteadyStateProbe): Promise<boolean> {
|
|
624
|
-
try {
|
|
625
|
-
// Query metrics endpoint (expects JSON response with 'value' field)
|
|
626
|
-
const result = await this.httpClient.get(probe.target, {
|
|
627
|
-
timeout: probe.timeout ?? 5000,
|
|
628
|
-
retries: 1,
|
|
629
|
-
circuitBreaker: false,
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
if (!result.success) {
|
|
633
|
-
console.log(`Metric probe failed: ${probe.name} -> ${result.error.message}`);
|
|
634
|
-
return false;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
const response = result.value;
|
|
638
|
-
if (!response.ok) {
|
|
639
|
-
console.log(`Metric probe HTTP error: ${probe.name} -> ${response.status}`);
|
|
640
|
-
return false;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Parse response body for metric value
|
|
644
|
-
const text = await response.text();
|
|
645
|
-
let metricValue: number;
|
|
646
|
-
|
|
647
|
-
try {
|
|
648
|
-
const json = JSON.parse(text);
|
|
649
|
-
metricValue = typeof json.value === 'number' ? json.value : parseFloat(json.value);
|
|
650
|
-
} catch {
|
|
651
|
-
// Try parsing as plain number
|
|
652
|
-
metricValue = parseFloat(text);
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
if (isNaN(metricValue)) {
|
|
656
|
-
console.log(`Metric probe ${probe.name}: could not parse metric value from response`);
|
|
657
|
-
return false;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
// Check threshold if specified
|
|
661
|
-
if (probe.threshold !== undefined) {
|
|
662
|
-
const { operator, value } = probe.threshold;
|
|
663
|
-
switch (operator) {
|
|
664
|
-
case 'lt': return metricValue < value;
|
|
665
|
-
case 'gt': return metricValue > value;
|
|
666
|
-
case 'lte': return metricValue <= value;
|
|
667
|
-
case 'gte': return metricValue >= value;
|
|
668
|
-
case 'eq': return metricValue === value;
|
|
669
|
-
default: return true;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
return true;
|
|
674
|
-
} catch (error) {
|
|
675
|
-
console.log(`Metric probe error: ${probe.name} -> ${error instanceof Error ? error.message : String(error)}`);
|
|
676
|
-
return false;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
private async performFaultInjection(fault: FaultInjection): Promise<Result<number>> {
|
|
681
|
-
const faultHandlers: Record<FaultType, () => Promise<Result<number>>> = {
|
|
682
|
-
'latency': async () => this.injectLatency(fault),
|
|
683
|
-
'error': async () => this.injectError(fault),
|
|
684
|
-
'timeout': async () => this.injectTimeout(fault),
|
|
685
|
-
'packet-loss': async () => this.injectPacketLoss(fault),
|
|
686
|
-
'cpu-stress': async () => this.injectCpuStress(fault),
|
|
687
|
-
'memory-stress': async () => this.injectMemoryStress(fault),
|
|
688
|
-
'disk-stress': async () => this.injectDiskStress(fault),
|
|
689
|
-
'network-partition': async () => this.injectNetworkPartition(fault),
|
|
690
|
-
'dns-failure': async () => this.injectDnsFailure(fault),
|
|
691
|
-
'process-kill': async () => this.injectProcessKill(fault),
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
const handler = faultHandlers[fault.type];
|
|
695
|
-
if (handler) {
|
|
696
|
-
return handler();
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
return err(new Error(`Unknown fault type: ${fault.type}`));
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
private async injectLatency(fault: FaultInjection): Promise<Result<number>> {
|
|
703
|
-
// Latency injection is typically done at proxy/network level
|
|
704
|
-
// For simulation, we store the config and check during probe execution
|
|
705
|
-
const latencyMs = fault.parameters.latencyMs ?? 100;
|
|
706
|
-
console.log(`Latency injection configured: ${latencyMs}ms for ${fault.target.selector}`);
|
|
707
|
-
console.log(`Note: Actual latency injection requires network proxy (e.g., Toxiproxy, tc)`);
|
|
708
|
-
return ok(1);
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
private async injectError(fault: FaultInjection): Promise<Result<number>> {
|
|
712
|
-
// Error injection typically requires proxy/service mesh
|
|
713
|
-
const errorCode = fault.parameters.errorCode ?? 500;
|
|
714
|
-
console.log(`Error injection configured: ${errorCode} for ${fault.target.selector}`);
|
|
715
|
-
console.log(`Note: Actual error injection requires service mesh (e.g., Istio, Linkerd)`);
|
|
716
|
-
return ok(1);
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
private async injectTimeout(fault: FaultInjection): Promise<Result<number>> {
|
|
720
|
-
// Timeout injection via proxy configuration
|
|
721
|
-
console.log(`Timeout injection configured for ${fault.target.selector}`);
|
|
722
|
-
console.log(`Note: Actual timeout injection requires network proxy configuration`);
|
|
723
|
-
return ok(1);
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
private async injectPacketLoss(fault: FaultInjection): Promise<Result<number>> {
|
|
727
|
-
const lossPercent = fault.parameters.packetLossPercent ?? 10;
|
|
728
|
-
console.log(`Packet loss configured: ${lossPercent}% for ${fault.target.selector}`);
|
|
729
|
-
console.log(`Note: Actual packet loss requires tc/iptables (Linux) or similar`);
|
|
730
|
-
return ok(1);
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
private async injectCpuStress(fault: FaultInjection): Promise<Result<number>> {
|
|
734
|
-
// Real CPU stress implementation using busy loops
|
|
735
|
-
const cpuPercent = fault.parameters.cpuPercent ?? 80;
|
|
736
|
-
const cores = fault.parameters.cores ?? 1;
|
|
737
|
-
const duration = fault.duration;
|
|
738
|
-
|
|
739
|
-
console.log(`Injecting CPU stress: ${cpuPercent}% on ${cores} core(s) for ${duration}ms`);
|
|
740
|
-
|
|
741
|
-
// Create CPU-intensive work
|
|
742
|
-
const startTime = Date.now();
|
|
743
|
-
const workInterval = setInterval(() => {
|
|
744
|
-
if (Date.now() - startTime >= duration) {
|
|
745
|
-
clearInterval(workInterval);
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
// Busy work based on target CPU percentage
|
|
750
|
-
const busyTime = 10 * (cpuPercent / 100);
|
|
751
|
-
|
|
752
|
-
const busyStart = Date.now();
|
|
753
|
-
while (Date.now() - busyStart < busyTime) {
|
|
754
|
-
// Busy loop - CPU intensive operations
|
|
755
|
-
Math.random() * Math.random();
|
|
756
|
-
}
|
|
757
|
-
// Note: Idle time is handled by the interval itself (10ms interval)
|
|
758
|
-
// In real implementation, this would use worker threads for true parallelism
|
|
759
|
-
}, 10);
|
|
760
|
-
|
|
761
|
-
this.stressWorkers.set(fault.id, workInterval);
|
|
762
|
-
|
|
763
|
-
return ok(cores as number);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
private async injectMemoryStress(fault: FaultInjection): Promise<Result<number>> {
|
|
767
|
-
// Real memory stress implementation by allocating buffers
|
|
768
|
-
const memoryBytes = fault.parameters.memoryBytes ?? 1024 * 1024 * 100; // 100MB default
|
|
769
|
-
const memoryMB = Math.round(memoryBytes / (1024 * 1024));
|
|
770
|
-
|
|
771
|
-
console.log(`Injecting memory stress: ${memoryMB}MB allocation`);
|
|
772
|
-
|
|
773
|
-
try {
|
|
774
|
-
// Allocate memory in chunks to avoid single large allocation issues
|
|
775
|
-
const chunkSize = 1024 * 1024; // 1MB chunks
|
|
776
|
-
const chunks = Math.ceil(memoryBytes / chunkSize);
|
|
777
|
-
const allocatedMemory: number[][] = [];
|
|
778
|
-
|
|
779
|
-
for (let i = 0; i < chunks; i++) {
|
|
780
|
-
const size = Math.min(chunkSize, memoryBytes - (i * chunkSize));
|
|
781
|
-
// Use Array to allocate memory that won't be easily garbage collected
|
|
782
|
-
const chunk = new Array(size).fill(Math.random());
|
|
783
|
-
allocatedMemory.push(chunk);
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
// Store reference to prevent garbage collection
|
|
787
|
-
this.stressWorkers.set(fault.id, allocatedMemory as unknown as number[]);
|
|
788
|
-
|
|
789
|
-
console.log(`Memory stress active: ${allocatedMemory.length} chunks allocated`);
|
|
790
|
-
return ok(1);
|
|
791
|
-
} catch (error) {
|
|
792
|
-
return err(new Error(`Failed to allocate memory: ${error instanceof Error ? error.message : String(error)}`));
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
private async injectDiskStress(fault: FaultInjection): Promise<Result<number>> {
|
|
797
|
-
// Disk stress would require file system operations
|
|
798
|
-
console.log(`Disk stress configured for ${fault.target.selector}`);
|
|
799
|
-
console.log(`Note: Actual disk stress requires file system write permissions`);
|
|
800
|
-
return ok(1);
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
private async injectNetworkPartition(fault: FaultInjection): Promise<Result<number>> {
|
|
804
|
-
// Network partition typically requires iptables or similar
|
|
805
|
-
console.log(`Network partition configured for ${fault.target.selector}`);
|
|
806
|
-
console.log(`Note: Actual network partition requires iptables/firewall rules`);
|
|
807
|
-
return ok(1);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
private async injectDnsFailure(fault: FaultInjection): Promise<Result<number>> {
|
|
811
|
-
// DNS failure injection via /etc/hosts or DNS server configuration
|
|
812
|
-
console.log(`DNS failure configured for ${fault.target.selector}`);
|
|
813
|
-
console.log(`Note: Actual DNS failure requires DNS server or /etc/hosts modification`);
|
|
814
|
-
return ok(1);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
private async injectProcessKill(fault: FaultInjection): Promise<Result<number>> {
|
|
818
|
-
// Process kill via system commands
|
|
819
|
-
const processPattern = fault.target.selector;
|
|
820
|
-
console.log(`Process kill configured for pattern: ${processPattern}`);
|
|
821
|
-
console.log(`Note: Actual process kill requires appropriate permissions`);
|
|
822
|
-
|
|
823
|
-
// In dry-run mode or without permissions, just log
|
|
824
|
-
if (this.config.enableDryRun) {
|
|
825
|
-
console.log(`[DRY RUN] Would kill processes matching: ${processPattern}`);
|
|
826
|
-
return ok(0);
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
return ok(1);
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
private async performFaultRemoval(fault: FaultInjection): Promise<void> {
|
|
833
|
-
console.log(`Removing fault: ${fault.id} (${fault.type})`);
|
|
834
|
-
|
|
835
|
-
// Clean up any active stress workers
|
|
836
|
-
const worker = this.stressWorkers.get(fault.id);
|
|
837
|
-
if (worker) {
|
|
838
|
-
if (typeof worker === 'object' && 'unref' in worker) {
|
|
839
|
-
// It's a timeout/interval
|
|
840
|
-
clearInterval(worker as NodeJS.Timeout);
|
|
841
|
-
}
|
|
842
|
-
// Memory allocations will be garbage collected when reference is removed
|
|
843
|
-
this.stressWorkers.delete(fault.id);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
private async collectMetricsDuringExperiment(
|
|
848
|
-
execution: ExperimentExecution,
|
|
849
|
-
experiment: ChaosExperiment
|
|
850
|
-
): Promise<void> {
|
|
851
|
-
const metricsToCollect = experiment.hypothesis.metrics.map((m) => m.metric);
|
|
852
|
-
const startTime = Date.now();
|
|
853
|
-
const duration = Math.max(
|
|
854
|
-
...experiment.faults.map((f) => f.duration),
|
|
855
|
-
this.config.defaultTimeout
|
|
856
|
-
);
|
|
857
|
-
|
|
858
|
-
// Collect real metrics during experiment execution
|
|
859
|
-
while (Date.now() - startTime < Math.min(duration, 5000)) {
|
|
860
|
-
for (const metric of metricsToCollect) {
|
|
861
|
-
const snapshot: MetricSnapshot = {
|
|
862
|
-
timestamp: new Date(),
|
|
863
|
-
name: metric,
|
|
864
|
-
value: this.collectRealMetricValue(metric),
|
|
865
|
-
labels: { experiment: experiment.id },
|
|
866
|
-
};
|
|
867
|
-
execution.result.metrics.push(snapshot);
|
|
868
|
-
}
|
|
869
|
-
await this.sleep(this.config.safetyCheckInterval);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
private collectRealMetricValue(metric: string): number {
|
|
874
|
-
// Collect real system metrics using SystemMetricsCollector
|
|
875
|
-
return this.metricsCollector.getChaosMetricValue(metric);
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
private validateHypothesis(
|
|
879
|
-
hypothesis: ChaosExperiment['hypothesis'],
|
|
880
|
-
metrics: MetricSnapshot[]
|
|
881
|
-
): boolean {
|
|
882
|
-
// Check each metric expectation
|
|
883
|
-
for (const expectation of hypothesis.metrics) {
|
|
884
|
-
const relevantMetrics = metrics.filter((m) => m.name === expectation.metric);
|
|
885
|
-
|
|
886
|
-
if (relevantMetrics.length === 0) {
|
|
887
|
-
return false; // Missing metric data
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
const avgValue =
|
|
891
|
-
relevantMetrics.reduce((sum, m) => sum + m.value, 0) / relevantMetrics.length;
|
|
892
|
-
|
|
893
|
-
if (!this.checkMetricExpectation(avgValue, expectation)) {
|
|
894
|
-
return false;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
// Check tolerances
|
|
899
|
-
for (const tolerance of hypothesis.tolerances) {
|
|
900
|
-
const relevantMetrics = metrics.filter((m) => m.name === tolerance.metric);
|
|
901
|
-
|
|
902
|
-
if (relevantMetrics.length === 0) continue;
|
|
903
|
-
|
|
904
|
-
const values = relevantMetrics.map((m) => m.value);
|
|
905
|
-
const deviation = this.calculateDeviation(values);
|
|
906
|
-
|
|
907
|
-
const maxAllowed =
|
|
908
|
-
tolerance.unit === 'percent'
|
|
909
|
-
? (deviation / values[0]) * 100
|
|
910
|
-
: deviation;
|
|
911
|
-
|
|
912
|
-
if (maxAllowed > tolerance.maxDeviation) {
|
|
913
|
-
return false;
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
return true;
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
private checkMetricExpectation(
|
|
921
|
-
actual: number,
|
|
922
|
-
expectation: ChaosExperiment['hypothesis']['metrics'][0]
|
|
923
|
-
): boolean {
|
|
924
|
-
const { operator, value } = expectation;
|
|
925
|
-
|
|
926
|
-
switch (operator) {
|
|
927
|
-
case 'eq':
|
|
928
|
-
return actual === value;
|
|
929
|
-
case 'lt':
|
|
930
|
-
return actual < (value as number);
|
|
931
|
-
case 'gt':
|
|
932
|
-
return actual > (value as number);
|
|
933
|
-
case 'lte':
|
|
934
|
-
return actual <= (value as number);
|
|
935
|
-
case 'gte':
|
|
936
|
-
return actual >= (value as number);
|
|
937
|
-
case 'between':
|
|
938
|
-
const [min, max] = value as [number, number];
|
|
939
|
-
return actual >= min && actual <= max;
|
|
940
|
-
default:
|
|
941
|
-
return false;
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
private calculateDeviation(values: number[]): number {
|
|
946
|
-
if (values.length === 0) return 0;
|
|
947
|
-
const avg = values.reduce((a, b) => a + b, 0) / values.length;
|
|
948
|
-
const squaredDiffs = values.map((v) => Math.pow(v - avg, 2));
|
|
949
|
-
return Math.sqrt(squaredDiffs.reduce((a, b) => a + b, 0) / values.length);
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
private determineExperimentStatus(
|
|
953
|
-
execution: ExperimentExecution,
|
|
954
|
-
finalSteadyState: boolean
|
|
955
|
-
): ExperimentStatus {
|
|
956
|
-
if (!execution.result.steadyStateVerified) {
|
|
957
|
-
return 'failed';
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
if (!finalSteadyState) {
|
|
961
|
-
return 'failed';
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
if (execution.result.hypothesisValidated) {
|
|
965
|
-
return 'completed';
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// Check if any faults failed to inject
|
|
969
|
-
const failedFaults = execution.result.faultResults.filter((f) => !f.injected);
|
|
970
|
-
if (failedFaults.length > 0) {
|
|
971
|
-
return 'failed';
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
return 'completed';
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
private async rollbackExperiment(experiment: ChaosExperiment): Promise<void> {
|
|
978
|
-
// Execute rollback steps in order
|
|
979
|
-
for (const step of experiment.rollbackPlan.steps.sort((a, b) => a.order - b.order)) {
|
|
980
|
-
console.log(`Executing rollback step ${step.order}: ${step.action}`);
|
|
981
|
-
|
|
982
|
-
try {
|
|
983
|
-
await this.executeRollbackAction(step.action, step.target, step.timeout);
|
|
984
|
-
} catch (error) {
|
|
985
|
-
console.error(
|
|
986
|
-
`Rollback step ${step.order} failed: ${error instanceof Error ? error.message : String(error)}`
|
|
987
|
-
);
|
|
988
|
-
// Continue with other rollback steps even if one fails
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
// Remove all active faults
|
|
993
|
-
for (const fault of experiment.faults) {
|
|
994
|
-
await this.removeFault(fault.id);
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
private async executeRollbackAction(
|
|
999
|
-
action: string,
|
|
1000
|
-
target?: string,
|
|
1001
|
-
timeout: number = 30000
|
|
1002
|
-
): Promise<void> {
|
|
1003
|
-
// Determine action type and execute accordingly
|
|
1004
|
-
if (action.startsWith('http://') || action.startsWith('https://')) {
|
|
1005
|
-
// HTTP endpoint rollback
|
|
1006
|
-
await this.executeHttpRollback(action, timeout);
|
|
1007
|
-
} else if (action.startsWith('cmd:')) {
|
|
1008
|
-
// Command-based rollback
|
|
1009
|
-
await this.executeCommandRollback(action.slice(4), timeout);
|
|
1010
|
-
} else if (target && (target.startsWith('http://') || target.startsWith('https://'))) {
|
|
1011
|
-
// HTTP target with action name
|
|
1012
|
-
await this.executeHttpRollback(`${target}/_chaos/${action}`, timeout);
|
|
1013
|
-
} else {
|
|
1014
|
-
// Built-in action or description-only step
|
|
1015
|
-
await this.executeBuiltInRollback(action, target, timeout);
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
private async executeHttpRollback(url: string, timeout: number): Promise<void> {
|
|
1020
|
-
const result = await this.httpClient.post(url, {}, { timeout, retries: 1 });
|
|
1021
|
-
if (!result.success) {
|
|
1022
|
-
throw new Error(`HTTP rollback failed: ${result.error.message}`);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
/**
|
|
1027
|
-
* Allowed commands for rollback operations (security whitelist)
|
|
1028
|
-
*/
|
|
1029
|
-
private static readonly ALLOWED_ROLLBACK_COMMANDS = [
|
|
1030
|
-
'kill', 'pkill', // Process termination
|
|
1031
|
-
'rm', 'rmdir', // File cleanup
|
|
1032
|
-
'mv', 'cp', // File operations
|
|
1033
|
-
'systemctl', 'service', // Service management
|
|
1034
|
-
'docker', 'kubectl', // Container management
|
|
1035
|
-
'iptables', // Network rules (for cleanup)
|
|
1036
|
-
'tc', // Traffic control (for cleanup)
|
|
1037
|
-
'echo', 'true', // No-op commands
|
|
1038
|
-
];
|
|
1039
|
-
|
|
1040
|
-
private executeCommandRollback(command: string, timeout: number): Promise<void> {
|
|
1041
|
-
return new Promise((resolve, reject) => {
|
|
1042
|
-
// Validate command against whitelist to prevent injection (CWE-78)
|
|
1043
|
-
const validation = validateCommand(command, ChaosEngineerService.ALLOWED_ROLLBACK_COMMANDS);
|
|
1044
|
-
if (!validation.valid) {
|
|
1045
|
-
reject(new Error(`Rollback command blocked: ${validation.error}`));
|
|
1046
|
-
return;
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
// Parse command into executable and arguments
|
|
1050
|
-
const sanitizedCommand = validation.sanitizedCommand || command;
|
|
1051
|
-
const parts = sanitizedCommand.trim().split(/\s+/);
|
|
1052
|
-
const executable = parts[0];
|
|
1053
|
-
const args = parts.slice(1);
|
|
1054
|
-
|
|
1055
|
-
// Use execFile instead of exec to avoid shell interpretation
|
|
1056
|
-
execFile(executable, args, { timeout }, (error, _stdout, stderr) => {
|
|
1057
|
-
if (error) {
|
|
1058
|
-
reject(new Error(`Command rollback failed: ${error.message}. ${stderr}`));
|
|
1059
|
-
} else {
|
|
1060
|
-
resolve();
|
|
1061
|
-
}
|
|
1062
|
-
});
|
|
1063
|
-
});
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
private async executeBuiltInRollback(
|
|
1067
|
-
action: string,
|
|
1068
|
-
target?: string,
|
|
1069
|
-
_timeout?: number
|
|
1070
|
-
): Promise<void> {
|
|
1071
|
-
// Handle built-in rollback actions
|
|
1072
|
-
const actionLower = action.toLowerCase();
|
|
1073
|
-
|
|
1074
|
-
if (actionLower.includes('remove') || actionLower.includes('clear')) {
|
|
1075
|
-
// Clear any remaining state
|
|
1076
|
-
if (target) {
|
|
1077
|
-
console.log(`Clearing state for target: ${target}`);
|
|
1078
|
-
}
|
|
1079
|
-
} else if (actionLower.includes('restart')) {
|
|
1080
|
-
// Restart service (log only - actual restart would require orchestration)
|
|
1081
|
-
console.log(`Restart requested for: ${target || 'service'}`);
|
|
1082
|
-
} else if (actionLower.includes('restore')) {
|
|
1083
|
-
// Restore to previous state
|
|
1084
|
-
console.log(`Restore requested for: ${target || 'system'}`);
|
|
1085
|
-
} else {
|
|
1086
|
-
// Log-only for description actions
|
|
1087
|
-
console.log(`Rollback action logged: ${action}`);
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
// Brief pause between actions
|
|
1091
|
-
await this.sleep(100);
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
private sleep(ms: number): Promise<void> {
|
|
1095
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1096
|
-
}
|
|
1097
|
-
}
|