agentic-qe 3.3.0 → 3.3.2
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/README.md +6 -2
- package/package.json +6 -1
- package/v3/CHANGELOG.md +134 -0
- package/v3/dist/cli/bundle.js +29332 -22739
- package/v3/dist/cli/command-registry.d.ts +55 -0
- package/v3/dist/cli/command-registry.d.ts.map +1 -0
- package/v3/dist/cli/command-registry.js +103 -0
- package/v3/dist/cli/command-registry.js.map +1 -0
- package/v3/dist/cli/commands/code.d.ts +9 -0
- package/v3/dist/cli/commands/code.d.ts.map +1 -0
- package/v3/dist/cli/commands/code.js +254 -0
- package/v3/dist/cli/commands/code.js.map +1 -0
- package/v3/dist/cli/commands/completions.d.ts +8 -0
- package/v3/dist/cli/commands/completions.d.ts.map +1 -0
- package/v3/dist/cli/commands/completions.js +99 -0
- package/v3/dist/cli/commands/completions.js.map +1 -0
- package/v3/dist/cli/commands/coverage.d.ts +9 -0
- package/v3/dist/cli/commands/coverage.d.ts.map +1 -0
- package/v3/dist/cli/commands/coverage.js +208 -0
- package/v3/dist/cli/commands/coverage.js.map +1 -0
- package/v3/dist/cli/commands/fleet.d.ts +11 -0
- package/v3/dist/cli/commands/fleet.d.ts.map +1 -0
- package/v3/dist/cli/commands/fleet.js +338 -0
- package/v3/dist/cli/commands/fleet.js.map +1 -0
- package/v3/dist/cli/commands/migrate.d.ts +9 -0
- package/v3/dist/cli/commands/migrate.d.ts.map +1 -0
- package/v3/dist/cli/commands/migrate.js +566 -0
- package/v3/dist/cli/commands/migrate.js.map +1 -0
- package/v3/dist/cli/commands/quality.d.ts +9 -0
- package/v3/dist/cli/commands/quality.d.ts.map +1 -0
- package/v3/dist/cli/commands/quality.js +40 -0
- package/v3/dist/cli/commands/quality.js.map +1 -0
- package/v3/dist/cli/commands/security.d.ts +9 -0
- package/v3/dist/cli/commands/security.d.ts.map +1 -0
- package/v3/dist/cli/commands/security.js +124 -0
- package/v3/dist/cli/commands/security.js.map +1 -0
- package/v3/dist/cli/commands/sync.d.ts +19 -0
- package/v3/dist/cli/commands/sync.d.ts.map +1 -0
- package/v3/dist/cli/commands/sync.js +283 -0
- package/v3/dist/cli/commands/sync.js.map +1 -0
- package/v3/dist/cli/commands/test.d.ts +9 -0
- package/v3/dist/cli/commands/test.d.ts.map +1 -0
- package/v3/dist/cli/commands/test.js +166 -0
- package/v3/dist/cli/commands/test.js.map +1 -0
- package/v3/dist/cli/handlers/agent-handler.d.ts +20 -0
- package/v3/dist/cli/handlers/agent-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/agent-handler.js +158 -0
- package/v3/dist/cli/handlers/agent-handler.js.map +1 -0
- package/v3/dist/cli/handlers/domain-handler.d.ts +20 -0
- package/v3/dist/cli/handlers/domain-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/domain-handler.js +115 -0
- package/v3/dist/cli/handlers/domain-handler.js.map +1 -0
- package/v3/dist/cli/handlers/index.d.ts +13 -0
- package/v3/dist/cli/handlers/index.d.ts.map +1 -0
- package/v3/dist/cli/handlers/index.js +15 -0
- package/v3/dist/cli/handlers/index.js.map +1 -0
- package/v3/dist/cli/handlers/init-handler.d.ts +38 -0
- package/v3/dist/cli/handlers/init-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/init-handler.js +288 -0
- package/v3/dist/cli/handlers/init-handler.js.map +1 -0
- package/v3/dist/cli/handlers/interfaces.d.ts +104 -0
- package/v3/dist/cli/handlers/interfaces.d.ts.map +1 -0
- package/v3/dist/cli/handlers/interfaces.js +109 -0
- package/v3/dist/cli/handlers/interfaces.js.map +1 -0
- package/v3/dist/cli/handlers/protocol-handler.d.ts +19 -0
- package/v3/dist/cli/handlers/protocol-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/protocol-handler.js +79 -0
- package/v3/dist/cli/handlers/protocol-handler.js.map +1 -0
- package/v3/dist/cli/handlers/status-handler.d.ts +30 -0
- package/v3/dist/cli/handlers/status-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/status-handler.js +218 -0
- package/v3/dist/cli/handlers/status-handler.js.map +1 -0
- package/v3/dist/cli/handlers/task-handler.d.ts +22 -0
- package/v3/dist/cli/handlers/task-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/task-handler.js +271 -0
- package/v3/dist/cli/handlers/task-handler.js.map +1 -0
- package/v3/dist/cli/index.d.ts +4 -0
- package/v3/dist/cli/index.d.ts.map +1 -1
- package/v3/dist/cli/index.js +48 -2677
- package/v3/dist/cli/index.js.map +1 -1
- package/v3/dist/cli/wizards/core/index.d.ts +11 -0
- package/v3/dist/cli/wizards/core/index.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/index.js +15 -0
- package/v3/dist/cli/wizards/core/index.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-base.d.ts +87 -0
- package/v3/dist/cli/wizards/core/wizard-base.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-base.js +120 -0
- package/v3/dist/cli/wizards/core/wizard-base.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-command.d.ts +182 -0
- package/v3/dist/cli/wizards/core/wizard-command.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-command.js +45 -0
- package/v3/dist/cli/wizards/core/wizard-command.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-step.d.ts +109 -0
- package/v3/dist/cli/wizards/core/wizard-step.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-step.js +384 -0
- package/v3/dist/cli/wizards/core/wizard-step.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-utils.d.ts +117 -0
- package/v3/dist/cli/wizards/core/wizard-utils.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-utils.js +291 -0
- package/v3/dist/cli/wizards/core/wizard-utils.js.map +1 -0
- package/v3/dist/cli/wizards/coverage-wizard.d.ts +13 -68
- package/v3/dist/cli/wizards/coverage-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/coverage-wizard.js +127 -391
- package/v3/dist/cli/wizards/coverage-wizard.js.map +1 -1
- package/v3/dist/cli/wizards/fleet-wizard.d.ts +13 -64
- package/v3/dist/cli/wizards/fleet-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/fleet-wizard.js +150 -363
- package/v3/dist/cli/wizards/fleet-wizard.js.map +1 -1
- package/v3/dist/cli/wizards/index.d.ts +2 -0
- package/v3/dist/cli/wizards/index.d.ts.map +1 -1
- package/v3/dist/cli/wizards/index.js +3 -0
- package/v3/dist/cli/wizards/index.js.map +1 -1
- package/v3/dist/cli/wizards/security-wizard.d.ts +13 -64
- package/v3/dist/cli/wizards/security-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/security-wizard.js +152 -395
- package/v3/dist/cli/wizards/security-wizard.js.map +1 -1
- package/v3/dist/cli/wizards/test-wizard.d.ts +13 -77
- package/v3/dist/cli/wizards/test-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/test-wizard.js +196 -328
- package/v3/dist/cli/wizards/test-wizard.js.map +1 -1
- package/v3/dist/coordination/mincut/mincut-health-monitor.d.ts +3 -0
- package/v3/dist/coordination/mincut/mincut-health-monitor.d.ts.map +1 -1
- package/v3/dist/coordination/mincut/mincut-health-monitor.js +6 -2
- package/v3/dist/coordination/mincut/mincut-health-monitor.js.map +1 -1
- package/v3/dist/coordination/mincut/queen-integration.d.ts +3 -0
- package/v3/dist/coordination/mincut/queen-integration.d.ts.map +1 -1
- package/v3/dist/coordination/mincut/queen-integration.js +6 -1
- package/v3/dist/coordination/mincut/queen-integration.js.map +1 -1
- package/v3/dist/coordination/queen-coordinator.d.ts +13 -1
- package/v3/dist/coordination/queen-coordinator.d.ts.map +1 -1
- package/v3/dist/coordination/queen-coordinator.js +91 -3
- package/v3/dist/coordination/queen-coordinator.js.map +1 -1
- package/v3/dist/coordination/task-executor.js +2 -2
- package/v3/dist/coordination/task-executor.js.map +1 -1
- package/v3/dist/domains/chaos-resilience/plugin.js +2 -2
- package/v3/dist/domains/chaos-resilience/plugin.js.map +1 -1
- package/v3/dist/domains/code-intelligence/plugin.js +2 -2
- package/v3/dist/domains/code-intelligence/plugin.js.map +1 -1
- package/v3/dist/domains/contract-testing/plugin.js +2 -2
- package/v3/dist/domains/contract-testing/plugin.js.map +1 -1
- package/v3/dist/domains/coverage-analysis/plugin.d.ts +6 -1
- package/v3/dist/domains/coverage-analysis/plugin.d.ts.map +1 -1
- package/v3/dist/domains/coverage-analysis/plugin.js +75 -1
- package/v3/dist/domains/coverage-analysis/plugin.js.map +1 -1
- package/v3/dist/domains/defect-intelligence/plugin.js +2 -2
- package/v3/dist/domains/defect-intelligence/plugin.js.map +1 -1
- package/v3/dist/domains/domain-interface.d.ts +39 -2
- package/v3/dist/domains/domain-interface.d.ts.map +1 -1
- package/v3/dist/domains/domain-interface.js +102 -1
- package/v3/dist/domains/domain-interface.js.map +1 -1
- package/v3/dist/domains/learning-optimization/coordinator.d.ts +83 -0
- package/v3/dist/domains/learning-optimization/coordinator.d.ts.map +1 -1
- package/v3/dist/domains/learning-optimization/coordinator.js +174 -0
- package/v3/dist/domains/learning-optimization/coordinator.js.map +1 -1
- package/v3/dist/domains/learning-optimization/interfaces.d.ts +14 -0
- package/v3/dist/domains/learning-optimization/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/learning-optimization/plugin.js +2 -2
- package/v3/dist/domains/learning-optimization/plugin.js.map +1 -1
- package/v3/dist/domains/quality-assessment/coordinator.d.ts +23 -0
- package/v3/dist/domains/quality-assessment/coordinator.d.ts.map +1 -1
- package/v3/dist/domains/quality-assessment/coordinator.js +139 -1
- package/v3/dist/domains/quality-assessment/coordinator.js.map +1 -1
- package/v3/dist/domains/quality-assessment/plugin.d.ts +6 -1
- package/v3/dist/domains/quality-assessment/plugin.d.ts.map +1 -1
- package/v3/dist/domains/quality-assessment/plugin.js +69 -2
- package/v3/dist/domains/quality-assessment/plugin.js.map +1 -1
- package/v3/dist/domains/requirements-validation/plugin.js +2 -2
- package/v3/dist/domains/requirements-validation/plugin.js.map +1 -1
- package/v3/dist/domains/security-compliance/plugin.js +2 -2
- package/v3/dist/domains/security-compliance/plugin.js.map +1 -1
- package/v3/dist/domains/test-execution/index.d.ts +2 -1
- package/v3/dist/domains/test-execution/index.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/index.js +0 -2
- package/v3/dist/domains/test-execution/index.js.map +1 -1
- package/v3/dist/domains/test-execution/interfaces.d.ts +222 -25
- package/v3/dist/domains/test-execution/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/interfaces.js +130 -3
- package/v3/dist/domains/test-execution/interfaces.js.map +1 -1
- package/v3/dist/domains/test-execution/plugin.d.ts +6 -1
- package/v3/dist/domains/test-execution/plugin.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/plugin.js +79 -1
- package/v3/dist/domains/test-execution/plugin.js.map +1 -1
- package/v3/dist/domains/test-execution/test-prioritization-types.d.ts +5 -172
- package/v3/dist/domains/test-execution/test-prioritization-types.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/test-prioritization-types.js +6 -129
- package/v3/dist/domains/test-execution/test-prioritization-types.js.map +1 -1
- package/v3/dist/domains/test-execution/types/index.d.ts +7 -3
- package/v3/dist/domains/test-execution/types/index.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/types/index.js +7 -17
- package/v3/dist/domains/test-execution/types/index.js.map +1 -1
- package/v3/dist/domains/test-generation/coordinator.d.ts +41 -1
- package/v3/dist/domains/test-generation/coordinator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/coordinator.js +187 -4
- package/v3/dist/domains/test-generation/coordinator.js.map +1 -1
- package/v3/dist/domains/test-generation/factories/index.d.ts +8 -0
- package/v3/dist/domains/test-generation/factories/index.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/factories/index.js +8 -0
- package/v3/dist/domains/test-generation/factories/index.js.map +1 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.d.ts +108 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.js +158 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.d.ts +79 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.js +252 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/index.d.ts +11 -0
- package/v3/dist/domains/test-generation/generators/index.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/index.js +13 -0
- package/v3/dist/domains/test-generation/generators/index.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts +77 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js +365 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts +56 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.js +197 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts +66 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.js +240 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/index.d.ts +2 -2
- package/v3/dist/domains/test-generation/index.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/index.js +3 -3
- package/v3/dist/domains/test-generation/index.js.map +1 -1
- package/v3/dist/domains/test-generation/interfaces/index.d.ts +9 -0
- package/v3/dist/domains/test-generation/interfaces/index.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/interfaces/index.js +9 -0
- package/v3/dist/domains/test-generation/interfaces/index.js.map +1 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts +166 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.js +8 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.js.map +1 -0
- package/v3/dist/domains/test-generation/interfaces.d.ts +163 -24
- package/v3/dist/domains/test-generation/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/interfaces.js +2 -2
- package/v3/dist/domains/test-generation/plugin.d.ts +6 -1
- package/v3/dist/domains/test-generation/plugin.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/plugin.js +90 -5
- package/v3/dist/domains/test-generation/plugin.js.map +1 -1
- package/v3/dist/domains/test-generation/{coherence-gate.d.ts → services/coherence-gate-service.d.ts} +4 -4
- package/v3/dist/domains/test-generation/services/coherence-gate-service.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/{coherence-gate.js → services/coherence-gate-service.js} +2 -2
- package/v3/dist/domains/test-generation/services/coherence-gate-service.js.map +1 -0
- package/v3/dist/domains/test-generation/services/index.d.ts +8 -2
- package/v3/dist/domains/test-generation/services/index.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/index.js +10 -3
- package/v3/dist/domains/test-generation/services/index.js.map +1 -1
- package/v3/dist/domains/test-generation/services/property-test-generator.d.ts +34 -0
- package/v3/dist/domains/test-generation/services/property-test-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/services/property-test-generator.js +306 -0
- package/v3/dist/domains/test-generation/services/property-test-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.d.ts +33 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.js +342 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.d.ts +34 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.js +245 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/services/test-generator.d.ts +51 -160
- package/v3/dist/domains/test-generation/services/test-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/test-generator.js +101 -1858
- package/v3/dist/domains/test-generation/services/test-generator.js.map +1 -1
- package/v3/dist/domains/visual-accessibility/plugin.js +2 -2
- package/v3/dist/domains/visual-accessibility/plugin.js.map +1 -1
- package/v3/dist/init/phases/12-verification.d.ts +23 -0
- package/v3/dist/init/phases/12-verification.d.ts.map +1 -1
- package/v3/dist/init/phases/12-verification.js +185 -2
- package/v3/dist/init/phases/12-verification.js.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.d.ts +24 -62
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.d.ts.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.js +45 -497
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.js.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/router.js +2 -2
- package/v3/dist/integrations/agentic-flow/model-router/router.js.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts +98 -0
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js +197 -0
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts +102 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js +372 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.d.ts +64 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.d.ts.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.js +120 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.js.map +1 -0
- package/v3/dist/integrations/coherence/coherence-service.d.ts.map +1 -1
- package/v3/dist/integrations/coherence/coherence-service.js +87 -30
- package/v3/dist/integrations/coherence/coherence-service.js.map +1 -1
- package/v3/dist/integrations/coherence/engines/spectral-adapter.d.ts.map +1 -1
- package/v3/dist/integrations/coherence/engines/spectral-adapter.js +124 -35
- package/v3/dist/integrations/coherence/engines/spectral-adapter.js.map +1 -1
- package/v3/dist/kernel/interfaces.d.ts +54 -1
- package/v3/dist/kernel/interfaces.d.ts.map +1 -1
- package/v3/dist/learning/dream/dream-scheduler.d.ts +302 -0
- package/v3/dist/learning/dream/dream-scheduler.d.ts.map +1 -0
- package/v3/dist/learning/dream/dream-scheduler.js +551 -0
- package/v3/dist/learning/dream/dream-scheduler.js.map +1 -0
- package/v3/dist/learning/dream/index.d.ts +1 -0
- package/v3/dist/learning/dream/index.d.ts.map +1 -1
- package/v3/dist/learning/dream/index.js +4 -0
- package/v3/dist/learning/dream/index.js.map +1 -1
- package/v3/dist/learning/memory-auditor.d.ts.map +1 -1
- package/v3/dist/learning/memory-auditor.js +3 -1
- package/v3/dist/learning/memory-auditor.js.map +1 -1
- package/v3/dist/mcp/bundle.js +30870 -23598
- package/v3/dist/mcp/handlers/core-handlers.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/core-handlers.js +16 -2
- package/v3/dist/mcp/handlers/core-handlers.js.map +1 -1
- package/v3/dist/mcp/handlers/task-handlers.d.ts +1 -0
- package/v3/dist/mcp/handlers/task-handlers.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/task-handlers.js +46 -12
- package/v3/dist/mcp/handlers/task-handlers.js.map +1 -1
- package/v3/dist/mcp/security/cve-prevention.d.ts +31 -134
- package/v3/dist/mcp/security/cve-prevention.d.ts.map +1 -1
- package/v3/dist/mcp/security/cve-prevention.js +37 -562
- package/v3/dist/mcp/security/cve-prevention.js.map +1 -1
- package/v3/dist/mcp/security/index.d.ts +5 -1
- package/v3/dist/mcp/security/index.d.ts.map +1 -1
- package/v3/dist/mcp/security/validators/command-validator.d.ts +41 -0
- package/v3/dist/mcp/security/validators/command-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/command-validator.js +123 -0
- package/v3/dist/mcp/security/validators/command-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/crypto-validator.d.ts +40 -0
- package/v3/dist/mcp/security/validators/crypto-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/crypto-validator.js +72 -0
- package/v3/dist/mcp/security/validators/crypto-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/index.d.ts +12 -0
- package/v3/dist/mcp/security/validators/index.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/index.js +22 -0
- package/v3/dist/mcp/security/validators/index.js.map +1 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.d.ts +56 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.js +157 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.js.map +1 -0
- package/v3/dist/mcp/security/validators/interfaces.d.ts +164 -0
- package/v3/dist/mcp/security/validators/interfaces.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/interfaces.js +6 -0
- package/v3/dist/mcp/security/validators/interfaces.js.map +1 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.d.ts +50 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.js +242 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.d.ts +50 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.js +183 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.d.ts +66 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.js +146 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.js.map +1 -0
- package/v3/dist/mcp/server.d.ts.map +1 -1
- package/v3/dist/mcp/server.js +1 -0
- package/v3/dist/mcp/server.js.map +1 -1
- package/v3/dist/mcp/services/reasoning-bank-service.d.ts +87 -13
- package/v3/dist/mcp/services/reasoning-bank-service.d.ts.map +1 -1
- package/v3/dist/mcp/services/reasoning-bank-service.js +291 -31
- package/v3/dist/mcp/services/reasoning-bank-service.js.map +1 -1
- package/v3/dist/mcp/tool-registry.d.ts +3 -1
- package/v3/dist/mcp/tool-registry.d.ts.map +1 -1
- package/v3/dist/mcp/tool-registry.js +155 -2
- package/v3/dist/mcp/tool-registry.js.map +1 -1
- package/v3/dist/mcp/tools/test-generation/generate.d.ts +1 -0
- package/v3/dist/mcp/tools/test-generation/generate.d.ts.map +1 -1
- package/v3/dist/mcp/tools/test-generation/generate.js +3 -2
- package/v3/dist/mcp/tools/test-generation/generate.js.map +1 -1
- package/v3/dist/routing/qe-agent-registry.d.ts +27 -0
- package/v3/dist/routing/qe-agent-registry.d.ts.map +1 -1
- package/v3/dist/routing/qe-agent-registry.js +96 -0
- package/v3/dist/routing/qe-agent-registry.js.map +1 -1
- package/v3/dist/shared/events/domain-events.d.ts +27 -0
- package/v3/dist/shared/events/domain-events.d.ts.map +1 -1
- package/v3/dist/shared/events/domain-events.js +1 -0
- package/v3/dist/shared/events/domain-events.js.map +1 -1
- package/v3/dist/sync/cloud/index.d.ts +8 -0
- package/v3/dist/sync/cloud/index.d.ts.map +1 -0
- package/v3/dist/sync/cloud/index.js +8 -0
- package/v3/dist/sync/cloud/index.js.map +1 -0
- package/v3/dist/sync/cloud/postgres-writer.d.ts +88 -0
- package/v3/dist/sync/cloud/postgres-writer.d.ts.map +1 -0
- package/v3/dist/sync/cloud/postgres-writer.js +319 -0
- package/v3/dist/sync/cloud/postgres-writer.js.map +1 -0
- package/v3/dist/sync/cloud/tunnel-manager.d.ts +75 -0
- package/v3/dist/sync/cloud/tunnel-manager.d.ts.map +1 -0
- package/v3/dist/sync/cloud/tunnel-manager.js +221 -0
- package/v3/dist/sync/cloud/tunnel-manager.js.map +1 -0
- package/v3/dist/sync/index.d.ts +35 -0
- package/v3/dist/sync/index.d.ts.map +1 -0
- package/v3/dist/sync/index.js +35 -0
- package/v3/dist/sync/index.js.map +1 -0
- package/v3/dist/sync/interfaces.d.ts +245 -0
- package/v3/dist/sync/interfaces.d.ts.map +1 -0
- package/v3/dist/sync/interfaces.js +160 -0
- package/v3/dist/sync/interfaces.js.map +1 -0
- package/v3/dist/sync/readers/index.d.ts +8 -0
- package/v3/dist/sync/readers/index.d.ts.map +1 -0
- package/v3/dist/sync/readers/index.js +8 -0
- package/v3/dist/sync/readers/index.js.map +1 -0
- package/v3/dist/sync/readers/json-reader.d.ts +95 -0
- package/v3/dist/sync/readers/json-reader.d.ts.map +1 -0
- package/v3/dist/sync/readers/json-reader.js +306 -0
- package/v3/dist/sync/readers/json-reader.js.map +1 -0
- package/v3/dist/sync/readers/sqlite-reader.d.ts +88 -0
- package/v3/dist/sync/readers/sqlite-reader.d.ts.map +1 -0
- package/v3/dist/sync/readers/sqlite-reader.js +255 -0
- package/v3/dist/sync/readers/sqlite-reader.js.map +1 -0
- package/v3/dist/sync/sync-agent.d.ts +116 -0
- package/v3/dist/sync/sync-agent.d.ts.map +1 -0
- package/v3/dist/sync/sync-agent.js +416 -0
- package/v3/dist/sync/sync-agent.js.map +1 -0
- package/v3/package.json +13 -2
- package/v3/dist/domains/test-generation/coherence-gate.d.ts.map +0 -1
- package/v3/dist/domains/test-generation/coherence-gate.js.map +0 -1
package/v3/dist/cli/index.js
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Provides CLI access to the v3 DDD architecture through the Queen Coordinator.
|
|
6
6
|
* All commands delegate to domain services via the coordination layer.
|
|
7
|
+
*
|
|
8
|
+
* Refactored to use CommandRegistry and handlers for better maintainability.
|
|
9
|
+
* See: cli/handlers/ for command implementations
|
|
10
|
+
* See: cli/commands/ for additional command modules
|
|
7
11
|
*/
|
|
8
12
|
import { Command } from 'commander';
|
|
9
13
|
import chalk from 'chalk';
|
|
@@ -14,19 +18,16 @@ import { CrossDomainEventRouter } from '../coordination/cross-domain-router';
|
|
|
14
18
|
import { DefaultProtocolExecutor } from '../coordination/protocol-executor';
|
|
15
19
|
import { WorkflowOrchestrator } from '../coordination/workflow-orchestrator';
|
|
16
20
|
import { ALL_DOMAINS } from '../shared/types';
|
|
17
|
-
import { InitOrchestrator } from '../init/init-wizard';
|
|
18
|
-
import { createModularInitOrchestrator, } from '../init/orchestrator.js';
|
|
19
|
-
import { integrateCodeIntelligence } from '../init/fleet-integration';
|
|
20
|
-
import { setupClaudeFlowIntegration } from './commands/claude-flow-setup.js';
|
|
21
|
-
import { generateCompletion, detectShell, getInstallInstructions, DOMAINS as COMPLETION_DOMAINS, QE_AGENTS, OTHER_AGENTS, } from './completions/index.js';
|
|
22
|
-
import { FleetProgressManager, createTimedSpinner, } from './utils/progress';
|
|
23
21
|
import { bootstrapTokenTracking, shutdownTokenTracking } from '../init/token-bootstrap.js';
|
|
24
22
|
import { parsePipelineFile, validatePipeline, describeCronSchedule, } from './utils/workflow-parser.js';
|
|
25
|
-
import {
|
|
26
|
-
import { parseJsonOption, parseJsonFile } from './helpers/safe-json.js';
|
|
27
|
-
import { runFleetInitWizard, } from './wizards/fleet-wizard.js';
|
|
23
|
+
import { parseJsonOption } from './helpers/safe-json.js';
|
|
28
24
|
import { createPersistentScheduler, createScheduleEntry, } from './scheduler/index.js';
|
|
29
|
-
|
|
25
|
+
// Import handlers and registry
|
|
26
|
+
import { createCommandRegistry } from './command-registry.js';
|
|
27
|
+
import { formatDuration } from './handlers/interfaces.js';
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// CLI State
|
|
30
|
+
// ============================================================================
|
|
30
31
|
const context = {
|
|
31
32
|
kernel: null,
|
|
32
33
|
queen: null,
|
|
@@ -38,85 +39,40 @@ const context = {
|
|
|
38
39
|
};
|
|
39
40
|
/**
|
|
40
41
|
* Register domain workflow actions with the WorkflowOrchestrator (Issue #206)
|
|
41
|
-
* This enables domain-specific actions to be used in pipeline YAML workflows.
|
|
42
42
|
*/
|
|
43
43
|
function registerDomainWorkflowActions(kernel, orchestrator) {
|
|
44
|
-
// Register visual-accessibility domain actions
|
|
45
44
|
const visualAccessibilityAPI = kernel.getDomainAPI('visual-accessibility');
|
|
46
45
|
if (visualAccessibilityAPI?.registerWorkflowActions) {
|
|
47
46
|
try {
|
|
48
47
|
visualAccessibilityAPI.registerWorkflowActions(orchestrator);
|
|
49
48
|
}
|
|
50
49
|
catch (error) {
|
|
51
|
-
|
|
52
|
-
console.error(chalk.yellow(` ⚠ Could not register visual-accessibility workflow actions: ${error instanceof Error ? error.message : String(error)}`));
|
|
50
|
+
console.error(chalk.yellow(` Warning: Could not register visual-accessibility workflow actions: ${error instanceof Error ? error.message : String(error)}`));
|
|
53
51
|
}
|
|
54
52
|
}
|
|
55
|
-
// Additional domain action registrations can be added here as needed
|
|
56
|
-
// Example: registerTestGenerationWorkflowActions(kernel, orchestrator);
|
|
57
53
|
}
|
|
58
54
|
// ============================================================================
|
|
59
55
|
// Helper Functions
|
|
60
56
|
// ============================================================================
|
|
61
|
-
function getStatusColor(status) {
|
|
62
|
-
switch (status) {
|
|
63
|
-
case 'healthy':
|
|
64
|
-
case 'completed':
|
|
65
|
-
return chalk.green(status);
|
|
66
|
-
case 'idle':
|
|
67
|
-
// Issue #205 fix: 'idle' is normal - show in cyan (neutral/ready)
|
|
68
|
-
return chalk.cyan(status);
|
|
69
|
-
case 'degraded':
|
|
70
|
-
case 'running':
|
|
71
|
-
return chalk.yellow(status);
|
|
72
|
-
case 'unhealthy':
|
|
73
|
-
case 'failed':
|
|
74
|
-
return chalk.red(status);
|
|
75
|
-
default:
|
|
76
|
-
return chalk.gray(status);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function formatDuration(ms) {
|
|
80
|
-
if (ms < 1000)
|
|
81
|
-
return `${ms}ms`;
|
|
82
|
-
if (ms < 60000)
|
|
83
|
-
return `${(ms / 1000).toFixed(1)}s`;
|
|
84
|
-
if (ms < 3600000)
|
|
85
|
-
return `${(ms / 60000).toFixed(1)}m`;
|
|
86
|
-
return `${(ms / 3600000).toFixed(1)}h`;
|
|
87
|
-
}
|
|
88
|
-
function formatUptime(ms) {
|
|
89
|
-
const hours = Math.floor(ms / 3600000);
|
|
90
|
-
const minutes = Math.floor((ms % 3600000) / 60000);
|
|
91
|
-
const seconds = Math.floor((ms % 60000) / 1000);
|
|
92
|
-
return `${hours}h ${minutes}m ${seconds}s`;
|
|
93
|
-
}
|
|
94
57
|
async function autoInitialize() {
|
|
95
|
-
// Create kernel with defaults
|
|
96
58
|
context.kernel = new QEKernelImpl({
|
|
97
59
|
maxConcurrentAgents: 15,
|
|
98
60
|
memoryBackend: 'sqlite',
|
|
99
61
|
hnswEnabled: true,
|
|
100
|
-
lazyLoading: true,
|
|
62
|
+
lazyLoading: true,
|
|
101
63
|
enabledDomains: [...ALL_DOMAINS],
|
|
102
64
|
});
|
|
103
65
|
await context.kernel.initialize();
|
|
104
|
-
// Create cross-domain router
|
|
105
66
|
context.router = new CrossDomainEventRouter(context.kernel.eventBus);
|
|
106
67
|
await context.router.initialize();
|
|
107
|
-
// Create protocol executor
|
|
108
68
|
const getDomainAPI = (domain) => {
|
|
109
69
|
return context.kernel.getDomainAPI(domain);
|
|
110
70
|
};
|
|
111
71
|
const protocolExecutor = new DefaultProtocolExecutor(context.kernel.eventBus, context.kernel.memory, getDomainAPI);
|
|
112
|
-
// Create workflow orchestrator
|
|
113
72
|
context.workflowOrchestrator = new WorkflowOrchestrator(context.kernel.eventBus, context.kernel.memory, context.kernel.coordinator);
|
|
114
73
|
await context.workflowOrchestrator.initialize();
|
|
115
|
-
// Register domain workflow actions (Issue #206)
|
|
116
74
|
registerDomainWorkflowActions(context.kernel, context.workflowOrchestrator);
|
|
117
|
-
// Create persistent scheduler for workflow scheduling (ADR-041)
|
|
118
75
|
context.persistentScheduler = createPersistentScheduler();
|
|
119
|
-
// Create Queen Coordinator
|
|
120
76
|
context.queen = createQueenCoordinator(context.kernel, context.router, protocolExecutor, undefined);
|
|
121
77
|
await context.queen.initialize();
|
|
122
78
|
context.initialized = true;
|
|
@@ -125,18 +81,14 @@ async function ensureInitialized() {
|
|
|
125
81
|
if (context.initialized && context.kernel && context.queen) {
|
|
126
82
|
return true;
|
|
127
83
|
}
|
|
128
|
-
// Auto-initialize with defaults and timeout
|
|
129
84
|
console.log(chalk.gray('Auto-initializing v3 system...'));
|
|
130
|
-
const timeout = 30000;
|
|
85
|
+
const timeout = 30000;
|
|
131
86
|
const timeoutPromise = new Promise((_, reject) => {
|
|
132
87
|
setTimeout(() => reject(new Error('Initialization timeout after 30 seconds')), timeout);
|
|
133
88
|
});
|
|
134
89
|
try {
|
|
135
|
-
await Promise.race([
|
|
136
|
-
|
|
137
|
-
timeoutPromise
|
|
138
|
-
]);
|
|
139
|
-
console.log(chalk.green('✓ System ready\n'));
|
|
90
|
+
await Promise.race([autoInitialize(), timeoutPromise]);
|
|
91
|
+
console.log(chalk.green('System ready\n'));
|
|
140
92
|
return true;
|
|
141
93
|
}
|
|
142
94
|
catch (err) {
|
|
@@ -157,7 +109,6 @@ async function ensureInitialized() {
|
|
|
157
109
|
*/
|
|
158
110
|
async function cleanupAndExit(code = 0) {
|
|
159
111
|
try {
|
|
160
|
-
// ADR-042: Save token metrics before shutdown
|
|
161
112
|
await shutdownTokenTracking();
|
|
162
113
|
if (context.workflowOrchestrator) {
|
|
163
114
|
await context.workflowOrchestrator.dispose();
|
|
@@ -171,8 +122,6 @@ async function cleanupAndExit(code = 0) {
|
|
|
171
122
|
if (context.kernel) {
|
|
172
123
|
await context.kernel.dispose();
|
|
173
124
|
}
|
|
174
|
-
// Close the UnifiedMemoryManager singleton to release database connection
|
|
175
|
-
// This is critical for CLI commands to exit properly
|
|
176
125
|
UnifiedMemoryManager.resetInstance();
|
|
177
126
|
}
|
|
178
127
|
catch {
|
|
@@ -184,735 +133,16 @@ async function cleanupAndExit(code = 0) {
|
|
|
184
133
|
// CLI Program
|
|
185
134
|
// ============================================================================
|
|
186
135
|
const program = new Command();
|
|
187
|
-
// Version injected at build time from root package.json
|
|
188
136
|
const VERSION = typeof __CLI_VERSION__ !== 'undefined' ? __CLI_VERSION__ : '0.0.0-dev';
|
|
189
137
|
program
|
|
190
138
|
.name('aqe')
|
|
191
139
|
.description('Agentic QE - Domain-Driven Quality Engineering')
|
|
192
140
|
.version(VERSION);
|
|
193
141
|
// ============================================================================
|
|
194
|
-
//
|
|
195
|
-
// ============================================================================
|
|
196
|
-
program
|
|
197
|
-
.command('init')
|
|
198
|
-
.description('Initialize the AQE v3 system')
|
|
199
|
-
.option('-d, --domains <domains>', 'Comma-separated list of domains to enable', 'all')
|
|
200
|
-
.option('-m, --max-agents <number>', 'Maximum concurrent agents', '15')
|
|
201
|
-
.option('--memory <backend>', 'Memory backend (sqlite|agentdb|hybrid)', 'hybrid')
|
|
202
|
-
.option('--lazy', 'Enable lazy loading of domains')
|
|
203
|
-
.option('--wizard', 'Run interactive setup wizard')
|
|
204
|
-
.option('--auto', 'Auto-configure based on project analysis')
|
|
205
|
-
.option('--minimal', 'Minimal configuration (skip optional features)')
|
|
206
|
-
.option('--skip-patterns', 'Skip loading pre-trained patterns')
|
|
207
|
-
.option('--with-n8n', 'Install n8n workflow testing agents and skills')
|
|
208
|
-
.option('--auto-migrate', 'Automatically migrate from v2 if detected')
|
|
209
|
-
.option('--with-claude-flow', 'Force Claude Flow integration setup')
|
|
210
|
-
.option('--skip-claude-flow', 'Skip Claude Flow integration')
|
|
211
|
-
.option('--modular', 'Use new modular init system (default for --auto)')
|
|
212
|
-
.action(async (options) => {
|
|
213
|
-
try {
|
|
214
|
-
// --auto-migrate implies --auto (must use orchestrator for migration)
|
|
215
|
-
if (options.autoMigrate && !options.auto && !options.wizard) {
|
|
216
|
-
options.auto = true;
|
|
217
|
-
}
|
|
218
|
-
// Check if wizard mode requested
|
|
219
|
-
if (options.wizard || options.auto) {
|
|
220
|
-
console.log(chalk.blue('\n🚀 Agentic QE v3 Initialization\n'));
|
|
221
|
-
// Use modular orchestrator for --auto or --modular
|
|
222
|
-
if (options.auto || options.modular) {
|
|
223
|
-
const orchestrator = createModularInitOrchestrator({
|
|
224
|
-
projectRoot: process.cwd(),
|
|
225
|
-
autoMode: options.auto,
|
|
226
|
-
minimal: options.minimal,
|
|
227
|
-
skipPatterns: options.skipPatterns,
|
|
228
|
-
withN8n: options.withN8n,
|
|
229
|
-
autoMigrate: options.autoMigrate,
|
|
230
|
-
});
|
|
231
|
-
console.log(chalk.white('🔍 Analyzing project...\n'));
|
|
232
|
-
const result = await orchestrator.initialize();
|
|
233
|
-
// Display step results
|
|
234
|
-
for (const step of result.steps) {
|
|
235
|
-
const statusIcon = step.status === 'success' ? '✓' : step.status === 'error' ? '✗' : '⚠';
|
|
236
|
-
const statusColor = step.status === 'success' ? chalk.green : step.status === 'error' ? chalk.red : chalk.yellow;
|
|
237
|
-
console.log(statusColor(` ${statusIcon} ${step.step} (${step.durationMs}ms)`));
|
|
238
|
-
}
|
|
239
|
-
console.log('');
|
|
240
|
-
// Claude Flow integration (after base init)
|
|
241
|
-
let cfResult;
|
|
242
|
-
if (!options.skipClaudeFlow && (options.withClaudeFlow || result.success)) {
|
|
243
|
-
try {
|
|
244
|
-
cfResult = await setupClaudeFlowIntegration({
|
|
245
|
-
projectRoot: process.cwd(),
|
|
246
|
-
force: options.withClaudeFlow,
|
|
247
|
-
});
|
|
248
|
-
if (cfResult.available) {
|
|
249
|
-
console.log(chalk.green('✓ Claude Flow integration enabled'));
|
|
250
|
-
if (cfResult.features.trajectories) {
|
|
251
|
-
console.log(chalk.gray(' • SONA trajectory tracking'));
|
|
252
|
-
}
|
|
253
|
-
if (cfResult.features.modelRouting) {
|
|
254
|
-
console.log(chalk.gray(' • 3-tier model routing (haiku/sonnet/opus)'));
|
|
255
|
-
}
|
|
256
|
-
if (cfResult.features.pretrain) {
|
|
257
|
-
console.log(chalk.gray(' • Codebase pretrain analysis'));
|
|
258
|
-
}
|
|
259
|
-
console.log('');
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
// Claude Flow not available - continue without it
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
if (result.success) {
|
|
267
|
-
console.log(chalk.green('✅ AQE v3 initialized successfully!\n'));
|
|
268
|
-
// Show summary
|
|
269
|
-
console.log(chalk.blue('📊 Summary:'));
|
|
270
|
-
console.log(chalk.gray(` • Patterns loaded: ${result.summary.patternsLoaded}`));
|
|
271
|
-
console.log(chalk.gray(` • Skills installed: ${result.summary.skillsInstalled}`));
|
|
272
|
-
console.log(chalk.gray(` • Agents installed: ${result.summary.agentsInstalled}`));
|
|
273
|
-
console.log(chalk.gray(` • Hooks configured: ${result.summary.hooksConfigured ? 'Yes' : 'No'}`));
|
|
274
|
-
console.log(chalk.gray(` • Workers started: ${result.summary.workersStarted}`));
|
|
275
|
-
console.log(chalk.gray(` • Claude Flow: ${cfResult?.available ? 'Enabled' : 'Standalone mode'}`));
|
|
276
|
-
console.log(chalk.gray(` • Total time: ${result.totalDurationMs}ms\n`));
|
|
277
|
-
console.log(chalk.white('Next steps:'));
|
|
278
|
-
console.log(chalk.gray(' 1. Add MCP: claude mcp add aqe -- aqe-mcp'));
|
|
279
|
-
console.log(chalk.gray(' 2. Run tests: aqe test <path>'));
|
|
280
|
-
console.log(chalk.gray(' 3. Check status: aqe status\n'));
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
console.log(chalk.red('❌ Initialization failed. Check errors above.\n'));
|
|
284
|
-
await cleanupAndExit(1);
|
|
285
|
-
}
|
|
286
|
-
await cleanupAndExit(0);
|
|
287
|
-
}
|
|
288
|
-
// Legacy wizard mode using InitOrchestrator
|
|
289
|
-
const orchestratorOptions = {
|
|
290
|
-
projectRoot: process.cwd(),
|
|
291
|
-
autoMode: options.auto,
|
|
292
|
-
minimal: options.minimal,
|
|
293
|
-
skipPatterns: options.skipPatterns,
|
|
294
|
-
withN8n: options.withN8n,
|
|
295
|
-
autoMigrate: options.autoMigrate,
|
|
296
|
-
};
|
|
297
|
-
const orchestrator = new InitOrchestrator(orchestratorOptions);
|
|
298
|
-
if (options.wizard) {
|
|
299
|
-
// Show wizard steps
|
|
300
|
-
console.log(chalk.white('📋 Setup Wizard Steps:\n'));
|
|
301
|
-
const steps = orchestrator.getWizardSteps();
|
|
302
|
-
for (let i = 0; i < steps.length; i++) {
|
|
303
|
-
console.log(chalk.gray(` ${i + 1}. ${steps[i].title}`));
|
|
304
|
-
console.log(chalk.gray(` ${steps[i].description}\n`));
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
console.log(chalk.white('🔍 Analyzing project...\n'));
|
|
308
|
-
const result = await orchestrator.initialize();
|
|
309
|
-
// Display step results
|
|
310
|
-
for (const step of result.steps) {
|
|
311
|
-
const statusIcon = step.status === 'success' ? '✓' : step.status === 'error' ? '✗' : '⚠';
|
|
312
|
-
const statusColor = step.status === 'success' ? chalk.green : step.status === 'error' ? chalk.red : chalk.yellow;
|
|
313
|
-
console.log(statusColor(` ${statusIcon} ${step.step} (${step.durationMs}ms)`));
|
|
314
|
-
}
|
|
315
|
-
console.log('');
|
|
316
|
-
if (result.success) {
|
|
317
|
-
console.log(chalk.green('✅ AQE v3 initialized successfully!\n'));
|
|
318
|
-
// Show summary
|
|
319
|
-
console.log(chalk.blue('📊 Summary:'));
|
|
320
|
-
console.log(chalk.gray(` • Patterns loaded: ${result.summary.patternsLoaded}`));
|
|
321
|
-
console.log(chalk.gray(` • Hooks configured: ${result.summary.hooksConfigured ? 'Yes' : 'No'}`));
|
|
322
|
-
console.log(chalk.gray(` • Workers started: ${result.summary.workersStarted}`));
|
|
323
|
-
if (result.summary.n8nInstalled) {
|
|
324
|
-
console.log(chalk.gray(` • N8n agents: ${result.summary.n8nInstalled.agents}`));
|
|
325
|
-
console.log(chalk.gray(` • N8n skills: ${result.summary.n8nInstalled.skills}`));
|
|
326
|
-
}
|
|
327
|
-
console.log(chalk.gray(` • Total time: ${result.totalDurationMs}ms\n`));
|
|
328
|
-
console.log(chalk.white('Next steps:'));
|
|
329
|
-
console.log(chalk.gray(' 1. Add MCP: claude mcp add aqe -- aqe-mcp'));
|
|
330
|
-
console.log(chalk.gray(' 2. Run tests: aqe test <path>'));
|
|
331
|
-
console.log(chalk.gray(' 3. Check status: aqe status\n'));
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
console.log(chalk.red('❌ Initialization failed. Check errors above.\n'));
|
|
335
|
-
await cleanupAndExit(1);
|
|
336
|
-
}
|
|
337
|
-
await cleanupAndExit(0);
|
|
338
|
-
}
|
|
339
|
-
// Standard init without wizard
|
|
340
|
-
console.log(chalk.blue('\n🚀 Initializing Agentic QE v3...\n'));
|
|
341
|
-
// Determine enabled domains
|
|
342
|
-
const enabledDomains = options.domains === 'all'
|
|
343
|
-
? [...ALL_DOMAINS]
|
|
344
|
-
: options.domains.split(',').filter((d) => ALL_DOMAINS.includes(d));
|
|
345
|
-
console.log(chalk.gray(` Domains: ${enabledDomains.length}`));
|
|
346
|
-
console.log(chalk.gray(` Max Agents: ${options.maxAgents}`));
|
|
347
|
-
console.log(chalk.gray(` Memory: ${options.memory}`));
|
|
348
|
-
console.log(chalk.gray(` Lazy Loading: ${options.lazy ? 'enabled' : 'disabled'}\n`));
|
|
349
|
-
// Create kernel
|
|
350
|
-
context.kernel = new QEKernelImpl({
|
|
351
|
-
maxConcurrentAgents: parseInt(options.maxAgents, 10),
|
|
352
|
-
memoryBackend: options.memory,
|
|
353
|
-
hnswEnabled: true,
|
|
354
|
-
lazyLoading: options.lazy || false,
|
|
355
|
-
enabledDomains,
|
|
356
|
-
});
|
|
357
|
-
await context.kernel.initialize();
|
|
358
|
-
console.log(chalk.green(' ✓ Kernel initialized'));
|
|
359
|
-
// Create cross-domain router
|
|
360
|
-
context.router = new CrossDomainEventRouter(context.kernel.eventBus);
|
|
361
|
-
await context.router.initialize();
|
|
362
|
-
console.log(chalk.green(' ✓ Cross-domain router initialized'));
|
|
363
|
-
// Create protocol executor
|
|
364
|
-
const getDomainAPI = (domain) => {
|
|
365
|
-
return context.kernel.getDomainAPI(domain);
|
|
366
|
-
};
|
|
367
|
-
const protocolExecutor = new DefaultProtocolExecutor(context.kernel.eventBus, context.kernel.memory, getDomainAPI);
|
|
368
|
-
console.log(chalk.green(' ✓ Protocol executor initialized'));
|
|
369
|
-
// Create workflow orchestrator
|
|
370
|
-
context.workflowOrchestrator = new WorkflowOrchestrator(context.kernel.eventBus, context.kernel.memory, context.kernel.coordinator);
|
|
371
|
-
await context.workflowOrchestrator.initialize();
|
|
372
|
-
// Register domain workflow actions (Issue #206)
|
|
373
|
-
registerDomainWorkflowActions(context.kernel, context.workflowOrchestrator);
|
|
374
|
-
console.log(chalk.green(' ✓ Workflow orchestrator initialized'));
|
|
375
|
-
// Create Queen Coordinator
|
|
376
|
-
// Note: workflowExecutor is omitted as WorkflowOrchestrator uses different interface
|
|
377
|
-
context.queen = createQueenCoordinator(context.kernel, context.router, protocolExecutor, undefined // WorkflowExecutor - optional, can be added later
|
|
378
|
-
);
|
|
379
|
-
await context.queen.initialize();
|
|
380
|
-
console.log(chalk.green(' ✓ Queen Coordinator initialized'));
|
|
381
|
-
context.initialized = true;
|
|
382
|
-
console.log(chalk.green('\n✅ AQE v3 initialized successfully!\n'));
|
|
383
|
-
// Show enabled domains
|
|
384
|
-
console.log(chalk.blue('📦 Enabled Domains:'));
|
|
385
|
-
for (const domain of enabledDomains) {
|
|
386
|
-
console.log(chalk.gray(` • ${domain}`));
|
|
387
|
-
}
|
|
388
|
-
console.log('');
|
|
389
|
-
await cleanupAndExit(0);
|
|
390
|
-
}
|
|
391
|
-
catch (error) {
|
|
392
|
-
console.error(chalk.red('\n❌ Failed to initialize:'), error);
|
|
393
|
-
await cleanupAndExit(1);
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
// ============================================================================
|
|
397
|
-
// Status Command
|
|
398
|
-
// ============================================================================
|
|
399
|
-
program
|
|
400
|
-
.command('status')
|
|
401
|
-
.description('Show system status')
|
|
402
|
-
.option('-v, --verbose', 'Show detailed status')
|
|
403
|
-
.action(async (options) => {
|
|
404
|
-
if (!await ensureInitialized())
|
|
405
|
-
return;
|
|
406
|
-
try {
|
|
407
|
-
const health = context.queen.getHealth();
|
|
408
|
-
const metrics = context.queen.getMetrics();
|
|
409
|
-
console.log(chalk.blue('\n📊 AQE v3 Status\n'));
|
|
410
|
-
// Overall health
|
|
411
|
-
console.log(` Status: ${getStatusColor(health.status)}`);
|
|
412
|
-
console.log(` Uptime: ${chalk.cyan(formatUptime(metrics.uptime))}`);
|
|
413
|
-
console.log(` Work Stealing: ${health.workStealingActive ? chalk.green('active') : chalk.gray('inactive')}`);
|
|
414
|
-
// Agents
|
|
415
|
-
console.log(chalk.blue('\n👥 Agents:'));
|
|
416
|
-
console.log(` Total: ${chalk.cyan(health.totalAgents)}`);
|
|
417
|
-
console.log(` Active: ${chalk.yellow(health.activeAgents)}`);
|
|
418
|
-
console.log(` Utilization: ${chalk.cyan((metrics.agentUtilization * 100).toFixed(1))}%`);
|
|
419
|
-
// Tasks
|
|
420
|
-
console.log(chalk.blue('\n📋 Tasks:'));
|
|
421
|
-
console.log(` Received: ${chalk.cyan(metrics.tasksReceived)}`);
|
|
422
|
-
console.log(` Completed: ${chalk.green(metrics.tasksCompleted)}`);
|
|
423
|
-
console.log(` Failed: ${chalk.red(metrics.tasksFailed)}`);
|
|
424
|
-
console.log(` Pending: ${chalk.yellow(health.pendingTasks)}`);
|
|
425
|
-
console.log(` Running: ${chalk.yellow(health.runningTasks)}`);
|
|
426
|
-
if (metrics.tasksStolen > 0) {
|
|
427
|
-
console.log(` Stolen (work stealing): ${chalk.cyan(metrics.tasksStolen)}`);
|
|
428
|
-
}
|
|
429
|
-
// Protocols & Workflows
|
|
430
|
-
if (metrics.protocolsExecuted > 0 || metrics.workflowsExecuted > 0) {
|
|
431
|
-
console.log(chalk.blue('\n🔄 Coordination:'));
|
|
432
|
-
console.log(` Protocols Executed: ${chalk.cyan(metrics.protocolsExecuted)}`);
|
|
433
|
-
console.log(` Workflows Executed: ${chalk.cyan(metrics.workflowsExecuted)}`);
|
|
434
|
-
}
|
|
435
|
-
// Verbose domain status
|
|
436
|
-
if (options.verbose) {
|
|
437
|
-
console.log(chalk.blue('\n📦 Domain Status:'));
|
|
438
|
-
for (const [domain, domainHealth] of health.domainHealth) {
|
|
439
|
-
console.log(` ${domain}: ${getStatusColor(domainHealth.status)}`);
|
|
440
|
-
console.log(chalk.gray(` Agents: ${domainHealth.agents.active}/${domainHealth.agents.total} active`));
|
|
441
|
-
if (domainHealth.errors.length > 0) {
|
|
442
|
-
console.log(chalk.red(` Errors: ${domainHealth.errors.length}`));
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
// Domain utilization
|
|
446
|
-
console.log(chalk.blue('\n📈 Domain Load:'));
|
|
447
|
-
for (const [domain, load] of metrics.domainUtilization) {
|
|
448
|
-
const bar = '█'.repeat(Math.min(load, 20)) + '░'.repeat(Math.max(0, 20 - load));
|
|
449
|
-
console.log(` ${domain.padEnd(25)} ${bar} ${load}`);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
// Health issues
|
|
453
|
-
if (health.issues.length > 0) {
|
|
454
|
-
console.log(chalk.red('\n⚠️ Issues:'));
|
|
455
|
-
for (const issue of health.issues) {
|
|
456
|
-
const color = issue.severity === 'high' ? chalk.red :
|
|
457
|
-
issue.severity === 'medium' ? chalk.yellow : chalk.gray;
|
|
458
|
-
console.log(` ${color(`[${issue.severity}]`)} ${issue.message}`);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
console.log('');
|
|
462
|
-
await cleanupAndExit(0);
|
|
463
|
-
}
|
|
464
|
-
catch (error) {
|
|
465
|
-
console.error(chalk.red('\n❌ Failed to get status:'), error);
|
|
466
|
-
await cleanupAndExit(1);
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
// ============================================================================
|
|
470
|
-
// Health Command
|
|
471
|
-
// ============================================================================
|
|
472
|
-
program
|
|
473
|
-
.command('health')
|
|
474
|
-
.description('Check system health')
|
|
475
|
-
.option('-d, --domain <domain>', 'Check specific domain health')
|
|
476
|
-
.action(async (options) => {
|
|
477
|
-
if (!await ensureInitialized())
|
|
478
|
-
return;
|
|
479
|
-
try {
|
|
480
|
-
if (options.domain) {
|
|
481
|
-
const domain = options.domain;
|
|
482
|
-
const health = context.queen.getDomainHealth(domain);
|
|
483
|
-
if (!health) {
|
|
484
|
-
console.log(chalk.red(`\n❌ Domain not found: ${domain}\n`));
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
console.log(chalk.blue(`\n🏥 Health: ${domain}\n`));
|
|
488
|
-
console.log(` Status: ${getStatusColor(health.status)}`);
|
|
489
|
-
console.log(` Agents: ${health.agents.active}/${health.agents.total} active`);
|
|
490
|
-
console.log(` Idle: ${health.agents.idle}`);
|
|
491
|
-
console.log(` Failed: ${health.agents.failed}`);
|
|
492
|
-
if (health.lastActivity) {
|
|
493
|
-
console.log(` Last Activity: ${health.lastActivity.toISOString()}`);
|
|
494
|
-
}
|
|
495
|
-
if (health.errors.length > 0) {
|
|
496
|
-
console.log(chalk.red(`\n Errors:`));
|
|
497
|
-
health.errors.forEach(err => console.log(chalk.red(` • ${err}`)));
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
else {
|
|
501
|
-
const health = context.queen.getHealth();
|
|
502
|
-
console.log(chalk.blue('\n🏥 System Health\n'));
|
|
503
|
-
console.log(` Overall: ${getStatusColor(health.status)}`);
|
|
504
|
-
console.log(` Last Check: ${health.lastHealthCheck.toISOString()}`);
|
|
505
|
-
// Issue #205 fix: Summary by status including 'idle'
|
|
506
|
-
let healthy = 0, idle = 0, degraded = 0, unhealthy = 0;
|
|
507
|
-
for (const [, domainHealth] of health.domainHealth) {
|
|
508
|
-
if (domainHealth.status === 'healthy')
|
|
509
|
-
healthy++;
|
|
510
|
-
else if (domainHealth.status === 'idle')
|
|
511
|
-
idle++;
|
|
512
|
-
else if (domainHealth.status === 'degraded')
|
|
513
|
-
degraded++;
|
|
514
|
-
else
|
|
515
|
-
unhealthy++;
|
|
516
|
-
}
|
|
517
|
-
console.log(chalk.blue('\n📦 Domains:'));
|
|
518
|
-
console.log(` ${chalk.green('●')} Healthy: ${healthy}`);
|
|
519
|
-
console.log(` ${chalk.cyan('●')} Idle (ready): ${idle}`);
|
|
520
|
-
console.log(` ${chalk.yellow('●')} Degraded: ${degraded}`);
|
|
521
|
-
console.log(` ${chalk.red('●')} Unhealthy: ${unhealthy}`);
|
|
522
|
-
// Issue #205 fix: Add helpful tip for fresh installs
|
|
523
|
-
if (idle > 0 && healthy === 0 && degraded === 0 && unhealthy === 0) {
|
|
524
|
-
console.log(chalk.gray('\n 💡 Tip: Domains are idle (ready). Run a task to spawn agents.'));
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
console.log('');
|
|
528
|
-
await cleanupAndExit(0);
|
|
529
|
-
}
|
|
530
|
-
catch (error) {
|
|
531
|
-
console.error(chalk.red('\n❌ Health check failed:'), error);
|
|
532
|
-
await cleanupAndExit(1);
|
|
533
|
-
}
|
|
534
|
-
});
|
|
535
|
-
// ============================================================================
|
|
536
|
-
// Task Command Group
|
|
537
|
-
// ============================================================================
|
|
538
|
-
const taskCmd = program
|
|
539
|
-
.command('task')
|
|
540
|
-
.description('Manage QE tasks');
|
|
541
|
-
taskCmd
|
|
542
|
-
.command('submit <type>')
|
|
543
|
-
.description('Submit a task to the Queen Coordinator')
|
|
544
|
-
.option('-p, --priority <priority>', 'Task priority (p0|p1|p2|p3)', 'p1')
|
|
545
|
-
.option('-d, --domain <domain>', 'Target domain')
|
|
546
|
-
.option('-t, --timeout <ms>', 'Task timeout in ms', '300000')
|
|
547
|
-
.option('--payload <json>', 'Task payload as JSON', '{}')
|
|
548
|
-
.option('--wait', 'Wait for task completion with progress')
|
|
549
|
-
.option('--no-progress', 'Disable progress indicator')
|
|
550
|
-
.action(async (type, options) => {
|
|
551
|
-
if (!await ensureInitialized())
|
|
552
|
-
return;
|
|
553
|
-
try {
|
|
554
|
-
const taskType = type;
|
|
555
|
-
const payload = parseJsonOption(options.payload, 'payload');
|
|
556
|
-
const targetDomains = options.domain ? [options.domain] : [];
|
|
557
|
-
console.log(chalk.blue(`\n Submitting task: ${taskType}\n`));
|
|
558
|
-
// Use spinner for submit operation
|
|
559
|
-
const spinner = options.progress !== false
|
|
560
|
-
? createTimedSpinner(`Submitting ${taskType} task`)
|
|
561
|
-
: null;
|
|
562
|
-
const result = await context.queen.submitTask({
|
|
563
|
-
type: taskType,
|
|
564
|
-
priority: options.priority,
|
|
565
|
-
targetDomains,
|
|
566
|
-
payload,
|
|
567
|
-
timeout: parseInt(options.timeout, 10),
|
|
568
|
-
});
|
|
569
|
-
if (spinner) {
|
|
570
|
-
if (result.success) {
|
|
571
|
-
spinner.succeed(`Task submitted successfully`);
|
|
572
|
-
}
|
|
573
|
-
else {
|
|
574
|
-
spinner.fail(`Failed to submit task`);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
if (result.success) {
|
|
578
|
-
console.log(chalk.cyan(` ID: ${result.value}`));
|
|
579
|
-
console.log(chalk.gray(` Type: ${taskType}`));
|
|
580
|
-
console.log(chalk.gray(` Priority: ${options.priority}`));
|
|
581
|
-
// If --wait flag is provided, poll for task completion with progress
|
|
582
|
-
if (options.wait) {
|
|
583
|
-
console.log('');
|
|
584
|
-
const taskId = result.value;
|
|
585
|
-
const waitSpinner = createTimedSpinner('Waiting for task completion');
|
|
586
|
-
const timeout = parseInt(options.timeout, 10);
|
|
587
|
-
const startTime = Date.now();
|
|
588
|
-
let completed = false;
|
|
589
|
-
while (!completed && (Date.now() - startTime) < timeout) {
|
|
590
|
-
const taskStatus = context.queen.getTaskStatus(taskId);
|
|
591
|
-
if (taskStatus) {
|
|
592
|
-
if (taskStatus.status === 'completed') {
|
|
593
|
-
waitSpinner.succeed('Task completed successfully');
|
|
594
|
-
completed = true;
|
|
595
|
-
}
|
|
596
|
-
else if (taskStatus.status === 'failed') {
|
|
597
|
-
waitSpinner.fail(`Task failed: ${taskStatus.error || 'Unknown error'}`);
|
|
598
|
-
completed = true;
|
|
599
|
-
}
|
|
600
|
-
else {
|
|
601
|
-
// Update spinner with progress info
|
|
602
|
-
waitSpinner.spinner.text = `Task ${taskStatus.status}... (${Math.round((Date.now() - startTime) / 1000)}s)`;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
if (!completed) {
|
|
606
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
if (!completed) {
|
|
610
|
-
waitSpinner.fail('Task timed out');
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
console.log(chalk.red(` Error: ${result.error.message}`));
|
|
616
|
-
}
|
|
617
|
-
console.log('');
|
|
618
|
-
}
|
|
619
|
-
catch (error) {
|
|
620
|
-
console.error(chalk.red('\n Failed to submit task:'), error);
|
|
621
|
-
await cleanupAndExit(1);
|
|
622
|
-
}
|
|
623
|
-
});
|
|
624
|
-
taskCmd
|
|
625
|
-
.command('list')
|
|
626
|
-
.description('List all tasks')
|
|
627
|
-
.option('-s, --status <status>', 'Filter by status')
|
|
628
|
-
.option('-p, --priority <priority>', 'Filter by priority')
|
|
629
|
-
.option('-d, --domain <domain>', 'Filter by domain')
|
|
630
|
-
.action(async (options) => {
|
|
631
|
-
if (!await ensureInitialized())
|
|
632
|
-
return;
|
|
633
|
-
try {
|
|
634
|
-
const tasks = context.queen.listTasks({
|
|
635
|
-
status: options.status,
|
|
636
|
-
priority: options.priority,
|
|
637
|
-
domain: options.domain,
|
|
638
|
-
});
|
|
639
|
-
console.log(chalk.blue(`\n📋 Tasks (${tasks.length})\n`));
|
|
640
|
-
if (tasks.length === 0) {
|
|
641
|
-
console.log(chalk.gray(' No tasks found'));
|
|
642
|
-
}
|
|
643
|
-
else {
|
|
644
|
-
for (const task of tasks) {
|
|
645
|
-
console.log(` ${chalk.cyan(task.taskId)}`);
|
|
646
|
-
console.log(` Type: ${task.task.type}`);
|
|
647
|
-
console.log(` Status: ${getStatusColor(task.status)}`);
|
|
648
|
-
console.log(` Priority: ${task.task.priority}`);
|
|
649
|
-
if (task.assignedDomain) {
|
|
650
|
-
console.log(` Domain: ${task.assignedDomain}`);
|
|
651
|
-
}
|
|
652
|
-
if (task.startedAt) {
|
|
653
|
-
console.log(chalk.gray(` Started: ${task.startedAt.toISOString()}`));
|
|
654
|
-
}
|
|
655
|
-
console.log('');
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
catch (error) {
|
|
660
|
-
console.error(chalk.red('\n❌ Failed to list tasks:'), error);
|
|
661
|
-
await cleanupAndExit(1);
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
taskCmd
|
|
665
|
-
.command('cancel <taskId>')
|
|
666
|
-
.description('Cancel a task')
|
|
667
|
-
.action(async (taskId) => {
|
|
668
|
-
if (!await ensureInitialized())
|
|
669
|
-
return;
|
|
670
|
-
try {
|
|
671
|
-
const result = await context.queen.cancelTask(taskId);
|
|
672
|
-
if (result.success) {
|
|
673
|
-
console.log(chalk.green(`\n✅ Task cancelled: ${taskId}\n`));
|
|
674
|
-
}
|
|
675
|
-
else {
|
|
676
|
-
console.log(chalk.red(`\n❌ Failed to cancel task: ${result.error.message}\n`));
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
catch (error) {
|
|
680
|
-
console.error(chalk.red('\n❌ Failed to cancel task:'), error);
|
|
681
|
-
await cleanupAndExit(1);
|
|
682
|
-
}
|
|
683
|
-
});
|
|
684
|
-
taskCmd
|
|
685
|
-
.command('status <taskId>')
|
|
686
|
-
.description('Get task status')
|
|
687
|
-
.action(async (taskId) => {
|
|
688
|
-
if (!await ensureInitialized())
|
|
689
|
-
return;
|
|
690
|
-
try {
|
|
691
|
-
const task = context.queen.getTaskStatus(taskId);
|
|
692
|
-
if (!task) {
|
|
693
|
-
console.log(chalk.red(`\n❌ Task not found: ${taskId}\n`));
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
console.log(chalk.blue(`\n📋 Task: ${taskId}\n`));
|
|
697
|
-
console.log(` Type: ${task.task.type}`);
|
|
698
|
-
console.log(` Status: ${getStatusColor(task.status)}`);
|
|
699
|
-
console.log(` Priority: ${task.task.priority}`);
|
|
700
|
-
if (task.assignedDomain) {
|
|
701
|
-
console.log(` Domain: ${task.assignedDomain}`);
|
|
702
|
-
}
|
|
703
|
-
if (task.assignedAgents.length > 0) {
|
|
704
|
-
console.log(` Agents: ${task.assignedAgents.join(', ')}`);
|
|
705
|
-
}
|
|
706
|
-
console.log(` Created: ${task.task.createdAt.toISOString()}`);
|
|
707
|
-
if (task.startedAt) {
|
|
708
|
-
console.log(` Started: ${task.startedAt.toISOString()}`);
|
|
709
|
-
}
|
|
710
|
-
if (task.completedAt) {
|
|
711
|
-
console.log(` Completed: ${task.completedAt.toISOString()}`);
|
|
712
|
-
const duration = task.completedAt.getTime() - task.startedAt.getTime();
|
|
713
|
-
console.log(` Duration: ${formatDuration(duration)}`);
|
|
714
|
-
}
|
|
715
|
-
if (task.error) {
|
|
716
|
-
console.log(chalk.red(` Error: ${task.error}`));
|
|
717
|
-
}
|
|
718
|
-
if (task.retryCount > 0) {
|
|
719
|
-
console.log(chalk.yellow(` Retries: ${task.retryCount}`));
|
|
720
|
-
}
|
|
721
|
-
console.log('');
|
|
722
|
-
}
|
|
723
|
-
catch (error) {
|
|
724
|
-
console.error(chalk.red('\n❌ Failed to get task status:'), error);
|
|
725
|
-
await cleanupAndExit(1);
|
|
726
|
-
}
|
|
727
|
-
});
|
|
728
|
-
// ============================================================================
|
|
729
|
-
// Agent Command Group
|
|
730
|
-
// ============================================================================
|
|
731
|
-
const agentCmd = program
|
|
732
|
-
.command('agent')
|
|
733
|
-
.description('Manage QE agents');
|
|
734
|
-
agentCmd
|
|
735
|
-
.command('list')
|
|
736
|
-
.description('List all agents')
|
|
737
|
-
.option('-d, --domain <domain>', 'Filter by domain')
|
|
738
|
-
.option('-s, --status <status>', 'Filter by status')
|
|
739
|
-
.action(async (options) => {
|
|
740
|
-
if (!await ensureInitialized())
|
|
741
|
-
return;
|
|
742
|
-
try {
|
|
743
|
-
let agents = options.domain
|
|
744
|
-
? context.queen.getAgentsByDomain(options.domain)
|
|
745
|
-
: context.queen.listAllAgents();
|
|
746
|
-
if (options.status) {
|
|
747
|
-
agents = agents.filter(a => a.status === options.status);
|
|
748
|
-
}
|
|
749
|
-
console.log(chalk.blue(`\n👥 Agents (${agents.length})\n`));
|
|
750
|
-
if (agents.length === 0) {
|
|
751
|
-
console.log(chalk.gray(' No agents found'));
|
|
752
|
-
}
|
|
753
|
-
else {
|
|
754
|
-
// Group by domain
|
|
755
|
-
const byDomain = new Map();
|
|
756
|
-
for (const agent of agents) {
|
|
757
|
-
if (!byDomain.has(agent.domain)) {
|
|
758
|
-
byDomain.set(agent.domain, []);
|
|
759
|
-
}
|
|
760
|
-
byDomain.get(agent.domain).push(agent);
|
|
761
|
-
}
|
|
762
|
-
for (const [domain, domainAgents] of byDomain) {
|
|
763
|
-
console.log(chalk.cyan(` ${domain}:`));
|
|
764
|
-
for (const agent of domainAgents) {
|
|
765
|
-
console.log(` ${agent.id}`);
|
|
766
|
-
console.log(` Type: ${agent.type}`);
|
|
767
|
-
console.log(` Status: ${getStatusColor(agent.status)}`);
|
|
768
|
-
if (agent.startedAt) {
|
|
769
|
-
console.log(chalk.gray(` Started: ${agent.startedAt.toISOString()}`));
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
console.log('');
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
catch (error) {
|
|
777
|
-
console.error(chalk.red('\n❌ Failed to list agents:'), error);
|
|
778
|
-
await cleanupAndExit(1);
|
|
779
|
-
}
|
|
780
|
-
});
|
|
781
|
-
agentCmd
|
|
782
|
-
.command('spawn <domain>')
|
|
783
|
-
.description('Spawn an agent in a domain')
|
|
784
|
-
.option('-t, --type <type>', 'Agent type', 'worker')
|
|
785
|
-
.option('-c, --capabilities <caps>', 'Comma-separated capabilities', 'general')
|
|
786
|
-
.option('--no-progress', 'Disable progress indicator')
|
|
787
|
-
.action(async (domain, options) => {
|
|
788
|
-
if (!await ensureInitialized())
|
|
789
|
-
return;
|
|
790
|
-
try {
|
|
791
|
-
const capabilities = options.capabilities.split(',');
|
|
792
|
-
console.log(chalk.blue(`\n Spawning agent in ${domain}...\n`));
|
|
793
|
-
// Use spinner for spawn operation
|
|
794
|
-
const spinner = options.progress !== false
|
|
795
|
-
? createTimedSpinner(`Spawning ${options.type} agent`)
|
|
796
|
-
: null;
|
|
797
|
-
const result = await context.queen.requestAgentSpawn(domain, options.type, capabilities);
|
|
798
|
-
if (spinner) {
|
|
799
|
-
if (result.success) {
|
|
800
|
-
spinner.succeed(`Agent spawned successfully`);
|
|
801
|
-
}
|
|
802
|
-
else {
|
|
803
|
-
spinner.fail(`Failed to spawn agent`);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
if (result.success) {
|
|
807
|
-
console.log(chalk.cyan(` ID: ${result.value}`));
|
|
808
|
-
console.log(chalk.gray(` Domain: ${domain}`));
|
|
809
|
-
console.log(chalk.gray(` Type: ${options.type}`));
|
|
810
|
-
console.log(chalk.gray(` Capabilities: ${capabilities.join(', ')}`));
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
console.log(chalk.red(` Error: ${result.error.message}`));
|
|
814
|
-
}
|
|
815
|
-
console.log('');
|
|
816
|
-
}
|
|
817
|
-
catch (error) {
|
|
818
|
-
console.error(chalk.red('\n Failed to spawn agent:'), error);
|
|
819
|
-
await cleanupAndExit(1);
|
|
820
|
-
}
|
|
821
|
-
});
|
|
822
|
-
// ============================================================================
|
|
823
|
-
// Domain Command Group
|
|
824
|
-
// ============================================================================
|
|
825
|
-
const domainCmd = program
|
|
826
|
-
.command('domain')
|
|
827
|
-
.description('Domain operations');
|
|
828
|
-
domainCmd
|
|
829
|
-
.command('list')
|
|
830
|
-
.description('List all domains')
|
|
831
|
-
.action(async () => {
|
|
832
|
-
if (!await ensureInitialized())
|
|
833
|
-
return;
|
|
834
|
-
try {
|
|
835
|
-
console.log(chalk.blue('\n📦 Domains\n'));
|
|
836
|
-
for (const domain of ALL_DOMAINS) {
|
|
837
|
-
const health = context.queen.getDomainHealth(domain);
|
|
838
|
-
const load = context.queen.getDomainLoad(domain);
|
|
839
|
-
console.log(` ${chalk.cyan(domain)}`);
|
|
840
|
-
console.log(` Status: ${getStatusColor(health?.status || 'unknown')}`);
|
|
841
|
-
console.log(` Load: ${load} tasks`);
|
|
842
|
-
if (health) {
|
|
843
|
-
console.log(` Agents: ${health.agents.active}/${health.agents.total}`);
|
|
844
|
-
}
|
|
845
|
-
console.log('');
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
catch (error) {
|
|
849
|
-
console.error(chalk.red('\n❌ Failed to list domains:'), error);
|
|
850
|
-
await cleanupAndExit(1);
|
|
851
|
-
}
|
|
852
|
-
});
|
|
853
|
-
domainCmd
|
|
854
|
-
.command('health <domain>')
|
|
855
|
-
.description('Get domain health')
|
|
856
|
-
.action(async (domain) => {
|
|
857
|
-
if (!await ensureInitialized())
|
|
858
|
-
return;
|
|
859
|
-
try {
|
|
860
|
-
const health = context.queen.getDomainHealth(domain);
|
|
861
|
-
if (!health) {
|
|
862
|
-
console.log(chalk.red(`\n❌ Domain not found: ${domain}\n`));
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
console.log(chalk.blue(`\n🏥 ${domain} Health\n`));
|
|
866
|
-
console.log(` Status: ${getStatusColor(health.status)}`);
|
|
867
|
-
console.log(` Agents Total: ${health.agents.total}`);
|
|
868
|
-
console.log(` Agents Active: ${chalk.green(health.agents.active)}`);
|
|
869
|
-
console.log(` Agents Idle: ${chalk.yellow(health.agents.idle)}`);
|
|
870
|
-
console.log(` Agents Failed: ${chalk.red(health.agents.failed)}`);
|
|
871
|
-
if (health.lastActivity) {
|
|
872
|
-
console.log(` Last Activity: ${health.lastActivity.toISOString()}`);
|
|
873
|
-
}
|
|
874
|
-
if (health.errors.length > 0) {
|
|
875
|
-
console.log(chalk.red('\n Errors:'));
|
|
876
|
-
health.errors.forEach(err => console.log(chalk.red(` • ${err}`)));
|
|
877
|
-
}
|
|
878
|
-
console.log('');
|
|
879
|
-
}
|
|
880
|
-
catch (error) {
|
|
881
|
-
console.error(chalk.red('\n❌ Failed to get domain health:'), error);
|
|
882
|
-
await cleanupAndExit(1);
|
|
883
|
-
}
|
|
884
|
-
});
|
|
885
|
-
// ============================================================================
|
|
886
|
-
// Protocol Command Group
|
|
142
|
+
// Register Handlers via CommandRegistry
|
|
887
143
|
// ============================================================================
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
.description('Execute coordination protocols');
|
|
891
|
-
protocolCmd
|
|
892
|
-
.command('run <protocolId>')
|
|
893
|
-
.description('Execute a protocol')
|
|
894
|
-
.option('--params <json>', 'Protocol parameters as JSON', '{}')
|
|
895
|
-
.action(async (protocolId, options) => {
|
|
896
|
-
if (!await ensureInitialized())
|
|
897
|
-
return;
|
|
898
|
-
try {
|
|
899
|
-
const params = parseJsonOption(options.params, 'params');
|
|
900
|
-
console.log(chalk.blue(`\n🔄 Executing protocol: ${protocolId}\n`));
|
|
901
|
-
const result = await context.queen.executeProtocol(protocolId, params);
|
|
902
|
-
if (result.success) {
|
|
903
|
-
console.log(chalk.green(`✅ Protocol execution started`));
|
|
904
|
-
console.log(chalk.cyan(` Execution ID: ${result.value}`));
|
|
905
|
-
}
|
|
906
|
-
else {
|
|
907
|
-
console.log(chalk.red(`❌ Failed to execute protocol: ${result.error.message}`));
|
|
908
|
-
}
|
|
909
|
-
console.log('');
|
|
910
|
-
}
|
|
911
|
-
catch (error) {
|
|
912
|
-
console.error(chalk.red('\n❌ Failed to execute protocol:'), error);
|
|
913
|
-
await cleanupAndExit(1);
|
|
914
|
-
}
|
|
915
|
-
});
|
|
144
|
+
const registry = createCommandRegistry(context, cleanupAndExit, ensureInitialized);
|
|
145
|
+
registry.registerAll(program);
|
|
916
146
|
// ============================================================================
|
|
917
147
|
// Workflow Command Group (ADR-041)
|
|
918
148
|
// ============================================================================
|
|
@@ -933,7 +163,6 @@ workflowCmd
|
|
|
933
163
|
const filePath = pathModule.resolve(file);
|
|
934
164
|
try {
|
|
935
165
|
console.log(chalk.blue(`\n Running workflow from: ${file}\n`));
|
|
936
|
-
// Parse the pipeline file
|
|
937
166
|
const parseResult = parsePipelineFile(filePath);
|
|
938
167
|
if (!parseResult.success || !parseResult.workflow) {
|
|
939
168
|
console.log(chalk.red('Failed to parse pipeline:'));
|
|
@@ -942,11 +171,8 @@ workflowCmd
|
|
|
942
171
|
}
|
|
943
172
|
await cleanupAndExit(1);
|
|
944
173
|
}
|
|
945
|
-
// Additional params (SEC-001: safe parsing prevents prototype pollution)
|
|
946
174
|
const additionalParams = parseJsonOption(options.params, 'params');
|
|
947
|
-
// Build input from pipeline params and additional params
|
|
948
175
|
const input = { ...additionalParams };
|
|
949
|
-
// Add stage params to input context
|
|
950
176
|
if (parseResult.pipeline) {
|
|
951
177
|
for (const stage of parseResult.pipeline.stages) {
|
|
952
178
|
if (stage.params) {
|
|
@@ -956,7 +182,6 @@ workflowCmd
|
|
|
956
182
|
}
|
|
957
183
|
}
|
|
958
184
|
}
|
|
959
|
-
// Register the workflow if not already registered
|
|
960
185
|
const existingWorkflow = context.workflowOrchestrator.getWorkflow(parseResult.workflow.id);
|
|
961
186
|
if (!existingWorkflow) {
|
|
962
187
|
const registerResult = context.workflowOrchestrator.registerWorkflow(parseResult.workflow);
|
|
@@ -965,19 +190,17 @@ workflowCmd
|
|
|
965
190
|
await cleanupAndExit(1);
|
|
966
191
|
}
|
|
967
192
|
}
|
|
968
|
-
// Execute the workflow
|
|
969
193
|
const execResult = await context.workflowOrchestrator.executeWorkflow(parseResult.workflow.id, input);
|
|
970
194
|
if (!execResult.success) {
|
|
971
195
|
console.log(chalk.red(`Failed to start workflow: ${execResult.error.message}`));
|
|
972
196
|
await cleanupAndExit(1);
|
|
973
|
-
return;
|
|
197
|
+
return;
|
|
974
198
|
}
|
|
975
199
|
const executionId = execResult.value;
|
|
976
200
|
console.log(chalk.cyan(` Execution ID: ${executionId}`));
|
|
977
201
|
console.log(chalk.gray(` Workflow: ${parseResult.workflow.name}`));
|
|
978
202
|
console.log(chalk.gray(` Stages: ${parseResult.workflow.steps.length}`));
|
|
979
203
|
console.log('');
|
|
980
|
-
// Watch progress if requested
|
|
981
204
|
if (options.watch) {
|
|
982
205
|
console.log(chalk.blue('Workflow Progress:\n'));
|
|
983
206
|
let lastStatus;
|
|
@@ -986,12 +209,10 @@ workflowCmd
|
|
|
986
209
|
const status = context.workflowOrchestrator.getWorkflowStatus(executionId);
|
|
987
210
|
if (!status)
|
|
988
211
|
break;
|
|
989
|
-
// Update display if status changed
|
|
990
212
|
if (!lastStatus ||
|
|
991
213
|
lastStatus.progress !== status.progress ||
|
|
992
214
|
lastStatus.status !== status.status ||
|
|
993
215
|
JSON.stringify(lastStatus.currentSteps) !== JSON.stringify(status.currentSteps)) {
|
|
994
|
-
// Clear line and show progress
|
|
995
216
|
process.stdout.write('\r\x1b[K');
|
|
996
217
|
const progressBar = String.fromCharCode(0x2588).repeat(Math.floor(status.progress / 5)) +
|
|
997
218
|
String.fromCharCode(0x2591).repeat(20 - Math.floor(status.progress / 5));
|
|
@@ -1004,14 +225,11 @@ workflowCmd
|
|
|
1004
225
|
}
|
|
1005
226
|
lastStatus = status;
|
|
1006
227
|
}
|
|
1007
|
-
// Check if completed
|
|
1008
228
|
if (status.status === 'completed' || status.status === 'failed' || status.status === 'cancelled') {
|
|
1009
229
|
break;
|
|
1010
230
|
}
|
|
1011
|
-
// Wait before next check
|
|
1012
231
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
1013
232
|
}
|
|
1014
|
-
// Show final status
|
|
1015
233
|
const finalStatus = context.workflowOrchestrator.getWorkflowStatus(executionId);
|
|
1016
234
|
if (finalStatus) {
|
|
1017
235
|
console.log('');
|
|
@@ -1054,12 +272,10 @@ workflowCmd
|
|
|
1054
272
|
.action(async (file, options) => {
|
|
1055
273
|
if (!await ensureInitialized())
|
|
1056
274
|
return;
|
|
1057
|
-
const fs = await import('fs');
|
|
1058
275
|
const pathModule = await import('path');
|
|
1059
276
|
const filePath = pathModule.resolve(file);
|
|
1060
277
|
try {
|
|
1061
278
|
console.log(chalk.blue(`\nScheduling workflow from: ${file}\n`));
|
|
1062
|
-
// Parse the pipeline file
|
|
1063
279
|
const parseResult = parsePipelineFile(filePath);
|
|
1064
280
|
if (!parseResult.success || !parseResult.pipeline || !parseResult.workflow) {
|
|
1065
281
|
console.log(chalk.red('Failed to parse pipeline:'));
|
|
@@ -1068,14 +284,12 @@ workflowCmd
|
|
|
1068
284
|
}
|
|
1069
285
|
await cleanupAndExit(1);
|
|
1070
286
|
}
|
|
1071
|
-
// Get schedule from option or file
|
|
1072
287
|
const schedule = options.cron || parseResult.pipeline.schedule;
|
|
1073
288
|
if (!schedule) {
|
|
1074
289
|
console.log(chalk.red('No schedule specified'));
|
|
1075
290
|
console.log(chalk.gray(' Add "schedule" field to YAML or use --cron option'));
|
|
1076
291
|
await cleanupAndExit(1);
|
|
1077
292
|
}
|
|
1078
|
-
// Register the workflow
|
|
1079
293
|
const existingWorkflow = context.workflowOrchestrator.getWorkflow(parseResult.workflow.id);
|
|
1080
294
|
if (!existingWorkflow) {
|
|
1081
295
|
const registerResult = context.workflowOrchestrator.registerWorkflow(parseResult.workflow);
|
|
@@ -1084,7 +298,6 @@ workflowCmd
|
|
|
1084
298
|
await cleanupAndExit(1);
|
|
1085
299
|
}
|
|
1086
300
|
}
|
|
1087
|
-
// Create scheduled workflow entry using persistent scheduler (ADR-041)
|
|
1088
301
|
const persistedSchedule = createScheduleEntry({
|
|
1089
302
|
workflowId: parseResult.workflow.id,
|
|
1090
303
|
pipelinePath: filePath,
|
|
@@ -1092,9 +305,7 @@ workflowCmd
|
|
|
1092
305
|
scheduleDescription: describeCronSchedule(schedule),
|
|
1093
306
|
enabled: options.enable !== false,
|
|
1094
307
|
});
|
|
1095
|
-
// Persist to disk using PersistentScheduler
|
|
1096
308
|
await context.persistentScheduler.saveSchedule(persistedSchedule);
|
|
1097
|
-
// Also keep in memory for backward compatibility
|
|
1098
309
|
const scheduledWorkflow = {
|
|
1099
310
|
id: persistedSchedule.id,
|
|
1100
311
|
workflowId: persistedSchedule.workflowId,
|
|
@@ -1135,17 +346,15 @@ workflowCmd
|
|
|
1135
346
|
return;
|
|
1136
347
|
try {
|
|
1137
348
|
console.log(chalk.blue('\nWorkflows\n'));
|
|
1138
|
-
// Show scheduled workflows (from PersistentScheduler)
|
|
1139
349
|
if (options.scheduled || options.all) {
|
|
1140
350
|
console.log(chalk.cyan('Scheduled Workflows:'));
|
|
1141
|
-
// Load schedules from persistent storage (ADR-041)
|
|
1142
351
|
const scheduled = await context.persistentScheduler.getSchedules();
|
|
1143
352
|
if (scheduled.length === 0) {
|
|
1144
353
|
console.log(chalk.gray(' No scheduled workflows\n'));
|
|
1145
354
|
}
|
|
1146
355
|
else {
|
|
1147
356
|
for (const sched of scheduled) {
|
|
1148
|
-
const statusIcon = sched.enabled ? chalk.green('
|
|
357
|
+
const statusIcon = sched.enabled ? chalk.green('*') : chalk.gray('o');
|
|
1149
358
|
console.log(` ${statusIcon} ${chalk.white(sched.workflowId)}`);
|
|
1150
359
|
console.log(chalk.gray(` ID: ${sched.id}`));
|
|
1151
360
|
console.log(chalk.gray(` Schedule: ${sched.schedule} (${sched.scheduleDescription})`));
|
|
@@ -1159,7 +368,6 @@ workflowCmd
|
|
|
1159
368
|
}
|
|
1160
369
|
}
|
|
1161
370
|
}
|
|
1162
|
-
// Show active executions
|
|
1163
371
|
if (options.active || options.all) {
|
|
1164
372
|
console.log(chalk.cyan('Active Executions:'));
|
|
1165
373
|
const activeExecutions = context.workflowOrchestrator.getActiveExecutions();
|
|
@@ -1180,7 +388,6 @@ workflowCmd
|
|
|
1180
388
|
}
|
|
1181
389
|
}
|
|
1182
390
|
}
|
|
1183
|
-
// Show registered workflows (default behavior)
|
|
1184
391
|
if (!options.scheduled && !options.active || options.all) {
|
|
1185
392
|
console.log(chalk.cyan('Registered Workflows:'));
|
|
1186
393
|
const workflows = context.workflowOrchestrator.listWorkflows();
|
|
@@ -1222,12 +429,10 @@ workflowCmd
|
|
|
1222
429
|
const filePath = pathModule.resolve(file);
|
|
1223
430
|
try {
|
|
1224
431
|
console.log(chalk.blue(`\nValidating pipeline: ${file}\n`));
|
|
1225
|
-
// Check file exists
|
|
1226
432
|
if (!fs.existsSync(filePath)) {
|
|
1227
433
|
console.log(chalk.red(`File not found: ${filePath}`));
|
|
1228
434
|
await cleanupAndExit(1);
|
|
1229
435
|
}
|
|
1230
|
-
// Parse the pipeline file
|
|
1231
436
|
const parseResult = parsePipelineFile(filePath);
|
|
1232
437
|
if (!parseResult.success) {
|
|
1233
438
|
console.log(chalk.red('Parse errors:'));
|
|
@@ -1236,9 +441,7 @@ workflowCmd
|
|
|
1236
441
|
}
|
|
1237
442
|
await cleanupAndExit(1);
|
|
1238
443
|
}
|
|
1239
|
-
// Validate the pipeline structure
|
|
1240
444
|
const validationResult = validatePipeline(parseResult.pipeline);
|
|
1241
|
-
// Show results
|
|
1242
445
|
if (validationResult.valid) {
|
|
1243
446
|
console.log(chalk.green('Pipeline is valid\n'));
|
|
1244
447
|
}
|
|
@@ -1249,7 +452,6 @@ workflowCmd
|
|
|
1249
452
|
}
|
|
1250
453
|
console.log('');
|
|
1251
454
|
}
|
|
1252
|
-
// Show warnings
|
|
1253
455
|
if (validationResult.warnings.length > 0) {
|
|
1254
456
|
console.log(chalk.yellow('Warnings:'));
|
|
1255
457
|
for (const warning of validationResult.warnings) {
|
|
@@ -1257,7 +459,6 @@ workflowCmd
|
|
|
1257
459
|
}
|
|
1258
460
|
console.log('');
|
|
1259
461
|
}
|
|
1260
|
-
// Show pipeline details if verbose
|
|
1261
462
|
if (options.verbose && parseResult.pipeline) {
|
|
1262
463
|
const pipeline = parseResult.pipeline;
|
|
1263
464
|
console.log(chalk.cyan('Pipeline Details:\n'));
|
|
@@ -1297,7 +498,6 @@ workflowCmd
|
|
|
1297
498
|
}
|
|
1298
499
|
}
|
|
1299
500
|
}
|
|
1300
|
-
// Show converted workflow definition if verbose
|
|
1301
501
|
if (options.verbose && parseResult.workflow) {
|
|
1302
502
|
console.log(chalk.cyan('\n Converted Workflow ID: ') + chalk.white(parseResult.workflow.id));
|
|
1303
503
|
console.log(chalk.gray(` Steps: ${parseResult.workflow.steps.length}`));
|
|
@@ -1325,7 +525,7 @@ workflowCmd
|
|
|
1325
525
|
if (!status) {
|
|
1326
526
|
console.log(chalk.red(`\nExecution not found: ${executionId}\n`));
|
|
1327
527
|
await cleanupAndExit(1);
|
|
1328
|
-
return;
|
|
528
|
+
return;
|
|
1329
529
|
}
|
|
1330
530
|
console.log(chalk.blue(`\nWorkflow Execution Status\n`));
|
|
1331
531
|
const statusColor = status.status === 'completed' ? chalk.green :
|
|
@@ -1352,7 +552,6 @@ workflowCmd
|
|
|
1352
552
|
if (status.error) {
|
|
1353
553
|
console.log(chalk.red(`\n Error: ${status.error}`));
|
|
1354
554
|
}
|
|
1355
|
-
// Show detailed step results if verbose
|
|
1356
555
|
if (options.verbose && status.stepResults.size > 0) {
|
|
1357
556
|
console.log(chalk.cyan('\n Step Results:'));
|
|
1358
557
|
for (const [stepId, result] of status.stepResults) {
|
|
@@ -1401,1863 +600,36 @@ workflowCmd
|
|
|
1401
600
|
}
|
|
1402
601
|
});
|
|
1403
602
|
// ============================================================================
|
|
1404
|
-
// Shortcut Commands
|
|
603
|
+
// Shortcut Commands (test, coverage, quality, security, code)
|
|
1405
604
|
// ============================================================================
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
console.log(chalk.red('❌ Test generation domain not available'));
|
|
1424
|
-
return;
|
|
1425
|
-
}
|
|
1426
|
-
// Collect source files
|
|
1427
|
-
const fs = await import('fs');
|
|
1428
|
-
const path = await import('path');
|
|
1429
|
-
const targetPath = path.resolve(target || '.');
|
|
1430
|
-
let sourceFiles = [];
|
|
1431
|
-
if (fs.existsSync(targetPath)) {
|
|
1432
|
-
if (fs.statSync(targetPath).isDirectory()) {
|
|
1433
|
-
const walkDir = (dir, depth = 0) => {
|
|
1434
|
-
if (depth > 4)
|
|
1435
|
-
return [];
|
|
1436
|
-
const result = [];
|
|
1437
|
-
const items = fs.readdirSync(dir);
|
|
1438
|
-
for (const item of items) {
|
|
1439
|
-
if (item === 'node_modules' || item === 'dist' || item === 'tests' || item.includes('.test.') || item.includes('.spec.'))
|
|
1440
|
-
continue;
|
|
1441
|
-
const fullPath = path.join(dir, item);
|
|
1442
|
-
const stat = fs.statSync(fullPath);
|
|
1443
|
-
if (stat.isDirectory()) {
|
|
1444
|
-
result.push(...walkDir(fullPath, depth + 1));
|
|
1445
|
-
}
|
|
1446
|
-
else if (item.endsWith('.ts') && !item.endsWith('.d.ts')) {
|
|
1447
|
-
result.push(fullPath);
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
return result;
|
|
1451
|
-
};
|
|
1452
|
-
sourceFiles = walkDir(targetPath);
|
|
1453
|
-
}
|
|
1454
|
-
else {
|
|
1455
|
-
sourceFiles = [targetPath];
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
if (sourceFiles.length === 0) {
|
|
1459
|
-
console.log(chalk.yellow('No source files found'));
|
|
1460
|
-
return;
|
|
1461
|
-
}
|
|
1462
|
-
console.log(chalk.gray(` Found ${sourceFiles.length} source files\n`));
|
|
1463
|
-
// Generate tests
|
|
1464
|
-
const result = await testGenAPI.generateTests({
|
|
1465
|
-
sourceFiles,
|
|
1466
|
-
testType: options.type,
|
|
1467
|
-
framework: options.framework,
|
|
1468
|
-
coverageTarget: 80,
|
|
1469
|
-
});
|
|
1470
|
-
if (result.success && result.value) {
|
|
1471
|
-
const generated = result.value;
|
|
1472
|
-
console.log(chalk.green(`✅ Generated ${generated.tests.length} tests\n`));
|
|
1473
|
-
console.log(chalk.cyan(' Tests:'));
|
|
1474
|
-
for (const test of generated.tests.slice(0, 10)) {
|
|
1475
|
-
console.log(` ${chalk.white(test.name)}`);
|
|
1476
|
-
console.log(chalk.gray(` Source: ${path.basename(test.sourceFile)}`));
|
|
1477
|
-
console.log(chalk.gray(` Assertions: ${test.assertions}`));
|
|
1478
|
-
}
|
|
1479
|
-
if (generated.tests.length > 10) {
|
|
1480
|
-
console.log(chalk.gray(` ... and ${generated.tests.length - 10} more`));
|
|
1481
|
-
}
|
|
1482
|
-
console.log(`\n Coverage Estimate: ${chalk.yellow(generated.coverageEstimate + '%')}`);
|
|
1483
|
-
if (generated.patternsUsed.length > 0) {
|
|
1484
|
-
console.log(` Patterns Used: ${chalk.cyan(generated.patternsUsed.join(', '))}`);
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
else {
|
|
1488
|
-
console.log(chalk.red(`❌ Failed: ${result.error?.message || 'Unknown error'}`));
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
else if (action === 'execute') {
|
|
1492
|
-
console.log(chalk.blue(`\n🧪 Executing tests in ${target || 'current directory'}...\n`));
|
|
1493
|
-
// Get test execution domain API (with lazy loading support)
|
|
1494
|
-
const testExecAPI = await context.kernel.getDomainAPIAsync('test-execution');
|
|
1495
|
-
if (!testExecAPI) {
|
|
1496
|
-
console.log(chalk.red('❌ Test execution domain not available'));
|
|
1497
|
-
return;
|
|
1498
|
-
}
|
|
1499
|
-
// Collect test files
|
|
1500
|
-
const fs = await import('fs');
|
|
1501
|
-
const path = await import('path');
|
|
1502
|
-
const targetPath = path.resolve(target || '.');
|
|
1503
|
-
let testFiles = [];
|
|
1504
|
-
if (fs.existsSync(targetPath)) {
|
|
1505
|
-
if (fs.statSync(targetPath).isDirectory()) {
|
|
1506
|
-
const walkDir = (dir, depth = 0) => {
|
|
1507
|
-
if (depth > 4)
|
|
1508
|
-
return [];
|
|
1509
|
-
const result = [];
|
|
1510
|
-
const items = fs.readdirSync(dir);
|
|
1511
|
-
for (const item of items) {
|
|
1512
|
-
if (item === 'node_modules' || item === 'dist')
|
|
1513
|
-
continue;
|
|
1514
|
-
const fullPath = path.join(dir, item);
|
|
1515
|
-
const stat = fs.statSync(fullPath);
|
|
1516
|
-
if (stat.isDirectory()) {
|
|
1517
|
-
result.push(...walkDir(fullPath, depth + 1));
|
|
1518
|
-
}
|
|
1519
|
-
else if ((item.includes('.test.') || item.includes('.spec.')) && item.endsWith('.ts')) {
|
|
1520
|
-
result.push(fullPath);
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
return result;
|
|
1524
|
-
};
|
|
1525
|
-
testFiles = walkDir(targetPath);
|
|
1526
|
-
}
|
|
1527
|
-
else {
|
|
1528
|
-
testFiles = [targetPath];
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
if (testFiles.length === 0) {
|
|
1532
|
-
console.log(chalk.yellow('No test files found'));
|
|
1533
|
-
return;
|
|
1534
|
-
}
|
|
1535
|
-
console.log(chalk.gray(` Found ${testFiles.length} test files\n`));
|
|
1536
|
-
const result = await testExecAPI.runTests({
|
|
1537
|
-
testFiles,
|
|
1538
|
-
parallel: true,
|
|
1539
|
-
retryCount: 2,
|
|
1540
|
-
});
|
|
1541
|
-
if (result.success && result.value) {
|
|
1542
|
-
const run = result.value;
|
|
1543
|
-
const total = run.passed + run.failed + run.skipped;
|
|
1544
|
-
console.log(chalk.green(`✅ Test run complete`));
|
|
1545
|
-
console.log(`\n Results:`);
|
|
1546
|
-
console.log(` Total: ${chalk.white(total)}`);
|
|
1547
|
-
console.log(` Passed: ${chalk.green(run.passed)}`);
|
|
1548
|
-
console.log(` Failed: ${chalk.red(run.failed)}`);
|
|
1549
|
-
console.log(` Skipped: ${chalk.yellow(run.skipped)}`);
|
|
1550
|
-
console.log(` Duration: ${chalk.cyan(run.duration + 'ms')}`);
|
|
1551
|
-
}
|
|
1552
|
-
else {
|
|
1553
|
-
console.log(chalk.red(`❌ Failed: ${result.error?.message || 'Unknown error'}`));
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
else {
|
|
1557
|
-
console.log(chalk.red(`\n❌ Unknown action: ${action}\n`));
|
|
1558
|
-
await cleanupAndExit(1);
|
|
1559
|
-
}
|
|
1560
|
-
console.log('');
|
|
1561
|
-
await cleanupAndExit(0);
|
|
1562
|
-
}
|
|
1563
|
-
catch (error) {
|
|
1564
|
-
console.error(chalk.red('\n❌ Failed:'), error);
|
|
1565
|
-
await cleanupAndExit(1);
|
|
1566
|
-
}
|
|
1567
|
-
});
|
|
1568
|
-
// aqe coverage <target>
|
|
1569
|
-
program
|
|
1570
|
-
.command('coverage')
|
|
1571
|
-
.description('Coverage analysis shortcut')
|
|
1572
|
-
.argument('[target]', 'Target file or directory', '.')
|
|
1573
|
-
.option('--risk', 'Include risk scoring')
|
|
1574
|
-
.option('--gaps', 'Detect coverage gaps')
|
|
1575
|
-
.option('--threshold <percent>', 'Coverage threshold percentage', '80')
|
|
1576
|
-
.option('--sensitivity <level>', 'Gap detection sensitivity (low|medium|high)', 'medium')
|
|
1577
|
-
.option('--wizard', 'Run interactive coverage analysis wizard')
|
|
1578
|
-
.action(async (target, options) => {
|
|
1579
|
-
let analyzeTarget = target;
|
|
1580
|
-
let includeRisk = options.risk;
|
|
1581
|
-
let detectGaps = options.gaps;
|
|
1582
|
-
let threshold = parseInt(options.threshold, 10);
|
|
1583
|
-
// Run wizard if requested
|
|
1584
|
-
if (options.wizard) {
|
|
1585
|
-
try {
|
|
1586
|
-
const wizardResult = await runCoverageAnalysisWizard({
|
|
1587
|
-
defaultTarget: target !== '.' ? target : undefined,
|
|
1588
|
-
defaultThreshold: options.threshold !== '80' ? parseInt(options.threshold, 10) : undefined,
|
|
1589
|
-
defaultRiskScoring: options.risk,
|
|
1590
|
-
defaultSensitivity: options.sensitivity !== 'medium' ? options.sensitivity : undefined,
|
|
1591
|
-
});
|
|
1592
|
-
if (wizardResult.cancelled) {
|
|
1593
|
-
console.log(chalk.yellow('\n Coverage analysis cancelled.\n'));
|
|
1594
|
-
await cleanupAndExit(0);
|
|
1595
|
-
}
|
|
1596
|
-
// Use wizard results
|
|
1597
|
-
analyzeTarget = wizardResult.target;
|
|
1598
|
-
includeRisk = wizardResult.riskScoring;
|
|
1599
|
-
detectGaps = true; // Wizard always enables gap detection
|
|
1600
|
-
threshold = wizardResult.threshold;
|
|
1601
|
-
console.log(chalk.green('\n Starting coverage analysis...\n'));
|
|
1602
|
-
}
|
|
1603
|
-
catch (err) {
|
|
1604
|
-
console.error(chalk.red('\n Wizard error:'), err);
|
|
1605
|
-
await cleanupAndExit(1);
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
if (!await ensureInitialized())
|
|
1609
|
-
return;
|
|
1610
|
-
try {
|
|
1611
|
-
console.log(chalk.blue(`\n Analyzing coverage for ${analyzeTarget}...\n`));
|
|
1612
|
-
// Get coverage analysis domain API directly (with lazy loading support)
|
|
1613
|
-
const coverageAPI = await context.kernel.getDomainAPIAsync('coverage-analysis');
|
|
1614
|
-
if (!coverageAPI) {
|
|
1615
|
-
console.log(chalk.red('❌ Coverage analysis domain not available'));
|
|
1616
|
-
return;
|
|
1617
|
-
}
|
|
1618
|
-
// Collect source files and generate synthetic coverage data for analysis
|
|
1619
|
-
const fs = await import('fs');
|
|
1620
|
-
const path = await import('path');
|
|
1621
|
-
const targetPath = path.resolve(analyzeTarget);
|
|
1622
|
-
let sourceFiles = [];
|
|
1623
|
-
if (fs.existsSync(targetPath)) {
|
|
1624
|
-
if (fs.statSync(targetPath).isDirectory()) {
|
|
1625
|
-
const walkDir = (dir, depth = 0) => {
|
|
1626
|
-
if (depth > 4)
|
|
1627
|
-
return [];
|
|
1628
|
-
const result = [];
|
|
1629
|
-
const items = fs.readdirSync(dir);
|
|
1630
|
-
for (const item of items) {
|
|
1631
|
-
if (item === 'node_modules' || item === 'dist')
|
|
1632
|
-
continue;
|
|
1633
|
-
const fullPath = path.join(dir, item);
|
|
1634
|
-
const stat = fs.statSync(fullPath);
|
|
1635
|
-
if (stat.isDirectory()) {
|
|
1636
|
-
result.push(...walkDir(fullPath, depth + 1));
|
|
1637
|
-
}
|
|
1638
|
-
else if (item.endsWith('.ts') && !item.endsWith('.d.ts')) {
|
|
1639
|
-
result.push(fullPath);
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
return result;
|
|
1643
|
-
};
|
|
1644
|
-
sourceFiles = walkDir(targetPath);
|
|
1645
|
-
}
|
|
1646
|
-
else {
|
|
1647
|
-
sourceFiles = [targetPath];
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
if (sourceFiles.length === 0) {
|
|
1651
|
-
console.log(chalk.yellow('No source files found'));
|
|
1652
|
-
return;
|
|
1653
|
-
}
|
|
1654
|
-
console.log(chalk.gray(` Analyzing ${sourceFiles.length} files...\n`));
|
|
1655
|
-
// Build coverage data from file analysis
|
|
1656
|
-
const files = sourceFiles.map(filePath => {
|
|
1657
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
1658
|
-
const lines = content.split('\n');
|
|
1659
|
-
const totalLines = lines.length;
|
|
1660
|
-
// Estimate coverage based on presence of corresponding test file
|
|
1661
|
-
const testFile = filePath.replace('.ts', '.test.ts').replace('/src/', '/tests/');
|
|
1662
|
-
const hasTest = fs.existsSync(testFile);
|
|
1663
|
-
const coverageRate = hasTest ? 0.75 + Math.random() * 0.2 : 0.2 + Math.random() * 0.3;
|
|
1664
|
-
const coveredLines = Math.floor(totalLines * coverageRate);
|
|
1665
|
-
const uncoveredLines = Array.from({ length: totalLines - coveredLines }, (_, i) => i + coveredLines + 1);
|
|
1666
|
-
return {
|
|
1667
|
-
path: filePath,
|
|
1668
|
-
lines: { covered: coveredLines, total: totalLines },
|
|
1669
|
-
branches: { covered: Math.floor(coveredLines * 0.8), total: totalLines },
|
|
1670
|
-
functions: { covered: Math.floor(coveredLines * 0.9), total: Math.ceil(totalLines / 20) },
|
|
1671
|
-
statements: { covered: coveredLines, total: totalLines },
|
|
1672
|
-
uncoveredLines,
|
|
1673
|
-
uncoveredBranches: uncoveredLines.slice(0, Math.floor(uncoveredLines.length / 2)),
|
|
1674
|
-
};
|
|
1675
|
-
});
|
|
1676
|
-
const totalLines = files.reduce((sum, f) => sum + f.lines.total, 0);
|
|
1677
|
-
const coveredLines = files.reduce((sum, f) => sum + f.lines.covered, 0);
|
|
1678
|
-
const totalBranches = files.reduce((sum, f) => sum + f.branches.total, 0);
|
|
1679
|
-
const coveredBranches = files.reduce((sum, f) => sum + f.branches.covered, 0);
|
|
1680
|
-
const totalFunctions = files.reduce((sum, f) => sum + f.functions.total, 0);
|
|
1681
|
-
const coveredFunctions = files.reduce((sum, f) => sum + f.functions.covered, 0);
|
|
1682
|
-
const coverageData = {
|
|
1683
|
-
files,
|
|
1684
|
-
summary: {
|
|
1685
|
-
line: Math.round((coveredLines / totalLines) * 100),
|
|
1686
|
-
branch: Math.round((coveredBranches / totalBranches) * 100),
|
|
1687
|
-
function: Math.round((coveredFunctions / totalFunctions) * 100),
|
|
1688
|
-
statement: Math.round((coveredLines / totalLines) * 100),
|
|
1689
|
-
files: files.length,
|
|
1690
|
-
},
|
|
1691
|
-
};
|
|
1692
|
-
// Run coverage analysis
|
|
1693
|
-
const result = await coverageAPI.analyze({
|
|
1694
|
-
coverageData,
|
|
1695
|
-
threshold,
|
|
1696
|
-
includeFileDetails: true,
|
|
1697
|
-
});
|
|
1698
|
-
if (result.success && result.value) {
|
|
1699
|
-
const report = result.value;
|
|
1700
|
-
console.log(chalk.cyan(' Coverage Summary:'));
|
|
1701
|
-
console.log(` Lines: ${getColorForPercent(report.summary.line)(report.summary.line + '%')}`);
|
|
1702
|
-
console.log(` Branches: ${getColorForPercent(report.summary.branch)(report.summary.branch + '%')}`);
|
|
1703
|
-
console.log(` Functions: ${getColorForPercent(report.summary.function)(report.summary.function + '%')}`);
|
|
1704
|
-
console.log(` Statements: ${getColorForPercent(report.summary.statement)(report.summary.statement + '%')}`);
|
|
1705
|
-
console.log(`\n Threshold: ${report.meetsThreshold ? chalk.green(`Met (${threshold}%)`) : chalk.red(`Not met (${threshold}%)`)}`);
|
|
1706
|
-
if (report.recommendations.length > 0) {
|
|
1707
|
-
console.log(chalk.cyan('\n Recommendations:'));
|
|
1708
|
-
for (const rec of report.recommendations) {
|
|
1709
|
-
console.log(chalk.gray(` - ${rec}`));
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
// Detect gaps if requested
|
|
1714
|
-
if (detectGaps) {
|
|
1715
|
-
console.log(chalk.cyan('\n Coverage Gaps:'));
|
|
1716
|
-
const gapResult = await coverageAPI.detectGaps({
|
|
1717
|
-
coverageData,
|
|
1718
|
-
minCoverage: threshold,
|
|
1719
|
-
prioritize: includeRisk ? 'risk' : 'size',
|
|
1720
|
-
});
|
|
1721
|
-
if (gapResult.success && gapResult.value) {
|
|
1722
|
-
const gaps = gapResult.value;
|
|
1723
|
-
console.log(chalk.gray(` Total uncovered lines: ${gaps.totalUncoveredLines}`));
|
|
1724
|
-
console.log(chalk.gray(` Estimated effort: ${gaps.estimatedEffort} hours\n`));
|
|
1725
|
-
for (const gap of gaps.gaps.slice(0, 8)) {
|
|
1726
|
-
const severityColor = gap.severity === 'high' ? chalk.red : gap.severity === 'medium' ? chalk.yellow : chalk.gray;
|
|
1727
|
-
const filePath = gap.file.replace(process.cwd() + '/', '');
|
|
1728
|
-
console.log(` ${severityColor(`[${gap.severity}]`)} ${chalk.white(filePath)}`);
|
|
1729
|
-
console.log(chalk.gray(` ${gap.lines.length} uncovered lines, Risk: ${(gap.riskScore * 100).toFixed(0)}%`));
|
|
1730
|
-
}
|
|
1731
|
-
if (gaps.gaps.length > 8) {
|
|
1732
|
-
console.log(chalk.gray(` ... and ${gaps.gaps.length - 8} more gaps`));
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
// Calculate risk if requested
|
|
1737
|
-
if (includeRisk) {
|
|
1738
|
-
console.log(chalk.cyan('\n⚠️ Risk Analysis:'));
|
|
1739
|
-
// Calculate risk for top 5 files with lowest coverage
|
|
1740
|
-
const lowCoverageFiles = [...files]
|
|
1741
|
-
.sort((a, b) => (a.lines.covered / a.lines.total) - (b.lines.covered / b.lines.total))
|
|
1742
|
-
.slice(0, 5);
|
|
1743
|
-
for (const file of lowCoverageFiles) {
|
|
1744
|
-
const riskResult = await coverageAPI.calculateRisk({
|
|
1745
|
-
file: file.path,
|
|
1746
|
-
uncoveredLines: file.uncoveredLines,
|
|
1747
|
-
});
|
|
1748
|
-
if (riskResult.success && riskResult.value) {
|
|
1749
|
-
const risk = riskResult.value;
|
|
1750
|
-
const riskColor = risk.riskLevel === 'high' ? chalk.red : risk.riskLevel === 'medium' ? chalk.yellow : chalk.green;
|
|
1751
|
-
const filePath = file.path.replace(process.cwd() + '/', '');
|
|
1752
|
-
console.log(` ${riskColor(`[${risk.riskLevel}]`)} ${chalk.white(filePath)}`);
|
|
1753
|
-
console.log(chalk.gray(` Risk: ${(risk.overallRisk * 100).toFixed(0)}%, Coverage: ${Math.round((file.lines.covered / file.lines.total) * 100)}%`));
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
console.log(chalk.green('\n✅ Coverage analysis complete\n'));
|
|
1758
|
-
await cleanupAndExit(0);
|
|
1759
|
-
}
|
|
1760
|
-
catch (error) {
|
|
1761
|
-
console.error(chalk.red('\n❌ Failed:'), error);
|
|
1762
|
-
await cleanupAndExit(1);
|
|
1763
|
-
}
|
|
1764
|
-
});
|
|
1765
|
-
function getColorForPercent(percent) {
|
|
1766
|
-
if (percent >= 80)
|
|
1767
|
-
return chalk.green;
|
|
1768
|
-
if (percent >= 50)
|
|
1769
|
-
return chalk.yellow;
|
|
1770
|
-
return chalk.red;
|
|
1771
|
-
}
|
|
1772
|
-
// aqe token-usage (ADR-042)
|
|
1773
|
-
import { createTokenUsageCommand } from './commands/token-usage.js';
|
|
1774
|
-
program.addCommand(createTokenUsageCommand());
|
|
1775
|
-
// aqe llm (ADR-043)
|
|
1776
|
-
import { createLLMRouterCommand } from './commands/llm-router.js';
|
|
1777
|
-
program.addCommand(createLLMRouterCommand());
|
|
1778
|
-
// aqe quality
|
|
1779
|
-
program
|
|
1780
|
-
.command('quality')
|
|
1781
|
-
.description('Quality assessment shortcut')
|
|
1782
|
-
.option('--gate', 'Run quality gate evaluation')
|
|
1783
|
-
.action(async (options) => {
|
|
1784
|
-
if (!await ensureInitialized())
|
|
1785
|
-
return;
|
|
1786
|
-
try {
|
|
1787
|
-
console.log(chalk.blue(`\n🎯 Running quality assessment...\n`));
|
|
1788
|
-
const result = await context.queen.submitTask({
|
|
1789
|
-
type: 'assess-quality',
|
|
1790
|
-
priority: 'p0',
|
|
1791
|
-
targetDomains: ['quality-assessment'],
|
|
1792
|
-
payload: { runGate: options.gate },
|
|
1793
|
-
timeout: 300000,
|
|
1794
|
-
});
|
|
1795
|
-
if (result.success) {
|
|
1796
|
-
console.log(chalk.green(`✅ Task submitted: ${result.value}`));
|
|
1797
|
-
console.log(chalk.gray(` Use 'aqe task status ${result.value}' to check progress`));
|
|
1798
|
-
}
|
|
1799
|
-
else {
|
|
1800
|
-
console.log(chalk.red(`❌ Failed: ${result.error.message}`));
|
|
1801
|
-
}
|
|
1802
|
-
console.log('');
|
|
1803
|
-
}
|
|
1804
|
-
catch (error) {
|
|
1805
|
-
console.error(chalk.red('\n❌ Failed:'), error);
|
|
1806
|
-
await cleanupAndExit(1);
|
|
1807
|
-
}
|
|
1808
|
-
});
|
|
1809
|
-
// aqe security
|
|
1810
|
-
program
|
|
1811
|
-
.command('security')
|
|
1812
|
-
.description('Security scanning shortcut')
|
|
1813
|
-
.option('--sast', 'Run SAST scan')
|
|
1814
|
-
.option('--dast', 'Run DAST scan')
|
|
1815
|
-
.option('--compliance <frameworks>', 'Check compliance (gdpr,hipaa,soc2)', '')
|
|
1816
|
-
.option('-t, --target <path>', 'Target directory to scan', '.')
|
|
1817
|
-
.action(async (options) => {
|
|
1818
|
-
if (!await ensureInitialized())
|
|
1819
|
-
return;
|
|
1820
|
-
try {
|
|
1821
|
-
console.log(chalk.blue(`\n🔒 Running security scan on ${options.target}...\n`));
|
|
1822
|
-
// Get security domain API directly (with lazy loading support)
|
|
1823
|
-
const securityAPI = await context.kernel.getDomainAPIAsync('security-compliance');
|
|
1824
|
-
if (!securityAPI) {
|
|
1825
|
-
console.log(chalk.red('❌ Security domain not available'));
|
|
1826
|
-
return;
|
|
1827
|
-
}
|
|
1828
|
-
// Collect files from target
|
|
1829
|
-
const fs = await import('fs');
|
|
1830
|
-
const path = await import('path');
|
|
1831
|
-
const targetPath = path.resolve(options.target);
|
|
1832
|
-
let files = [];
|
|
1833
|
-
if (fs.existsSync(targetPath)) {
|
|
1834
|
-
if (fs.statSync(targetPath).isDirectory()) {
|
|
1835
|
-
// Get TypeScript files recursively using fs
|
|
1836
|
-
const walkDir = (dir, depth = 0) => {
|
|
1837
|
-
if (depth > 4)
|
|
1838
|
-
return []; // Max depth limit
|
|
1839
|
-
const result = [];
|
|
1840
|
-
const items = fs.readdirSync(dir);
|
|
1841
|
-
for (const item of items) {
|
|
1842
|
-
if (item === 'node_modules' || item === 'dist')
|
|
1843
|
-
continue;
|
|
1844
|
-
const fullPath = path.join(dir, item);
|
|
1845
|
-
const stat = fs.statSync(fullPath);
|
|
1846
|
-
if (stat.isDirectory()) {
|
|
1847
|
-
result.push(...walkDir(fullPath, depth + 1));
|
|
1848
|
-
}
|
|
1849
|
-
else if (item.endsWith('.ts') && !item.endsWith('.d.ts')) {
|
|
1850
|
-
result.push(fullPath);
|
|
1851
|
-
}
|
|
1852
|
-
}
|
|
1853
|
-
return result;
|
|
1854
|
-
};
|
|
1855
|
-
files = walkDir(targetPath);
|
|
1856
|
-
}
|
|
1857
|
-
else {
|
|
1858
|
-
files = [targetPath];
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
if (files.length === 0) {
|
|
1862
|
-
console.log(chalk.yellow('No files found to scan'));
|
|
1863
|
-
return;
|
|
1864
|
-
}
|
|
1865
|
-
console.log(chalk.gray(` Scanning ${files.length} files...\n`));
|
|
1866
|
-
// Run SAST if requested
|
|
1867
|
-
if (options.sast) {
|
|
1868
|
-
console.log(chalk.blue('📋 SAST Scan:'));
|
|
1869
|
-
const sastResult = await securityAPI.runSASTScan(files);
|
|
1870
|
-
if (sastResult.success && sastResult.value) {
|
|
1871
|
-
const result = sastResult.value;
|
|
1872
|
-
const vulns = result.vulnerabilities || [];
|
|
1873
|
-
if (vulns.length === 0) {
|
|
1874
|
-
console.log(chalk.green(' ✓ No vulnerabilities found'));
|
|
1875
|
-
}
|
|
1876
|
-
else {
|
|
1877
|
-
console.log(chalk.yellow(` ⚠ Found ${vulns.length} potential issues:`));
|
|
1878
|
-
for (const v of vulns.slice(0, 10)) {
|
|
1879
|
-
const color = v.severity === 'high' ? chalk.red : v.severity === 'medium' ? chalk.yellow : chalk.gray;
|
|
1880
|
-
console.log(color(` [${v.severity}] ${v.type}: ${v.file}:${v.line}`));
|
|
1881
|
-
console.log(chalk.gray(` ${v.message}`));
|
|
1882
|
-
}
|
|
1883
|
-
if (vulns.length > 10) {
|
|
1884
|
-
console.log(chalk.gray(` ... and ${vulns.length - 10} more`));
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
else {
|
|
1889
|
-
console.log(chalk.red(` ✗ SAST failed: ${sastResult.error?.message || 'Unknown error'}`));
|
|
1890
|
-
}
|
|
1891
|
-
console.log('');
|
|
1892
|
-
}
|
|
1893
|
-
// Run compliance check if requested
|
|
1894
|
-
if (options.compliance) {
|
|
1895
|
-
const frameworks = options.compliance.split(',');
|
|
1896
|
-
console.log(chalk.blue(`📜 Compliance Check (${frameworks.join(', ')}):`));
|
|
1897
|
-
const compResult = await securityAPI.checkCompliance(frameworks);
|
|
1898
|
-
if (compResult.success && compResult.value) {
|
|
1899
|
-
const result = compResult.value;
|
|
1900
|
-
if (result.compliant) {
|
|
1901
|
-
console.log(chalk.green(' ✓ Compliant with all frameworks'));
|
|
1902
|
-
}
|
|
1903
|
-
else {
|
|
1904
|
-
console.log(chalk.yellow(' ⚠ Compliance issues found:'));
|
|
1905
|
-
for (const issue of (result.issues || []).slice(0, 5)) {
|
|
1906
|
-
console.log(chalk.yellow(` [${issue.framework}] ${issue.issue}`));
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
else {
|
|
1911
|
-
console.log(chalk.red(` ✗ Compliance check failed: ${compResult.error?.message || 'Unknown error'}`));
|
|
1912
|
-
}
|
|
1913
|
-
console.log('');
|
|
1914
|
-
}
|
|
1915
|
-
// DAST note
|
|
1916
|
-
if (options.dast) {
|
|
1917
|
-
console.log(chalk.gray('Note: DAST requires running application URLs. Use --target with URLs for DAST scanning.'));
|
|
1918
|
-
}
|
|
1919
|
-
console.log(chalk.green('✅ Security scan complete\n'));
|
|
1920
|
-
await cleanupAndExit(0);
|
|
1921
|
-
}
|
|
1922
|
-
catch (err) {
|
|
1923
|
-
console.error(chalk.red('\n❌ Failed:'), err);
|
|
1924
|
-
await cleanupAndExit(1);
|
|
1925
|
-
}
|
|
1926
|
-
});
|
|
1927
|
-
// aqe code (code intelligence)
|
|
1928
|
-
program
|
|
1929
|
-
.command('code')
|
|
1930
|
-
.description('Code intelligence analysis')
|
|
1931
|
-
.argument('<action>', 'Action (index|search|impact|deps)')
|
|
1932
|
-
.argument('[target]', 'Target path or query')
|
|
1933
|
-
.option('--depth <depth>', 'Analysis depth', '3')
|
|
1934
|
-
.option('--include-tests', 'Include test files')
|
|
1935
|
-
.action(async (action, target, options) => {
|
|
1936
|
-
if (!await ensureInitialized())
|
|
1937
|
-
return;
|
|
1938
|
-
try {
|
|
1939
|
-
// Get code intelligence domain API directly (with lazy loading support)
|
|
1940
|
-
const codeAPI = await context.kernel.getDomainAPIAsync('code-intelligence');
|
|
1941
|
-
if (!codeAPI) {
|
|
1942
|
-
console.log(chalk.red('❌ Code intelligence domain not available'));
|
|
1943
|
-
return;
|
|
1944
|
-
}
|
|
1945
|
-
const fs = await import('fs');
|
|
1946
|
-
const path = await import('path');
|
|
1947
|
-
if (action === 'index') {
|
|
1948
|
-
console.log(chalk.blue(`\n🗂️ Indexing codebase at ${target || '.'}...\n`));
|
|
1949
|
-
const targetPath = path.resolve(target || '.');
|
|
1950
|
-
let paths = [];
|
|
1951
|
-
if (fs.existsSync(targetPath)) {
|
|
1952
|
-
if (fs.statSync(targetPath).isDirectory()) {
|
|
1953
|
-
const walkDir = (dir, depth = 0) => {
|
|
1954
|
-
if (depth > 4)
|
|
1955
|
-
return [];
|
|
1956
|
-
const result = [];
|
|
1957
|
-
const items = fs.readdirSync(dir);
|
|
1958
|
-
for (const item of items) {
|
|
1959
|
-
if (item === 'node_modules' || item === 'dist')
|
|
1960
|
-
continue;
|
|
1961
|
-
const fullPath = path.join(dir, item);
|
|
1962
|
-
const stat = fs.statSync(fullPath);
|
|
1963
|
-
if (stat.isDirectory()) {
|
|
1964
|
-
result.push(...walkDir(fullPath, depth + 1));
|
|
1965
|
-
}
|
|
1966
|
-
else if (item.endsWith('.ts') && !item.endsWith('.d.ts')) {
|
|
1967
|
-
result.push(fullPath);
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
return result;
|
|
1971
|
-
};
|
|
1972
|
-
paths = walkDir(targetPath);
|
|
1973
|
-
}
|
|
1974
|
-
else {
|
|
1975
|
-
paths = [targetPath];
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
console.log(chalk.gray(` Found ${paths.length} files to index...\n`));
|
|
1979
|
-
const result = await codeAPI.index({
|
|
1980
|
-
paths,
|
|
1981
|
-
incremental: false,
|
|
1982
|
-
includeTests: options.includeTests || false,
|
|
1983
|
-
});
|
|
1984
|
-
if (result.success && result.value) {
|
|
1985
|
-
const idx = result.value;
|
|
1986
|
-
console.log(chalk.green(`✅ Indexing complete\n`));
|
|
1987
|
-
console.log(chalk.cyan(' Results:'));
|
|
1988
|
-
console.log(` Files indexed: ${chalk.white(idx.filesIndexed)}`);
|
|
1989
|
-
console.log(` Nodes created: ${chalk.white(idx.nodesCreated)}`);
|
|
1990
|
-
console.log(` Edges created: ${chalk.white(idx.edgesCreated)}`);
|
|
1991
|
-
console.log(` Duration: ${chalk.yellow(idx.duration + 'ms')}`);
|
|
1992
|
-
if (idx.errors.length > 0) {
|
|
1993
|
-
console.log(chalk.red(`\n Errors (${idx.errors.length}):`));
|
|
1994
|
-
for (const err of idx.errors.slice(0, 5)) {
|
|
1995
|
-
console.log(chalk.red(` ${err.file}: ${err.error}`));
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
else {
|
|
2000
|
-
console.log(chalk.red(`❌ Failed: ${result.error?.message || 'Unknown error'}`));
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
else if (action === 'search') {
|
|
2004
|
-
if (!target) {
|
|
2005
|
-
console.log(chalk.red('❌ Search query required'));
|
|
2006
|
-
return;
|
|
2007
|
-
}
|
|
2008
|
-
console.log(chalk.blue(`\n🔎 Searching for: "${target}"...\n`));
|
|
2009
|
-
const result = await codeAPI.search({
|
|
2010
|
-
query: target,
|
|
2011
|
-
type: 'semantic',
|
|
2012
|
-
limit: 10,
|
|
2013
|
-
});
|
|
2014
|
-
if (result.success && result.value) {
|
|
2015
|
-
const search = result.value;
|
|
2016
|
-
console.log(chalk.green(`✅ Found ${search.total} results (${search.searchTime}ms)\n`));
|
|
2017
|
-
for (const r of search.results) {
|
|
2018
|
-
const filePath = r.file.replace(process.cwd() + '/', '');
|
|
2019
|
-
console.log(` ${chalk.cyan(filePath)}${r.line ? ':' + r.line : ''}`);
|
|
2020
|
-
console.log(chalk.gray(` ${r.snippet.slice(0, 100)}...`));
|
|
2021
|
-
console.log(chalk.gray(` Score: ${(r.score * 100).toFixed(0)}%\n`));
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
else {
|
|
2025
|
-
console.log(chalk.red(`❌ Failed: ${result.error?.message || 'Unknown error'}`));
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
else if (action === 'impact') {
|
|
2029
|
-
console.log(chalk.blue(`\n📊 Analyzing impact for ${target || 'recent changes'}...\n`));
|
|
2030
|
-
const targetPath = path.resolve(target || '.');
|
|
2031
|
-
let changedFiles = [];
|
|
2032
|
-
if (fs.existsSync(targetPath)) {
|
|
2033
|
-
if (fs.statSync(targetPath).isFile()) {
|
|
2034
|
-
changedFiles = [targetPath];
|
|
2035
|
-
}
|
|
2036
|
-
else {
|
|
2037
|
-
// Get recently modified files (simulated)
|
|
2038
|
-
const walkDir = (dir, depth = 0) => {
|
|
2039
|
-
if (depth > 2)
|
|
2040
|
-
return [];
|
|
2041
|
-
const result = [];
|
|
2042
|
-
const items = fs.readdirSync(dir);
|
|
2043
|
-
for (const item of items) {
|
|
2044
|
-
if (item === 'node_modules' || item === 'dist')
|
|
2045
|
-
continue;
|
|
2046
|
-
const fullPath = path.join(dir, item);
|
|
2047
|
-
const stat = fs.statSync(fullPath);
|
|
2048
|
-
if (stat.isDirectory()) {
|
|
2049
|
-
result.push(...walkDir(fullPath, depth + 1));
|
|
2050
|
-
}
|
|
2051
|
-
else if (item.endsWith('.ts') && !item.endsWith('.d.ts')) {
|
|
2052
|
-
result.push(fullPath);
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
return result;
|
|
2056
|
-
};
|
|
2057
|
-
changedFiles = walkDir(targetPath).slice(0, 10);
|
|
2058
|
-
}
|
|
2059
|
-
}
|
|
2060
|
-
const result = await codeAPI.analyzeImpact({
|
|
2061
|
-
changedFiles,
|
|
2062
|
-
depth: parseInt(options.depth),
|
|
2063
|
-
includeTests: options.includeTests || false,
|
|
2064
|
-
});
|
|
2065
|
-
if (result.success && result.value) {
|
|
2066
|
-
const impact = result.value;
|
|
2067
|
-
const riskColor = impact.riskLevel === 'high' ? chalk.red : impact.riskLevel === 'medium' ? chalk.yellow : chalk.green;
|
|
2068
|
-
console.log(` Risk Level: ${riskColor(impact.riskLevel)}\n`);
|
|
2069
|
-
console.log(chalk.cyan(` Direct Impact (${impact.directImpact.length} files):`));
|
|
2070
|
-
for (const file of impact.directImpact.slice(0, 5)) {
|
|
2071
|
-
const filePath = file.file.replace(process.cwd() + '/', '');
|
|
2072
|
-
console.log(` ${chalk.white(filePath)}`);
|
|
2073
|
-
console.log(chalk.gray(` Reason: ${file.reason}, Risk: ${(file.riskScore * 100).toFixed(0)}%`));
|
|
2074
|
-
}
|
|
2075
|
-
if (impact.transitiveImpact.length > 0) {
|
|
2076
|
-
console.log(chalk.cyan(`\n Transitive Impact (${impact.transitiveImpact.length} files):`));
|
|
2077
|
-
for (const file of impact.transitiveImpact.slice(0, 5)) {
|
|
2078
|
-
const filePath = file.file.replace(process.cwd() + '/', '');
|
|
2079
|
-
console.log(` ${chalk.white(filePath)} (distance: ${file.distance})`);
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
if (impact.impactedTests.length > 0) {
|
|
2083
|
-
console.log(chalk.cyan(`\n Impacted Tests (${impact.impactedTests.length}):`));
|
|
2084
|
-
for (const test of impact.impactedTests.slice(0, 5)) {
|
|
2085
|
-
console.log(` ${chalk.gray(test)}`);
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
if (impact.recommendations.length > 0) {
|
|
2089
|
-
console.log(chalk.cyan('\n Recommendations:'));
|
|
2090
|
-
for (const rec of impact.recommendations) {
|
|
2091
|
-
console.log(chalk.gray(` • ${rec}`));
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
else {
|
|
2096
|
-
console.log(chalk.red(`❌ Failed: ${result.error?.message || 'Unknown error'}`));
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
else if (action === 'deps') {
|
|
2100
|
-
console.log(chalk.blue(`\n🔗 Mapping dependencies for ${target || '.'}...\n`));
|
|
2101
|
-
const targetPath = path.resolve(target || '.');
|
|
2102
|
-
let files = [];
|
|
2103
|
-
if (fs.existsSync(targetPath)) {
|
|
2104
|
-
if (fs.statSync(targetPath).isFile()) {
|
|
2105
|
-
files = [targetPath];
|
|
2106
|
-
}
|
|
2107
|
-
else {
|
|
2108
|
-
const walkDir = (dir, depth = 0) => {
|
|
2109
|
-
if (depth > 2)
|
|
2110
|
-
return [];
|
|
2111
|
-
const result = [];
|
|
2112
|
-
const items = fs.readdirSync(dir);
|
|
2113
|
-
for (const item of items) {
|
|
2114
|
-
if (item === 'node_modules' || item === 'dist')
|
|
2115
|
-
continue;
|
|
2116
|
-
const fullPath = path.join(dir, item);
|
|
2117
|
-
const stat = fs.statSync(fullPath);
|
|
2118
|
-
if (stat.isDirectory()) {
|
|
2119
|
-
result.push(...walkDir(fullPath, depth + 1));
|
|
2120
|
-
}
|
|
2121
|
-
else if (item.endsWith('.ts') && !item.endsWith('.d.ts')) {
|
|
2122
|
-
result.push(fullPath);
|
|
2123
|
-
}
|
|
2124
|
-
}
|
|
2125
|
-
return result;
|
|
2126
|
-
};
|
|
2127
|
-
files = walkDir(targetPath).slice(0, 50);
|
|
2128
|
-
}
|
|
2129
|
-
}
|
|
2130
|
-
const result = await codeAPI.mapDependencies({
|
|
2131
|
-
files,
|
|
2132
|
-
direction: 'both',
|
|
2133
|
-
depth: parseInt(options.depth),
|
|
2134
|
-
});
|
|
2135
|
-
if (result.success && result.value) {
|
|
2136
|
-
const deps = result.value;
|
|
2137
|
-
console.log(chalk.cyan(' Dependency Metrics:'));
|
|
2138
|
-
console.log(` Nodes: ${chalk.white(deps.metrics.totalNodes)}`);
|
|
2139
|
-
console.log(` Edges: ${chalk.white(deps.metrics.totalEdges)}`);
|
|
2140
|
-
console.log(` Avg Degree: ${chalk.yellow(deps.metrics.avgDegree.toFixed(2))}`);
|
|
2141
|
-
console.log(` Max Depth: ${chalk.yellow(deps.metrics.maxDepth)}`);
|
|
2142
|
-
console.log(` Cyclomatic Complexity: ${chalk.yellow(deps.metrics.cyclomaticComplexity)}`);
|
|
2143
|
-
if (deps.cycles.length > 0) {
|
|
2144
|
-
console.log(chalk.red(`\n ⚠️ Circular Dependencies (${deps.cycles.length}):`));
|
|
2145
|
-
for (const cycle of deps.cycles.slice(0, 3)) {
|
|
2146
|
-
console.log(chalk.red(` ${cycle.join(' → ')}`));
|
|
2147
|
-
}
|
|
2148
|
-
}
|
|
2149
|
-
console.log(chalk.cyan(`\n Top Dependencies (by connections):`));
|
|
2150
|
-
const sortedNodes = [...deps.nodes].sort((a, b) => (b.inDegree + b.outDegree) - (a.inDegree + a.outDegree));
|
|
2151
|
-
for (const node of sortedNodes.slice(0, 8)) {
|
|
2152
|
-
const filePath = node.path.replace(process.cwd() + '/', '');
|
|
2153
|
-
console.log(` ${chalk.white(filePath)}`);
|
|
2154
|
-
console.log(chalk.gray(` In: ${node.inDegree}, Out: ${node.outDegree}, Type: ${node.type}`));
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
else {
|
|
2158
|
-
console.log(chalk.red(`❌ Failed: ${result.error?.message || 'Unknown error'}`));
|
|
2159
|
-
}
|
|
2160
|
-
}
|
|
2161
|
-
else {
|
|
2162
|
-
console.log(chalk.red(`\n❌ Unknown action: ${action}`));
|
|
2163
|
-
console.log(chalk.gray(' Available: index, search, impact, deps\n'));
|
|
2164
|
-
await cleanupAndExit(1);
|
|
2165
|
-
}
|
|
2166
|
-
console.log('');
|
|
2167
|
-
await cleanupAndExit(0);
|
|
2168
|
-
}
|
|
2169
|
-
catch (error) {
|
|
2170
|
-
console.error(chalk.red('\n❌ Failed:'), error);
|
|
2171
|
-
await cleanupAndExit(1);
|
|
2172
|
-
}
|
|
2173
|
-
});
|
|
605
|
+
import { createTestCommand } from './commands/test.js';
|
|
606
|
+
import { createCoverageCommand } from './commands/coverage.js';
|
|
607
|
+
import { createQualityCommand } from './commands/quality.js';
|
|
608
|
+
import { createSecurityCommand } from './commands/security.js';
|
|
609
|
+
import { createCodeCommand } from './commands/code.js';
|
|
610
|
+
import { createMigrateCommand } from './commands/migrate.js';
|
|
611
|
+
import { createCompletionsCommand } from './commands/completions.js';
|
|
612
|
+
import { createFleetCommand } from './commands/fleet.js';
|
|
613
|
+
// Register shortcut commands
|
|
614
|
+
program.addCommand(createTestCommand(context, cleanupAndExit, ensureInitialized));
|
|
615
|
+
program.addCommand(createCoverageCommand(context, cleanupAndExit, ensureInitialized));
|
|
616
|
+
program.addCommand(createQualityCommand(context, cleanupAndExit, ensureInitialized));
|
|
617
|
+
program.addCommand(createSecurityCommand(context, cleanupAndExit, ensureInitialized));
|
|
618
|
+
program.addCommand(createCodeCommand(context, cleanupAndExit, ensureInitialized));
|
|
619
|
+
program.addCommand(createMigrateCommand(context, cleanupAndExit, ensureInitialized));
|
|
620
|
+
program.addCommand(createCompletionsCommand(cleanupAndExit));
|
|
621
|
+
program.addCommand(createFleetCommand(context, cleanupAndExit, ensureInitialized, registerDomainWorkflowActions));
|
|
2174
622
|
// ============================================================================
|
|
2175
|
-
//
|
|
2176
|
-
// ============================================================================
|
|
2177
|
-
const migrateCmd = program
|
|
2178
|
-
.command('migrate')
|
|
2179
|
-
.description('V2-to-V3 migration tools with agent compatibility (ADR-048)');
|
|
2180
|
-
// Helper to check path existence
|
|
2181
|
-
const pathExists = (p) => {
|
|
2182
|
-
try {
|
|
2183
|
-
require('fs').accessSync(p);
|
|
2184
|
-
return true;
|
|
2185
|
-
}
|
|
2186
|
-
catch {
|
|
2187
|
-
return false;
|
|
2188
|
-
}
|
|
2189
|
-
};
|
|
2190
|
-
// migrate run - Main migration command (default behavior)
|
|
2191
|
-
migrateCmd
|
|
2192
|
-
.command('run')
|
|
2193
|
-
.description('Run full migration from v2 to v3')
|
|
2194
|
-
.option('--dry-run', 'Preview migration without making changes')
|
|
2195
|
-
.option('--backup', 'Create backup before migration (recommended)', true)
|
|
2196
|
-
.option('--skip-memory', 'Skip memory database migration')
|
|
2197
|
-
.option('--skip-patterns', 'Skip pattern migration')
|
|
2198
|
-
.option('--skip-config', 'Skip configuration migration')
|
|
2199
|
-
.option('--skip-agents', 'Skip agent name migration')
|
|
2200
|
-
.option('--target <component>', 'Migrate specific component (agents, skills, config, memory)')
|
|
2201
|
-
.option('--force', 'Force migration even if v3 already exists')
|
|
2202
|
-
.action(async (options) => {
|
|
2203
|
-
const fs = await import('fs');
|
|
2204
|
-
const path = await import('path');
|
|
2205
|
-
console.log(chalk.blue('\n🔄 Agentic QE v2 to v3 Migration (ADR-048)\n'));
|
|
2206
|
-
const cwd = process.cwd();
|
|
2207
|
-
const v2Dir = path.join(cwd, '.agentic-qe');
|
|
2208
|
-
const v3Dir = path.join(cwd, '.aqe');
|
|
2209
|
-
const claudeAgentDir = path.join(cwd, '.claude', 'agents');
|
|
2210
|
-
// Step 1: Detect v2 installation
|
|
2211
|
-
console.log(chalk.white('1. Detecting v2 installation...'));
|
|
2212
|
-
const hasV2Dir = fs.existsSync(v2Dir);
|
|
2213
|
-
const hasClaudeAgents = fs.existsSync(claudeAgentDir);
|
|
2214
|
-
if (!hasV2Dir && !hasClaudeAgents) {
|
|
2215
|
-
console.log(chalk.yellow(' ⚠ No v2 installation found'));
|
|
2216
|
-
console.log(chalk.gray(' This might be a fresh project. Use `aqe init` instead.'));
|
|
2217
|
-
await cleanupAndExit(0);
|
|
2218
|
-
}
|
|
2219
|
-
const v2Files = {
|
|
2220
|
-
memoryDb: path.join(v2Dir, 'memory.db'),
|
|
2221
|
-
config: path.join(v2Dir, 'config.json'),
|
|
2222
|
-
patterns: path.join(v2Dir, 'patterns'),
|
|
2223
|
-
};
|
|
2224
|
-
const hasMemory = hasV2Dir && fs.existsSync(v2Files.memoryDb);
|
|
2225
|
-
const hasConfig = hasV2Dir && fs.existsSync(v2Files.config);
|
|
2226
|
-
const hasPatterns = hasV2Dir && fs.existsSync(v2Files.patterns);
|
|
2227
|
-
// Detect v2 agents needing migration
|
|
2228
|
-
const agentsToMigrate = [];
|
|
2229
|
-
if (hasClaudeAgents) {
|
|
2230
|
-
const files = fs.readdirSync(claudeAgentDir);
|
|
2231
|
-
for (const file of files) {
|
|
2232
|
-
if (file.endsWith('.md') && file.startsWith('qe-')) {
|
|
2233
|
-
const agentName = file.replace('.md', '');
|
|
2234
|
-
if (isDeprecatedAgent(agentName)) {
|
|
2235
|
-
agentsToMigrate.push(agentName);
|
|
2236
|
-
}
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
}
|
|
2240
|
-
console.log(chalk.green(' ✓ Found v2 installation:'));
|
|
2241
|
-
console.log(chalk.gray(` Memory DB: ${hasMemory ? '✓' : '✗'}`));
|
|
2242
|
-
console.log(chalk.gray(` Config: ${hasConfig ? '✓' : '✗'}`));
|
|
2243
|
-
console.log(chalk.gray(` Patterns: ${hasPatterns ? '✓' : '✗'}`));
|
|
2244
|
-
console.log(chalk.gray(` Agents to migrate: ${agentsToMigrate.length}\n`));
|
|
2245
|
-
// Step 2: Check v3 existence
|
|
2246
|
-
console.log(chalk.white('2. Checking v3 status...'));
|
|
2247
|
-
if (fs.existsSync(v3Dir) && !options.force) {
|
|
2248
|
-
console.log(chalk.yellow(' ⚠ v3 directory already exists at .aqe/'));
|
|
2249
|
-
console.log(chalk.gray(' Use --force to overwrite existing v3 installation.'));
|
|
2250
|
-
await cleanupAndExit(1);
|
|
2251
|
-
}
|
|
2252
|
-
console.log(chalk.green(' ✓ Ready for migration\n'));
|
|
2253
|
-
// Dry run mode
|
|
2254
|
-
if (options.dryRun) {
|
|
2255
|
-
console.log(chalk.blue('📋 Dry Run - Migration Plan:\n'));
|
|
2256
|
-
if (!options.skipMemory && hasMemory) {
|
|
2257
|
-
const stats = fs.statSync(v2Files.memoryDb);
|
|
2258
|
-
console.log(chalk.gray(` • Migrate memory.db (${(stats.size / 1024).toFixed(1)} KB)`));
|
|
2259
|
-
}
|
|
2260
|
-
if (!options.skipConfig && hasConfig) {
|
|
2261
|
-
console.log(chalk.gray(' • Convert config.json to v3 format'));
|
|
2262
|
-
}
|
|
2263
|
-
if (!options.skipPatterns && hasPatterns) {
|
|
2264
|
-
const patternFiles = fs.readdirSync(v2Files.patterns);
|
|
2265
|
-
console.log(chalk.gray(` • Migrate ${patternFiles.length} pattern files`));
|
|
2266
|
-
}
|
|
2267
|
-
if (!options.skipAgents && agentsToMigrate.length > 0) {
|
|
2268
|
-
console.log(chalk.gray(` • Migrate ${agentsToMigrate.length} agent names:`));
|
|
2269
|
-
for (const agent of agentsToMigrate) {
|
|
2270
|
-
console.log(chalk.gray(` ${agent} → ${resolveAgentName(agent)}`));
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
console.log(chalk.yellow('\n⚠ This is a dry run. No changes were made.'));
|
|
2274
|
-
console.log(chalk.gray('Run without --dry-run to execute migration.\n'));
|
|
2275
|
-
await cleanupAndExit(0);
|
|
2276
|
-
}
|
|
2277
|
-
// Step 3: Create backup
|
|
2278
|
-
if (options.backup) {
|
|
2279
|
-
console.log(chalk.white('3. Creating backup...'));
|
|
2280
|
-
const backupDir = path.join(cwd, '.aqe-backup', `backup-${Date.now()}`);
|
|
2281
|
-
try {
|
|
2282
|
-
fs.mkdirSync(backupDir, { recursive: true });
|
|
2283
|
-
const copyDir = (src, dest) => {
|
|
2284
|
-
if (!fs.existsSync(src))
|
|
2285
|
-
return;
|
|
2286
|
-
if (fs.statSync(src).isDirectory()) {
|
|
2287
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
2288
|
-
for (const file of fs.readdirSync(src)) {
|
|
2289
|
-
copyDir(path.join(src, file), path.join(dest, file));
|
|
2290
|
-
}
|
|
2291
|
-
}
|
|
2292
|
-
else {
|
|
2293
|
-
fs.copyFileSync(src, dest);
|
|
2294
|
-
}
|
|
2295
|
-
};
|
|
2296
|
-
if (hasV2Dir)
|
|
2297
|
-
copyDir(v2Dir, path.join(backupDir, '.agentic-qe'));
|
|
2298
|
-
if (hasClaudeAgents)
|
|
2299
|
-
copyDir(claudeAgentDir, path.join(backupDir, '.claude', 'agents'));
|
|
2300
|
-
console.log(chalk.green(` ✓ Backup created at .aqe-backup/\n`));
|
|
2301
|
-
}
|
|
2302
|
-
catch (err) {
|
|
2303
|
-
console.log(chalk.red(` ✗ Backup failed: ${err}`));
|
|
2304
|
-
await cleanupAndExit(1);
|
|
2305
|
-
}
|
|
2306
|
-
}
|
|
2307
|
-
else {
|
|
2308
|
-
console.log(chalk.yellow('3. Backup skipped (--no-backup)\n'));
|
|
2309
|
-
}
|
|
2310
|
-
// Step 4: Create v3 directory structure
|
|
2311
|
-
if (!options.target || options.target === 'config' || options.target === 'memory') {
|
|
2312
|
-
console.log(chalk.white('4. Creating v3 directory structure...'));
|
|
2313
|
-
try {
|
|
2314
|
-
fs.mkdirSync(v3Dir, { recursive: true });
|
|
2315
|
-
fs.mkdirSync(path.join(v3Dir, 'agentdb'), { recursive: true });
|
|
2316
|
-
fs.mkdirSync(path.join(v3Dir, 'reasoning-bank'), { recursive: true });
|
|
2317
|
-
fs.mkdirSync(path.join(v3Dir, 'cache'), { recursive: true });
|
|
2318
|
-
fs.mkdirSync(path.join(v3Dir, 'logs'), { recursive: true });
|
|
2319
|
-
console.log(chalk.green(' ✓ Directory structure created\n'));
|
|
2320
|
-
}
|
|
2321
|
-
catch (err) {
|
|
2322
|
-
console.log(chalk.red(` ✗ Failed: ${err}\n`));
|
|
2323
|
-
await cleanupAndExit(1);
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
|
-
// Step 5: Migrate memory database
|
|
2327
|
-
if ((!options.target || options.target === 'memory') && !options.skipMemory && hasMemory) {
|
|
2328
|
-
console.log(chalk.white('5. Migrating memory database...'));
|
|
2329
|
-
try {
|
|
2330
|
-
const destDb = path.join(v3Dir, 'agentdb', 'memory.db');
|
|
2331
|
-
fs.copyFileSync(v2Files.memoryDb, destDb);
|
|
2332
|
-
const indexFile = path.join(v3Dir, 'agentdb', 'index.json');
|
|
2333
|
-
fs.writeFileSync(indexFile, JSON.stringify({
|
|
2334
|
-
version: '3.0.0',
|
|
2335
|
-
migratedFrom: 'v2',
|
|
2336
|
-
migratedAt: new Date().toISOString(),
|
|
2337
|
-
hnswEnabled: true,
|
|
2338
|
-
vectorDimensions: 128,
|
|
2339
|
-
}, null, 2));
|
|
2340
|
-
const stats = fs.statSync(v2Files.memoryDb);
|
|
2341
|
-
console.log(chalk.green(` ✓ Memory database migrated (${(stats.size / 1024).toFixed(1)} KB)\n`));
|
|
2342
|
-
}
|
|
2343
|
-
catch (err) {
|
|
2344
|
-
console.log(chalk.red(` ✗ Migration failed: ${err}\n`));
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
else if (options.target && options.target !== 'memory') {
|
|
2348
|
-
console.log(chalk.gray('5. Memory migration skipped (--target)\n'));
|
|
2349
|
-
}
|
|
2350
|
-
else if (options.skipMemory) {
|
|
2351
|
-
console.log(chalk.yellow('5. Memory migration skipped\n'));
|
|
2352
|
-
}
|
|
2353
|
-
else {
|
|
2354
|
-
console.log(chalk.gray('5. No memory database to migrate\n'));
|
|
2355
|
-
}
|
|
2356
|
-
// Step 6: Migrate configuration
|
|
2357
|
-
if ((!options.target || options.target === 'config') && !options.skipConfig && hasConfig) {
|
|
2358
|
-
console.log(chalk.white('6. Migrating configuration...'));
|
|
2359
|
-
try {
|
|
2360
|
-
const v2ConfigRaw = fs.readFileSync(v2Files.config, 'utf-8');
|
|
2361
|
-
const v2Config = parseJsonFile(v2ConfigRaw, v2Files.config);
|
|
2362
|
-
const v3Config = {
|
|
2363
|
-
version: '3.0.0',
|
|
2364
|
-
migratedFrom: v2Config.version || '2.x',
|
|
2365
|
-
migratedAt: new Date().toISOString(),
|
|
2366
|
-
kernel: { eventBus: 'in-memory', coordinator: 'queen' },
|
|
2367
|
-
domains: {
|
|
2368
|
-
'test-generation': { enabled: true },
|
|
2369
|
-
'test-execution': { enabled: true },
|
|
2370
|
-
'coverage-analysis': { enabled: true, algorithm: 'hnsw', dimensions: 128 },
|
|
2371
|
-
'quality-assessment': { enabled: true },
|
|
2372
|
-
'defect-intelligence': { enabled: true },
|
|
2373
|
-
'requirements-validation': { enabled: true },
|
|
2374
|
-
'code-intelligence': { enabled: true },
|
|
2375
|
-
'security-compliance': { enabled: true },
|
|
2376
|
-
'contract-testing': { enabled: true },
|
|
2377
|
-
'visual-accessibility': { enabled: false },
|
|
2378
|
-
'chaos-resilience': { enabled: true },
|
|
2379
|
-
'learning-optimization': { enabled: true },
|
|
2380
|
-
},
|
|
2381
|
-
memory: {
|
|
2382
|
-
backend: 'hybrid',
|
|
2383
|
-
path: '.aqe/agentdb/',
|
|
2384
|
-
hnsw: { M: 16, efConstruction: 200 },
|
|
2385
|
-
},
|
|
2386
|
-
learning: {
|
|
2387
|
-
reasoningBank: true,
|
|
2388
|
-
sona: true,
|
|
2389
|
-
patternRetention: v2Config.learning?.patternRetention || 180,
|
|
2390
|
-
},
|
|
2391
|
-
v2Migration: {
|
|
2392
|
-
originalConfig: v2Config,
|
|
2393
|
-
migrationDate: new Date().toISOString(),
|
|
2394
|
-
},
|
|
2395
|
-
};
|
|
2396
|
-
const destConfig = path.join(v3Dir, 'config.json');
|
|
2397
|
-
fs.writeFileSync(destConfig, JSON.stringify(v3Config, null, 2));
|
|
2398
|
-
console.log(chalk.green(' ✓ Configuration migrated\n'));
|
|
2399
|
-
}
|
|
2400
|
-
catch (err) {
|
|
2401
|
-
console.log(chalk.red(` ✗ Config migration failed: ${err}\n`));
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
else if (options.target && options.target !== 'config') {
|
|
2405
|
-
console.log(chalk.gray('6. Config migration skipped (--target)\n'));
|
|
2406
|
-
}
|
|
2407
|
-
else if (options.skipConfig) {
|
|
2408
|
-
console.log(chalk.yellow('6. Configuration migration skipped\n'));
|
|
2409
|
-
}
|
|
2410
|
-
else {
|
|
2411
|
-
console.log(chalk.gray('6. No configuration to migrate\n'));
|
|
2412
|
-
}
|
|
2413
|
-
// Step 7: Migrate patterns
|
|
2414
|
-
if ((!options.target || options.target === 'memory') && !options.skipPatterns && hasPatterns) {
|
|
2415
|
-
console.log(chalk.white('7. Migrating patterns to ReasoningBank...'));
|
|
2416
|
-
try {
|
|
2417
|
-
const patternFiles = fs.readdirSync(v2Files.patterns);
|
|
2418
|
-
let migratedCount = 0;
|
|
2419
|
-
for (const file of patternFiles) {
|
|
2420
|
-
const srcPath = path.join(v2Files.patterns, file);
|
|
2421
|
-
const destPath = path.join(v3Dir, 'reasoning-bank', file);
|
|
2422
|
-
if (fs.statSync(srcPath).isFile()) {
|
|
2423
|
-
fs.copyFileSync(srcPath, destPath);
|
|
2424
|
-
migratedCount++;
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
const indexPath = path.join(v3Dir, 'reasoning-bank', 'index.json');
|
|
2428
|
-
fs.writeFileSync(indexPath, JSON.stringify({
|
|
2429
|
-
version: '3.0.0',
|
|
2430
|
-
migratedFrom: 'v2',
|
|
2431
|
-
migratedAt: new Date().toISOString(),
|
|
2432
|
-
patternCount: migratedCount,
|
|
2433
|
-
hnswIndexed: false,
|
|
2434
|
-
}, null, 2));
|
|
2435
|
-
console.log(chalk.green(` ✓ ${migratedCount} patterns migrated\n`));
|
|
2436
|
-
}
|
|
2437
|
-
catch (err) {
|
|
2438
|
-
console.log(chalk.red(` ✗ Pattern migration failed: ${err}\n`));
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
|
-
else if (options.skipPatterns) {
|
|
2442
|
-
console.log(chalk.yellow('7. Pattern migration skipped\n'));
|
|
2443
|
-
}
|
|
2444
|
-
else {
|
|
2445
|
-
console.log(chalk.gray('7. No patterns to migrate\n'));
|
|
2446
|
-
}
|
|
2447
|
-
// Step 8: Migrate agent names (ADR-048)
|
|
2448
|
-
if ((!options.target || options.target === 'agents') && !options.skipAgents && agentsToMigrate.length > 0) {
|
|
2449
|
-
console.log(chalk.white('8. Migrating agent names (ADR-048)...'));
|
|
2450
|
-
let migratedAgents = 0;
|
|
2451
|
-
const deprecatedDir = path.join(claudeAgentDir, 'deprecated');
|
|
2452
|
-
// Create deprecated directory for old agents
|
|
2453
|
-
if (!fs.existsSync(deprecatedDir)) {
|
|
2454
|
-
fs.mkdirSync(deprecatedDir, { recursive: true });
|
|
2455
|
-
}
|
|
2456
|
-
for (const v2Name of agentsToMigrate) {
|
|
2457
|
-
const v3Name = resolveAgentName(v2Name);
|
|
2458
|
-
const v2FilePath = path.join(claudeAgentDir, `${v2Name}.md`);
|
|
2459
|
-
const v3FilePath = path.join(claudeAgentDir, `${v3Name}.md`);
|
|
2460
|
-
const deprecatedPath = path.join(deprecatedDir, `${v2Name}.md.v2`);
|
|
2461
|
-
try {
|
|
2462
|
-
// Read the original file
|
|
2463
|
-
const content = fs.readFileSync(v2FilePath, 'utf-8');
|
|
2464
|
-
// Parse frontmatter (between first two ---)
|
|
2465
|
-
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
2466
|
-
if (!frontmatterMatch) {
|
|
2467
|
-
console.log(chalk.yellow(` ⚠ ${v2Name}: No frontmatter found, skipping`));
|
|
2468
|
-
continue;
|
|
2469
|
-
}
|
|
2470
|
-
const frontmatter = frontmatterMatch[1];
|
|
2471
|
-
const bodyStart = content.indexOf('---', 4) + 4; // After second ---
|
|
2472
|
-
let body = content.slice(bodyStart);
|
|
2473
|
-
// Update frontmatter: change name and add v2_compat
|
|
2474
|
-
let newFrontmatter = frontmatter.replace(/^name:\s*.+$/m, `name: ${v3Name}`);
|
|
2475
|
-
// Add v2_compat field if not present
|
|
2476
|
-
if (!newFrontmatter.includes('v2_compat:')) {
|
|
2477
|
-
newFrontmatter += `\nv2_compat:\n name: ${v2Name}\n deprecated_in: "3.0.0"\n removed_in: "4.0.0"`;
|
|
2478
|
-
}
|
|
2479
|
-
// Update body content: replace old agent name references
|
|
2480
|
-
// Convert kebab-case to Title Case for display names
|
|
2481
|
-
const toTitleCase = (s) => s.replace('qe-', '').split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
2482
|
-
const v2DisplayName = toTitleCase(v2Name);
|
|
2483
|
-
const v3DisplayName = toTitleCase(v3Name);
|
|
2484
|
-
// Replace display names in body (e.g., "Test Generator" → "Test Architect")
|
|
2485
|
-
body = body.replace(new RegExp(v2DisplayName, 'g'), v3DisplayName);
|
|
2486
|
-
// Replace kebab-case references (e.g., "qe-test-generator" → "qe-test-architect")
|
|
2487
|
-
body = body.replace(new RegExp(v2Name, 'g'), v3Name);
|
|
2488
|
-
// Create new content
|
|
2489
|
-
const newContent = `---\n${newFrontmatter}\n---${body}`;
|
|
2490
|
-
// Write new v3 agent file
|
|
2491
|
-
fs.writeFileSync(v3FilePath, newContent, 'utf-8');
|
|
2492
|
-
// Move old file to deprecated folder
|
|
2493
|
-
fs.renameSync(v2FilePath, deprecatedPath);
|
|
2494
|
-
console.log(chalk.gray(` ${v2Name} → ${v3Name}`));
|
|
2495
|
-
migratedAgents++;
|
|
2496
|
-
}
|
|
2497
|
-
catch (err) {
|
|
2498
|
-
console.log(chalk.red(` ✗ ${v2Name}: ${err}`));
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
if (migratedAgents > 0) {
|
|
2502
|
-
console.log(chalk.green(` ✓ ${migratedAgents} agents migrated`));
|
|
2503
|
-
console.log(chalk.gray(` Old files archived to: ${deprecatedDir}\n`));
|
|
2504
|
-
}
|
|
2505
|
-
else {
|
|
2506
|
-
console.log(chalk.yellow(' ⚠ No agents were migrated\n'));
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
else if (options.skipAgents) {
|
|
2510
|
-
console.log(chalk.yellow('8. Agent migration skipped\n'));
|
|
2511
|
-
}
|
|
2512
|
-
else {
|
|
2513
|
-
console.log(chalk.gray('8. No agents need migration\n'));
|
|
2514
|
-
}
|
|
2515
|
-
// Step 9: Validation
|
|
2516
|
-
console.log(chalk.white('9. Validating migration...'));
|
|
2517
|
-
const validationResults = {
|
|
2518
|
-
v3DirExists: fs.existsSync(v3Dir),
|
|
2519
|
-
configExists: fs.existsSync(path.join(v3Dir, 'config.json')),
|
|
2520
|
-
agentdbExists: fs.existsSync(path.join(v3Dir, 'agentdb')),
|
|
2521
|
-
reasoningBankExists: fs.existsSync(path.join(v3Dir, 'reasoning-bank')),
|
|
2522
|
-
};
|
|
2523
|
-
const allValid = Object.values(validationResults).every(v => v);
|
|
2524
|
-
if (allValid) {
|
|
2525
|
-
console.log(chalk.green(' ✓ Migration validated successfully\n'));
|
|
2526
|
-
}
|
|
2527
|
-
else {
|
|
2528
|
-
console.log(chalk.yellow(' ⚠ Some validations failed:'));
|
|
2529
|
-
for (const [key, value] of Object.entries(validationResults)) {
|
|
2530
|
-
console.log(chalk.gray(` ${key}: ${value ? '✓' : '✗'}`));
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
// Summary
|
|
2534
|
-
console.log(chalk.blue('═══════════════════════════════════════════════'));
|
|
2535
|
-
console.log(chalk.green.bold('✅ Migration Complete!\n'));
|
|
2536
|
-
console.log(chalk.white('Next steps:'));
|
|
2537
|
-
console.log(chalk.gray(' 1. Run `aqe migrate verify` to validate'));
|
|
2538
|
-
console.log(chalk.gray(' 2. Run `aqe migrate status` to check'));
|
|
2539
|
-
console.log(chalk.gray(' 3. Use `aqe migrate rollback` if needed\n'));
|
|
2540
|
-
await cleanupAndExit(0);
|
|
2541
|
-
});
|
|
2542
|
-
// migrate status - Check migration status
|
|
2543
|
-
migrateCmd
|
|
2544
|
-
.command('status')
|
|
2545
|
-
.description('Check migration status of current project')
|
|
2546
|
-
.option('--json', 'Output as JSON')
|
|
2547
|
-
.action(async (options) => {
|
|
2548
|
-
const fs = await import('fs');
|
|
2549
|
-
const path = await import('path');
|
|
2550
|
-
const cwd = process.cwd();
|
|
2551
|
-
const v2Dir = path.join(cwd, '.agentic-qe');
|
|
2552
|
-
const v3Dir = path.join(cwd, '.aqe');
|
|
2553
|
-
const claudeAgentDir = path.join(cwd, '.claude', 'agents');
|
|
2554
|
-
const isV2Project = fs.existsSync(v2Dir);
|
|
2555
|
-
const isV3Project = fs.existsSync(v3Dir);
|
|
2556
|
-
// Find agents needing migration
|
|
2557
|
-
const agentsToMigrate = [];
|
|
2558
|
-
const agentsMigrated = [];
|
|
2559
|
-
if (fs.existsSync(claudeAgentDir)) {
|
|
2560
|
-
const files = fs.readdirSync(claudeAgentDir);
|
|
2561
|
-
for (const file of files) {
|
|
2562
|
-
if (file.endsWith('.md') && file.startsWith('qe-')) {
|
|
2563
|
-
const agentName = file.replace('.md', '');
|
|
2564
|
-
if (isDeprecatedAgent(agentName)) {
|
|
2565
|
-
agentsToMigrate.push(agentName);
|
|
2566
|
-
}
|
|
2567
|
-
else if (v3Agents.includes(agentName)) {
|
|
2568
|
-
agentsMigrated.push(agentName);
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
}
|
|
2573
|
-
const needsMigration = isV2Project && !isV3Project || agentsToMigrate.length > 0;
|
|
2574
|
-
const status = {
|
|
2575
|
-
version: '3.0.0',
|
|
2576
|
-
isV2Project,
|
|
2577
|
-
isV3Project,
|
|
2578
|
-
needsMigration,
|
|
2579
|
-
agentsToMigrate,
|
|
2580
|
-
agentsMigrated,
|
|
2581
|
-
components: [
|
|
2582
|
-
{ name: 'Data Directory', status: isV3Project ? 'migrated' : (isV2Project ? 'pending' : 'not-required') },
|
|
2583
|
-
{ name: 'Agent Names', status: agentsToMigrate.length === 0 ? 'migrated' : 'pending' },
|
|
2584
|
-
],
|
|
2585
|
-
};
|
|
2586
|
-
if (options.json) {
|
|
2587
|
-
console.log(JSON.stringify(status, null, 2));
|
|
2588
|
-
return;
|
|
2589
|
-
}
|
|
2590
|
-
console.log(chalk.bold('\n📊 Migration Status\n'));
|
|
2591
|
-
console.log(`Version: ${chalk.cyan(status.version)}`);
|
|
2592
|
-
console.log(`V2 Project: ${status.isV2Project ? chalk.yellow('Yes') : chalk.dim('No')}`);
|
|
2593
|
-
console.log(`V3 Project: ${status.isV3Project ? chalk.green('Yes') : chalk.dim('No')}`);
|
|
2594
|
-
console.log(`Needs Migration: ${status.needsMigration ? chalk.yellow('Yes') : chalk.green('No')}`);
|
|
2595
|
-
console.log(chalk.bold('\n📦 Components\n'));
|
|
2596
|
-
for (const comp of status.components) {
|
|
2597
|
-
const color = comp.status === 'migrated' ? chalk.green : comp.status === 'pending' ? chalk.yellow : chalk.dim;
|
|
2598
|
-
console.log(` ${comp.name}: ${color(comp.status)}`);
|
|
2599
|
-
}
|
|
2600
|
-
if (agentsToMigrate.length > 0) {
|
|
2601
|
-
console.log(chalk.bold('\n⚠️ Agents Needing Migration\n'));
|
|
2602
|
-
for (const agent of agentsToMigrate) {
|
|
2603
|
-
console.log(` ${chalk.yellow(agent)} → ${chalk.green(resolveAgentName(agent))}`);
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
console.log();
|
|
2607
|
-
await cleanupAndExit(0);
|
|
2608
|
-
});
|
|
2609
|
-
// migrate verify - Verify migration
|
|
2610
|
-
migrateCmd
|
|
2611
|
-
.command('verify')
|
|
2612
|
-
.description('Verify migration integrity')
|
|
2613
|
-
.option('--fix', 'Attempt to fix issues automatically')
|
|
2614
|
-
.action(async (options) => {
|
|
2615
|
-
const fs = await import('fs');
|
|
2616
|
-
const path = await import('path');
|
|
2617
|
-
console.log(chalk.bold('\n🔍 Verifying Migration...\n'));
|
|
2618
|
-
const cwd = process.cwd();
|
|
2619
|
-
const v3Dir = path.join(cwd, '.aqe');
|
|
2620
|
-
const claudeAgentDir = path.join(cwd, '.claude', 'agents');
|
|
2621
|
-
// Find deprecated agents still in use
|
|
2622
|
-
const deprecatedInUse = [];
|
|
2623
|
-
if (fs.existsSync(claudeAgentDir)) {
|
|
2624
|
-
const files = fs.readdirSync(claudeAgentDir);
|
|
2625
|
-
for (const file of files) {
|
|
2626
|
-
if (file.endsWith('.md') && file.startsWith('qe-')) {
|
|
2627
|
-
const agentName = file.replace('.md', '');
|
|
2628
|
-
if (isDeprecatedAgent(agentName)) {
|
|
2629
|
-
deprecatedInUse.push(agentName);
|
|
2630
|
-
}
|
|
2631
|
-
}
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
const checks = [
|
|
2635
|
-
{
|
|
2636
|
-
name: 'V3 Directory',
|
|
2637
|
-
passed: fs.existsSync(v3Dir),
|
|
2638
|
-
message: fs.existsSync(v3Dir) ? 'Exists' : 'Missing .aqe/',
|
|
2639
|
-
},
|
|
2640
|
-
{
|
|
2641
|
-
name: 'Agent Compatibility',
|
|
2642
|
-
passed: deprecatedInUse.length === 0,
|
|
2643
|
-
message: deprecatedInUse.length === 0 ? 'All agents use v3 names' : `${deprecatedInUse.length} deprecated agents`,
|
|
2644
|
-
},
|
|
2645
|
-
{
|
|
2646
|
-
name: 'Config Format',
|
|
2647
|
-
passed: fs.existsSync(path.join(v3Dir, 'config.json')),
|
|
2648
|
-
message: 'Valid v3 config',
|
|
2649
|
-
},
|
|
2650
|
-
];
|
|
2651
|
-
let allPassed = true;
|
|
2652
|
-
for (const check of checks) {
|
|
2653
|
-
const icon = check.passed ? chalk.green('✓') : chalk.red('✗');
|
|
2654
|
-
const color = check.passed ? chalk.green : chalk.red;
|
|
2655
|
-
console.log(` ${icon} ${check.name}: ${color(check.message)}`);
|
|
2656
|
-
if (!check.passed)
|
|
2657
|
-
allPassed = false;
|
|
2658
|
-
}
|
|
2659
|
-
console.log();
|
|
2660
|
-
if (allPassed) {
|
|
2661
|
-
console.log(chalk.green('✅ All verification checks passed!\n'));
|
|
2662
|
-
}
|
|
2663
|
-
else {
|
|
2664
|
-
console.log(chalk.yellow('⚠️ Some checks failed.'));
|
|
2665
|
-
if (options.fix) {
|
|
2666
|
-
console.log(chalk.dim(' Attempting automatic fixes...\n'));
|
|
2667
|
-
let fixedCount = 0;
|
|
2668
|
-
// Fix 1: Create v3 directory if missing
|
|
2669
|
-
if (!fs.existsSync(v3Dir)) {
|
|
2670
|
-
fs.mkdirSync(v3Dir, { recursive: true });
|
|
2671
|
-
fs.mkdirSync(path.join(v3Dir, 'agentdb'), { recursive: true });
|
|
2672
|
-
fs.mkdirSync(path.join(v3Dir, 'reasoning-bank'), { recursive: true });
|
|
2673
|
-
fs.writeFileSync(path.join(v3Dir, 'config.json'), JSON.stringify({
|
|
2674
|
-
version: '3.0.0',
|
|
2675
|
-
createdAt: new Date().toISOString(),
|
|
2676
|
-
autoCreated: true,
|
|
2677
|
-
}, null, 2));
|
|
2678
|
-
console.log(chalk.green(' ✓ Created .aqe/ directory structure'));
|
|
2679
|
-
fixedCount++;
|
|
2680
|
-
}
|
|
2681
|
-
// Fix 2: Migrate deprecated agents
|
|
2682
|
-
if (deprecatedInUse.length > 0) {
|
|
2683
|
-
const deprecatedDir = path.join(claudeAgentDir, 'deprecated');
|
|
2684
|
-
if (!fs.existsSync(deprecatedDir)) {
|
|
2685
|
-
fs.mkdirSync(deprecatedDir, { recursive: true });
|
|
2686
|
-
}
|
|
2687
|
-
for (const v2Name of deprecatedInUse) {
|
|
2688
|
-
const v3Name = resolveAgentName(v2Name);
|
|
2689
|
-
const v2FilePath = path.join(claudeAgentDir, `${v2Name}.md`);
|
|
2690
|
-
const v3FilePath = path.join(claudeAgentDir, `${v3Name}.md`);
|
|
2691
|
-
const deprecatedPath = path.join(deprecatedDir, `${v2Name}.md.v2`);
|
|
2692
|
-
try {
|
|
2693
|
-
const content = fs.readFileSync(v2FilePath, 'utf-8');
|
|
2694
|
-
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
2695
|
-
if (frontmatterMatch) {
|
|
2696
|
-
const frontmatter = frontmatterMatch[1];
|
|
2697
|
-
const bodyStart = content.indexOf('---', 4) + 4;
|
|
2698
|
-
let body = content.slice(bodyStart);
|
|
2699
|
-
let newFrontmatter = frontmatter.replace(/^name:\s*.+$/m, `name: ${v3Name}`);
|
|
2700
|
-
if (!newFrontmatter.includes('v2_compat:')) {
|
|
2701
|
-
newFrontmatter += `\nv2_compat:\n name: ${v2Name}\n deprecated_in: "3.0.0"\n removed_in: "4.0.0"`;
|
|
2702
|
-
}
|
|
2703
|
-
// Update body content: replace old agent name references
|
|
2704
|
-
const toTitleCase = (s) => s.replace('qe-', '').split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
2705
|
-
body = body.replace(new RegExp(toTitleCase(v2Name), 'g'), toTitleCase(v3Name));
|
|
2706
|
-
body = body.replace(new RegExp(v2Name, 'g'), v3Name);
|
|
2707
|
-
const newContent = `---\n${newFrontmatter}\n---${body}`;
|
|
2708
|
-
fs.writeFileSync(v3FilePath, newContent, 'utf-8');
|
|
2709
|
-
fs.renameSync(v2FilePath, deprecatedPath);
|
|
2710
|
-
console.log(chalk.green(` ✓ Migrated ${v2Name} → ${v3Name}`));
|
|
2711
|
-
fixedCount++;
|
|
2712
|
-
}
|
|
2713
|
-
}
|
|
2714
|
-
catch (err) {
|
|
2715
|
-
console.log(chalk.red(` ✗ Failed to migrate ${v2Name}: ${err}`));
|
|
2716
|
-
}
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
if (fixedCount > 0) {
|
|
2720
|
-
console.log(chalk.green(`\n✅ Applied ${fixedCount} fixes. Re-run 'aqe migrate verify' to confirm.\n`));
|
|
2721
|
-
}
|
|
2722
|
-
else {
|
|
2723
|
-
console.log(chalk.yellow('\n⚠️ No automatic fixes available for remaining issues.\n'));
|
|
2724
|
-
}
|
|
2725
|
-
}
|
|
2726
|
-
else {
|
|
2727
|
-
console.log(chalk.dim(' Run with --fix to attempt fixes.\n'));
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
await cleanupAndExit(0);
|
|
2731
|
-
});
|
|
2732
|
-
// migrate rollback - Rollback migration
|
|
2733
|
-
migrateCmd
|
|
2734
|
-
.command('rollback')
|
|
2735
|
-
.description('Rollback to previous version from backup')
|
|
2736
|
-
.option('--backup-id <id>', 'Specific backup to restore')
|
|
2737
|
-
.option('--force', 'Skip confirmation')
|
|
2738
|
-
.action(async (options) => {
|
|
2739
|
-
const fs = await import('fs');
|
|
2740
|
-
const path = await import('path');
|
|
2741
|
-
const cwd = process.cwd();
|
|
2742
|
-
const backupRoot = path.join(cwd, '.aqe-backup');
|
|
2743
|
-
if (!fs.existsSync(backupRoot)) {
|
|
2744
|
-
console.log(chalk.yellow('\n⚠️ No backups found.\n'));
|
|
2745
|
-
return;
|
|
2746
|
-
}
|
|
2747
|
-
const backups = fs.readdirSync(backupRoot)
|
|
2748
|
-
.filter(f => f.startsWith('backup-'))
|
|
2749
|
-
.sort()
|
|
2750
|
-
.reverse();
|
|
2751
|
-
if (backups.length === 0) {
|
|
2752
|
-
console.log(chalk.yellow('\n⚠️ No backups found.\n'));
|
|
2753
|
-
return;
|
|
2754
|
-
}
|
|
2755
|
-
console.log(chalk.bold('\n📦 Available Backups\n'));
|
|
2756
|
-
for (const backup of backups.slice(0, 5)) {
|
|
2757
|
-
const timestamp = backup.replace('backup-', '');
|
|
2758
|
-
const date = new Date(parseInt(timestamp));
|
|
2759
|
-
console.log(` ${chalk.cyan(backup)} - ${date.toLocaleString()}`);
|
|
2760
|
-
}
|
|
2761
|
-
const targetBackup = options.backupId || backups[0];
|
|
2762
|
-
const backupPath = path.join(backupRoot, targetBackup);
|
|
2763
|
-
if (!fs.existsSync(backupPath)) {
|
|
2764
|
-
console.log(chalk.red(`\n❌ Backup not found: ${targetBackup}\n`));
|
|
2765
|
-
await cleanupAndExit(1);
|
|
2766
|
-
}
|
|
2767
|
-
if (!options.force) {
|
|
2768
|
-
console.log(chalk.yellow(`\n⚠️ This will restore from: ${targetBackup}`));
|
|
2769
|
-
console.log(chalk.dim(' Run with --force to confirm.\n'));
|
|
2770
|
-
return;
|
|
2771
|
-
}
|
|
2772
|
-
console.log(chalk.bold(`\n🔄 Rolling back to ${targetBackup}...\n`));
|
|
2773
|
-
// Restore backup
|
|
2774
|
-
const v2Backup = path.join(backupPath, '.agentic-qe');
|
|
2775
|
-
const agentsBackup = path.join(backupPath, '.claude', 'agents');
|
|
2776
|
-
if (fs.existsSync(v2Backup)) {
|
|
2777
|
-
const v2Dir = path.join(cwd, '.agentic-qe');
|
|
2778
|
-
fs.cpSync(v2Backup, v2Dir, { recursive: true });
|
|
2779
|
-
console.log(chalk.dim(' Restored .agentic-qe/'));
|
|
2780
|
-
}
|
|
2781
|
-
if (fs.existsSync(agentsBackup)) {
|
|
2782
|
-
const agentsDir = path.join(cwd, '.claude', 'agents');
|
|
2783
|
-
fs.cpSync(agentsBackup, agentsDir, { recursive: true });
|
|
2784
|
-
console.log(chalk.dim(' Restored .claude/agents/'));
|
|
2785
|
-
}
|
|
2786
|
-
// Remove v3 directory
|
|
2787
|
-
const v3Dir = path.join(cwd, '.aqe');
|
|
2788
|
-
if (fs.existsSync(v3Dir)) {
|
|
2789
|
-
fs.rmSync(v3Dir, { recursive: true, force: true });
|
|
2790
|
-
console.log(chalk.dim(' Removed .aqe/'));
|
|
2791
|
-
}
|
|
2792
|
-
console.log(chalk.green('\n✅ Rollback complete!\n'));
|
|
2793
|
-
await cleanupAndExit(0);
|
|
2794
|
-
});
|
|
2795
|
-
// migrate mapping - Show agent name mappings
|
|
2796
|
-
migrateCmd
|
|
2797
|
-
.command('mapping')
|
|
2798
|
-
.description('Show v2 to v3 agent name mappings (ADR-048)')
|
|
2799
|
-
.option('--json', 'Output as JSON')
|
|
2800
|
-
.action(async (options) => {
|
|
2801
|
-
if (options.json) {
|
|
2802
|
-
console.log(JSON.stringify(v2AgentMapping, null, 2));
|
|
2803
|
-
return;
|
|
2804
|
-
}
|
|
2805
|
-
console.log(chalk.bold('\n🔄 Agent Name Mappings (V2 → V3)\n'));
|
|
2806
|
-
const entries = Object.entries(v2AgentMapping);
|
|
2807
|
-
for (const [v2Name, v3Name] of entries) {
|
|
2808
|
-
console.log(` ${chalk.yellow(v2Name)} → ${chalk.green(v3Name)}`);
|
|
2809
|
-
}
|
|
2810
|
-
console.log(chalk.dim(`\n Total: ${entries.length} mappings\n`));
|
|
2811
|
-
console.log(chalk.gray(' See ADR-048 for full migration strategy.\n'));
|
|
2812
|
-
await cleanupAndExit(0);
|
|
2813
|
-
});
|
|
2814
|
-
// ============================================================================
|
|
2815
|
-
// Completions Command
|
|
2816
|
-
// ============================================================================
|
|
2817
|
-
const completionsCmd = program
|
|
2818
|
-
.command('completions')
|
|
2819
|
-
.description('Generate shell completions for aqe');
|
|
2820
|
-
completionsCmd
|
|
2821
|
-
.command('bash')
|
|
2822
|
-
.description('Generate Bash completion script')
|
|
2823
|
-
.action(() => {
|
|
2824
|
-
console.log(generateCompletion('bash'));
|
|
2825
|
-
});
|
|
2826
|
-
completionsCmd
|
|
2827
|
-
.command('zsh')
|
|
2828
|
-
.description('Generate Zsh completion script')
|
|
2829
|
-
.action(() => {
|
|
2830
|
-
console.log(generateCompletion('zsh'));
|
|
2831
|
-
});
|
|
2832
|
-
completionsCmd
|
|
2833
|
-
.command('fish')
|
|
2834
|
-
.description('Generate Fish completion script')
|
|
2835
|
-
.action(() => {
|
|
2836
|
-
console.log(generateCompletion('fish'));
|
|
2837
|
-
});
|
|
2838
|
-
completionsCmd
|
|
2839
|
-
.command('powershell')
|
|
2840
|
-
.description('Generate PowerShell completion script')
|
|
2841
|
-
.action(() => {
|
|
2842
|
-
console.log(generateCompletion('powershell'));
|
|
2843
|
-
});
|
|
2844
|
-
completionsCmd
|
|
2845
|
-
.command('install')
|
|
2846
|
-
.description('Auto-install completions for current shell')
|
|
2847
|
-
.option('-s, --shell <shell>', 'Target shell (bash|zsh|fish|powershell)')
|
|
2848
|
-
.action(async (options) => {
|
|
2849
|
-
const fs = await import('fs');
|
|
2850
|
-
const path = await import('path');
|
|
2851
|
-
const shellInfo = options.shell
|
|
2852
|
-
? { name: options.shell, configFile: null, detected: false }
|
|
2853
|
-
: detectShell();
|
|
2854
|
-
if (shellInfo.name === 'unknown') {
|
|
2855
|
-
console.log(chalk.red('Could not detect shell. Please specify with --shell option.\n'));
|
|
2856
|
-
console.log(getInstallInstructions('unknown'));
|
|
2857
|
-
await cleanupAndExit(1);
|
|
2858
|
-
return; // TypeScript flow control hint - cleanupAndExit exits but TS doesn't know
|
|
2859
|
-
}
|
|
2860
|
-
console.log(chalk.blue(`\nInstalling completions for ${shellInfo.name}...\n`));
|
|
2861
|
-
const script = generateCompletion(shellInfo.name);
|
|
2862
|
-
// For Fish, write directly to completions directory
|
|
2863
|
-
if (shellInfo.name === 'fish') {
|
|
2864
|
-
const fishCompletionsDir = `${process.env.HOME}/.config/fish/completions`;
|
|
2865
|
-
try {
|
|
2866
|
-
fs.mkdirSync(fishCompletionsDir, { recursive: true });
|
|
2867
|
-
const completionFile = path.join(fishCompletionsDir, 'aqe.fish');
|
|
2868
|
-
fs.writeFileSync(completionFile, script);
|
|
2869
|
-
console.log(chalk.green(`Completions installed to: ${completionFile}`));
|
|
2870
|
-
console.log(chalk.gray('\nRestart your shell or run: source ~/.config/fish/completions/aqe.fish\n'));
|
|
2871
|
-
}
|
|
2872
|
-
catch (err) {
|
|
2873
|
-
console.log(chalk.red(`Failed to install: ${err}`));
|
|
2874
|
-
console.log(chalk.yellow('\nManual installation:'));
|
|
2875
|
-
console.log(getInstallInstructions('fish'));
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
else {
|
|
2879
|
-
// For other shells, show instructions
|
|
2880
|
-
console.log(chalk.yellow('To install completions, follow these instructions:\n'));
|
|
2881
|
-
console.log(getInstallInstructions(shellInfo.name));
|
|
2882
|
-
console.log(chalk.gray('\n---\nCompletion script:\n'));
|
|
2883
|
-
console.log(script);
|
|
2884
|
-
}
|
|
2885
|
-
});
|
|
2886
|
-
completionsCmd
|
|
2887
|
-
.command('list')
|
|
2888
|
-
.description('List all completion values (domains, agents, etc.)')
|
|
2889
|
-
.option('-t, --type <type>', 'Type to list (domains|agents|v3-qe-agents)', 'all')
|
|
2890
|
-
.action((options) => {
|
|
2891
|
-
if (options.type === 'domains' || options.type === 'all') {
|
|
2892
|
-
console.log(chalk.blue('\n12 DDD Domains:'));
|
|
2893
|
-
COMPLETION_DOMAINS.forEach(d => console.log(chalk.gray(` ${d}`)));
|
|
2894
|
-
}
|
|
2895
|
-
if (options.type === 'v3-qe-agents' || options.type === 'all') {
|
|
2896
|
-
console.log(chalk.blue('\nQE Agents (' + QE_AGENTS.length + '):'));
|
|
2897
|
-
QE_AGENTS.forEach(a => console.log(chalk.gray(` ${a}`)));
|
|
2898
|
-
}
|
|
2899
|
-
if (options.type === 'agents' || options.type === 'all') {
|
|
2900
|
-
console.log(chalk.blue('\nOther Agents (' + OTHER_AGENTS.length + '):'));
|
|
2901
|
-
OTHER_AGENTS.forEach(a => console.log(chalk.gray(` ${a}`)));
|
|
2902
|
-
}
|
|
2903
|
-
console.log('');
|
|
2904
|
-
});
|
|
2905
|
-
// ============================================================================
|
|
2906
|
-
// Fleet Command Group - Multi-agent operations with progress
|
|
2907
|
-
// ============================================================================
|
|
2908
|
-
const fleetCmd = program
|
|
2909
|
-
.command('fleet')
|
|
2910
|
-
.description('Fleet operations with multi-agent progress tracking');
|
|
2911
|
-
// Fleet init with wizard (ADR-041)
|
|
2912
|
-
fleetCmd
|
|
2913
|
-
.command('init')
|
|
2914
|
-
.description('Initialize fleet with interactive wizard')
|
|
2915
|
-
.option('--wizard', 'Run interactive fleet initialization wizard')
|
|
2916
|
-
.option('-t, --topology <type>', 'Fleet topology (hierarchical|mesh|ring|adaptive|hierarchical-mesh)', 'hierarchical-mesh')
|
|
2917
|
-
.option('-m, --max-agents <count>', 'Maximum agent count (5-50)', '15')
|
|
2918
|
-
.option('-d, --domains <domains>', 'Domains to enable (comma-separated or "all")', 'all')
|
|
2919
|
-
.option('--memory <backend>', 'Memory backend (sqlite|agentdb|hybrid)', 'hybrid')
|
|
2920
|
-
.option('--lazy', 'Enable lazy loading', true)
|
|
2921
|
-
.option('--skip-patterns', 'Skip loading pre-trained patterns')
|
|
2922
|
-
.option('--skip-code-scan', 'Skip code intelligence index check')
|
|
2923
|
-
.action(async (options) => {
|
|
2924
|
-
try {
|
|
2925
|
-
let topology = options.topology;
|
|
2926
|
-
let maxAgents = parseInt(options.maxAgents, 10);
|
|
2927
|
-
let domains = options.domains;
|
|
2928
|
-
let memoryBackend = options.memory;
|
|
2929
|
-
let lazyLoading = options.lazy;
|
|
2930
|
-
let loadPatterns = !options.skipPatterns;
|
|
2931
|
-
// CI-005: Check code intelligence index before fleet initialization
|
|
2932
|
-
console.log(chalk.blue('\n 🧠 Code Intelligence Check\n'));
|
|
2933
|
-
const ciResult = await integrateCodeIntelligence(process.cwd(), {
|
|
2934
|
-
skipCodeScan: options.skipCodeScan,
|
|
2935
|
-
nonInteractive: !options.wizard, // Only prompt in wizard mode
|
|
2936
|
-
});
|
|
2937
|
-
// If user requested scan, exit and let them run it
|
|
2938
|
-
if (!ciResult.shouldProceed) {
|
|
2939
|
-
console.log(chalk.blue('\n Please run the code intelligence scan first:'));
|
|
2940
|
-
console.log(chalk.cyan(' aqe code-intelligence index\n'));
|
|
2941
|
-
console.log(chalk.gray(' Then re-run fleet init when ready.\n'));
|
|
2942
|
-
await cleanupAndExit(0);
|
|
2943
|
-
return;
|
|
2944
|
-
}
|
|
2945
|
-
// Run wizard if requested (ADR-041)
|
|
2946
|
-
if (options.wizard) {
|
|
2947
|
-
console.log(chalk.blue('\n🚀 Fleet Initialization Wizard\n'));
|
|
2948
|
-
const wizardResult = await runFleetInitWizard({
|
|
2949
|
-
defaultTopology: options.topology !== 'hierarchical-mesh' ? options.topology : undefined,
|
|
2950
|
-
defaultMaxAgents: options.maxAgents !== '15' ? parseInt(options.maxAgents, 10) : undefined,
|
|
2951
|
-
defaultDomains: options.domains !== 'all' ? options.domains.split(',') : undefined,
|
|
2952
|
-
defaultMemoryBackend: options.memory !== 'hybrid' ? options.memory : undefined,
|
|
2953
|
-
});
|
|
2954
|
-
if (wizardResult.cancelled) {
|
|
2955
|
-
console.log(chalk.yellow('\n Fleet initialization cancelled.\n'));
|
|
2956
|
-
await cleanupAndExit(0);
|
|
2957
|
-
}
|
|
2958
|
-
// Use wizard results
|
|
2959
|
-
topology = wizardResult.topology;
|
|
2960
|
-
maxAgents = wizardResult.maxAgents;
|
|
2961
|
-
domains = wizardResult.domains.join(',');
|
|
2962
|
-
memoryBackend = wizardResult.memoryBackend;
|
|
2963
|
-
lazyLoading = wizardResult.lazyLoading;
|
|
2964
|
-
loadPatterns = wizardResult.loadPatterns;
|
|
2965
|
-
console.log(chalk.green('\n Starting fleet initialization...\n'));
|
|
2966
|
-
}
|
|
2967
|
-
// Parse domains
|
|
2968
|
-
const enabledDomains = domains === 'all'
|
|
2969
|
-
? [...ALL_DOMAINS]
|
|
2970
|
-
: domains.split(',').filter((d) => ALL_DOMAINS.includes(d));
|
|
2971
|
-
console.log(chalk.blue('\n Fleet Configuration\n'));
|
|
2972
|
-
console.log(chalk.gray(` Topology: ${topology}`));
|
|
2973
|
-
console.log(chalk.gray(` Max Agents: ${maxAgents}`));
|
|
2974
|
-
console.log(chalk.gray(` Domains: ${enabledDomains.length}`));
|
|
2975
|
-
console.log(chalk.gray(` Memory: ${memoryBackend}`));
|
|
2976
|
-
console.log(chalk.gray(` Lazy Loading: ${lazyLoading ? 'enabled' : 'disabled'}`));
|
|
2977
|
-
console.log(chalk.gray(` Pre-trained Patterns: ${loadPatterns ? 'load' : 'skip'}\n`));
|
|
2978
|
-
// Initialize if not already done
|
|
2979
|
-
if (!context.initialized) {
|
|
2980
|
-
context.kernel = new QEKernelImpl({
|
|
2981
|
-
maxConcurrentAgents: maxAgents,
|
|
2982
|
-
memoryBackend,
|
|
2983
|
-
hnswEnabled: true,
|
|
2984
|
-
lazyLoading,
|
|
2985
|
-
enabledDomains,
|
|
2986
|
-
});
|
|
2987
|
-
await context.kernel.initialize();
|
|
2988
|
-
console.log(chalk.green(' ✓ Kernel initialized'));
|
|
2989
|
-
context.router = new CrossDomainEventRouter(context.kernel.eventBus);
|
|
2990
|
-
await context.router.initialize();
|
|
2991
|
-
console.log(chalk.green(' ✓ Cross-domain router initialized'));
|
|
2992
|
-
context.workflowOrchestrator = new WorkflowOrchestrator(context.kernel.eventBus, context.kernel.memory, context.kernel.coordinator);
|
|
2993
|
-
await context.workflowOrchestrator.initialize();
|
|
2994
|
-
// Register domain workflow actions (Issue #206)
|
|
2995
|
-
registerDomainWorkflowActions(context.kernel, context.workflowOrchestrator);
|
|
2996
|
-
console.log(chalk.green(' ✓ Workflow orchestrator initialized'));
|
|
2997
|
-
context.persistentScheduler = createPersistentScheduler();
|
|
2998
|
-
console.log(chalk.green(' ✓ Persistent scheduler initialized'));
|
|
2999
|
-
const getDomainAPI = (domain) => {
|
|
3000
|
-
return context.kernel.getDomainAPI(domain);
|
|
3001
|
-
};
|
|
3002
|
-
const protocolExecutor = new DefaultProtocolExecutor(context.kernel.eventBus, context.kernel.memory, getDomainAPI);
|
|
3003
|
-
context.queen = createQueenCoordinator(context.kernel, context.router, protocolExecutor, undefined);
|
|
3004
|
-
await context.queen.initialize();
|
|
3005
|
-
console.log(chalk.green(' ✓ Queen coordinator initialized'));
|
|
3006
|
-
context.initialized = true;
|
|
3007
|
-
}
|
|
3008
|
-
console.log(chalk.green('\n✅ Fleet initialized successfully!\n'));
|
|
3009
|
-
console.log(chalk.white('Next steps:'));
|
|
3010
|
-
console.log(chalk.gray(' 1. Spawn agents: aqe fleet spawn --domains test-generation'));
|
|
3011
|
-
console.log(chalk.gray(' 2. Run operation: aqe fleet run test --target ./src'));
|
|
3012
|
-
console.log(chalk.gray(' 3. Check status: aqe fleet status\n'));
|
|
3013
|
-
await cleanupAndExit(0);
|
|
3014
|
-
}
|
|
3015
|
-
catch (error) {
|
|
3016
|
-
console.error(chalk.red('\n Fleet initialization failed:'), error);
|
|
3017
|
-
await cleanupAndExit(1);
|
|
3018
|
-
}
|
|
3019
|
-
});
|
|
3020
|
-
fleetCmd
|
|
3021
|
-
.command('spawn')
|
|
3022
|
-
.description('Spawn multiple agents with progress tracking')
|
|
3023
|
-
.option('-d, --domains <domains>', 'Comma-separated domains', 'test-generation,coverage-analysis')
|
|
3024
|
-
.option('-t, --type <type>', 'Agent type for all', 'worker')
|
|
3025
|
-
.option('-c, --count <count>', 'Number of agents per domain', '1')
|
|
3026
|
-
.action(async (options) => {
|
|
3027
|
-
if (!await ensureInitialized())
|
|
3028
|
-
return;
|
|
3029
|
-
try {
|
|
3030
|
-
const domains = options.domains.split(',');
|
|
3031
|
-
const countPerDomain = parseInt(options.count, 10);
|
|
3032
|
-
console.log(chalk.blue('\n Fleet Spawn Operation\n'));
|
|
3033
|
-
// Create fleet progress manager
|
|
3034
|
-
const progress = new FleetProgressManager({
|
|
3035
|
-
title: 'Agent Spawn Progress',
|
|
3036
|
-
showEta: true,
|
|
3037
|
-
});
|
|
3038
|
-
const totalAgents = domains.length * countPerDomain;
|
|
3039
|
-
progress.start(totalAgents);
|
|
3040
|
-
// Track spawned agents
|
|
3041
|
-
const spawnedAgents = [];
|
|
3042
|
-
let agentIndex = 0;
|
|
3043
|
-
// Spawn agents across domains
|
|
3044
|
-
for (const domain of domains) {
|
|
3045
|
-
for (let i = 0; i < countPerDomain; i++) {
|
|
3046
|
-
const agentName = `${domain}-${options.type}-${i + 1}`;
|
|
3047
|
-
const agentId = `agent-${agentIndex++}`;
|
|
3048
|
-
// Add agent to progress tracker
|
|
3049
|
-
progress.addAgent({
|
|
3050
|
-
id: agentId,
|
|
3051
|
-
name: agentName,
|
|
3052
|
-
status: 'pending',
|
|
3053
|
-
progress: 0,
|
|
3054
|
-
});
|
|
3055
|
-
// Update to running
|
|
3056
|
-
progress.updateAgent(agentId, 10, { status: 'running' });
|
|
3057
|
-
try {
|
|
3058
|
-
// Spawn the agent
|
|
3059
|
-
progress.updateAgent(agentId, 30, { message: 'Initializing...' });
|
|
3060
|
-
const result = await context.queen.requestAgentSpawn(domain, options.type, ['general']);
|
|
3061
|
-
progress.updateAgent(agentId, 80, { message: 'Configuring...' });
|
|
3062
|
-
if (result.success) {
|
|
3063
|
-
progress.completeAgent(agentId, true);
|
|
3064
|
-
spawnedAgents.push({ id: result.value, domain, success: true });
|
|
3065
|
-
}
|
|
3066
|
-
else {
|
|
3067
|
-
progress.completeAgent(agentId, false);
|
|
3068
|
-
spawnedAgents.push({ id: agentId, domain, success: false });
|
|
3069
|
-
}
|
|
3070
|
-
}
|
|
3071
|
-
catch {
|
|
3072
|
-
progress.completeAgent(agentId, false);
|
|
3073
|
-
spawnedAgents.push({ id: agentId, domain, success: false });
|
|
3074
|
-
}
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
progress.stop();
|
|
3078
|
-
// Summary
|
|
3079
|
-
const successful = spawnedAgents.filter(a => a.success).length;
|
|
3080
|
-
const failed = spawnedAgents.filter(a => !a.success).length;
|
|
3081
|
-
console.log(chalk.blue('\n Fleet Summary:'));
|
|
3082
|
-
console.log(chalk.gray(` Domains: ${domains.join(', ')}`));
|
|
3083
|
-
console.log(chalk.green(` Successful: ${successful}`));
|
|
3084
|
-
if (failed > 0) {
|
|
3085
|
-
console.log(chalk.red(` Failed: ${failed}`));
|
|
3086
|
-
}
|
|
3087
|
-
console.log('');
|
|
3088
|
-
await cleanupAndExit(failed > 0 ? 1 : 0);
|
|
3089
|
-
}
|
|
3090
|
-
catch (error) {
|
|
3091
|
-
console.error(chalk.red('\n Fleet spawn failed:'), error);
|
|
3092
|
-
await cleanupAndExit(1);
|
|
3093
|
-
}
|
|
3094
|
-
});
|
|
3095
|
-
fleetCmd
|
|
3096
|
-
.command('run')
|
|
3097
|
-
.description('Run a coordinated fleet operation')
|
|
3098
|
-
.argument('<operation>', 'Operation type (test|analyze|scan)')
|
|
3099
|
-
.option('-t, --target <path>', 'Target path', '.')
|
|
3100
|
-
.option('--parallel <count>', 'Number of parallel agents', '4')
|
|
3101
|
-
.action(async (operation, options) => {
|
|
3102
|
-
if (!await ensureInitialized())
|
|
3103
|
-
return;
|
|
3104
|
-
try {
|
|
3105
|
-
const parallelCount = parseInt(options.parallel, 10);
|
|
3106
|
-
console.log(chalk.blue(`\n Fleet Operation: ${operation}\n`));
|
|
3107
|
-
// Create fleet progress manager
|
|
3108
|
-
const progress = new FleetProgressManager({
|
|
3109
|
-
title: `${operation.charAt(0).toUpperCase() + operation.slice(1)} Progress`,
|
|
3110
|
-
showEta: true,
|
|
3111
|
-
});
|
|
3112
|
-
progress.start(parallelCount);
|
|
3113
|
-
// Define agent operations based on operation type
|
|
3114
|
-
const domainMap = {
|
|
3115
|
-
test: 'test-generation',
|
|
3116
|
-
analyze: 'coverage-analysis',
|
|
3117
|
-
scan: 'security-compliance',
|
|
3118
|
-
};
|
|
3119
|
-
const domain = domainMap[operation] || 'test-generation';
|
|
3120
|
-
// Create parallel agent operations
|
|
3121
|
-
const agentOperations = Array.from({ length: parallelCount }, (_, i) => {
|
|
3122
|
-
const agentId = `${operation}-agent-${i + 1}`;
|
|
3123
|
-
return {
|
|
3124
|
-
id: agentId,
|
|
3125
|
-
name: `${operation}-worker-${i + 1}`,
|
|
3126
|
-
domain,
|
|
3127
|
-
};
|
|
3128
|
-
});
|
|
3129
|
-
// Add all agents to progress
|
|
3130
|
-
for (const op of agentOperations) {
|
|
3131
|
-
progress.addAgent({
|
|
3132
|
-
id: op.id,
|
|
3133
|
-
name: op.name,
|
|
3134
|
-
status: 'pending',
|
|
3135
|
-
progress: 0,
|
|
3136
|
-
});
|
|
3137
|
-
}
|
|
3138
|
-
// Execute operations in parallel with progress updates
|
|
3139
|
-
const results = await Promise.all(agentOperations.map(async (op, index) => {
|
|
3140
|
-
// Simulate staggered start
|
|
3141
|
-
await new Promise(resolve => setTimeout(resolve, index * 200));
|
|
3142
|
-
progress.updateAgent(op.id, 0, { status: 'running' });
|
|
3143
|
-
try {
|
|
3144
|
-
// Simulate operation phases with progress updates
|
|
3145
|
-
for (let p = 10; p <= 90; p += 20) {
|
|
3146
|
-
await new Promise(resolve => setTimeout(resolve, 300 + Math.random() * 200));
|
|
3147
|
-
progress.updateAgent(op.id, p, {
|
|
3148
|
-
eta: Math.round((100 - p) * 50),
|
|
3149
|
-
});
|
|
3150
|
-
}
|
|
3151
|
-
// Submit actual task
|
|
3152
|
-
const taskResult = await context.queen.submitTask({
|
|
3153
|
-
type: operation === 'test' ? 'generate-tests' :
|
|
3154
|
-
operation === 'analyze' ? 'analyze-coverage' :
|
|
3155
|
-
'scan-security',
|
|
3156
|
-
priority: 'p1',
|
|
3157
|
-
targetDomains: [domain],
|
|
3158
|
-
payload: { target: options.target, workerId: op.id },
|
|
3159
|
-
timeout: 60000,
|
|
3160
|
-
});
|
|
3161
|
-
progress.completeAgent(op.id, taskResult.success);
|
|
3162
|
-
return { id: op.id, success: taskResult.success };
|
|
3163
|
-
}
|
|
3164
|
-
catch {
|
|
3165
|
-
progress.completeAgent(op.id, false);
|
|
3166
|
-
return { id: op.id, success: false };
|
|
3167
|
-
}
|
|
3168
|
-
}));
|
|
3169
|
-
progress.stop();
|
|
3170
|
-
// Summary
|
|
3171
|
-
const successful = results.filter(r => r.success).length;
|
|
3172
|
-
const failed = results.filter(r => !r.success).length;
|
|
3173
|
-
console.log(chalk.blue('\n Operation Summary:'));
|
|
3174
|
-
console.log(chalk.gray(` Operation: ${operation}`));
|
|
3175
|
-
console.log(chalk.gray(` Target: ${options.target}`));
|
|
3176
|
-
console.log(chalk.green(` Successful: ${successful}`));
|
|
3177
|
-
if (failed > 0) {
|
|
3178
|
-
console.log(chalk.red(` Failed: ${failed}`));
|
|
3179
|
-
}
|
|
3180
|
-
console.log('');
|
|
3181
|
-
await cleanupAndExit(failed > 0 ? 1 : 0);
|
|
3182
|
-
}
|
|
3183
|
-
catch (error) {
|
|
3184
|
-
console.error(chalk.red('\n Fleet operation failed:'), error);
|
|
3185
|
-
await cleanupAndExit(1);
|
|
3186
|
-
}
|
|
3187
|
-
});
|
|
3188
|
-
fleetCmd
|
|
3189
|
-
.command('status')
|
|
3190
|
-
.description('Show fleet status with agent progress')
|
|
3191
|
-
.option('-w, --watch', 'Watch mode with live updates')
|
|
3192
|
-
.action(async (options) => {
|
|
3193
|
-
if (!await ensureInitialized())
|
|
3194
|
-
return;
|
|
3195
|
-
try {
|
|
3196
|
-
const showStatus = async () => {
|
|
3197
|
-
const health = context.queen.getHealth();
|
|
3198
|
-
const metrics = context.queen.getMetrics();
|
|
3199
|
-
console.log(chalk.blue('\n Fleet Status\n'));
|
|
3200
|
-
// Overall fleet bar
|
|
3201
|
-
const utilizationBar = '\u2588'.repeat(Math.min(Math.round(metrics.agentUtilization * 20), 20)) +
|
|
3202
|
-
'\u2591'.repeat(Math.max(20 - Math.round(metrics.agentUtilization * 20), 0));
|
|
3203
|
-
console.log(chalk.white(`Fleet Utilization ${chalk.cyan(utilizationBar)} ${(metrics.agentUtilization * 100).toFixed(0)}%`));
|
|
3204
|
-
console.log('');
|
|
3205
|
-
// Agent status by domain
|
|
3206
|
-
console.log(chalk.white('Agent Progress:'));
|
|
3207
|
-
for (const [domain, domainHealth] of health.domainHealth) {
|
|
3208
|
-
const active = domainHealth.agents.active;
|
|
3209
|
-
const total = domainHealth.agents.total;
|
|
3210
|
-
const progressPercent = total > 0 ? Math.round((active / total) * 100) : 0;
|
|
3211
|
-
const statusIcon = domainHealth.status === 'healthy' ? chalk.green('\u2713') :
|
|
3212
|
-
domainHealth.status === 'degraded' ? chalk.yellow('\u25B6') :
|
|
3213
|
-
chalk.red('\u2717');
|
|
3214
|
-
const bar = '\u2588'.repeat(Math.round(progressPercent / 5)) +
|
|
3215
|
-
'\u2591'.repeat(20 - Math.round(progressPercent / 5));
|
|
3216
|
-
console.log(` ${domain.padEnd(28)} ${chalk.cyan(bar)} ${progressPercent.toString().padStart(3)}% ${statusIcon}`);
|
|
3217
|
-
}
|
|
3218
|
-
console.log('');
|
|
3219
|
-
console.log(chalk.gray(` Active: ${health.activeAgents}/${health.totalAgents} agents`));
|
|
3220
|
-
console.log(chalk.gray(` Tasks: ${health.runningTasks} running, ${health.pendingTasks} pending`));
|
|
3221
|
-
console.log('');
|
|
3222
|
-
};
|
|
3223
|
-
if (options.watch) {
|
|
3224
|
-
const spinner = createTimedSpinner('Watching fleet status (Ctrl+C to exit)');
|
|
3225
|
-
// Initial display
|
|
3226
|
-
spinner.spinner.stop();
|
|
3227
|
-
await showStatus();
|
|
3228
|
-
// Watch mode - update every 2 seconds
|
|
3229
|
-
const interval = setInterval(async () => {
|
|
3230
|
-
console.clear();
|
|
3231
|
-
await showStatus();
|
|
3232
|
-
}, 2000);
|
|
3233
|
-
// Handle Ctrl+C - use once to avoid conflict with global handler
|
|
3234
|
-
process.once('SIGINT', async () => {
|
|
3235
|
-
clearInterval(interval);
|
|
3236
|
-
console.log(chalk.yellow('\nStopped watching.'));
|
|
3237
|
-
await cleanupAndExit(0);
|
|
3238
|
-
});
|
|
3239
|
-
}
|
|
3240
|
-
else {
|
|
3241
|
-
await showStatus();
|
|
3242
|
-
await cleanupAndExit(0);
|
|
3243
|
-
}
|
|
3244
|
-
}
|
|
3245
|
-
catch (error) {
|
|
3246
|
-
console.error(chalk.red('\n Failed to get fleet status:'), error);
|
|
3247
|
-
await cleanupAndExit(1);
|
|
3248
|
-
}
|
|
3249
|
-
});
|
|
3250
|
-
// ============================================================================
|
|
3251
|
-
// Hooks Command (AQE v3 Independent Hooks - using QEHookRegistry)
|
|
623
|
+
// External Command Modules
|
|
3252
624
|
// ============================================================================
|
|
625
|
+
import { createTokenUsageCommand } from './commands/token-usage.js';
|
|
626
|
+
import { createLLMRouterCommand } from './commands/llm-router.js';
|
|
627
|
+
import { createSyncCommands } from './commands/sync.js';
|
|
3253
628
|
import { createHooksCommand } from './commands/hooks.js';
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
program.addCommand(
|
|
3257
|
-
|
|
3258
|
-
// - QEHookRegistry for event handling
|
|
3259
|
-
// - QEReasoningBank for pattern learning
|
|
3260
|
-
// - setupQEHooks() for proper initialization
|
|
629
|
+
program.addCommand(createTokenUsageCommand());
|
|
630
|
+
program.addCommand(createLLMRouterCommand());
|
|
631
|
+
program.addCommand(createSyncCommands());
|
|
632
|
+
program.addCommand(createHooksCommand());
|
|
3261
633
|
// ============================================================================
|
|
3262
634
|
// Shutdown Handlers
|
|
3263
635
|
// ============================================================================
|
|
@@ -3274,7 +646,6 @@ process.on('SIGTERM', async () => {
|
|
|
3274
646
|
// Main
|
|
3275
647
|
// ============================================================================
|
|
3276
648
|
async function main() {
|
|
3277
|
-
// ADR-042: Initialize token tracking and optimization
|
|
3278
649
|
await bootstrapTokenTracking({
|
|
3279
650
|
enableOptimization: true,
|
|
3280
651
|
enablePersistence: true,
|