@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,237 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { QueueManager, parseQueueFile } from "../../src/queue/manager";
|
|
3
|
+
|
|
4
|
+
describe("QueueManager", () => {
|
|
5
|
+
test("enqueue and dequeue in priority order (highest first)", () => {
|
|
6
|
+
const qm = new QueueManager();
|
|
7
|
+
qm.enqueue("US-001", "Low priority", 1);
|
|
8
|
+
qm.enqueue("US-002", "High priority", 10);
|
|
9
|
+
qm.enqueue("US-003", "Medium priority", 5);
|
|
10
|
+
|
|
11
|
+
const first = qm.dequeue();
|
|
12
|
+
expect(first?.storyId).toBe("US-002"); // highest priority
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("peek returns next without removing", () => {
|
|
16
|
+
const qm = new QueueManager();
|
|
17
|
+
qm.enqueue("US-001", "Task", 1);
|
|
18
|
+
|
|
19
|
+
expect(qm.peek()?.storyId).toBe("US-001");
|
|
20
|
+
expect(qm.peek()?.storyId).toBe("US-001"); // still there
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("markComplete changes status", () => {
|
|
24
|
+
const qm = new QueueManager();
|
|
25
|
+
qm.enqueue("US-001", "Task", 1);
|
|
26
|
+
qm.markComplete("US-001");
|
|
27
|
+
|
|
28
|
+
const item = qm.getItem("US-001");
|
|
29
|
+
expect(item?.status).toBe("completed");
|
|
30
|
+
expect(qm.hasPending()).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("markFailed stores error", () => {
|
|
34
|
+
const qm = new QueueManager();
|
|
35
|
+
qm.enqueue("US-001", "Task", 1);
|
|
36
|
+
qm.markFailed("US-001", "Agent crashed");
|
|
37
|
+
|
|
38
|
+
const item = qm.getItem("US-001");
|
|
39
|
+
expect(item?.status).toBe("failed");
|
|
40
|
+
expect(item?.error).toBe("Agent crashed");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("empty queue returns null", () => {
|
|
44
|
+
const qm = new QueueManager();
|
|
45
|
+
expect(qm.dequeue()).toBeNull();
|
|
46
|
+
expect(qm.peek()).toBeNull();
|
|
47
|
+
expect(qm.isEmpty()).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("getStats returns correct counts", () => {
|
|
51
|
+
const qm = new QueueManager();
|
|
52
|
+
qm.enqueue("US-001", "A", 1);
|
|
53
|
+
qm.enqueue("US-002", "B", 2);
|
|
54
|
+
qm.enqueue("US-003", "C", 3);
|
|
55
|
+
qm.markComplete("US-001");
|
|
56
|
+
qm.markFailed("US-002", "err");
|
|
57
|
+
|
|
58
|
+
const stats = qm.getStats();
|
|
59
|
+
expect(stats.total).toBe(3);
|
|
60
|
+
expect(stats.pending).toBe(1);
|
|
61
|
+
expect(stats.completed).toBe(1);
|
|
62
|
+
expect(stats.failed).toBe(1);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("throws on duplicate enqueue", () => {
|
|
66
|
+
const qm = new QueueManager();
|
|
67
|
+
qm.enqueue("US-001", "Task", 1);
|
|
68
|
+
expect(() => qm.enqueue("US-001", "Dupe", 2)).toThrow("already in queue");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("resetToPending allows retry", () => {
|
|
72
|
+
const qm = new QueueManager();
|
|
73
|
+
qm.enqueue("US-001", "Task", 1);
|
|
74
|
+
qm.markFailed("US-001", "err");
|
|
75
|
+
qm.resetToPending("US-001");
|
|
76
|
+
|
|
77
|
+
expect(qm.getItem("US-001")?.status).toBe("pending");
|
|
78
|
+
expect(qm.hasPending()).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("markSkipped sets status to skipped", () => {
|
|
82
|
+
const qm = new QueueManager();
|
|
83
|
+
qm.enqueue("US-001", "Task", 1);
|
|
84
|
+
qm.markSkipped("US-001");
|
|
85
|
+
|
|
86
|
+
const item = qm.getItem("US-001");
|
|
87
|
+
expect(item?.status).toBe("skipped");
|
|
88
|
+
expect(item?.error).toBe("Skipped by user command");
|
|
89
|
+
expect(item?.completedAt).toBeDefined();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("getStats tracks skipped count separately", () => {
|
|
93
|
+
const qm = new QueueManager();
|
|
94
|
+
qm.enqueue("US-001", "A", 1);
|
|
95
|
+
qm.enqueue("US-002", "B", 2);
|
|
96
|
+
qm.enqueue("US-003", "C", 3);
|
|
97
|
+
qm.enqueue("US-004", "D", 4);
|
|
98
|
+
qm.markComplete("US-001");
|
|
99
|
+
qm.markFailed("US-002", "err");
|
|
100
|
+
qm.markSkipped("US-003");
|
|
101
|
+
|
|
102
|
+
const stats = qm.getStats();
|
|
103
|
+
expect(stats.total).toBe(4);
|
|
104
|
+
expect(stats.pending).toBe(1);
|
|
105
|
+
expect(stats.completed).toBe(1);
|
|
106
|
+
expect(stats.failed).toBe(1);
|
|
107
|
+
expect(stats.skipped).toBe(1);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("parseQueueFile", () => {
|
|
112
|
+
test("parses PAUSE command (case-insensitive)", () => {
|
|
113
|
+
const content = "PAUSE\n";
|
|
114
|
+
const result = parseQueueFile(content);
|
|
115
|
+
|
|
116
|
+
expect(result.commands).toHaveLength(1);
|
|
117
|
+
expect(result.commands[0]).toEqual({ type: "PAUSE" });
|
|
118
|
+
expect(result.guidance).toHaveLength(0);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("parses ABORT command (case-insensitive)", () => {
|
|
122
|
+
const content = "abort\n";
|
|
123
|
+
const result = parseQueueFile(content);
|
|
124
|
+
|
|
125
|
+
expect(result.commands).toHaveLength(1);
|
|
126
|
+
expect(result.commands[0]).toEqual({ type: "ABORT" });
|
|
127
|
+
expect(result.guidance).toHaveLength(0);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("parses SKIP command with story ID", () => {
|
|
131
|
+
const content = "SKIP US-042\n";
|
|
132
|
+
const result = parseQueueFile(content);
|
|
133
|
+
|
|
134
|
+
expect(result.commands).toHaveLength(1);
|
|
135
|
+
expect(result.commands[0]).toEqual({ type: "SKIP", storyId: "US-042" });
|
|
136
|
+
expect(result.guidance).toHaveLength(0);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("parses SKIP command case-insensitive", () => {
|
|
140
|
+
const content = "skip US-001\n";
|
|
141
|
+
const result = parseQueueFile(content);
|
|
142
|
+
|
|
143
|
+
expect(result.commands).toHaveLength(1);
|
|
144
|
+
expect(result.commands[0]).toEqual({ type: "SKIP", storyId: "US-001" });
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("parses multiple commands", () => {
|
|
148
|
+
const content = "SKIP US-001\nSKIP US-002\nPAUSE\n";
|
|
149
|
+
const result = parseQueueFile(content);
|
|
150
|
+
|
|
151
|
+
expect(result.commands).toHaveLength(3);
|
|
152
|
+
expect(result.commands[0]).toEqual({ type: "SKIP", storyId: "US-001" });
|
|
153
|
+
expect(result.commands[1]).toEqual({ type: "SKIP", storyId: "US-002" });
|
|
154
|
+
expect(result.commands[2]).toEqual({ type: "PAUSE" });
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("separates commands from guidance text", () => {
|
|
158
|
+
const content = `--- PENDING ---
|
|
159
|
+
PAUSE
|
|
160
|
+
Some guidance text here
|
|
161
|
+
More guidance on another line`;
|
|
162
|
+
|
|
163
|
+
const result = parseQueueFile(content);
|
|
164
|
+
|
|
165
|
+
expect(result.commands).toHaveLength(1);
|
|
166
|
+
expect(result.commands[0]).toEqual({ type: "PAUSE" });
|
|
167
|
+
expect(result.guidance).toHaveLength(2);
|
|
168
|
+
expect(result.guidance[0]).toBe("Some guidance text here");
|
|
169
|
+
expect(result.guidance[1]).toBe("More guidance on another line");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("mixed commands and guidance", () => {
|
|
173
|
+
const content = `ABORT
|
|
174
|
+
--- PENDING ---
|
|
175
|
+
Focus on error handling
|
|
176
|
+
SKIP US-003
|
|
177
|
+
Ensure test coverage`;
|
|
178
|
+
|
|
179
|
+
const result = parseQueueFile(content);
|
|
180
|
+
|
|
181
|
+
expect(result.commands).toHaveLength(2);
|
|
182
|
+
expect(result.commands[0]).toEqual({ type: "ABORT" });
|
|
183
|
+
expect(result.commands[1]).toEqual({ type: "SKIP", storyId: "US-003" });
|
|
184
|
+
expect(result.guidance).toHaveLength(2);
|
|
185
|
+
expect(result.guidance[0]).toBe("Focus on error handling");
|
|
186
|
+
expect(result.guidance[1]).toBe("Ensure test coverage");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("empty content returns empty result", () => {
|
|
190
|
+
const result = parseQueueFile("");
|
|
191
|
+
|
|
192
|
+
expect(result.commands).toHaveLength(0);
|
|
193
|
+
expect(result.guidance).toHaveLength(0);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("only guidance text (no commands)", () => {
|
|
197
|
+
const content = `--- PENDING ---
|
|
198
|
+
Just some guidance
|
|
199
|
+
No commands here`;
|
|
200
|
+
|
|
201
|
+
const result = parseQueueFile(content);
|
|
202
|
+
|
|
203
|
+
expect(result.commands).toHaveLength(0);
|
|
204
|
+
expect(result.guidance).toHaveLength(2);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("ignores whitespace-only lines", () => {
|
|
208
|
+
const content = `PAUSE
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
ABORT
|
|
212
|
+
`;
|
|
213
|
+
|
|
214
|
+
const result = parseQueueFile(content);
|
|
215
|
+
|
|
216
|
+
expect(result.commands).toHaveLength(2);
|
|
217
|
+
expect(result.commands[0]).toEqual({ type: "PAUSE" });
|
|
218
|
+
expect(result.commands[1]).toEqual({ type: "ABORT" });
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("handles SKIP without story ID gracefully", () => {
|
|
222
|
+
const content = "SKIP\n";
|
|
223
|
+
const result = parseQueueFile(content);
|
|
224
|
+
|
|
225
|
+
// Should treat as guidance text if no story ID provided
|
|
226
|
+
expect(result.commands).toHaveLength(0);
|
|
227
|
+
expect(result.guidance).toHaveLength(1);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("trims whitespace from story IDs", () => {
|
|
231
|
+
const content = "SKIP US-042 \n";
|
|
232
|
+
const result = parseQueueFile(content);
|
|
233
|
+
|
|
234
|
+
expect(result.commands).toHaveLength(1);
|
|
235
|
+
expect(result.commands[0]).toEqual({ type: "SKIP", storyId: "US-042" });
|
|
236
|
+
});
|
|
237
|
+
});
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for rectification core logic (v0.11)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import type { RectificationConfig } from "../../src/config";
|
|
7
|
+
import {
|
|
8
|
+
type RectificationState,
|
|
9
|
+
createRectificationPrompt,
|
|
10
|
+
shouldRetryRectification,
|
|
11
|
+
} from "../../src/execution/rectification";
|
|
12
|
+
import type { TestFailure } from "../../src/execution/test-output-parser";
|
|
13
|
+
import type { UserStory } from "../../src/prd";
|
|
14
|
+
|
|
15
|
+
describe("shouldRetryRectification", () => {
|
|
16
|
+
const baseConfig: RectificationConfig = {
|
|
17
|
+
enabled: true,
|
|
18
|
+
maxRetries: 2,
|
|
19
|
+
fullSuiteTimeoutSeconds: 120,
|
|
20
|
+
maxFailureSummaryChars: 2000,
|
|
21
|
+
abortOnIncreasingFailures: true,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
test("should retry when attempt < maxRetries and failures exist", () => {
|
|
25
|
+
const state: RectificationState = {
|
|
26
|
+
attempt: 0,
|
|
27
|
+
initialFailures: 5,
|
|
28
|
+
currentFailures: 3,
|
|
29
|
+
};
|
|
30
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("should retry on attempt 1 when maxRetries is 2", () => {
|
|
34
|
+
const state: RectificationState = {
|
|
35
|
+
attempt: 1,
|
|
36
|
+
initialFailures: 5,
|
|
37
|
+
currentFailures: 2,
|
|
38
|
+
};
|
|
39
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("should NOT retry when attempt >= maxRetries", () => {
|
|
43
|
+
const state: RectificationState = {
|
|
44
|
+
attempt: 2,
|
|
45
|
+
initialFailures: 5,
|
|
46
|
+
currentFailures: 3,
|
|
47
|
+
};
|
|
48
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("should NOT retry when currentFailures = 0 (all passing)", () => {
|
|
52
|
+
const state: RectificationState = {
|
|
53
|
+
attempt: 0,
|
|
54
|
+
initialFailures: 5,
|
|
55
|
+
currentFailures: 0,
|
|
56
|
+
};
|
|
57
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("should abort when failures increase and abortOnIncreasingFailures = true", () => {
|
|
61
|
+
const state: RectificationState = {
|
|
62
|
+
attempt: 1,
|
|
63
|
+
initialFailures: 3,
|
|
64
|
+
currentFailures: 5, // regression!
|
|
65
|
+
};
|
|
66
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(false);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("should continue when failures increase but abortOnIncreasingFailures = false", () => {
|
|
70
|
+
const config: RectificationConfig = {
|
|
71
|
+
...baseConfig,
|
|
72
|
+
abortOnIncreasingFailures: false,
|
|
73
|
+
};
|
|
74
|
+
const state: RectificationState = {
|
|
75
|
+
attempt: 1,
|
|
76
|
+
initialFailures: 3,
|
|
77
|
+
currentFailures: 5,
|
|
78
|
+
};
|
|
79
|
+
expect(shouldRetryRectification(state, config)).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("should retry when failures decreased (progress)", () => {
|
|
83
|
+
const state: RectificationState = {
|
|
84
|
+
attempt: 1,
|
|
85
|
+
initialFailures: 5,
|
|
86
|
+
currentFailures: 2,
|
|
87
|
+
};
|
|
88
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("should retry when failures stayed same", () => {
|
|
92
|
+
const state: RectificationState = {
|
|
93
|
+
attempt: 1,
|
|
94
|
+
initialFailures: 5,
|
|
95
|
+
currentFailures: 5,
|
|
96
|
+
};
|
|
97
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("should NOT retry at maxRetries even if failures exist", () => {
|
|
101
|
+
const state: RectificationState = {
|
|
102
|
+
attempt: 2,
|
|
103
|
+
initialFailures: 5,
|
|
104
|
+
currentFailures: 1,
|
|
105
|
+
};
|
|
106
|
+
expect(shouldRetryRectification(state, baseConfig)).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("should handle maxRetries = 0 (no retries allowed)", () => {
|
|
110
|
+
const config: RectificationConfig = {
|
|
111
|
+
...baseConfig,
|
|
112
|
+
maxRetries: 0,
|
|
113
|
+
};
|
|
114
|
+
const state: RectificationState = {
|
|
115
|
+
attempt: 0,
|
|
116
|
+
initialFailures: 5,
|
|
117
|
+
currentFailures: 5,
|
|
118
|
+
};
|
|
119
|
+
expect(shouldRetryRectification(state, config)).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("createRectificationPrompt", () => {
|
|
124
|
+
const mockStory: UserStory = {
|
|
125
|
+
id: "US-001",
|
|
126
|
+
title: "Add user authentication",
|
|
127
|
+
description: "Implement JWT-based authentication for API endpoints",
|
|
128
|
+
acceptanceCriteria: [
|
|
129
|
+
"Users can log in with email/password",
|
|
130
|
+
"JWT tokens are issued on successful login",
|
|
131
|
+
"Protected endpoints validate JWT tokens",
|
|
132
|
+
],
|
|
133
|
+
tags: ["security"],
|
|
134
|
+
dependencies: [],
|
|
135
|
+
status: "in-progress",
|
|
136
|
+
passes: false,
|
|
137
|
+
escalations: [],
|
|
138
|
+
attempts: 1,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const mockFailures: TestFailure[] = [
|
|
142
|
+
{
|
|
143
|
+
file: "test/auth.test.ts",
|
|
144
|
+
testName: "login > should return JWT on valid credentials",
|
|
145
|
+
error: "Expected status 200, got 401",
|
|
146
|
+
stackTrace: ["at test/auth.test.ts:15:20", "at Object.test (test/auth.test.ts:10:3)"],
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
file: "test/middleware.test.ts",
|
|
150
|
+
testName: "JWT middleware > should reject invalid tokens",
|
|
151
|
+
error: "Expected 403, got 200",
|
|
152
|
+
stackTrace: ["at test/middleware.test.ts:25:10"],
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
test("should include story title and description", () => {
|
|
157
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
158
|
+
expect(prompt).toContain("Add user authentication");
|
|
159
|
+
expect(prompt).toContain("Implement JWT-based authentication for API endpoints");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("should include all acceptance criteria", () => {
|
|
163
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
164
|
+
expect(prompt).toContain("1. Users can log in with email/password");
|
|
165
|
+
expect(prompt).toContain("2. JWT tokens are issued on successful login");
|
|
166
|
+
expect(prompt).toContain("3. Protected endpoints validate JWT tokens");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("should include formatted failure summary from R1's formatFailureSummary", () => {
|
|
170
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
171
|
+
expect(prompt).toContain("test/auth.test.ts > login > should return JWT on valid credentials");
|
|
172
|
+
expect(prompt).toContain("Expected status 200, got 401");
|
|
173
|
+
expect(prompt).toContain("test/middleware.test.ts > JWT middleware > should reject invalid tokens");
|
|
174
|
+
expect(prompt).toContain("Expected 403, got 200");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("should include specific bun test commands for failing files", () => {
|
|
178
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
179
|
+
expect(prompt).toContain("bun test test/auth.test.ts");
|
|
180
|
+
expect(prompt).toContain("bun test test/middleware.test.ts");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("should include clear instructions about fixing regressions", () => {
|
|
184
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
185
|
+
expect(prompt).toContain("Your changes caused test regressions");
|
|
186
|
+
expect(prompt).toContain("Fix these without breaking existing logic");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("should warn against loosening assertions", () => {
|
|
190
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
191
|
+
expect(prompt).toContain("Do NOT loosen assertions to mask implementation bugs");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("should warn against modifying tests unnecessarily", () => {
|
|
195
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
196
|
+
expect(prompt).toContain("Do NOT modify test files unless there is a legitimate bug in the test itself");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("should respect maxFailureSummaryChars config", () => {
|
|
200
|
+
const config: RectificationConfig = {
|
|
201
|
+
enabled: true,
|
|
202
|
+
maxRetries: 2,
|
|
203
|
+
fullSuiteTimeoutSeconds: 120,
|
|
204
|
+
maxFailureSummaryChars: 100, // very small limit
|
|
205
|
+
abortOnIncreasingFailures: true,
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const manyFailures: TestFailure[] = Array.from({ length: 20 }, (_, i) => ({
|
|
209
|
+
file: `test/file${i}.test.ts`,
|
|
210
|
+
testName: `test ${i}`,
|
|
211
|
+
error: `Error ${i}: Some long error message that takes up space`,
|
|
212
|
+
stackTrace: [`at test/file${i}.test.ts:${i}:0`],
|
|
213
|
+
}));
|
|
214
|
+
|
|
215
|
+
const prompt = createRectificationPrompt(manyFailures, mockStory, config);
|
|
216
|
+
// Should contain truncation message
|
|
217
|
+
expect(prompt).toMatch(/truncated/i);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("should handle single failure", () => {
|
|
221
|
+
const singleFailure: TestFailure[] = [mockFailures[0]];
|
|
222
|
+
const prompt = createRectificationPrompt(singleFailure, mockStory);
|
|
223
|
+
expect(prompt).toContain("test/auth.test.ts > login > should return JWT on valid credentials");
|
|
224
|
+
expect(prompt).toContain("bun test test/auth.test.ts");
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test("should deduplicate test commands for same file", () => {
|
|
228
|
+
const duplicateFileFailures: TestFailure[] = [
|
|
229
|
+
{
|
|
230
|
+
file: "test/auth.test.ts",
|
|
231
|
+
testName: "test 1",
|
|
232
|
+
error: "error 1",
|
|
233
|
+
stackTrace: [],
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
file: "test/auth.test.ts",
|
|
237
|
+
testName: "test 2",
|
|
238
|
+
error: "error 2",
|
|
239
|
+
stackTrace: [],
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
file: "test/middleware.test.ts",
|
|
243
|
+
testName: "test 3",
|
|
244
|
+
error: "error 3",
|
|
245
|
+
stackTrace: [],
|
|
246
|
+
},
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
const prompt = createRectificationPrompt(duplicateFileFailures, mockStory);
|
|
250
|
+
|
|
251
|
+
// Should only have 2 unique bun test commands
|
|
252
|
+
const testCommands = prompt.match(/bun test test\//g);
|
|
253
|
+
expect(testCommands).not.toBeNull();
|
|
254
|
+
expect(testCommands?.length).toBe(2);
|
|
255
|
+
|
|
256
|
+
// Should contain both unique files
|
|
257
|
+
expect(prompt).toContain("bun test test/auth.test.ts");
|
|
258
|
+
expect(prompt).toContain("bun test test/middleware.test.ts");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("should use default maxChars when config not provided", () => {
|
|
262
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
263
|
+
// Should not be truncated with default 2000 chars for just 2 failures
|
|
264
|
+
expect(prompt).not.toMatch(/truncated/i);
|
|
265
|
+
expect(prompt).toContain("test/auth.test.ts");
|
|
266
|
+
expect(prompt).toContain("test/middleware.test.ts");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("should handle empty acceptance criteria array", () => {
|
|
270
|
+
const storyNoAC: UserStory = {
|
|
271
|
+
...mockStory,
|
|
272
|
+
acceptanceCriteria: [],
|
|
273
|
+
};
|
|
274
|
+
const prompt = createRectificationPrompt(mockFailures, storyNoAC);
|
|
275
|
+
expect(prompt).toContain("Acceptance Criteria:");
|
|
276
|
+
// Should not crash, just show empty list
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test("should include instructions to run ONLY failing tests", () => {
|
|
280
|
+
const prompt = createRectificationPrompt(mockFailures, mockStory);
|
|
281
|
+
expect(prompt).toContain("run ONLY the failing test files shown above");
|
|
282
|
+
expect(prompt).toContain("NEVER run `bun test` without a file filter");
|
|
283
|
+
});
|
|
284
|
+
});
|