@nathapp/nax 0.18.1
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/.gitlab-ci.yml +96 -0
- package/BRIEF.md +140 -0
- package/CHANGELOG.md +60 -0
- package/CLAUDE.md +159 -0
- package/README.md +373 -0
- package/US-007-IMPLEMENTATION.md +139 -0
- package/bin/nax.ts +930 -0
- package/biome.json +14 -0
- package/bun.lock +168 -0
- package/bunfig.toml +11 -0
- package/docs/20260216-fix-plan-context-review.md +56 -0
- package/docs/20260216-relentless-vs-ngent-comparison.md +208 -0
- package/docs/20260216-v02-plan.md +136 -0
- package/docs/20260216-v02-review.md +685 -0
- package/docs/20260217-dogfood-findings.md +56 -0
- package/docs/20260217-p2-plus-plan.md +117 -0
- package/docs/20260217-partial-fixes-plan.md +62 -0
- package/docs/20260217-plan-analyze-spec.md +117 -0
- package/docs/20260217-post-impl-review.md +1137 -0
- package/docs/20260217-quick-wins-plan.md +66 -0
- package/docs/20260217-split-runner-plan.md +75 -0
- package/docs/20260217-v03-impl-plan.md +80 -0
- package/docs/20260217-v03-post-impl-review.md +589 -0
- package/docs/20260217-v04-impl-plan.md +86 -0
- package/docs/20260217-v05-post-impl-review.md +850 -0
- package/docs/20260217-v06-post-impl-review.md +817 -0
- package/docs/20260218-adr003-port-plan.md +151 -0
- package/docs/20260218-review-adr003-verification.md +175 -0
- package/docs/20260219-fix-plan-bug16-19.md +79 -0
- package/docs/20260219-fix-plan-bug20-22.md +114 -0
- package/docs/20260219-plan-llm-routing.md +116 -0
- package/docs/20260219-review-bug20-22-fixes.md +135 -0
- package/docs/20260219-routing-baseline-keyword.md +63 -0
- package/docs/20260220-plan-structured-logging-p1.md +80 -0
- package/docs/20260220-plan-structured-logging-p2.md +37 -0
- package/docs/20260220-review-llm-routing.md +180 -0
- package/docs/20260220-review-post-fix-llm-routing.md +70 -0
- package/docs/20260221-fix-plan-relevantfiles-split.md +101 -0
- package/docs/20260221-fix-plan-routing-mode.md +125 -0
- package/docs/20260221-review-v0.9-implementation.md +379 -0
- package/docs/20260222-fix-plan-v091-routing-isolation.md +197 -0
- package/docs/20260223-fix-plan-prompt-audit.md +62 -0
- package/docs/20260224-nax-roadmap-phases.md +189 -0
- package/docs/20260225-phase2-llm-service-layer.md +401 -0
- package/docs/20260225-review-v0.10.1.md +187 -0
- package/docs/20260303-v010-implementation-plan.md +165 -0
- package/docs/CLAUDE.md.bak +191 -0
- package/docs/ROADMAP.md +165 -0
- package/docs/SPEC-rectification.md +0 -0
- package/docs/SPEC.md +324 -0
- package/docs/US-001-plugin-loading-verification.md +152 -0
- package/docs/architecture-analysis.md +1076 -0
- package/docs/bugs/BUG-21-escalation-null-attempts.md +48 -0
- package/docs/bugs-from-dogfood-run-c.md +243 -0
- package/docs/code-review-20260228.md +612 -0
- package/docs/code-review-v0.15.0.md +629 -0
- package/docs/hook-lifecycle-test-plan.md +149 -0
- package/docs/releases/v0.11.0-and-earlier.md +20 -0
- package/docs/releases/v0.12.0.md +15 -0
- package/docs/releases/v0.13.0.md +14 -0
- package/docs/releases/v0.14.0.md +20 -0
- package/docs/releases/v0.14.1.md +36 -0
- package/docs/releases/v0.14.2.md +51 -0
- package/docs/releases/v0.14.3.md +174 -0
- package/docs/releases/v0.14.4.md +94 -0
- package/docs/releases/v0.15.0.md +502 -0
- package/docs/releases/v0.15.1.md +170 -0
- package/docs/releases/v0.15.3.md +193 -0
- package/docs/specs/status-file-v0.10.1.md +812 -0
- package/docs/v0.10-global-config.md +206 -0
- package/docs/v0.10-plugin-system.md +415 -0
- package/docs/v0.10-prompt-optimizer.md +234 -0
- package/docs/v0.3-spec.md +244 -0
- package/docs/v0.4-spec.md +140 -0
- package/docs/v0.5-spec.md +237 -0
- package/docs/v0.6-spec.md +371 -0
- package/docs/v0.7-spec.md +177 -0
- package/docs/v0.8-llm-routing.md +206 -0
- package/docs/v0.8-structured-logging.md +132 -0
- package/docs/v0.9.3-prompt-audit.md +112 -0
- package/examples/plugins/console-reporter/index.test.ts +207 -0
- package/examples/plugins/console-reporter/index.ts +110 -0
- package/nax/config.json +147 -0
- package/nax/features/bugfix-v0171/prd.json +52 -0
- package/nax/features/config-management/prd.json +108 -0
- package/nax/features/config-management/progress.txt +5 -0
- package/nax/features/diagnose/acceptance.test.ts +412 -0
- package/nax/features/diagnose/prd.json +41 -0
- package/nax/features/orchestration-fixes/prd.json +89 -0
- package/nax/features/orchestration-fixes/progress.txt +1 -0
- package/nax/features/plugin-integration/US-007-VERIFICATION.md +259 -0
- package/nax/features/plugin-integration/prd.json +208 -0
- package/nax/features/plugin-integration/progress.txt +5 -0
- package/nax/features/precheck/prd.json +205 -0
- package/nax/features/precheck/progress.txt +15 -0
- package/nax/features/structured-logging/prd.json +199 -0
- package/nax/features/unlock/prd.json +36 -0
- package/package.json +47 -0
- package/src/acceptance/fix-generator.ts +348 -0
- package/src/acceptance/generator.ts +282 -0
- package/src/acceptance/index.ts +30 -0
- package/src/acceptance/types.ts +79 -0
- package/src/agents/claude-decompose.ts +169 -0
- package/src/agents/claude-plan.ts +139 -0
- package/src/agents/claude.ts +324 -0
- package/src/agents/cost.ts +268 -0
- package/src/agents/index.ts +13 -0
- package/src/agents/registry.ts +48 -0
- package/src/agents/types-extended.ts +133 -0
- package/src/agents/types.ts +113 -0
- package/src/agents/validation.ts +69 -0
- package/src/analyze/classifier.ts +305 -0
- package/src/analyze/index.ts +16 -0
- package/src/analyze/scanner.ts +175 -0
- package/src/analyze/types.ts +51 -0
- package/src/cli/accept.ts +108 -0
- package/src/cli/analyze-parser.ts +284 -0
- package/src/cli/analyze.ts +207 -0
- package/src/cli/config.ts +561 -0
- package/src/cli/constitution.ts +109 -0
- package/src/cli/diagnose-analysis.ts +159 -0
- package/src/cli/diagnose-formatter.ts +87 -0
- package/src/cli/diagnose.ts +203 -0
- package/src/cli/generate.ts +127 -0
- package/src/cli/index.ts +37 -0
- package/src/cli/init.ts +188 -0
- package/src/cli/interact.ts +295 -0
- package/src/cli/plan.ts +198 -0
- package/src/cli/plugins.ts +111 -0
- package/src/cli/prompts.ts +295 -0
- package/src/cli/runs.ts +174 -0
- package/src/cli/status-cost.ts +151 -0
- package/src/cli/status-features.ts +338 -0
- package/src/cli/status.ts +13 -0
- package/src/commands/common.ts +171 -0
- package/src/commands/diagnose.ts +17 -0
- package/src/commands/index.ts +8 -0
- package/src/commands/logs.ts +384 -0
- package/src/commands/precheck.ts +86 -0
- package/src/commands/unlock.ts +96 -0
- package/src/config/defaults.ts +160 -0
- package/src/config/index.ts +22 -0
- package/src/config/loader.ts +121 -0
- package/src/config/merger.ts +147 -0
- package/src/config/path-security.ts +121 -0
- package/src/config/paths.ts +27 -0
- package/src/config/schema.ts +56 -0
- package/src/config/schemas.ts +286 -0
- package/src/config/types.ts +423 -0
- package/src/config/validate.ts +103 -0
- package/src/constitution/generator.ts +191 -0
- package/src/constitution/generators/aider.ts +41 -0
- package/src/constitution/generators/claude.ts +35 -0
- package/src/constitution/generators/cursor.ts +36 -0
- package/src/constitution/generators/opencode.ts +38 -0
- package/src/constitution/generators/types.ts +33 -0
- package/src/constitution/generators/windsurf.ts +36 -0
- package/src/constitution/index.ts +10 -0
- package/src/constitution/loader.ts +133 -0
- package/src/constitution/types.ts +31 -0
- package/src/context/auto-detect.ts +227 -0
- package/src/context/builder.ts +246 -0
- package/src/context/elements.ts +83 -0
- package/src/context/formatter.ts +107 -0
- package/src/context/generator.ts +129 -0
- package/src/context/generators/aider.ts +34 -0
- package/src/context/generators/claude.ts +28 -0
- package/src/context/generators/cursor.ts +28 -0
- package/src/context/generators/opencode.ts +30 -0
- package/src/context/generators/windsurf.ts +28 -0
- package/src/context/greenfield.ts +114 -0
- package/src/context/index.ts +33 -0
- package/src/context/injector.ts +279 -0
- package/src/context/test-scanner.ts +370 -0
- package/src/context/types.ts +98 -0
- package/src/errors.ts +67 -0
- package/src/execution/batching.ts +157 -0
- package/src/execution/crash-recovery.ts +373 -0
- package/src/execution/escalation/escalation.ts +44 -0
- package/src/execution/escalation/index.ts +13 -0
- package/src/execution/escalation/tier-escalation.ts +295 -0
- package/src/execution/escalation/tier-outcome.ts +158 -0
- package/src/execution/helpers.ts +38 -0
- package/src/execution/index.ts +45 -0
- package/src/execution/lifecycle/acceptance-loop.ts +272 -0
- package/src/execution/lifecycle/headless-formatter.ts +85 -0
- package/src/execution/lifecycle/index.ts +12 -0
- package/src/execution/lifecycle/parallel-lifecycle.ts +101 -0
- package/src/execution/lifecycle/precheck-runner.ts +140 -0
- package/src/execution/lifecycle/run-cleanup.ts +81 -0
- package/src/execution/lifecycle/run-completion.ts +129 -0
- package/src/execution/lifecycle/run-initialization.ts +141 -0
- package/src/execution/lifecycle/run-lifecycle.ts +312 -0
- package/src/execution/lifecycle/run-setup.ts +204 -0
- package/src/execution/lifecycle/story-hooks.ts +38 -0
- package/src/execution/lifecycle/story-size-prompts.ts +123 -0
- package/src/execution/lock.ts +115 -0
- package/src/execution/parallel-executor.ts +216 -0
- package/src/execution/parallel.ts +400 -0
- package/src/execution/pid-registry.ts +280 -0
- package/src/execution/pipeline-result-handler.ts +388 -0
- package/src/execution/post-verify-rectification.ts +188 -0
- package/src/execution/post-verify.ts +274 -0
- package/src/execution/progress.ts +25 -0
- package/src/execution/prompts.ts +127 -0
- package/src/execution/queue-handler.ts +109 -0
- package/src/execution/rectification.ts +13 -0
- package/src/execution/runner.ts +377 -0
- package/src/execution/sequential-executor.ts +388 -0
- package/src/execution/status-file.ts +264 -0
- package/src/execution/status-writer.ts +139 -0
- package/src/execution/story-context.ts +229 -0
- package/src/execution/test-output-parser.ts +14 -0
- package/src/execution/verification.ts +72 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/runner.ts +286 -0
- package/src/hooks/types.ts +67 -0
- package/src/interaction/chain.ts +154 -0
- package/src/interaction/index.ts +60 -0
- package/src/interaction/init.ts +83 -0
- package/src/interaction/plugins/auto.ts +217 -0
- package/src/interaction/plugins/cli.ts +300 -0
- package/src/interaction/plugins/telegram.ts +384 -0
- package/src/interaction/plugins/webhook.ts +258 -0
- package/src/interaction/state.ts +171 -0
- package/src/interaction/triggers.ts +229 -0
- package/src/interaction/types.ts +163 -0
- package/src/logger/formatters.ts +84 -0
- package/src/logger/index.ts +16 -0
- package/src/logger/logger.ts +298 -0
- package/src/logger/types.ts +48 -0
- package/src/logging/formatter.ts +355 -0
- package/src/logging/index.ts +22 -0
- package/src/logging/types.ts +93 -0
- package/src/metrics/aggregator.ts +190 -0
- package/src/metrics/index.ts +14 -0
- package/src/metrics/tracker.ts +200 -0
- package/src/metrics/types.ts +109 -0
- package/src/optimizer/index.ts +62 -0
- package/src/optimizer/noop.optimizer.ts +24 -0
- package/src/optimizer/rule-based.optimizer.ts +248 -0
- package/src/optimizer/types.ts +53 -0
- package/src/pipeline/events.ts +130 -0
- package/src/pipeline/index.ts +19 -0
- package/src/pipeline/runner.ts +161 -0
- package/src/pipeline/stages/acceptance.ts +197 -0
- package/src/pipeline/stages/completion.ts +99 -0
- package/src/pipeline/stages/constitution.ts +63 -0
- package/src/pipeline/stages/context.ts +117 -0
- package/src/pipeline/stages/execution.ts +194 -0
- package/src/pipeline/stages/index.ts +62 -0
- package/src/pipeline/stages/optimizer.ts +74 -0
- package/src/pipeline/stages/prompt.ts +57 -0
- package/src/pipeline/stages/queue-check.ts +103 -0
- package/src/pipeline/stages/review.ts +181 -0
- package/src/pipeline/stages/routing.ts +81 -0
- package/src/pipeline/stages/verify.ts +100 -0
- package/src/pipeline/types.ts +167 -0
- package/src/plugins/index.ts +31 -0
- package/src/plugins/loader.ts +287 -0
- package/src/plugins/registry.ts +168 -0
- package/src/plugins/types.ts +327 -0
- package/src/plugins/validator.ts +352 -0
- package/src/prd/index.ts +172 -0
- package/src/prd/types.ts +202 -0
- package/src/precheck/checks-blockers.ts +391 -0
- package/src/precheck/checks-warnings.ts +142 -0
- package/src/precheck/checks.ts +30 -0
- package/src/precheck/index.ts +247 -0
- package/src/precheck/story-size-gate.ts +144 -0
- package/src/precheck/types.ts +31 -0
- package/src/queue/index.ts +2 -0
- package/src/queue/manager.ts +254 -0
- package/src/queue/types.ts +54 -0
- package/src/review/index.ts +8 -0
- package/src/review/runner.ts +172 -0
- package/src/review/types.ts +66 -0
- package/src/routing/builder.ts +81 -0
- package/src/routing/chain.ts +74 -0
- package/src/routing/index.ts +16 -0
- package/src/routing/loader.ts +58 -0
- package/src/routing/router.ts +303 -0
- package/src/routing/strategies/adaptive.ts +215 -0
- package/src/routing/strategies/index.ts +8 -0
- package/src/routing/strategies/keyword.ts +163 -0
- package/src/routing/strategies/llm-prompts.ts +209 -0
- package/src/routing/strategies/llm.ts +235 -0
- package/src/routing/strategies/manual.ts +50 -0
- package/src/routing/strategy.ts +99 -0
- package/src/tdd/cleanup.ts +111 -0
- package/src/tdd/index.ts +23 -0
- package/src/tdd/isolation.ts +123 -0
- package/src/tdd/orchestrator.ts +383 -0
- package/src/tdd/prompts.ts +270 -0
- package/src/tdd/rectification-gate.ts +183 -0
- package/src/tdd/session-runner.ts +179 -0
- package/src/tdd/types.ts +81 -0
- package/src/tdd/verdict.ts +271 -0
- package/src/tui/App.tsx +265 -0
- package/src/tui/components/AgentPanel.tsx +75 -0
- package/src/tui/components/CostOverlay.tsx +118 -0
- package/src/tui/components/HelpOverlay.tsx +107 -0
- package/src/tui/components/StatusBar.tsx +63 -0
- package/src/tui/components/StoriesPanel.tsx +177 -0
- package/src/tui/hooks/useKeyboard.ts +142 -0
- package/src/tui/hooks/useLayout.ts +137 -0
- package/src/tui/hooks/usePipelineEvents.ts +183 -0
- package/src/tui/hooks/usePty.ts +194 -0
- package/src/tui/index.tsx +38 -0
- package/src/tui/types.ts +76 -0
- package/src/utils/git.ts +83 -0
- package/src/utils/queue-writer.ts +54 -0
- package/src/verification/executor.ts +235 -0
- package/src/verification/gate.ts +207 -0
- package/src/verification/index.ts +12 -0
- package/src/verification/parser.ts +230 -0
- package/src/verification/rectification.ts +108 -0
- package/src/verification/types.ts +113 -0
- package/src/worktree/dispatcher.ts +65 -0
- package/src/worktree/index.ts +2 -0
- package/src/worktree/manager.ts +187 -0
- package/src/worktree/merge.ts +301 -0
- package/src/worktree/types.ts +4 -0
- package/test/TEST_COVERAGE_US001.md +217 -0
- package/test/TEST_COVERAGE_US003.md +84 -0
- package/test/TEST_COVERAGE_US005.md +86 -0
- package/test/US-002-orchestrator.test.ts +246 -0
- package/test/acceptance/cm-003-default-view.test.ts +194 -0
- package/test/execution/pid-registry.test.ts +240 -0
- package/test/execution/post-verify.test.ts +224 -0
- package/test/helpers/timeout.ts +42 -0
- package/test/integration/US-002-TEST-SUMMARY.md +107 -0
- package/test/integration/US-003-TEST-SUMMARY.md +149 -0
- package/test/integration/US-004-TEST-SUMMARY.md +106 -0
- package/test/integration/US-005-TEST-SUMMARY.md +138 -0
- package/test/integration/US-007-TEST-SUMMARY.md +100 -0
- package/test/integration/agent-validation.test.ts +439 -0
- package/test/integration/analyze-integration.test.ts +261 -0
- package/test/integration/analyze-scanner.test.ts +131 -0
- package/test/integration/cli-config-default-edge-cases.test.ts +222 -0
- package/test/integration/cli-config-default-view.test.ts +229 -0
- package/test/integration/cli-config-diff.test.ts +460 -0
- package/test/integration/cli-config.test.ts +736 -0
- package/test/integration/cli-diagnose.test.ts +592 -0
- package/test/integration/cli-logs.test.ts +314 -0
- package/test/integration/cli-plugins.test.ts +678 -0
- package/test/integration/cli-precheck.test.ts +371 -0
- package/test/integration/cli-run-headless.test.ts +173 -0
- package/test/integration/cli.test.ts +75 -0
- package/test/integration/config/merger.test.ts +465 -0
- package/test/integration/config/paths.test.ts +51 -0
- package/test/integration/config-loader.test.ts +265 -0
- package/test/integration/config.test.ts +444 -0
- package/test/integration/context-integration.test.ts +702 -0
- package/test/integration/context-provider-injection.test.ts +506 -0
- package/test/integration/context-verification-integration.test.ts +295 -0
- package/test/integration/e2e.test.ts +896 -0
- package/test/integration/execution.test.ts +625 -0
- package/test/integration/helpers.test.ts +295 -0
- package/test/integration/hooks.test.ts +361 -0
- package/test/integration/interaction-chain-pipeline.test.ts +464 -0
- package/test/integration/isolation.test.ts +143 -0
- package/test/integration/logger.test.ts +461 -0
- package/test/integration/parallel.test.ts +250 -0
- package/test/integration/path-security.test.ts +173 -0
- package/test/integration/pipeline-acceptance.test.ts +302 -0
- package/test/integration/pipeline-events.test.ts +475 -0
- package/test/integration/pipeline.test.ts +658 -0
- package/test/integration/plan.test.ts +157 -0
- package/test/integration/plugin-routing.test.ts +921 -0
- package/test/integration/plugins/config-integration.test.ts +172 -0
- package/test/integration/plugins/config-resolution.test.ts +522 -0
- package/test/integration/plugins/loader.test.ts +641 -0
- package/test/integration/plugins/registry.test.ts +746 -0
- package/test/integration/plugins/validator.test.ts +563 -0
- package/test/integration/prd-pause.test.ts +205 -0
- package/test/integration/prd-resolvers.test.ts +185 -0
- package/test/integration/precheck-integration.test.ts +468 -0
- package/test/integration/precheck.test.ts +805 -0
- package/test/integration/progress.test.ts +34 -0
- package/test/integration/rectification-flow.test.ts +512 -0
- package/test/integration/reporter-lifecycle.test.ts +860 -0
- package/test/integration/review-config-commands.test.ts +319 -0
- package/test/integration/review-config-schema.test.ts +116 -0
- package/test/integration/review-plugin-integration.test.ts +722 -0
- package/test/integration/review.test.ts +149 -0
- package/test/integration/routing-stage-bug-021.test.ts +274 -0
- package/test/integration/routing-stage-greenfield.test.ts +286 -0
- package/test/integration/runner-config-plugins.test.ts +461 -0
- package/test/integration/runner-fixes.test.ts +399 -0
- package/test/integration/runner-plugin-integration.test.ts +543 -0
- package/test/integration/runner.test.ts +1679 -0
- package/test/integration/s5-greenfield-fallback.test.ts +297 -0
- package/test/integration/status-file-integration.test.ts +325 -0
- package/test/integration/status-file.test.ts +379 -0
- package/test/integration/status-writer.test.ts +345 -0
- package/test/integration/story-id-in-events.test.ts +273 -0
- package/test/integration/tdd-cleanup.test.ts +246 -0
- package/test/integration/tdd-orchestrator.test.ts +1762 -0
- package/test/integration/test-scanner.test.ts +403 -0
- package/test/integration/verification-asset-check.test.ts +142 -0
- package/test/integration/verify-stage.test.ts +275 -0
- package/test/integration/worktree/manager.test.ts +218 -0
- package/test/integration/worktree/merge.test.ts +341 -0
- package/test/manual/logging-formatter-demo.ts +158 -0
- package/test/ui/tui-agent-panel.test.tsx +99 -0
- package/test/ui/tui-controls.test.ts +334 -0
- package/test/ui/tui-cost-and-pty.test.ts +189 -0
- package/test/ui/tui-layout.test.ts +378 -0
- package/test/ui/tui-pty-integration.test.tsx +159 -0
- package/test/ui/tui-stories.test.ts +332 -0
- package/test/unit/acceptance.test.ts +186 -0
- package/test/unit/agent-stderr-capture.test.ts +146 -0
- package/test/unit/analyze-classifier.test.ts +215 -0
- package/test/unit/analyze.test.ts +224 -0
- package/test/unit/auto-detect.test.ts +249 -0
- package/test/unit/cli-status.test.ts +417 -0
- package/test/unit/commands/common.test.ts +320 -0
- package/test/unit/commands/logs.test.ts +416 -0
- package/test/unit/commands/unlock.test.ts +319 -0
- package/test/unit/constitution-generators.test.ts +160 -0
- package/test/unit/constitution.test.ts +209 -0
- package/test/unit/context.test.ts +1722 -0
- package/test/unit/cost.test.ts +231 -0
- package/test/unit/crash-recovery.test.ts +308 -0
- package/test/unit/escalation.test.ts +126 -0
- package/test/unit/execution-logging-stderr.test.ts +156 -0
- package/test/unit/execution-stage.test.ts +122 -0
- package/test/unit/fix-generator.test.ts +275 -0
- package/test/unit/formatters.test.ts +469 -0
- package/test/unit/greenfield.test.ts +179 -0
- package/test/unit/helpers.test.ts +317 -0
- package/test/unit/interaction/human-review-trigger.test.ts +164 -0
- package/test/unit/interaction-network-failures.test.ts +389 -0
- package/test/unit/interaction-plugins.test.ts +164 -0
- package/test/unit/isolation.test.ts +134 -0
- package/test/unit/logging/formatter.test.ts +455 -0
- package/test/unit/merge.test.ts +268 -0
- package/test/unit/metrics.test.ts +276 -0
- package/test/unit/optimizer/noop.optimizer.test.ts +125 -0
- package/test/unit/optimizer/rule-based.optimizer.test.ts +358 -0
- package/test/unit/prd-auto-default.test.ts +290 -0
- package/test/unit/prd-failure-category.test.ts +176 -0
- package/test/unit/prd-get-next-story.test.ts +186 -0
- package/test/unit/precheck-checks.test.ts +840 -0
- package/test/unit/precheck-story-size-gate.test.ts +287 -0
- package/test/unit/precheck-types.test.ts +142 -0
- package/test/unit/prompts.test.ts +475 -0
- package/test/unit/queue.test.ts +237 -0
- package/test/unit/rectification.test.ts +284 -0
- package/test/unit/registry.test.ts +287 -0
- package/test/unit/routing.test.ts +937 -0
- package/test/unit/run-lifecycle.test.ts +140 -0
- package/test/unit/storyid-events.test.ts +224 -0
- package/test/unit/tdd-verdict.test.ts +492 -0
- package/test/unit/test-output-parser.test.ts +377 -0
- package/test/unit/verdict.test.ts +324 -0
- package/test/unit/worktree-manager.test.ts +158 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for CLI precheck command
|
|
3
|
+
*
|
|
4
|
+
* Tests:
|
|
5
|
+
* - Command registration and flag parsing
|
|
6
|
+
* - Directory resolution via resolveProject()
|
|
7
|
+
* - Human and JSON output formats
|
|
8
|
+
* - Exit codes (0=pass, 1=blocker, 2=invalid PRD)
|
|
9
|
+
* - Error handling for missing feature/prd.json
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
13
|
+
import { mkdirSync, rmSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { precheckCommand } from "../../src/commands/precheck";
|
|
16
|
+
import type { PRD } from "../../src/prd/types";
|
|
17
|
+
import { EXIT_CODES } from "../../src/precheck";
|
|
18
|
+
|
|
19
|
+
const TEMP_DIR = join(import.meta.dir, "tmp-precheck-cli");
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Helper to create a test project structure
|
|
23
|
+
*/
|
|
24
|
+
function setupTestProject(name: string): {
|
|
25
|
+
projectDir: string;
|
|
26
|
+
naxDir: string;
|
|
27
|
+
featureDir: string;
|
|
28
|
+
prdPath: string;
|
|
29
|
+
} {
|
|
30
|
+
const projectDir = join(TEMP_DIR, name);
|
|
31
|
+
const naxDir = join(projectDir, "nax");
|
|
32
|
+
const featureDir = join(naxDir, "features", "test-feature");
|
|
33
|
+
const prdPath = join(featureDir, "prd.json");
|
|
34
|
+
|
|
35
|
+
mkdirSync(featureDir, { recursive: true });
|
|
36
|
+
|
|
37
|
+
// Write minimal config.json
|
|
38
|
+
Bun.write(
|
|
39
|
+
join(naxDir, "config.json"),
|
|
40
|
+
JSON.stringify(
|
|
41
|
+
{
|
|
42
|
+
feature: "test-feature",
|
|
43
|
+
routing: { enabled: true, tierLabels: { fast: 1, balanced: 2, powerful: 3 } },
|
|
44
|
+
quality: { test: { enabled: true, command: "echo test" } },
|
|
45
|
+
},
|
|
46
|
+
null,
|
|
47
|
+
2,
|
|
48
|
+
),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// Initialize git repo to satisfy checks
|
|
52
|
+
Bun.spawnSync(["git", "init", "-q"], { cwd: projectDir });
|
|
53
|
+
Bun.spawnSync(["git", "config", "user.name", "Test"], { cwd: projectDir });
|
|
54
|
+
Bun.spawnSync(["git", "config", "user.email", "test@example.com"], { cwd: projectDir });
|
|
55
|
+
|
|
56
|
+
// Create node_modules to satisfy dependencies check
|
|
57
|
+
mkdirSync(join(projectDir, "node_modules"), { recursive: true });
|
|
58
|
+
|
|
59
|
+
return { projectDir, naxDir, featureDir, prdPath };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Helper to create a valid PRD
|
|
64
|
+
*/
|
|
65
|
+
function createValidPRD(): PRD {
|
|
66
|
+
return {
|
|
67
|
+
version: "0.1.0",
|
|
68
|
+
project: "test-project",
|
|
69
|
+
feature: "test-feature",
|
|
70
|
+
branch: "feat/test-feature",
|
|
71
|
+
branchName: "feat/test-feature",
|
|
72
|
+
userStories: [
|
|
73
|
+
{
|
|
74
|
+
id: "US-001",
|
|
75
|
+
title: "Test Story",
|
|
76
|
+
description: "Test description",
|
|
77
|
+
acceptanceCriteria: [{ id: "AC-1", criterion: "Test criterion", testStrategy: "integration" }],
|
|
78
|
+
tags: [],
|
|
79
|
+
routing: {
|
|
80
|
+
tier: "fast",
|
|
81
|
+
complexity: "simple",
|
|
82
|
+
estimatedCost: 0.01,
|
|
83
|
+
security: false,
|
|
84
|
+
thinkingBudget: 1000,
|
|
85
|
+
},
|
|
86
|
+
dependencies: [],
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
totalStories: 1,
|
|
90
|
+
completedStories: 0,
|
|
91
|
+
progress: 0,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
describe("CLI precheck command", () => {
|
|
96
|
+
beforeEach(() => {
|
|
97
|
+
rmSync(TEMP_DIR, { recursive: true, force: true });
|
|
98
|
+
mkdirSync(TEMP_DIR, { recursive: true });
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
afterEach(() => {
|
|
102
|
+
rmSync(TEMP_DIR, { recursive: true, force: true });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("should resolve project directory with -d flag", async () => {
|
|
106
|
+
const { projectDir, prdPath } = setupTestProject("test-d-flag");
|
|
107
|
+
|
|
108
|
+
// Write valid PRD
|
|
109
|
+
await Bun.write(prdPath, JSON.stringify(createValidPRD()));
|
|
110
|
+
|
|
111
|
+
// Commit everything to satisfy working-tree-clean check
|
|
112
|
+
Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
|
|
113
|
+
Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
|
|
114
|
+
|
|
115
|
+
// Mock process.exit to capture exit code
|
|
116
|
+
let exitCode: number | undefined;
|
|
117
|
+
const originalExit = process.exit;
|
|
118
|
+
process.exit = ((code?: number) => {
|
|
119
|
+
exitCode = code;
|
|
120
|
+
// Don't actually exit in tests
|
|
121
|
+
}) as never;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
await precheckCommand({
|
|
125
|
+
feature: "test-feature",
|
|
126
|
+
dir: projectDir,
|
|
127
|
+
json: false,
|
|
128
|
+
});
|
|
129
|
+
} catch (err) {
|
|
130
|
+
// Expected - command calls process.exit
|
|
131
|
+
} finally {
|
|
132
|
+
process.exit = originalExit;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Should exit with code 0 (success) or 1 (warning)
|
|
136
|
+
expect(exitCode).toBeDefined();
|
|
137
|
+
expect([EXIT_CODES.SUCCESS, EXIT_CODES.BLOCKER]).toContain(exitCode);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("should accept -f flag for feature name", async () => {
|
|
141
|
+
const { projectDir, prdPath } = setupTestProject("test-f-flag");
|
|
142
|
+
|
|
143
|
+
// Write valid PRD
|
|
144
|
+
await Bun.write(prdPath, JSON.stringify(createValidPRD()));
|
|
145
|
+
|
|
146
|
+
// Commit to satisfy checks
|
|
147
|
+
Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
|
|
148
|
+
Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
|
|
149
|
+
|
|
150
|
+
let exitCode: number | undefined;
|
|
151
|
+
const originalExit = process.exit;
|
|
152
|
+
process.exit = ((code?: number) => {
|
|
153
|
+
exitCode = code;
|
|
154
|
+
}) as never;
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
await precheckCommand({
|
|
158
|
+
feature: "test-feature",
|
|
159
|
+
dir: projectDir,
|
|
160
|
+
json: false,
|
|
161
|
+
});
|
|
162
|
+
} catch (err) {
|
|
163
|
+
// Expected
|
|
164
|
+
} finally {
|
|
165
|
+
process.exit = originalExit;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
expect(exitCode).toBeDefined();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("should output JSON format with --json flag", async () => {
|
|
172
|
+
const { projectDir, prdPath } = setupTestProject("test-json-flag");
|
|
173
|
+
|
|
174
|
+
// Write valid PRD
|
|
175
|
+
await Bun.write(prdPath, JSON.stringify(createValidPRD()));
|
|
176
|
+
|
|
177
|
+
// Commit to satisfy checks
|
|
178
|
+
Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
|
|
179
|
+
Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
|
|
180
|
+
|
|
181
|
+
// Capture console.log output
|
|
182
|
+
const logs: string[] = [];
|
|
183
|
+
const originalLog = console.log;
|
|
184
|
+
console.log = (msg: string) => {
|
|
185
|
+
logs.push(msg);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
let exitCode: number | undefined;
|
|
189
|
+
const originalExit = process.exit;
|
|
190
|
+
process.exit = ((code?: number) => {
|
|
191
|
+
exitCode = code;
|
|
192
|
+
}) as never;
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
await precheckCommand({
|
|
196
|
+
feature: "test-feature",
|
|
197
|
+
dir: projectDir,
|
|
198
|
+
json: true,
|
|
199
|
+
});
|
|
200
|
+
} catch (err) {
|
|
201
|
+
// Expected
|
|
202
|
+
} finally {
|
|
203
|
+
console.log = originalLog;
|
|
204
|
+
process.exit = originalExit;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Should have JSON output
|
|
208
|
+
expect(logs.length).toBeGreaterThan(0);
|
|
209
|
+
|
|
210
|
+
// Try to parse first log as JSON
|
|
211
|
+
const jsonOutput = JSON.parse(logs[0]);
|
|
212
|
+
expect(jsonOutput).toHaveProperty("passed");
|
|
213
|
+
expect(jsonOutput).toHaveProperty("blockers");
|
|
214
|
+
expect(jsonOutput).toHaveProperty("warnings");
|
|
215
|
+
expect(jsonOutput).toHaveProperty("summary");
|
|
216
|
+
expect(jsonOutput).toHaveProperty("feature");
|
|
217
|
+
expect(jsonOutput.feature).toBe("test-feature");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("should exit with code 2 for invalid PRD", async () => {
|
|
221
|
+
const { projectDir, prdPath } = setupTestProject("test-invalid-prd");
|
|
222
|
+
|
|
223
|
+
// Write PRD that will pass loading but fail validation
|
|
224
|
+
await Bun.write(
|
|
225
|
+
prdPath,
|
|
226
|
+
JSON.stringify({
|
|
227
|
+
version: "0.1.0",
|
|
228
|
+
// Missing required fields: project, feature, branchName
|
|
229
|
+
userStories: [],
|
|
230
|
+
totalStories: 0,
|
|
231
|
+
completedStories: 0,
|
|
232
|
+
progress: 0,
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// Commit to satisfy git checks
|
|
237
|
+
Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
|
|
238
|
+
Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
|
|
239
|
+
|
|
240
|
+
let exitCode: number | undefined;
|
|
241
|
+
const originalExit = process.exit;
|
|
242
|
+
const originalError = console.error;
|
|
243
|
+
const originalLog = console.log;
|
|
244
|
+
console.error = () => {}; // Suppress error output
|
|
245
|
+
console.log = () => {}; // Suppress check output
|
|
246
|
+
|
|
247
|
+
process.exit = ((code?: number) => {
|
|
248
|
+
exitCode = code;
|
|
249
|
+
}) as never;
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
await precheckCommand({
|
|
253
|
+
feature: "test-feature",
|
|
254
|
+
dir: projectDir,
|
|
255
|
+
json: false,
|
|
256
|
+
});
|
|
257
|
+
} catch (err) {
|
|
258
|
+
// Expected
|
|
259
|
+
} finally {
|
|
260
|
+
process.exit = originalExit;
|
|
261
|
+
console.error = originalError;
|
|
262
|
+
console.log = originalLog;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
expect(exitCode).toBe(EXIT_CODES.INVALID_PRD);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test("should exit with code 2 when prd.json is missing", async () => {
|
|
269
|
+
const { projectDir } = setupTestProject("test-missing-prd");
|
|
270
|
+
|
|
271
|
+
// Don't create prd.json
|
|
272
|
+
|
|
273
|
+
let exitCode: number | undefined;
|
|
274
|
+
const originalExit = process.exit;
|
|
275
|
+
const originalError = console.error;
|
|
276
|
+
console.error = () => {}; // Suppress error output
|
|
277
|
+
|
|
278
|
+
process.exit = ((code?: number) => {
|
|
279
|
+
exitCode = code;
|
|
280
|
+
}) as never;
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
await precheckCommand({
|
|
284
|
+
feature: "test-feature",
|
|
285
|
+
dir: projectDir,
|
|
286
|
+
json: false,
|
|
287
|
+
});
|
|
288
|
+
} catch (err) {
|
|
289
|
+
// Expected
|
|
290
|
+
} finally {
|
|
291
|
+
process.exit = originalExit;
|
|
292
|
+
console.error = originalError;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
expect(exitCode).toBe(EXIT_CODES.INVALID_PRD);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("should handle missing feature flag with error", async () => {
|
|
299
|
+
const { projectDir, naxDir } = setupTestProject("test-no-feature");
|
|
300
|
+
|
|
301
|
+
// Remove feature from config
|
|
302
|
+
await Bun.write(
|
|
303
|
+
join(naxDir, "config.json"),
|
|
304
|
+
JSON.stringify(
|
|
305
|
+
{
|
|
306
|
+
routing: { enabled: true },
|
|
307
|
+
quality: { test: { enabled: true } },
|
|
308
|
+
},
|
|
309
|
+
null,
|
|
310
|
+
2,
|
|
311
|
+
),
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
let exitCode: number | undefined;
|
|
315
|
+
const originalExit = process.exit;
|
|
316
|
+
const originalError = console.error;
|
|
317
|
+
console.error = () => {}; // Suppress error output
|
|
318
|
+
|
|
319
|
+
process.exit = ((code?: number) => {
|
|
320
|
+
exitCode = code;
|
|
321
|
+
}) as never;
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
await precheckCommand({
|
|
325
|
+
dir: projectDir,
|
|
326
|
+
json: false,
|
|
327
|
+
});
|
|
328
|
+
} catch (err) {
|
|
329
|
+
// Expected
|
|
330
|
+
} finally {
|
|
331
|
+
process.exit = originalExit;
|
|
332
|
+
console.error = originalError;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
expect(exitCode).toBe(1);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("should use resolveProject() for directory resolution", async () => {
|
|
339
|
+
const { projectDir, prdPath } = setupTestProject("test-resolve-project");
|
|
340
|
+
|
|
341
|
+
// Write valid PRD
|
|
342
|
+
await Bun.write(prdPath, JSON.stringify(createValidPRD()));
|
|
343
|
+
|
|
344
|
+
// Commit to satisfy checks
|
|
345
|
+
Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
|
|
346
|
+
Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
|
|
347
|
+
|
|
348
|
+
let exitCode: number | undefined;
|
|
349
|
+
const originalExit = process.exit;
|
|
350
|
+
process.exit = ((code?: number) => {
|
|
351
|
+
exitCode = code;
|
|
352
|
+
}) as never;
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
// Should resolve project from explicit -d flag
|
|
356
|
+
await precheckCommand({
|
|
357
|
+
feature: "test-feature",
|
|
358
|
+
dir: projectDir,
|
|
359
|
+
json: false,
|
|
360
|
+
});
|
|
361
|
+
} catch (err) {
|
|
362
|
+
// Expected
|
|
363
|
+
} finally {
|
|
364
|
+
process.exit = originalExit;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Should succeed (or have blockers, but not fail to resolve)
|
|
368
|
+
expect(exitCode).toBeDefined();
|
|
369
|
+
expect(exitCode).not.toBe(undefined);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for headless mode with formatter
|
|
3
|
+
*
|
|
4
|
+
* Verifies that `nax run` uses formatted output in headless mode
|
|
5
|
+
* instead of raw JSONL, while still writing JSONL to disk.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
9
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { initLogger, resetLogger } from "../../src/logger";
|
|
12
|
+
|
|
13
|
+
describe("Headless mode formatter integration", () => {
|
|
14
|
+
const testDir = join(import.meta.dir, "..", "tmp", "headless-test");
|
|
15
|
+
const logFile = join(testDir, "test.jsonl");
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
// Clean up any existing logger
|
|
19
|
+
resetLogger();
|
|
20
|
+
|
|
21
|
+
// Create test directory
|
|
22
|
+
mkdirSync(testDir, { recursive: true });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
resetLogger();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("logger uses formatter in headless mode with normal verbosity", async () => {
|
|
30
|
+
// Initialize logger in headless mode with normal verbosity
|
|
31
|
+
const logger = initLogger({
|
|
32
|
+
level: "info",
|
|
33
|
+
filePath: logFile,
|
|
34
|
+
useChalk: false, // Disable colors for test output
|
|
35
|
+
formatterMode: "normal",
|
|
36
|
+
headless: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Capture console output
|
|
40
|
+
const originalLog = console.log;
|
|
41
|
+
const outputs: string[] = [];
|
|
42
|
+
console.log = (msg: string) => {
|
|
43
|
+
outputs.push(msg);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
// Log a test message
|
|
48
|
+
logger.info("test.stage", "Test message", { foo: "bar" });
|
|
49
|
+
|
|
50
|
+
// Verify console output uses formatter (not raw JSONL)
|
|
51
|
+
expect(outputs.length).toBeGreaterThan(0);
|
|
52
|
+
const output = outputs[0];
|
|
53
|
+
|
|
54
|
+
// Should NOT be raw JSON
|
|
55
|
+
expect(output.startsWith("{")).toBe(false);
|
|
56
|
+
|
|
57
|
+
// Should contain formatted elements
|
|
58
|
+
expect(output).toContain("test.stage");
|
|
59
|
+
expect(output).toContain("Test message");
|
|
60
|
+
} finally {
|
|
61
|
+
console.log = originalLog;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Verify JSONL file was written
|
|
65
|
+
expect(existsSync(logFile)).toBe(true);
|
|
66
|
+
const fileContent = await Bun.file(logFile).text();
|
|
67
|
+
expect(fileContent).toContain('"stage":"test.stage"');
|
|
68
|
+
expect(fileContent).toContain('"message":"Test message"');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("logger outputs raw JSONL in json mode", () => {
|
|
72
|
+
// Initialize logger in headless mode with json verbosity
|
|
73
|
+
const logger = initLogger({
|
|
74
|
+
level: "info",
|
|
75
|
+
filePath: logFile,
|
|
76
|
+
useChalk: false,
|
|
77
|
+
formatterMode: "json",
|
|
78
|
+
headless: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Capture console output
|
|
82
|
+
const originalLog = console.log;
|
|
83
|
+
const outputs: string[] = [];
|
|
84
|
+
console.log = (msg: string) => {
|
|
85
|
+
outputs.push(msg);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
// Log a test message
|
|
90
|
+
logger.info("test.stage", "Test message", { foo: "bar" });
|
|
91
|
+
|
|
92
|
+
// Verify console output is raw JSONL
|
|
93
|
+
expect(outputs.length).toBe(1);
|
|
94
|
+
const output = outputs[0];
|
|
95
|
+
|
|
96
|
+
// Should be valid JSON
|
|
97
|
+
const parsed = JSON.parse(output);
|
|
98
|
+
expect(parsed.stage).toBe("test.stage");
|
|
99
|
+
expect(parsed.message).toBe("Test message");
|
|
100
|
+
expect(parsed.data.foo).toBe("bar");
|
|
101
|
+
} finally {
|
|
102
|
+
console.log = originalLog;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("logger suppresses debug logs in quiet mode", () => {
|
|
107
|
+
// Initialize logger in quiet mode
|
|
108
|
+
const logger = initLogger({
|
|
109
|
+
level: "debug", // Log level allows everything through
|
|
110
|
+
filePath: logFile,
|
|
111
|
+
useChalk: false,
|
|
112
|
+
formatterMode: "quiet", // Formatter filters what's displayed
|
|
113
|
+
headless: true,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Capture console output
|
|
117
|
+
const originalLog = console.log;
|
|
118
|
+
const outputs: string[] = [];
|
|
119
|
+
console.log = (msg: string) => {
|
|
120
|
+
outputs.push(msg);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
// Log debug and info messages
|
|
125
|
+
logger.debug("test.stage", "Debug message");
|
|
126
|
+
logger.info("test.stage", "Info message");
|
|
127
|
+
|
|
128
|
+
// In quiet mode, info logs should be filtered out
|
|
129
|
+
// (unless they're critical events like run.start/run.end)
|
|
130
|
+
expect(outputs.length).toBe(0);
|
|
131
|
+
|
|
132
|
+
// But errors should still show (reset outputs first)
|
|
133
|
+
outputs.length = 0;
|
|
134
|
+
logger.error("test.stage", "Error message");
|
|
135
|
+
expect(outputs.length).toBe(1);
|
|
136
|
+
expect(outputs[0]).toContain("Error message");
|
|
137
|
+
} finally {
|
|
138
|
+
console.log = originalLog;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("logger uses default console formatter when not in headless mode", () => {
|
|
143
|
+
// Initialize logger WITHOUT headless mode
|
|
144
|
+
const logger = initLogger({
|
|
145
|
+
level: "info",
|
|
146
|
+
filePath: logFile,
|
|
147
|
+
useChalk: false,
|
|
148
|
+
headless: false, // Not headless
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Capture console output
|
|
152
|
+
const originalLog = console.log;
|
|
153
|
+
const outputs: string[] = [];
|
|
154
|
+
console.log = (msg: string) => {
|
|
155
|
+
outputs.push(msg);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
// Log a test message
|
|
160
|
+
logger.info("test.stage", "Test message", { foo: "bar" });
|
|
161
|
+
|
|
162
|
+
// Verify console output uses default console formatter (not formatter)
|
|
163
|
+
expect(outputs.length).toBeGreaterThan(0);
|
|
164
|
+
const output = outputs[0];
|
|
165
|
+
|
|
166
|
+
// Default console format includes [timestamp] [stage] message
|
|
167
|
+
expect(output).toContain("[test.stage]");
|
|
168
|
+
expect(output).toContain("Test message");
|
|
169
|
+
} finally {
|
|
170
|
+
console.log = originalLog;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI --parallel flag tests
|
|
3
|
+
*
|
|
4
|
+
* Validates that the --parallel flag is correctly parsed and passed to RunOptions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
8
|
+
import type { RunOptions } from "../../src/execution/runner";
|
|
9
|
+
|
|
10
|
+
describe("CLI --parallel flag parsing", () => {
|
|
11
|
+
test("parses --parallel 4 correctly", () => {
|
|
12
|
+
// Simulate parsing --parallel 4
|
|
13
|
+
const parallelArg = "4";
|
|
14
|
+
const parallel = Number.parseInt(parallelArg, 10);
|
|
15
|
+
|
|
16
|
+
expect(parallel).toBe(4);
|
|
17
|
+
expect(Number.isNaN(parallel)).toBe(false);
|
|
18
|
+
expect(parallel).toBeGreaterThanOrEqual(0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("parses --parallel 0 (auto-detect mode) correctly", () => {
|
|
22
|
+
const parallelArg = "0";
|
|
23
|
+
const parallel = Number.parseInt(parallelArg, 10);
|
|
24
|
+
|
|
25
|
+
expect(parallel).toBe(0);
|
|
26
|
+
expect(Number.isNaN(parallel)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("omitted --parallel defaults to undefined (sequential)", () => {
|
|
30
|
+
// When flag is not provided, parallel should be undefined
|
|
31
|
+
const parallel: number | undefined = undefined;
|
|
32
|
+
|
|
33
|
+
expect(parallel).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("rejects negative --parallel values", () => {
|
|
37
|
+
const parallelArg = "-1";
|
|
38
|
+
const parallel = Number.parseInt(parallelArg, 10);
|
|
39
|
+
|
|
40
|
+
expect(parallel).toBe(-1);
|
|
41
|
+
expect(parallel).toBeLessThan(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("rejects non-numeric --parallel values", () => {
|
|
45
|
+
const parallelArg = "abc";
|
|
46
|
+
const parallel = Number.parseInt(parallelArg, 10);
|
|
47
|
+
|
|
48
|
+
expect(Number.isNaN(parallel)).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("RunOptions accepts parallel field", () => {
|
|
52
|
+
// Type-check that RunOptions accepts parallel field
|
|
53
|
+
const options: Partial<RunOptions> = {
|
|
54
|
+
parallel: 4,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
expect(options.parallel).toBe(4);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("RunOptions accepts parallel=0 (auto-detect)", () => {
|
|
61
|
+
const options: Partial<RunOptions> = {
|
|
62
|
+
parallel: 0,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
expect(options.parallel).toBe(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("RunOptions accepts parallel=undefined (sequential)", () => {
|
|
69
|
+
const options: Partial<RunOptions> = {
|
|
70
|
+
parallel: undefined,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
expect(options.parallel).toBeUndefined();
|
|
74
|
+
});
|
|
75
|
+
});
|