@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,270 @@
|
|
|
1
|
+
import type { RectificationConfig } from "../config";
|
|
2
|
+
import { createRectificationPrompt } from "../execution/rectification";
|
|
3
|
+
import type { TestFailure } from "../execution/test-output-parser";
|
|
4
|
+
import type { UserStory } from "../prd";
|
|
5
|
+
import type { TddSessionRole } from "./types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Prompt to build the TDD agent's role definition
|
|
9
|
+
*/
|
|
10
|
+
export function buildTddRolePrompt(
|
|
11
|
+
role: TddSessionRole,
|
|
12
|
+
story: UserStory,
|
|
13
|
+
config?: { projectRoot: string },
|
|
14
|
+
currentBranch?: string,
|
|
15
|
+
): string {
|
|
16
|
+
const common = `You are a TDD agent (role: ${role}) working on the story: "${story.title}".${config ? `\nProject root: ${config.projectRoot}` : ""}${currentBranch ? `\nCurrent branch: ${currentBranch}` : ""}
|
|
17
|
+
|
|
18
|
+
STORY DESCRIPTION:
|
|
19
|
+
${story.description}
|
|
20
|
+
|
|
21
|
+
ACCEPTANCE CRITERIA:
|
|
22
|
+
${story.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
if (role === "test-writer") {
|
|
28
|
+
return `${common}
|
|
29
|
+
YOUR TASK: Write ONLY test files for this story.
|
|
30
|
+
- Use the existing test framework (Bun test).
|
|
31
|
+
- Tests must fail because the feature is not implemented yet.
|
|
32
|
+
- Do NOT modify any existing source files.
|
|
33
|
+
- Do NOT implement the feature.
|
|
34
|
+
- Name tests consistently (e.g., test/*.test.ts).
|
|
35
|
+
|
|
36
|
+
IMPORTANT: Only write new test files or update existing ones. Do NOT touch src/*.`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (role === "implementer") {
|
|
40
|
+
return `${common}
|
|
41
|
+
YOUR TASK: Implement the feature to make the tests pass.
|
|
42
|
+
- Read the tests in the current branch.
|
|
43
|
+
- Modify source files in src/ as needed.
|
|
44
|
+
- Do NOT modify test files unless there is a bug in the tests.
|
|
45
|
+
- Run tests frequently to check progress.
|
|
46
|
+
- Goal: All tests pass.`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Verifier
|
|
50
|
+
return `${common}
|
|
51
|
+
YOUR TASK: Verify the implementation and tests.
|
|
52
|
+
- Ensure all tests pass.
|
|
53
|
+
- Check that the implementation meets all acceptance criteria.
|
|
54
|
+
- Fix any minor bugs or missing edge cases.
|
|
55
|
+
- Do NOT change the behavior unless it violates the criteria.
|
|
56
|
+
- When running tests, run ONLY test files related to your changes (e.g. \`bun test ./test/specific.test.ts\`). NEVER run \`bun test\` without a file filter — full suite output will flood your context window and cause failures.
|
|
57
|
+
- Goal: High-quality implementation and passing tests.`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Prompt to build the verifier's verification instructions (Session 3)
|
|
62
|
+
*/
|
|
63
|
+
export function buildVerifierPrompt(story: UserStory): string {
|
|
64
|
+
return `# Session 3: Verify — "${story.title}"
|
|
65
|
+
|
|
66
|
+
STORY:
|
|
67
|
+
${story.description}
|
|
68
|
+
|
|
69
|
+
ACCEPTANCE CRITERIA:
|
|
70
|
+
${story.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## TASKS
|
|
75
|
+
|
|
76
|
+
1. Run all tests and verify they pass.
|
|
77
|
+
- When running tests, run ONLY test files related to your changes (e.g. \`bun test ./test/specific.test.ts\`). NEVER run \`bun test\` without a file filter — full suite output will flood your context window and cause failures.
|
|
78
|
+
2. Review the implementation for quality and correctness.
|
|
79
|
+
3. Check that the implementation meets all acceptance criteria.
|
|
80
|
+
4. Check if test files were modified by the implementer (make sure they are legitimate fixes, NOT just loosening assertions to mask bugs).
|
|
81
|
+
5. If any issues exist, fix them minimally — do NOT refactor.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## IMPORTANT — Write Verdict File
|
|
86
|
+
|
|
87
|
+
After completing your verification, you **MUST** write a verdict file at the **project root**:
|
|
88
|
+
|
|
89
|
+
**File:** \`.nax-verifier-verdict.json\`
|
|
90
|
+
|
|
91
|
+
Set \`approved: true\` when ALL of these conditions are met:
|
|
92
|
+
- All tests pass
|
|
93
|
+
- Implementation is clean and follows conventions
|
|
94
|
+
- All acceptance criteria met
|
|
95
|
+
- Any test modifications by implementer are legitimate fixes
|
|
96
|
+
|
|
97
|
+
Set \`approved: false\` when ANY of these conditions are true:
|
|
98
|
+
- Tests are failing and you cannot fix them
|
|
99
|
+
- The implementer loosened test assertions to mask bugs
|
|
100
|
+
- Critical acceptance criteria are not met
|
|
101
|
+
- Code quality is poor (security issues, severe bugs, etc.)
|
|
102
|
+
|
|
103
|
+
**Full JSON schema example** (fill in all fields with real values):
|
|
104
|
+
|
|
105
|
+
\`\`\`json
|
|
106
|
+
{
|
|
107
|
+
"version": 1,
|
|
108
|
+
"approved": true,
|
|
109
|
+
"tests": {
|
|
110
|
+
"allPassing": true,
|
|
111
|
+
"passCount": 42,
|
|
112
|
+
"failCount": 0
|
|
113
|
+
},
|
|
114
|
+
"testModifications": {
|
|
115
|
+
"detected": false,
|
|
116
|
+
"files": [],
|
|
117
|
+
"legitimate": true,
|
|
118
|
+
"reasoning": "No test files were modified by the implementer"
|
|
119
|
+
},
|
|
120
|
+
"acceptanceCriteria": {
|
|
121
|
+
"allMet": true,
|
|
122
|
+
"criteria": [
|
|
123
|
+
{ "criterion": "Example criterion", "met": true }
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
"quality": {
|
|
127
|
+
"rating": "good",
|
|
128
|
+
"issues": []
|
|
129
|
+
},
|
|
130
|
+
"fixes": [],
|
|
131
|
+
"reasoning": "All tests pass, implementation is clean, all acceptance criteria are met."
|
|
132
|
+
}
|
|
133
|
+
\`\`\`
|
|
134
|
+
|
|
135
|
+
**Field notes:**
|
|
136
|
+
- \`quality.rating\` must be one of: \`"good"\`, \`"acceptable"\`, \`"poor"\`
|
|
137
|
+
- \`testModifications.files\` — list any test files the implementer changed
|
|
138
|
+
- \`fixes\` — list any fixes you applied yourself during this verification session
|
|
139
|
+
- \`reasoning\` — brief summary of your overall assessment
|
|
140
|
+
|
|
141
|
+
When done, commit any fixes with message: "fix: verify and adjust ${story.title}"`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Prompt for a test-writer session (single-session lite variant)
|
|
146
|
+
*/
|
|
147
|
+
export function buildTestWriterPrompt(story: UserStory, contextMarkdown?: string): string {
|
|
148
|
+
const contextSection = contextMarkdown ? `\n\n---\n\n${contextMarkdown}` : "";
|
|
149
|
+
return `# Test Writer — "${story.title}"
|
|
150
|
+
|
|
151
|
+
Your role: Write failing tests ONLY. Do NOT implement any source code.
|
|
152
|
+
|
|
153
|
+
STORY:
|
|
154
|
+
${story.description}
|
|
155
|
+
|
|
156
|
+
ACCEPTANCE CRITERIA:
|
|
157
|
+
${story.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
|
|
158
|
+
|
|
159
|
+
RULES:
|
|
160
|
+
- Only create or modify files in the test/ directory.
|
|
161
|
+
- Tests must fail (feature not implemented yet).
|
|
162
|
+
- Use Bun test (describe/test/expect).
|
|
163
|
+
- Cover all acceptance criteria.
|
|
164
|
+
- When running tests, run ONLY test files related to your changes (e.g. \`bun test ./test/specific.test.ts\`). NEVER run \`bun test\` without a file filter — full suite output will flood your context window and cause failures.${contextSection}`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Prompt for a test-writer lite session (no isolation enforcement)
|
|
169
|
+
*/
|
|
170
|
+
export function buildTestWriterLitePrompt(story: UserStory, contextMarkdown?: string): string {
|
|
171
|
+
const contextSection = contextMarkdown ? `\n\n---\n\n${contextMarkdown}` : "";
|
|
172
|
+
return `# Test Writer (Lite) — "${story.title}"
|
|
173
|
+
|
|
174
|
+
Your role: Write failing tests. You MAY read source files and MAY import from source files to ensure correct types/interfaces. You may create minimal stubs in src/ if needed to make imports work, but do NOT implement real logic.
|
|
175
|
+
|
|
176
|
+
STORY:
|
|
177
|
+
${story.description}
|
|
178
|
+
|
|
179
|
+
ACCEPTANCE CRITERIA:
|
|
180
|
+
${story.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
|
|
181
|
+
|
|
182
|
+
RULES:
|
|
183
|
+
- Primarily CREATE test files in the test/ directory.
|
|
184
|
+
- Stub-only src/ files are allowed (empty exports, no logic).
|
|
185
|
+
- Tests must fail for the right reasons (feature not implemented).
|
|
186
|
+
- Use Bun test (describe/test/expect).
|
|
187
|
+
- When running tests, run ONLY test files related to your changes (e.g. \`bun test ./test/specific.test.ts\`). NEVER run \`bun test\` without a file filter — full suite output will flood your context window and cause failures.${contextSection}`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Prompt for an implementer session
|
|
192
|
+
*/
|
|
193
|
+
export function buildImplementerPrompt(story: UserStory, contextMarkdown?: string): string {
|
|
194
|
+
const contextSection = contextMarkdown ? `\n\n---\n\n${contextMarkdown}` : "";
|
|
195
|
+
return `# Implementer — "${story.title}"
|
|
196
|
+
|
|
197
|
+
Your role: Make all failing tests pass.
|
|
198
|
+
|
|
199
|
+
STORY:
|
|
200
|
+
${story.description}
|
|
201
|
+
|
|
202
|
+
ACCEPTANCE CRITERIA:
|
|
203
|
+
${story.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
|
|
204
|
+
|
|
205
|
+
RULES:
|
|
206
|
+
- Implement source code in src/ to make tests pass.
|
|
207
|
+
- Do NOT modify test files.
|
|
208
|
+
- Run tests frequently to track progress.
|
|
209
|
+
- When running tests, run ONLY test files related to your changes (e.g. \`bun test ./test/specific.test.ts\`). NEVER run \`bun test\` without a file filter — full suite output will flood your context window and cause failures.
|
|
210
|
+
- Goal: all tests green.${contextSection}`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Build implementer rectification prompt (v0.11)
|
|
215
|
+
*
|
|
216
|
+
* Used during the full-suite gate in three-session TDD when the implementer
|
|
217
|
+
* introduced regressions. Provides failure context to guide fixes.
|
|
218
|
+
*/
|
|
219
|
+
export function buildImplementerRectificationPrompt(
|
|
220
|
+
failures: TestFailure[],
|
|
221
|
+
story: UserStory,
|
|
222
|
+
contextMarkdown?: string,
|
|
223
|
+
config?: RectificationConfig,
|
|
224
|
+
): string {
|
|
225
|
+
// Reuse the existing rectification prompt builder from R2
|
|
226
|
+
// It already includes story context, failure details, and instructions
|
|
227
|
+
return createRectificationPrompt(failures, story, config);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Prompt for an implementer lite session (combined test + implement)
|
|
232
|
+
*/
|
|
233
|
+
export function buildImplementerLitePrompt(story: UserStory, contextMarkdown?: string): string {
|
|
234
|
+
const contextSection = contextMarkdown ? `\n\n---\n\n${contextMarkdown}` : "";
|
|
235
|
+
return `# Implementer (Lite) — "${story.title}"
|
|
236
|
+
|
|
237
|
+
Your role: Write tests AND implement the feature in a single session.
|
|
238
|
+
|
|
239
|
+
STORY:
|
|
240
|
+
${story.description}
|
|
241
|
+
|
|
242
|
+
ACCEPTANCE CRITERIA:
|
|
243
|
+
${story.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
|
|
244
|
+
|
|
245
|
+
RULES:
|
|
246
|
+
- Write tests first (test/ directory), then implement (src/ directory).
|
|
247
|
+
- All tests must pass by the end.
|
|
248
|
+
- Use Bun test (describe/test/expect).
|
|
249
|
+
- When running tests, run ONLY test files related to your changes (e.g. \`bun test ./test/specific.test.ts\`). NEVER run \`bun test\` without a file filter — full suite output will flood your context window and cause failures.
|
|
250
|
+
- Goal: all tests green, all criteria met.${contextSection}`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Build rectification prompt for retry after test failures
|
|
255
|
+
*
|
|
256
|
+
* Wrapper around createRectificationPrompt from the rectification core module.
|
|
257
|
+
* Used when tests fail after implementation to provide failure context for retry.
|
|
258
|
+
*
|
|
259
|
+
* @param story - User story being implemented
|
|
260
|
+
* @param failures - Array of test failures from test output parser
|
|
261
|
+
* @param config - Optional rectification config (for maxFailureSummaryChars)
|
|
262
|
+
* @returns Formatted rectification prompt with failure details
|
|
263
|
+
*/
|
|
264
|
+
export function buildRectificationPrompt(
|
|
265
|
+
story: UserStory,
|
|
266
|
+
failures: TestFailure[],
|
|
267
|
+
config?: RectificationConfig,
|
|
268
|
+
): string {
|
|
269
|
+
return createRectificationPrompt(failures, story, config);
|
|
270
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TDD Full-Suite Rectification Gate
|
|
3
|
+
*
|
|
4
|
+
* Extracted from orchestrator.ts: runFullSuiteGate
|
|
5
|
+
* Runs the full test suite before the verifier session and performs
|
|
6
|
+
* rectification retries if regressions are detected.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AgentAdapter } from "../agents";
|
|
10
|
+
import type { ModelTier, NaxConfig } from "../config";
|
|
11
|
+
import { resolveModel } from "../config";
|
|
12
|
+
import type { getLogger } from "../logger";
|
|
13
|
+
import type { UserStory } from "../prd";
|
|
14
|
+
import { captureGitRef } from "../utils/git";
|
|
15
|
+
import {
|
|
16
|
+
type RectificationState,
|
|
17
|
+
executeWithTimeout,
|
|
18
|
+
parseBunTestOutput,
|
|
19
|
+
shouldRetryRectification,
|
|
20
|
+
} from "../verification";
|
|
21
|
+
import { cleanupProcessTree } from "./cleanup";
|
|
22
|
+
import { verifyImplementerIsolation } from "./isolation";
|
|
23
|
+
import { buildImplementerRectificationPrompt } from "./prompts";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Run full test suite gate before verifier session (v0.11 Rectification).
|
|
27
|
+
*/
|
|
28
|
+
export async function runFullSuiteGate(
|
|
29
|
+
story: UserStory,
|
|
30
|
+
config: NaxConfig,
|
|
31
|
+
workdir: string,
|
|
32
|
+
agent: AgentAdapter,
|
|
33
|
+
implementerTier: ModelTier,
|
|
34
|
+
contextMarkdown: string | undefined,
|
|
35
|
+
lite: boolean,
|
|
36
|
+
logger: ReturnType<typeof getLogger>,
|
|
37
|
+
): Promise<void> {
|
|
38
|
+
const rectificationEnabled = config.execution.rectification?.enabled ?? false;
|
|
39
|
+
if (!rectificationEnabled) return;
|
|
40
|
+
|
|
41
|
+
const rectificationConfig = config.execution.rectification;
|
|
42
|
+
const testCmd = config.quality?.commands?.test ?? "bun test";
|
|
43
|
+
const fullSuiteTimeout = rectificationConfig.fullSuiteTimeoutSeconds;
|
|
44
|
+
|
|
45
|
+
logger.info("tdd", "-> Running full test suite gate (before Verifier)", {
|
|
46
|
+
storyId: story.id,
|
|
47
|
+
timeout: fullSuiteTimeout,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const fullSuiteResult = await executeWithTimeout(testCmd, fullSuiteTimeout, undefined, { cwd: workdir });
|
|
51
|
+
const fullSuitePassed = fullSuiteResult.success && fullSuiteResult.exitCode === 0;
|
|
52
|
+
|
|
53
|
+
if (!fullSuitePassed && fullSuiteResult.output) {
|
|
54
|
+
const testSummary = parseBunTestOutput(fullSuiteResult.output);
|
|
55
|
+
|
|
56
|
+
if (testSummary.failed > 0) {
|
|
57
|
+
await runRectificationLoop(
|
|
58
|
+
story,
|
|
59
|
+
config,
|
|
60
|
+
workdir,
|
|
61
|
+
agent,
|
|
62
|
+
implementerTier,
|
|
63
|
+
contextMarkdown,
|
|
64
|
+
lite,
|
|
65
|
+
logger,
|
|
66
|
+
testSummary,
|
|
67
|
+
rectificationConfig,
|
|
68
|
+
testCmd,
|
|
69
|
+
fullSuiteTimeout,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
} else if (fullSuitePassed) {
|
|
73
|
+
logger.info("tdd", "Full suite gate passed", { storyId: story.id });
|
|
74
|
+
} else {
|
|
75
|
+
logger.warn("tdd", "Full suite gate execution failed (no output)", {
|
|
76
|
+
storyId: story.id,
|
|
77
|
+
exitCode: fullSuiteResult.exitCode,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Run the rectification retry loop when full suite gate detects regressions. */
|
|
83
|
+
async function runRectificationLoop(
|
|
84
|
+
story: UserStory,
|
|
85
|
+
config: NaxConfig,
|
|
86
|
+
workdir: string,
|
|
87
|
+
agent: AgentAdapter,
|
|
88
|
+
implementerTier: ModelTier,
|
|
89
|
+
contextMarkdown: string | undefined,
|
|
90
|
+
lite: boolean,
|
|
91
|
+
logger: ReturnType<typeof getLogger>,
|
|
92
|
+
testSummary: ReturnType<typeof parseBunTestOutput>,
|
|
93
|
+
rectificationConfig: NonNullable<NaxConfig["execution"]["rectification"]>,
|
|
94
|
+
testCmd: string,
|
|
95
|
+
fullSuiteTimeout: number,
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
const rectificationState: RectificationState = {
|
|
98
|
+
attempt: 0,
|
|
99
|
+
initialFailures: testSummary.failed,
|
|
100
|
+
currentFailures: testSummary.failed,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
logger.warn("tdd", "Full suite gate detected regressions", {
|
|
104
|
+
storyId: story.id,
|
|
105
|
+
failedTests: testSummary.failed,
|
|
106
|
+
passedTests: testSummary.passed,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
while (shouldRetryRectification(rectificationState, rectificationConfig)) {
|
|
110
|
+
rectificationState.attempt++;
|
|
111
|
+
|
|
112
|
+
logger.info(
|
|
113
|
+
"tdd",
|
|
114
|
+
`-> Implementer rectification attempt ${rectificationState.attempt}/${rectificationConfig.maxRetries}`,
|
|
115
|
+
{ storyId: story.id, currentFailures: rectificationState.currentFailures },
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const rectificationPrompt = buildImplementerRectificationPrompt(
|
|
119
|
+
testSummary.failures,
|
|
120
|
+
story,
|
|
121
|
+
contextMarkdown,
|
|
122
|
+
rectificationConfig,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const rectifyBeforeRef = (await captureGitRef(workdir)) ?? "HEAD";
|
|
126
|
+
|
|
127
|
+
const rectifyResult = await agent.run({
|
|
128
|
+
prompt: rectificationPrompt,
|
|
129
|
+
workdir,
|
|
130
|
+
modelTier: implementerTier,
|
|
131
|
+
modelDef: resolveModel(config.models[implementerTier]),
|
|
132
|
+
timeoutSeconds: config.execution.sessionTimeoutSeconds,
|
|
133
|
+
dangerouslySkipPermissions: config.execution.dangerouslySkipPermissions,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (!rectifyResult.success && rectifyResult.pid) {
|
|
137
|
+
await cleanupProcessTree(rectifyResult.pid);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const rectifyIsolation = lite ? undefined : await verifyImplementerIsolation(workdir, rectifyBeforeRef);
|
|
141
|
+
|
|
142
|
+
if (rectifyIsolation && !rectifyIsolation.passed) {
|
|
143
|
+
logger.error("tdd", "Rectification violated isolation", {
|
|
144
|
+
storyId: story.id,
|
|
145
|
+
attempt: rectificationState.attempt,
|
|
146
|
+
violations: rectifyIsolation.violations,
|
|
147
|
+
});
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const retryFullSuite = await executeWithTimeout(testCmd, fullSuiteTimeout, undefined, { cwd: workdir });
|
|
152
|
+
const retrySuitePassed = retryFullSuite.success && retryFullSuite.exitCode === 0;
|
|
153
|
+
|
|
154
|
+
if (retrySuitePassed) {
|
|
155
|
+
logger.info("tdd", "Full suite gate passed after rectification!", {
|
|
156
|
+
storyId: story.id,
|
|
157
|
+
attempt: rectificationState.attempt,
|
|
158
|
+
});
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (retryFullSuite.output) {
|
|
163
|
+
const newTestSummary = parseBunTestOutput(retryFullSuite.output);
|
|
164
|
+
rectificationState.currentFailures = newTestSummary.failed;
|
|
165
|
+
testSummary.failures = newTestSummary.failures;
|
|
166
|
+
testSummary.failed = newTestSummary.failed;
|
|
167
|
+
testSummary.passed = newTestSummary.passed;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const finalFullSuite = await executeWithTimeout(testCmd, fullSuiteTimeout, undefined, { cwd: workdir });
|
|
172
|
+
const finalSuitePassed = finalFullSuite.success && finalFullSuite.exitCode === 0;
|
|
173
|
+
|
|
174
|
+
if (!finalSuitePassed) {
|
|
175
|
+
logger.warn("tdd", "[WARN] Full suite gate failed after rectification exhausted", {
|
|
176
|
+
storyId: story.id,
|
|
177
|
+
attempts: rectificationState.attempt,
|
|
178
|
+
remainingFailures: rectificationState.currentFailures,
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
logger.info("tdd", "Full suite gate passed", { storyId: story.id });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TDD Session Runner
|
|
3
|
+
*
|
|
4
|
+
* Extracted from orchestrator.ts: runTddSession, truncateTestOutput, rollbackToRef
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { AgentAdapter } from "../agents";
|
|
8
|
+
import type { ModelTier, NaxConfig } from "../config";
|
|
9
|
+
import { resolveModel } from "../config";
|
|
10
|
+
import { getLogger } from "../logger";
|
|
11
|
+
import type { UserStory } from "../prd";
|
|
12
|
+
import { cleanupProcessTree } from "./cleanup";
|
|
13
|
+
import { getChangedFiles, verifyImplementerIsolation, verifyTestWriterIsolation } from "./isolation";
|
|
14
|
+
import {
|
|
15
|
+
buildImplementerLitePrompt,
|
|
16
|
+
buildImplementerPrompt,
|
|
17
|
+
buildTestWriterLitePrompt,
|
|
18
|
+
buildTestWriterPrompt,
|
|
19
|
+
buildVerifierPrompt,
|
|
20
|
+
} from "./prompts";
|
|
21
|
+
import type { IsolationCheck } from "./types";
|
|
22
|
+
import type { TddSessionResult, TddSessionRole } from "./types";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Truncate test output to prevent context flooding.
|
|
26
|
+
* Keeps first 10 lines and last 40 lines with a separator.
|
|
27
|
+
*/
|
|
28
|
+
export function truncateTestOutput(output: string, maxLines = 50): string {
|
|
29
|
+
const lines = output.split("\n");
|
|
30
|
+
if (lines.length <= maxLines) {
|
|
31
|
+
return output;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const headLines = 10;
|
|
35
|
+
const tailLines = 40;
|
|
36
|
+
const head = lines.slice(0, headLines).join("\n");
|
|
37
|
+
const tail = lines.slice(-tailLines).join("\n");
|
|
38
|
+
const truncatedCount = lines.length - headLines - tailLines;
|
|
39
|
+
|
|
40
|
+
return `${head}\n\n... (${truncatedCount} lines truncated) ...\n\n${tail}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Rollback git changes to a specific ref.
|
|
45
|
+
* Used when TDD fails to revert uncommitted/committed changes.
|
|
46
|
+
*/
|
|
47
|
+
export async function rollbackToRef(workdir: string, ref: string): Promise<void> {
|
|
48
|
+
const logger = getLogger();
|
|
49
|
+
logger.warn("tdd", "Rolling back git changes", { ref });
|
|
50
|
+
|
|
51
|
+
const resetProc = Bun.spawn(["git", "reset", "--hard", ref], {
|
|
52
|
+
cwd: workdir,
|
|
53
|
+
stdout: "pipe",
|
|
54
|
+
stderr: "pipe",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const exitCode = await resetProc.exited;
|
|
58
|
+
if (exitCode !== 0) {
|
|
59
|
+
const stderr = await new Response(resetProc.stderr).text();
|
|
60
|
+
logger.error("tdd", "Failed to rollback git changes", { ref, stderr });
|
|
61
|
+
throw new Error(`Git rollback failed: ${stderr}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const cleanProc = Bun.spawn(["git", "clean", "-fd"], {
|
|
65
|
+
cwd: workdir,
|
|
66
|
+
stdout: "pipe",
|
|
67
|
+
stderr: "pipe",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const cleanExitCode = await cleanProc.exited;
|
|
71
|
+
if (cleanExitCode !== 0) {
|
|
72
|
+
const stderr = await new Response(cleanProc.stderr).text();
|
|
73
|
+
logger.warn("tdd", "Failed to clean untracked files", { stderr });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
logger.info("tdd", "Successfully rolled back git changes", { ref });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Run a single TDD session */
|
|
80
|
+
export async function runTddSession(
|
|
81
|
+
role: TddSessionRole,
|
|
82
|
+
agent: AgentAdapter,
|
|
83
|
+
story: UserStory,
|
|
84
|
+
config: NaxConfig,
|
|
85
|
+
workdir: string,
|
|
86
|
+
modelTier: ModelTier,
|
|
87
|
+
beforeRef: string,
|
|
88
|
+
contextMarkdown?: string,
|
|
89
|
+
lite = false,
|
|
90
|
+
skipIsolation = false,
|
|
91
|
+
): Promise<TddSessionResult> {
|
|
92
|
+
const startTime = Date.now();
|
|
93
|
+
|
|
94
|
+
// Build prompt based on role and mode (lite vs strict)
|
|
95
|
+
let prompt: string;
|
|
96
|
+
switch (role) {
|
|
97
|
+
case "test-writer":
|
|
98
|
+
prompt = lite ? buildTestWriterLitePrompt(story, contextMarkdown) : buildTestWriterPrompt(story, contextMarkdown);
|
|
99
|
+
break;
|
|
100
|
+
case "implementer":
|
|
101
|
+
prompt = lite
|
|
102
|
+
? buildImplementerLitePrompt(story, contextMarkdown)
|
|
103
|
+
: buildImplementerPrompt(story, contextMarkdown);
|
|
104
|
+
break;
|
|
105
|
+
case "verifier":
|
|
106
|
+
prompt = buildVerifierPrompt(story);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const logger = getLogger();
|
|
111
|
+
logger.info("tdd", `-> Session: ${role}`, { role, storyId: story.id, lite });
|
|
112
|
+
|
|
113
|
+
// Run the agent
|
|
114
|
+
const result = await agent.run({
|
|
115
|
+
prompt,
|
|
116
|
+
workdir,
|
|
117
|
+
modelTier,
|
|
118
|
+
modelDef: resolveModel(config.models[modelTier]),
|
|
119
|
+
timeoutSeconds: config.execution.sessionTimeoutSeconds,
|
|
120
|
+
dangerouslySkipPermissions: config.execution.dangerouslySkipPermissions,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// BUG-21 Fix: Clean up orphaned child processes if agent failed
|
|
124
|
+
if (!result.success && result.pid) {
|
|
125
|
+
await cleanupProcessTree(result.pid);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check isolation based on role and skipIsolation flag.
|
|
129
|
+
let isolation: IsolationCheck | undefined;
|
|
130
|
+
if (!skipIsolation) {
|
|
131
|
+
if (role === "test-writer") {
|
|
132
|
+
const allowedPaths = config.tdd.testWriterAllowedPaths ?? ["src/index.ts", "src/**/index.ts"];
|
|
133
|
+
isolation = await verifyTestWriterIsolation(workdir, beforeRef, allowedPaths);
|
|
134
|
+
} else if (role === "implementer" || role === "verifier") {
|
|
135
|
+
isolation = await verifyImplementerIsolation(workdir, beforeRef);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Get changed files
|
|
140
|
+
const filesChanged = await getChangedFiles(workdir, beforeRef);
|
|
141
|
+
|
|
142
|
+
const durationMs = Date.now() - startTime;
|
|
143
|
+
|
|
144
|
+
if (isolation && !isolation.passed) {
|
|
145
|
+
logger.error("tdd", "Isolation violated", {
|
|
146
|
+
role,
|
|
147
|
+
storyId: story.id,
|
|
148
|
+
description: isolation.description,
|
|
149
|
+
violations: isolation.violations,
|
|
150
|
+
});
|
|
151
|
+
} else if (isolation) {
|
|
152
|
+
if (isolation.softViolations && isolation.softViolations.length > 0) {
|
|
153
|
+
logger.warn("tdd", "[WARN] Isolation soft violations (allowed files modified)", {
|
|
154
|
+
role,
|
|
155
|
+
storyId: story.id,
|
|
156
|
+
softViolations: isolation.softViolations,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (isolation.warnings && isolation.warnings.length > 0) {
|
|
160
|
+
logger.warn("tdd", "[WARN] Isolation maintained with warnings", {
|
|
161
|
+
role,
|
|
162
|
+
storyId: story.id,
|
|
163
|
+
warnings: isolation.warnings,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (!isolation.softViolations?.length && !isolation.warnings?.length) {
|
|
167
|
+
logger.info("tdd", "Isolation maintained", { role, storyId: story.id });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
role,
|
|
173
|
+
success: result.success && (!isolation || isolation.passed),
|
|
174
|
+
isolation,
|
|
175
|
+
filesChanged,
|
|
176
|
+
durationMs,
|
|
177
|
+
estimatedCost: result.estimatedCost,
|
|
178
|
+
};
|
|
179
|
+
}
|