@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,15 @@
|
|
|
1
|
+
[2026-02-27T11:20:44.967Z] US-001 — FAILED — Precheck types and check implementations — All tiers exhausted
|
|
2
|
+
[2026-02-27T11:22:41.995Z] US-005 — FAILED — Config-driven review commands replacing hardcoded lint — All tiers exhausted
|
|
3
|
+
[2026-02-27T11:24:08.156Z] US-006 — FAILED — PRD auto-default and router tags fix — All tiers exhausted
|
|
4
|
+
[2026-02-27T12:12:00.514Z] US-001 — FAILED — Precheck types and check implementations — All tiers exhausted
|
|
5
|
+
[2026-02-27T15:30:00.000Z] US-003 — PASSED — CLI nax precheck command with --json flag — Implementation complete
|
|
6
|
+
|
|
7
|
+
Implementation summary:
|
|
8
|
+
- Created src/commands/precheck.ts with precheckCommand()
|
|
9
|
+
- Registered command in bin/nax.ts with -f, -d, and --json flags
|
|
10
|
+
- Uses resolveProject() for directory resolution (same as status/logs)
|
|
11
|
+
- Calls runPrecheck() orchestrator from US-002
|
|
12
|
+
- Returns proper exit codes: 0=pass, 1=blocker, 2=invalid PRD
|
|
13
|
+
- 7 integration tests in test/integration/cli-precheck.test.ts
|
|
14
|
+
- All acceptance criteria verified
|
|
15
|
+
[2026-02-27T14:00:33.162Z] US-003 — FAILED — CLI nax precheck command with --json flag — All tiers exhausted
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": "nax",
|
|
3
|
+
"feature": "structured-logging",
|
|
4
|
+
"branchName": "feat/structured-logging",
|
|
5
|
+
"createdAt": "2026-02-27T05:50:00Z",
|
|
6
|
+
"updatedAt": "2026-02-27T08:42:37.832Z",
|
|
7
|
+
"userStories": [
|
|
8
|
+
{
|
|
9
|
+
"id": "US-001",
|
|
10
|
+
"title": "Project resolver with CWD and -d flag support",
|
|
11
|
+
"description": "Create src/commands/common.ts with resolveProject(options) function. Resolution order: 1) -d flag path, 2) CWD if it contains nax/ directory, 3) Error with helpful message. Validate: nax/ exists, nax/config.json exists. If -f flag given, validate nax/features/<name>/ exists. Return resolved {projectDir, configPath, featureDir?}. This is shared by status, logs, and future CLI commands.",
|
|
12
|
+
"acceptanceCriteria": [
|
|
13
|
+
"resolveProject() returns projectDir when CWD has nax/ directory",
|
|
14
|
+
"resolveProject({dir:\"/path\"}) uses explicit directory",
|
|
15
|
+
"Throws descriptive error when no nax/ directory found",
|
|
16
|
+
"Validates nax/config.json exists in resolved directory",
|
|
17
|
+
"When feature specified, validates nax/features/<name>/ exists",
|
|
18
|
+
"Error message lists available features when feature not found",
|
|
19
|
+
"Works with both relative and absolute -d paths"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": [],
|
|
22
|
+
"tags": [
|
|
23
|
+
"cli",
|
|
24
|
+
"resolver"
|
|
25
|
+
],
|
|
26
|
+
"status": "passed",
|
|
27
|
+
"attempts": 2,
|
|
28
|
+
"priorErrors": [
|
|
29
|
+
"Attempt 1 failed with model tier: balanced",
|
|
30
|
+
"Attempt 2 failed with model tier: balanced"
|
|
31
|
+
],
|
|
32
|
+
"escalations": []
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "US-002",
|
|
36
|
+
"title": "Human-friendly logging formatter with verbosity levels",
|
|
37
|
+
"description": "Create src/logging/formatter.ts and src/logging/types.ts. Transform JSONL entries into human-readable output with emoji indicators. Support 4 modes: quiet, normal, verbose, json. Include run header, story progress with tree-style output, stage results with emoji, retry indicators, run summary footer.",
|
|
38
|
+
"acceptanceCriteria": [
|
|
39
|
+
"formatLogEntry renders story start with title, complexity, tier",
|
|
40
|
+
"formatLogEntry renders stage results with appropriate emoji",
|
|
41
|
+
"formatRunSummary renders pass/fail/duration/cost stats",
|
|
42
|
+
"quiet mode only shows pass/fail + summary",
|
|
43
|
+
"verbose mode includes routing, tokens, context files",
|
|
44
|
+
"json mode passes through raw JSONL",
|
|
45
|
+
"Timestamps formatted in local timezone HH:MM:SS"
|
|
46
|
+
],
|
|
47
|
+
"dependencies": [],
|
|
48
|
+
"tags": [
|
|
49
|
+
"logging",
|
|
50
|
+
"formatter"
|
|
51
|
+
],
|
|
52
|
+
"status": "passed",
|
|
53
|
+
"attempts": 0,
|
|
54
|
+
"priorErrors": [],
|
|
55
|
+
"escalations": []
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "US-003",
|
|
59
|
+
"title": "status.json writer for live run state",
|
|
60
|
+
"description": "Create src/logging/status-writer.ts. Maintain status.json at nax/features/<feature>/status.json during runs. Write on: run start (runId, feature, totalStories, pid), story start (currentStory), story complete (status/duration/cost/commit), run end (completed/failed + totals). Atomic writes via tmp+rename.",
|
|
61
|
+
"acceptanceCriteria": [
|
|
62
|
+
"status.json created at run start with runId, feature, startedAt, pid, status=running",
|
|
63
|
+
"Updates currentStory on story begin",
|
|
64
|
+
"Updates story entry on completion",
|
|
65
|
+
"Updates totals after each story",
|
|
66
|
+
"Status changes to completed/failed at run end",
|
|
67
|
+
"Atomic writes prevent corruption",
|
|
68
|
+
"PID included for crash detection"
|
|
69
|
+
],
|
|
70
|
+
"dependencies": [],
|
|
71
|
+
"tags": [
|
|
72
|
+
"logging",
|
|
73
|
+
"state"
|
|
74
|
+
],
|
|
75
|
+
"status": "passed",
|
|
76
|
+
"attempts": 1,
|
|
77
|
+
"priorErrors": [
|
|
78
|
+
"Attempt 1 failed with model tier: balanced"
|
|
79
|
+
],
|
|
80
|
+
"escalations": [],
|
|
81
|
+
"passes": true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "US-004",
|
|
85
|
+
"title": "nax status command with active run detection",
|
|
86
|
+
"description": "Create src/commands/status.ts, register in CLI. Uses resolveProject(). Show feature table (done/failed/pending, last run, cost). Detect active run via status.json+PID. Detect crash via status.json+dead PID. Support -f for single feature.",
|
|
87
|
+
"acceptanceCriteria": [
|
|
88
|
+
"Shows table of all features with counts and last run",
|
|
89
|
+
"Detailed single-feature view with story table",
|
|
90
|
+
"Active run detected via PID alive check",
|
|
91
|
+
"Crashed run shows warning with recovery hints",
|
|
92
|
+
"No status.json shows No runs yet",
|
|
93
|
+
"Uses resolveProject() for resolution",
|
|
94
|
+
"Registered as CLI subcommand"
|
|
95
|
+
],
|
|
96
|
+
"dependencies": [
|
|
97
|
+
"US-001",
|
|
98
|
+
"US-003"
|
|
99
|
+
],
|
|
100
|
+
"tags": [
|
|
101
|
+
"cli",
|
|
102
|
+
"status"
|
|
103
|
+
],
|
|
104
|
+
"status": "passed",
|
|
105
|
+
"attempts": 0,
|
|
106
|
+
"priorErrors": [],
|
|
107
|
+
"escalations": [],
|
|
108
|
+
"passes": true
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "US-005",
|
|
112
|
+
"title": "nax logs command with filtering and follow mode",
|
|
113
|
+
"description": "Create src/commands/logs.ts, register in CLI. Uses resolveProject(). Supports: default (latest run formatted), --follow (tail -f), --story (filter), --level (filter), --list (run table), --run (specific run), --json (raw). Uses formatter from US-002.",
|
|
114
|
+
"acceptanceCriteria": [
|
|
115
|
+
"Shows latest run logs formatted",
|
|
116
|
+
"--follow streams new entries real-time",
|
|
117
|
+
"--story filters to one story",
|
|
118
|
+
"--level filters by severity",
|
|
119
|
+
"--list shows runs table",
|
|
120
|
+
"--run selects specific run",
|
|
121
|
+
"--json outputs raw JSONL",
|
|
122
|
+
"Filters combinable",
|
|
123
|
+
"Uses resolveProject()"
|
|
124
|
+
],
|
|
125
|
+
"dependencies": [
|
|
126
|
+
"US-001",
|
|
127
|
+
"US-002"
|
|
128
|
+
],
|
|
129
|
+
"tags": [
|
|
130
|
+
"cli",
|
|
131
|
+
"logs"
|
|
132
|
+
],
|
|
133
|
+
"status": "passed",
|
|
134
|
+
"attempts": 1,
|
|
135
|
+
"priorErrors": [],
|
|
136
|
+
"escalations": [],
|
|
137
|
+
"passes": true
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "US-006",
|
|
141
|
+
"title": "Integrate formatter into headless runner",
|
|
142
|
+
"description": "Modify src/execution/runner.ts to use formatter for headless stdout instead of raw JSONL. Default=normal. Add --quiet/--verbose/--json flags to nax run. Wire status-writer into run loop. JSONL still written to disk. Integrate status.json updates at lifecycle points.",
|
|
143
|
+
"acceptanceCriteria": [
|
|
144
|
+
"Headless stdout shows formatted output by default",
|
|
145
|
+
"JSONL still written to disk (unchanged)",
|
|
146
|
+
"--json flag restores raw JSONL stdout",
|
|
147
|
+
"--quiet and --verbose flags work",
|
|
148
|
+
"status.json written throughout lifecycle",
|
|
149
|
+
"Run header with version, feature, count, path",
|
|
150
|
+
"Run footer with summary stats"
|
|
151
|
+
],
|
|
152
|
+
"dependencies": [
|
|
153
|
+
"US-002",
|
|
154
|
+
"US-003"
|
|
155
|
+
],
|
|
156
|
+
"tags": [
|
|
157
|
+
"runner",
|
|
158
|
+
"integration"
|
|
159
|
+
],
|
|
160
|
+
"status": "passed",
|
|
161
|
+
"attempts": 0,
|
|
162
|
+
"priorErrors": [],
|
|
163
|
+
"escalations": [],
|
|
164
|
+
"passes": true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"id": "US-007",
|
|
168
|
+
"title": "Crash recovery with signal handlers heartbeat and exit summary",
|
|
169
|
+
"description": "Add SIGTERM/SIGINT/SIGHUP handlers and uncaught exception handlers. On signal: write fatal JSONL + update status.json to crashed + exit. During agent execution: heartbeat every 60s. On normal exit: write exit summary entry.",
|
|
170
|
+
"acceptanceCriteria": [
|
|
171
|
+
"Signal handlers write fatal log with signal name",
|
|
172
|
+
"Signal handlers update status.json to crashed",
|
|
173
|
+
"Uncaught exceptions write fatal log with stack",
|
|
174
|
+
"Heartbeat every 60s during agent execution",
|
|
175
|
+
"Normal exit writes summary entry",
|
|
176
|
+
"Signal handlers exit cleanly",
|
|
177
|
+
"Heartbeat timer cleaned up on story completion"
|
|
178
|
+
],
|
|
179
|
+
"dependencies": [
|
|
180
|
+
"US-003"
|
|
181
|
+
],
|
|
182
|
+
"tags": [
|
|
183
|
+
"crash-recovery",
|
|
184
|
+
"signals"
|
|
185
|
+
],
|
|
186
|
+
"status": "passed",
|
|
187
|
+
"attempts": 1,
|
|
188
|
+
"priorErrors": [
|
|
189
|
+
"Attempt 1 failed with model tier: balanced"
|
|
190
|
+
],
|
|
191
|
+
"escalations": [],
|
|
192
|
+
"passes": true
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
"analyzeConfig": {
|
|
196
|
+
"maxStories": 15,
|
|
197
|
+
"granularity": "medium"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"feature": "unlock",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"project": "nax",
|
|
5
|
+
"branchName": "feat/unlock-command",
|
|
6
|
+
"description": "Implement `nax unlock` CLI command to safely release a stale execution lock (nax.lock) without requiring manual filesystem access.",
|
|
7
|
+
"userStories": [
|
|
8
|
+
{
|
|
9
|
+
"id": "US-001",
|
|
10
|
+
"title": "nax unlock command releases stale lock safely",
|
|
11
|
+
"description": "Add a `nax unlock` CLI command to bin/nax.ts and implement its logic in src/commands/unlock.ts.\n\nExisting patterns to follow:\n- Look at src/commands/precheck.ts for a complete command example (imports, structure, Commander wiring)\n- Look at src/execution/lock.ts for acquireLock/releaseLock/isProcessAlive logic\n- Look at test/unit/commands/ for existing unit test examples (e.g. test/unit/commands/precheck.test.ts)\n- Tests go in: test/unit/commands/unlock.test.ts\n- Test runner: `bun test --no-coverage test/unit/commands/unlock.test.ts`\n\nThe command must:\n- Read nax.lock and verify the holding process is actually dead before removing\n- Refuse to unlock if the lock-holding process is still alive (active run)\n- Print the lock state (PID, age, alive/dead) before acting\n- Accept `--force` flag to skip the liveness check and remove unconditionally\n- Accept `-d <dir>` / `--dir <dir>` flag to target a specific project directory (defaults to cwd)\n- Exit 0 on success, non-zero on failure\n- Export an `unlockCommand` function and wire into bin/nax.ts program",
|
|
12
|
+
"acceptanceCriteria": [
|
|
13
|
+
"AC1: `nax unlock` with no lock file prints 'No lock file found' and exits 0",
|
|
14
|
+
"AC2: `nax unlock` when lock PID is alive prints error 'nax is still running (PID <n>). Use --force to override.' and exits 1 without deleting lock",
|
|
15
|
+
"AC3: `nax unlock` when lock PID is dead prints lock info (PID, age in minutes) then removes nax.lock and exits 0",
|
|
16
|
+
"AC4: `nax unlock --force` removes nax.lock unconditionally regardless of process state and exits 0",
|
|
17
|
+
"AC5: `nax unlock -d <path>` targets the specified directory (not cwd)",
|
|
18
|
+
"AC6: Unit tests in test/unit/commands/unlock.test.ts cover all four scenarios (no lock, alive, dead, force)"
|
|
19
|
+
],
|
|
20
|
+
"complexity": "simple",
|
|
21
|
+
"status": "paused",
|
|
22
|
+
"contextFiles": [
|
|
23
|
+
"src/commands/precheck.ts",
|
|
24
|
+
"src/execution/lock.ts",
|
|
25
|
+
"bin/nax.ts"
|
|
26
|
+
],
|
|
27
|
+
"attempts": 1,
|
|
28
|
+
"priorErrors": [],
|
|
29
|
+
"escalations": [],
|
|
30
|
+
"dependencies": [],
|
|
31
|
+
"tags": [],
|
|
32
|
+
"storyPoints": 1
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"updatedAt": "2026-03-01T09:04:03.679Z"
|
|
36
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nathapp/nax",
|
|
3
|
+
"version": "0.18.1",
|
|
4
|
+
"description": "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"nax": "./bin/nax.ts"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "bun run bin/nax.ts",
|
|
11
|
+
"build": "bun build bin/nax.ts --outdir dist --target bun",
|
|
12
|
+
"typecheck": "bun x tsc --noEmit",
|
|
13
|
+
"lint": "bun x biome check src/ bin/",
|
|
14
|
+
"test": "NAX_SKIP_PRECHECK=1 bun test test/ --timeout=60000",
|
|
15
|
+
"test:watch": "bun test --watch",
|
|
16
|
+
"test:unit": "bun test ./test/unit/ --timeout=60000",
|
|
17
|
+
"test:integration": "bun test ./test/integration/ --timeout=60000",
|
|
18
|
+
"test:ui": "bun test ./test/ui/ --timeout=60000"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@anthropic-ai/sdk": "^0.74.0",
|
|
22
|
+
"@types/react": "^19.2.14",
|
|
23
|
+
"chalk": "^5.6.2",
|
|
24
|
+
"commander": "^13.1.0",
|
|
25
|
+
"ink": "^6.7.0",
|
|
26
|
+
"ink-spinner": "^5.0.0",
|
|
27
|
+
"ink-testing-library": "^4.0.0",
|
|
28
|
+
"node-pty": "^1.1.0",
|
|
29
|
+
"react": "^19.2.4",
|
|
30
|
+
"zod": "^4.3.6"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@biomejs/biome": "^1.9.4",
|
|
34
|
+
"@types/bun": "^1.2.4",
|
|
35
|
+
"react-devtools-core": "^7.0.1",
|
|
36
|
+
"typescript": "^5.7.3"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"author": "William Khoo",
|
|
40
|
+
"keywords": [
|
|
41
|
+
"ai",
|
|
42
|
+
"agent",
|
|
43
|
+
"orchestrator",
|
|
44
|
+
"tdd",
|
|
45
|
+
"coding"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fix Story Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates fix stories from failed acceptance criteria.
|
|
5
|
+
* Maps failed ACs to related stories and creates targeted fix descriptions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AgentAdapter } from "../agents/types";
|
|
9
|
+
import type { ModelDef } from "../config/schema";
|
|
10
|
+
import { getLogger } from "../logger";
|
|
11
|
+
import type { PRD, UserStory } from "../prd/types";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A fix story generated from a failed acceptance criterion.
|
|
15
|
+
*
|
|
16
|
+
* Fix stories are appended to the PRD and executed through the normal pipeline.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const fixStory: FixStory = {
|
|
21
|
+
* id: "US-FIX-001",
|
|
22
|
+
* title: "Fix: AC-2 TTL expiry timing",
|
|
23
|
+
* failedAC: "AC-2",
|
|
24
|
+
* testOutput: "Expected undefined, got 'value'",
|
|
25
|
+
* relatedStories: ["US-002"],
|
|
26
|
+
* description: "Update TTL implementation to properly expire entries...",
|
|
27
|
+
* };
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface FixStory {
|
|
31
|
+
/** Story ID (e.g., "US-FIX-001") */
|
|
32
|
+
id: string;
|
|
33
|
+
/** Story title */
|
|
34
|
+
title: string;
|
|
35
|
+
/** Failed AC identifier (e.g., "AC-2") */
|
|
36
|
+
failedAC: string;
|
|
37
|
+
/** Test output showing actual vs expected */
|
|
38
|
+
testOutput: string;
|
|
39
|
+
/** Original stories that built this functionality */
|
|
40
|
+
relatedStories: string[];
|
|
41
|
+
/** LLM-generated fix description */
|
|
42
|
+
description: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Options for generating fix stories.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const options: GenerateFixStoriesOptions = {
|
|
51
|
+
* failedACs: ["AC-2", "AC-5"],
|
|
52
|
+
* testOutput: "...",
|
|
53
|
+
* prd: loadedPRD,
|
|
54
|
+
* specContent: "# Feature...",
|
|
55
|
+
* workdir: "/project",
|
|
56
|
+
* modelDef: { provider: "anthropic", model: "claude-sonnet-4-5" },
|
|
57
|
+
* };
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export interface GenerateFixStoriesOptions {
|
|
61
|
+
/** Failed AC identifiers */
|
|
62
|
+
failedACs: string[];
|
|
63
|
+
/** Full test output from bun test */
|
|
64
|
+
testOutput: string;
|
|
65
|
+
/** Current PRD with all stories */
|
|
66
|
+
prd: PRD;
|
|
67
|
+
/** Original spec.md content */
|
|
68
|
+
specContent: string;
|
|
69
|
+
/** Working directory */
|
|
70
|
+
workdir: string;
|
|
71
|
+
/** Model definition for LLM call */
|
|
72
|
+
modelDef: ModelDef;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Map failed ACs to related stories.
|
|
77
|
+
*
|
|
78
|
+
* Uses heuristics to find which stories likely implemented the failed AC:
|
|
79
|
+
* 1. Stories with matching AC in acceptanceCriteria
|
|
80
|
+
* 2. Stories with similar keywords in description
|
|
81
|
+
* 3. Recently completed stories (if no better match)
|
|
82
|
+
*
|
|
83
|
+
* @param failedAC - Failed AC identifier (e.g., "AC-2")
|
|
84
|
+
* @param prd - Current PRD
|
|
85
|
+
* @returns Array of related story IDs
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const related = findRelatedStories("AC-2", prd);
|
|
90
|
+
* // Returns: ["US-002", "US-005"]
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export function findRelatedStories(failedAC: string, prd: PRD): string[] {
|
|
94
|
+
const relatedStoryIds: string[] = [];
|
|
95
|
+
|
|
96
|
+
// Strategy 1: Find stories with this AC in their acceptanceCriteria
|
|
97
|
+
for (const story of prd.userStories) {
|
|
98
|
+
for (const ac of story.acceptanceCriteria) {
|
|
99
|
+
if (ac.includes(failedAC)) {
|
|
100
|
+
relatedStoryIds.push(story.id);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// If we found stories with matching AC, return those
|
|
107
|
+
if (relatedStoryIds.length > 0) {
|
|
108
|
+
return relatedStoryIds;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Strategy 2: Return all passed stories (fallback)
|
|
112
|
+
// The LLM will figure out which code is relevant
|
|
113
|
+
const passedStories = prd.userStories.filter((s) => s.status === "passed").map((s) => s.id);
|
|
114
|
+
|
|
115
|
+
return passedStories.slice(0, 5); // Limit to 5 most recent
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Build LLM prompt for generating a fix story.
|
|
120
|
+
*
|
|
121
|
+
* @param failedAC - Failed AC identifier
|
|
122
|
+
* @param acText - Original AC text from spec
|
|
123
|
+
* @param testOutput - Test failure output
|
|
124
|
+
* @param relatedStories - Related story IDs
|
|
125
|
+
* @param prd - Current PRD
|
|
126
|
+
* @returns Formatted prompt string
|
|
127
|
+
*/
|
|
128
|
+
export function buildFixPrompt(
|
|
129
|
+
failedAC: string,
|
|
130
|
+
acText: string,
|
|
131
|
+
testOutput: string,
|
|
132
|
+
relatedStories: string[],
|
|
133
|
+
prd: PRD,
|
|
134
|
+
): string {
|
|
135
|
+
const relatedStoriesText = relatedStories
|
|
136
|
+
.map((id) => {
|
|
137
|
+
const story = prd.userStories.find((s) => s.id === id);
|
|
138
|
+
if (!story) return "";
|
|
139
|
+
return `${story.id}: ${story.title}\n ${story.description}`;
|
|
140
|
+
})
|
|
141
|
+
.filter(Boolean)
|
|
142
|
+
.join("\n\n");
|
|
143
|
+
|
|
144
|
+
return `You are a debugging expert. A feature acceptance test has failed.
|
|
145
|
+
|
|
146
|
+
FAILED ACCEPTANCE CRITERION:
|
|
147
|
+
${failedAC}: ${acText}
|
|
148
|
+
|
|
149
|
+
TEST FAILURE OUTPUT:
|
|
150
|
+
${testOutput}
|
|
151
|
+
|
|
152
|
+
RELATED STORIES (implemented this functionality):
|
|
153
|
+
${relatedStoriesText}
|
|
154
|
+
|
|
155
|
+
Your task: Generate a fix story description that will make the acceptance test pass.
|
|
156
|
+
|
|
157
|
+
Requirements:
|
|
158
|
+
1. Analyze the test failure to understand the root cause
|
|
159
|
+
2. Identify what needs to change in the code
|
|
160
|
+
3. Write a clear, actionable fix description (2-4 sentences)
|
|
161
|
+
4. Focus on the specific issue, not general improvements
|
|
162
|
+
5. Reference the relevant story IDs if needed
|
|
163
|
+
|
|
164
|
+
Respond with ONLY the fix description (no JSON, no markdown, just the description text).`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Generate fix stories from failed acceptance criteria.
|
|
169
|
+
*
|
|
170
|
+
* For each failed AC:
|
|
171
|
+
* 1. Find related stories
|
|
172
|
+
* 2. Build LLM prompt with context
|
|
173
|
+
* 3. Generate fix description
|
|
174
|
+
* 4. Create FixStory object
|
|
175
|
+
*
|
|
176
|
+
* @param adapter - Agent adapter for LLM calls
|
|
177
|
+
* @param options - Generation options
|
|
178
|
+
* @returns Array of generated fix stories
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* const adapter = new ClaudeCodeAdapter();
|
|
183
|
+
* const fixStories = await generateFixStories(adapter, {
|
|
184
|
+
* failedACs: ["AC-2", "AC-5"],
|
|
185
|
+
* testOutput: "...",
|
|
186
|
+
* prd: loadedPRD,
|
|
187
|
+
* specContent: "...",
|
|
188
|
+
* workdir: "/project",
|
|
189
|
+
* modelDef: { provider: "anthropic", model: "claude-sonnet-4-5" },
|
|
190
|
+
* });
|
|
191
|
+
*
|
|
192
|
+
* // Append to PRD
|
|
193
|
+
* prd.userStories.push(...fixStories.map(convertToUserStory));
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export async function generateFixStories(
|
|
197
|
+
adapter: AgentAdapter,
|
|
198
|
+
options: GenerateFixStoriesOptions,
|
|
199
|
+
): Promise<FixStory[]> {
|
|
200
|
+
const { failedACs, testOutput, prd, specContent, workdir, modelDef } = options;
|
|
201
|
+
|
|
202
|
+
const fixStories: FixStory[] = [];
|
|
203
|
+
|
|
204
|
+
// Parse spec to get AC text
|
|
205
|
+
const acTextMap = parseACTextFromSpec(specContent);
|
|
206
|
+
|
|
207
|
+
const logger = getLogger();
|
|
208
|
+
for (let i = 0; i < failedACs.length; i++) {
|
|
209
|
+
const failedAC = failedACs[i];
|
|
210
|
+
const acText = acTextMap[failedAC] || "No description available";
|
|
211
|
+
|
|
212
|
+
logger.info("acceptance", "Generating fix for failed AC", { failedAC });
|
|
213
|
+
|
|
214
|
+
// Find related stories
|
|
215
|
+
const relatedStories = findRelatedStories(failedAC, prd);
|
|
216
|
+
|
|
217
|
+
if (relatedStories.length === 0) {
|
|
218
|
+
logger.warn("acceptance", "⚠ No related stories found for failed AC — skipping", { failedAC });
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Build prompt
|
|
223
|
+
const prompt = buildFixPrompt(failedAC, acText, testOutput, relatedStories, prd);
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
// Call agent to generate fix description
|
|
227
|
+
const cmd = [adapter.binary, "--model", modelDef.model, "--dangerously-skip-permissions", "-p", prompt];
|
|
228
|
+
|
|
229
|
+
const proc = Bun.spawn(cmd, {
|
|
230
|
+
cwd: workdir,
|
|
231
|
+
stdout: "pipe",
|
|
232
|
+
stderr: "pipe",
|
|
233
|
+
env: {
|
|
234
|
+
...process.env,
|
|
235
|
+
...(modelDef.env || {}),
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const exitCode = await proc.exited;
|
|
240
|
+
const stdout = await new Response(proc.stdout).text();
|
|
241
|
+
const stderr = await new Response(proc.stderr).text();
|
|
242
|
+
|
|
243
|
+
if (exitCode !== 0) {
|
|
244
|
+
logger.warn("acceptance", "⚠ Agent fix generation failed", { failedAC, stderr });
|
|
245
|
+
// Use fallback description
|
|
246
|
+
fixStories.push({
|
|
247
|
+
id: `US-FIX-${String(i + 1).padStart(3, "0")}`,
|
|
248
|
+
title: `Fix: ${failedAC}`,
|
|
249
|
+
failedAC,
|
|
250
|
+
testOutput,
|
|
251
|
+
relatedStories,
|
|
252
|
+
description: `Fix the implementation to make ${failedAC} pass. Related stories: ${relatedStories.join(", ")}.`,
|
|
253
|
+
});
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Extract fix description
|
|
258
|
+
const fixDescription = stdout.trim();
|
|
259
|
+
|
|
260
|
+
fixStories.push({
|
|
261
|
+
id: `US-FIX-${String(i + 1).padStart(3, "0")}`,
|
|
262
|
+
title: `Fix: ${failedAC} — ${acText.slice(0, 50)}`,
|
|
263
|
+
failedAC,
|
|
264
|
+
testOutput,
|
|
265
|
+
relatedStories,
|
|
266
|
+
description: fixDescription,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
logger.info("acceptance", "✓ Generated fix story", { storyId: fixStories[fixStories.length - 1].id });
|
|
270
|
+
} catch (error) {
|
|
271
|
+
logger.warn("acceptance", "⚠ Error generating fix", {
|
|
272
|
+
failedAC,
|
|
273
|
+
error: (error as Error).message,
|
|
274
|
+
});
|
|
275
|
+
// Use fallback
|
|
276
|
+
fixStories.push({
|
|
277
|
+
id: `US-FIX-${String(i + 1).padStart(3, "0")}`,
|
|
278
|
+
title: `Fix: ${failedAC}`,
|
|
279
|
+
failedAC,
|
|
280
|
+
testOutput,
|
|
281
|
+
relatedStories,
|
|
282
|
+
description: `Fix the implementation to make ${failedAC} pass. Related stories: ${relatedStories.join(", ")}.`,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return fixStories;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Parse AC text from spec.md content.
|
|
292
|
+
*
|
|
293
|
+
* Extracts AC-N lines and maps them to their text descriptions.
|
|
294
|
+
*
|
|
295
|
+
* @param specContent - Full spec.md content
|
|
296
|
+
* @returns Map of AC ID to text (e.g., { "AC-2": "set(key, value, ttl)..." })
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```ts
|
|
300
|
+
* const spec = "- AC-1: handles empty input\n- AC-2: TTL expiry";
|
|
301
|
+
* const map = parseACTextFromSpec(spec);
|
|
302
|
+
* // Returns: { "AC-1": "handles empty input", "AC-2": "TTL expiry" }
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
export function parseACTextFromSpec(specContent: string): Record<string, string> {
|
|
306
|
+
const map: Record<string, string> = {};
|
|
307
|
+
const lines = specContent.split("\n");
|
|
308
|
+
|
|
309
|
+
for (const line of lines) {
|
|
310
|
+
const acMatch = line.match(/^\s*-?\s*(?:\[.\])?\s*(AC-\d+):\s*(.+)$/i);
|
|
311
|
+
if (acMatch) {
|
|
312
|
+
const id = acMatch[1].toUpperCase();
|
|
313
|
+
const text = acMatch[2].trim();
|
|
314
|
+
map[id] = text;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return map;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Convert a FixStory to a UserStory for PRD insertion.
|
|
323
|
+
*
|
|
324
|
+
* @param fixStory - Fix story to convert
|
|
325
|
+
* @returns UserStory object ready for PRD
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* const fixStory: FixStory = { id: "US-FIX-001", ... };
|
|
330
|
+
* const userStory = convertFixStoryToUserStory(fixStory);
|
|
331
|
+
* prd.userStories.push(userStory);
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
export function convertFixStoryToUserStory(fixStory: FixStory): UserStory {
|
|
335
|
+
return {
|
|
336
|
+
id: fixStory.id,
|
|
337
|
+
title: fixStory.title,
|
|
338
|
+
description: fixStory.description,
|
|
339
|
+
acceptanceCriteria: [`Fix ${fixStory.failedAC}`],
|
|
340
|
+
tags: ["fix", "acceptance-failure"],
|
|
341
|
+
dependencies: fixStory.relatedStories,
|
|
342
|
+
status: "pending",
|
|
343
|
+
passes: false,
|
|
344
|
+
escalations: [],
|
|
345
|
+
attempts: 0,
|
|
346
|
+
contextFiles: [],
|
|
347
|
+
};
|
|
348
|
+
}
|