@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.
Files changed (459) hide show
  1. package/.gitlab-ci.yml +96 -0
  2. package/BRIEF.md +140 -0
  3. package/CHANGELOG.md +60 -0
  4. package/CLAUDE.md +159 -0
  5. package/README.md +373 -0
  6. package/US-007-IMPLEMENTATION.md +139 -0
  7. package/bin/nax.ts +930 -0
  8. package/biome.json +14 -0
  9. package/bun.lock +168 -0
  10. package/bunfig.toml +11 -0
  11. package/docs/20260216-fix-plan-context-review.md +56 -0
  12. package/docs/20260216-relentless-vs-ngent-comparison.md +208 -0
  13. package/docs/20260216-v02-plan.md +136 -0
  14. package/docs/20260216-v02-review.md +685 -0
  15. package/docs/20260217-dogfood-findings.md +56 -0
  16. package/docs/20260217-p2-plus-plan.md +117 -0
  17. package/docs/20260217-partial-fixes-plan.md +62 -0
  18. package/docs/20260217-plan-analyze-spec.md +117 -0
  19. package/docs/20260217-post-impl-review.md +1137 -0
  20. package/docs/20260217-quick-wins-plan.md +66 -0
  21. package/docs/20260217-split-runner-plan.md +75 -0
  22. package/docs/20260217-v03-impl-plan.md +80 -0
  23. package/docs/20260217-v03-post-impl-review.md +589 -0
  24. package/docs/20260217-v04-impl-plan.md +86 -0
  25. package/docs/20260217-v05-post-impl-review.md +850 -0
  26. package/docs/20260217-v06-post-impl-review.md +817 -0
  27. package/docs/20260218-adr003-port-plan.md +151 -0
  28. package/docs/20260218-review-adr003-verification.md +175 -0
  29. package/docs/20260219-fix-plan-bug16-19.md +79 -0
  30. package/docs/20260219-fix-plan-bug20-22.md +114 -0
  31. package/docs/20260219-plan-llm-routing.md +116 -0
  32. package/docs/20260219-review-bug20-22-fixes.md +135 -0
  33. package/docs/20260219-routing-baseline-keyword.md +63 -0
  34. package/docs/20260220-plan-structured-logging-p1.md +80 -0
  35. package/docs/20260220-plan-structured-logging-p2.md +37 -0
  36. package/docs/20260220-review-llm-routing.md +180 -0
  37. package/docs/20260220-review-post-fix-llm-routing.md +70 -0
  38. package/docs/20260221-fix-plan-relevantfiles-split.md +101 -0
  39. package/docs/20260221-fix-plan-routing-mode.md +125 -0
  40. package/docs/20260221-review-v0.9-implementation.md +379 -0
  41. package/docs/20260222-fix-plan-v091-routing-isolation.md +197 -0
  42. package/docs/20260223-fix-plan-prompt-audit.md +62 -0
  43. package/docs/20260224-nax-roadmap-phases.md +189 -0
  44. package/docs/20260225-phase2-llm-service-layer.md +401 -0
  45. package/docs/20260225-review-v0.10.1.md +187 -0
  46. package/docs/20260303-v010-implementation-plan.md +165 -0
  47. package/docs/CLAUDE.md.bak +191 -0
  48. package/docs/ROADMAP.md +165 -0
  49. package/docs/SPEC-rectification.md +0 -0
  50. package/docs/SPEC.md +324 -0
  51. package/docs/US-001-plugin-loading-verification.md +152 -0
  52. package/docs/architecture-analysis.md +1076 -0
  53. package/docs/bugs/BUG-21-escalation-null-attempts.md +48 -0
  54. package/docs/bugs-from-dogfood-run-c.md +243 -0
  55. package/docs/code-review-20260228.md +612 -0
  56. package/docs/code-review-v0.15.0.md +629 -0
  57. package/docs/hook-lifecycle-test-plan.md +149 -0
  58. package/docs/releases/v0.11.0-and-earlier.md +20 -0
  59. package/docs/releases/v0.12.0.md +15 -0
  60. package/docs/releases/v0.13.0.md +14 -0
  61. package/docs/releases/v0.14.0.md +20 -0
  62. package/docs/releases/v0.14.1.md +36 -0
  63. package/docs/releases/v0.14.2.md +51 -0
  64. package/docs/releases/v0.14.3.md +174 -0
  65. package/docs/releases/v0.14.4.md +94 -0
  66. package/docs/releases/v0.15.0.md +502 -0
  67. package/docs/releases/v0.15.1.md +170 -0
  68. package/docs/releases/v0.15.3.md +193 -0
  69. package/docs/specs/status-file-v0.10.1.md +812 -0
  70. package/docs/v0.10-global-config.md +206 -0
  71. package/docs/v0.10-plugin-system.md +415 -0
  72. package/docs/v0.10-prompt-optimizer.md +234 -0
  73. package/docs/v0.3-spec.md +244 -0
  74. package/docs/v0.4-spec.md +140 -0
  75. package/docs/v0.5-spec.md +237 -0
  76. package/docs/v0.6-spec.md +371 -0
  77. package/docs/v0.7-spec.md +177 -0
  78. package/docs/v0.8-llm-routing.md +206 -0
  79. package/docs/v0.8-structured-logging.md +132 -0
  80. package/docs/v0.9.3-prompt-audit.md +112 -0
  81. package/examples/plugins/console-reporter/index.test.ts +207 -0
  82. package/examples/plugins/console-reporter/index.ts +110 -0
  83. package/nax/config.json +147 -0
  84. package/nax/features/bugfix-v0171/prd.json +52 -0
  85. package/nax/features/config-management/prd.json +108 -0
  86. package/nax/features/config-management/progress.txt +5 -0
  87. package/nax/features/diagnose/acceptance.test.ts +412 -0
  88. package/nax/features/diagnose/prd.json +41 -0
  89. package/nax/features/orchestration-fixes/prd.json +89 -0
  90. package/nax/features/orchestration-fixes/progress.txt +1 -0
  91. package/nax/features/plugin-integration/US-007-VERIFICATION.md +259 -0
  92. package/nax/features/plugin-integration/prd.json +208 -0
  93. package/nax/features/plugin-integration/progress.txt +5 -0
  94. package/nax/features/precheck/prd.json +205 -0
  95. package/nax/features/precheck/progress.txt +15 -0
  96. package/nax/features/structured-logging/prd.json +199 -0
  97. package/nax/features/unlock/prd.json +36 -0
  98. package/package.json +47 -0
  99. package/src/acceptance/fix-generator.ts +348 -0
  100. package/src/acceptance/generator.ts +282 -0
  101. package/src/acceptance/index.ts +30 -0
  102. package/src/acceptance/types.ts +79 -0
  103. package/src/agents/claude-decompose.ts +169 -0
  104. package/src/agents/claude-plan.ts +139 -0
  105. package/src/agents/claude.ts +324 -0
  106. package/src/agents/cost.ts +268 -0
  107. package/src/agents/index.ts +13 -0
  108. package/src/agents/registry.ts +48 -0
  109. package/src/agents/types-extended.ts +133 -0
  110. package/src/agents/types.ts +113 -0
  111. package/src/agents/validation.ts +69 -0
  112. package/src/analyze/classifier.ts +305 -0
  113. package/src/analyze/index.ts +16 -0
  114. package/src/analyze/scanner.ts +175 -0
  115. package/src/analyze/types.ts +51 -0
  116. package/src/cli/accept.ts +108 -0
  117. package/src/cli/analyze-parser.ts +284 -0
  118. package/src/cli/analyze.ts +207 -0
  119. package/src/cli/config.ts +561 -0
  120. package/src/cli/constitution.ts +109 -0
  121. package/src/cli/diagnose-analysis.ts +159 -0
  122. package/src/cli/diagnose-formatter.ts +87 -0
  123. package/src/cli/diagnose.ts +203 -0
  124. package/src/cli/generate.ts +127 -0
  125. package/src/cli/index.ts +37 -0
  126. package/src/cli/init.ts +188 -0
  127. package/src/cli/interact.ts +295 -0
  128. package/src/cli/plan.ts +198 -0
  129. package/src/cli/plugins.ts +111 -0
  130. package/src/cli/prompts.ts +295 -0
  131. package/src/cli/runs.ts +174 -0
  132. package/src/cli/status-cost.ts +151 -0
  133. package/src/cli/status-features.ts +338 -0
  134. package/src/cli/status.ts +13 -0
  135. package/src/commands/common.ts +171 -0
  136. package/src/commands/diagnose.ts +17 -0
  137. package/src/commands/index.ts +8 -0
  138. package/src/commands/logs.ts +384 -0
  139. package/src/commands/precheck.ts +86 -0
  140. package/src/commands/unlock.ts +96 -0
  141. package/src/config/defaults.ts +160 -0
  142. package/src/config/index.ts +22 -0
  143. package/src/config/loader.ts +121 -0
  144. package/src/config/merger.ts +147 -0
  145. package/src/config/path-security.ts +121 -0
  146. package/src/config/paths.ts +27 -0
  147. package/src/config/schema.ts +56 -0
  148. package/src/config/schemas.ts +286 -0
  149. package/src/config/types.ts +423 -0
  150. package/src/config/validate.ts +103 -0
  151. package/src/constitution/generator.ts +191 -0
  152. package/src/constitution/generators/aider.ts +41 -0
  153. package/src/constitution/generators/claude.ts +35 -0
  154. package/src/constitution/generators/cursor.ts +36 -0
  155. package/src/constitution/generators/opencode.ts +38 -0
  156. package/src/constitution/generators/types.ts +33 -0
  157. package/src/constitution/generators/windsurf.ts +36 -0
  158. package/src/constitution/index.ts +10 -0
  159. package/src/constitution/loader.ts +133 -0
  160. package/src/constitution/types.ts +31 -0
  161. package/src/context/auto-detect.ts +227 -0
  162. package/src/context/builder.ts +246 -0
  163. package/src/context/elements.ts +83 -0
  164. package/src/context/formatter.ts +107 -0
  165. package/src/context/generator.ts +129 -0
  166. package/src/context/generators/aider.ts +34 -0
  167. package/src/context/generators/claude.ts +28 -0
  168. package/src/context/generators/cursor.ts +28 -0
  169. package/src/context/generators/opencode.ts +30 -0
  170. package/src/context/generators/windsurf.ts +28 -0
  171. package/src/context/greenfield.ts +114 -0
  172. package/src/context/index.ts +33 -0
  173. package/src/context/injector.ts +279 -0
  174. package/src/context/test-scanner.ts +370 -0
  175. package/src/context/types.ts +98 -0
  176. package/src/errors.ts +67 -0
  177. package/src/execution/batching.ts +157 -0
  178. package/src/execution/crash-recovery.ts +373 -0
  179. package/src/execution/escalation/escalation.ts +44 -0
  180. package/src/execution/escalation/index.ts +13 -0
  181. package/src/execution/escalation/tier-escalation.ts +295 -0
  182. package/src/execution/escalation/tier-outcome.ts +158 -0
  183. package/src/execution/helpers.ts +38 -0
  184. package/src/execution/index.ts +45 -0
  185. package/src/execution/lifecycle/acceptance-loop.ts +272 -0
  186. package/src/execution/lifecycle/headless-formatter.ts +85 -0
  187. package/src/execution/lifecycle/index.ts +12 -0
  188. package/src/execution/lifecycle/parallel-lifecycle.ts +101 -0
  189. package/src/execution/lifecycle/precheck-runner.ts +140 -0
  190. package/src/execution/lifecycle/run-cleanup.ts +81 -0
  191. package/src/execution/lifecycle/run-completion.ts +129 -0
  192. package/src/execution/lifecycle/run-initialization.ts +141 -0
  193. package/src/execution/lifecycle/run-lifecycle.ts +312 -0
  194. package/src/execution/lifecycle/run-setup.ts +204 -0
  195. package/src/execution/lifecycle/story-hooks.ts +38 -0
  196. package/src/execution/lifecycle/story-size-prompts.ts +123 -0
  197. package/src/execution/lock.ts +115 -0
  198. package/src/execution/parallel-executor.ts +216 -0
  199. package/src/execution/parallel.ts +400 -0
  200. package/src/execution/pid-registry.ts +280 -0
  201. package/src/execution/pipeline-result-handler.ts +388 -0
  202. package/src/execution/post-verify-rectification.ts +188 -0
  203. package/src/execution/post-verify.ts +274 -0
  204. package/src/execution/progress.ts +25 -0
  205. package/src/execution/prompts.ts +127 -0
  206. package/src/execution/queue-handler.ts +109 -0
  207. package/src/execution/rectification.ts +13 -0
  208. package/src/execution/runner.ts +377 -0
  209. package/src/execution/sequential-executor.ts +388 -0
  210. package/src/execution/status-file.ts +264 -0
  211. package/src/execution/status-writer.ts +139 -0
  212. package/src/execution/story-context.ts +229 -0
  213. package/src/execution/test-output-parser.ts +14 -0
  214. package/src/execution/verification.ts +72 -0
  215. package/src/hooks/index.ts +2 -0
  216. package/src/hooks/runner.ts +286 -0
  217. package/src/hooks/types.ts +67 -0
  218. package/src/interaction/chain.ts +154 -0
  219. package/src/interaction/index.ts +60 -0
  220. package/src/interaction/init.ts +83 -0
  221. package/src/interaction/plugins/auto.ts +217 -0
  222. package/src/interaction/plugins/cli.ts +300 -0
  223. package/src/interaction/plugins/telegram.ts +384 -0
  224. package/src/interaction/plugins/webhook.ts +258 -0
  225. package/src/interaction/state.ts +171 -0
  226. package/src/interaction/triggers.ts +229 -0
  227. package/src/interaction/types.ts +163 -0
  228. package/src/logger/formatters.ts +84 -0
  229. package/src/logger/index.ts +16 -0
  230. package/src/logger/logger.ts +298 -0
  231. package/src/logger/types.ts +48 -0
  232. package/src/logging/formatter.ts +355 -0
  233. package/src/logging/index.ts +22 -0
  234. package/src/logging/types.ts +93 -0
  235. package/src/metrics/aggregator.ts +190 -0
  236. package/src/metrics/index.ts +14 -0
  237. package/src/metrics/tracker.ts +200 -0
  238. package/src/metrics/types.ts +109 -0
  239. package/src/optimizer/index.ts +62 -0
  240. package/src/optimizer/noop.optimizer.ts +24 -0
  241. package/src/optimizer/rule-based.optimizer.ts +248 -0
  242. package/src/optimizer/types.ts +53 -0
  243. package/src/pipeline/events.ts +130 -0
  244. package/src/pipeline/index.ts +19 -0
  245. package/src/pipeline/runner.ts +161 -0
  246. package/src/pipeline/stages/acceptance.ts +197 -0
  247. package/src/pipeline/stages/completion.ts +99 -0
  248. package/src/pipeline/stages/constitution.ts +63 -0
  249. package/src/pipeline/stages/context.ts +117 -0
  250. package/src/pipeline/stages/execution.ts +194 -0
  251. package/src/pipeline/stages/index.ts +62 -0
  252. package/src/pipeline/stages/optimizer.ts +74 -0
  253. package/src/pipeline/stages/prompt.ts +57 -0
  254. package/src/pipeline/stages/queue-check.ts +103 -0
  255. package/src/pipeline/stages/review.ts +181 -0
  256. package/src/pipeline/stages/routing.ts +81 -0
  257. package/src/pipeline/stages/verify.ts +100 -0
  258. package/src/pipeline/types.ts +167 -0
  259. package/src/plugins/index.ts +31 -0
  260. package/src/plugins/loader.ts +287 -0
  261. package/src/plugins/registry.ts +168 -0
  262. package/src/plugins/types.ts +327 -0
  263. package/src/plugins/validator.ts +352 -0
  264. package/src/prd/index.ts +172 -0
  265. package/src/prd/types.ts +202 -0
  266. package/src/precheck/checks-blockers.ts +391 -0
  267. package/src/precheck/checks-warnings.ts +142 -0
  268. package/src/precheck/checks.ts +30 -0
  269. package/src/precheck/index.ts +247 -0
  270. package/src/precheck/story-size-gate.ts +144 -0
  271. package/src/precheck/types.ts +31 -0
  272. package/src/queue/index.ts +2 -0
  273. package/src/queue/manager.ts +254 -0
  274. package/src/queue/types.ts +54 -0
  275. package/src/review/index.ts +8 -0
  276. package/src/review/runner.ts +172 -0
  277. package/src/review/types.ts +66 -0
  278. package/src/routing/builder.ts +81 -0
  279. package/src/routing/chain.ts +74 -0
  280. package/src/routing/index.ts +16 -0
  281. package/src/routing/loader.ts +58 -0
  282. package/src/routing/router.ts +303 -0
  283. package/src/routing/strategies/adaptive.ts +215 -0
  284. package/src/routing/strategies/index.ts +8 -0
  285. package/src/routing/strategies/keyword.ts +163 -0
  286. package/src/routing/strategies/llm-prompts.ts +209 -0
  287. package/src/routing/strategies/llm.ts +235 -0
  288. package/src/routing/strategies/manual.ts +50 -0
  289. package/src/routing/strategy.ts +99 -0
  290. package/src/tdd/cleanup.ts +111 -0
  291. package/src/tdd/index.ts +23 -0
  292. package/src/tdd/isolation.ts +123 -0
  293. package/src/tdd/orchestrator.ts +383 -0
  294. package/src/tdd/prompts.ts +270 -0
  295. package/src/tdd/rectification-gate.ts +183 -0
  296. package/src/tdd/session-runner.ts +179 -0
  297. package/src/tdd/types.ts +81 -0
  298. package/src/tdd/verdict.ts +271 -0
  299. package/src/tui/App.tsx +265 -0
  300. package/src/tui/components/AgentPanel.tsx +75 -0
  301. package/src/tui/components/CostOverlay.tsx +118 -0
  302. package/src/tui/components/HelpOverlay.tsx +107 -0
  303. package/src/tui/components/StatusBar.tsx +63 -0
  304. package/src/tui/components/StoriesPanel.tsx +177 -0
  305. package/src/tui/hooks/useKeyboard.ts +142 -0
  306. package/src/tui/hooks/useLayout.ts +137 -0
  307. package/src/tui/hooks/usePipelineEvents.ts +183 -0
  308. package/src/tui/hooks/usePty.ts +194 -0
  309. package/src/tui/index.tsx +38 -0
  310. package/src/tui/types.ts +76 -0
  311. package/src/utils/git.ts +83 -0
  312. package/src/utils/queue-writer.ts +54 -0
  313. package/src/verification/executor.ts +235 -0
  314. package/src/verification/gate.ts +207 -0
  315. package/src/verification/index.ts +12 -0
  316. package/src/verification/parser.ts +230 -0
  317. package/src/verification/rectification.ts +108 -0
  318. package/src/verification/types.ts +113 -0
  319. package/src/worktree/dispatcher.ts +65 -0
  320. package/src/worktree/index.ts +2 -0
  321. package/src/worktree/manager.ts +187 -0
  322. package/src/worktree/merge.ts +301 -0
  323. package/src/worktree/types.ts +4 -0
  324. package/test/TEST_COVERAGE_US001.md +217 -0
  325. package/test/TEST_COVERAGE_US003.md +84 -0
  326. package/test/TEST_COVERAGE_US005.md +86 -0
  327. package/test/US-002-orchestrator.test.ts +246 -0
  328. package/test/acceptance/cm-003-default-view.test.ts +194 -0
  329. package/test/execution/pid-registry.test.ts +240 -0
  330. package/test/execution/post-verify.test.ts +224 -0
  331. package/test/helpers/timeout.ts +42 -0
  332. package/test/integration/US-002-TEST-SUMMARY.md +107 -0
  333. package/test/integration/US-003-TEST-SUMMARY.md +149 -0
  334. package/test/integration/US-004-TEST-SUMMARY.md +106 -0
  335. package/test/integration/US-005-TEST-SUMMARY.md +138 -0
  336. package/test/integration/US-007-TEST-SUMMARY.md +100 -0
  337. package/test/integration/agent-validation.test.ts +439 -0
  338. package/test/integration/analyze-integration.test.ts +261 -0
  339. package/test/integration/analyze-scanner.test.ts +131 -0
  340. package/test/integration/cli-config-default-edge-cases.test.ts +222 -0
  341. package/test/integration/cli-config-default-view.test.ts +229 -0
  342. package/test/integration/cli-config-diff.test.ts +460 -0
  343. package/test/integration/cli-config.test.ts +736 -0
  344. package/test/integration/cli-diagnose.test.ts +592 -0
  345. package/test/integration/cli-logs.test.ts +314 -0
  346. package/test/integration/cli-plugins.test.ts +678 -0
  347. package/test/integration/cli-precheck.test.ts +371 -0
  348. package/test/integration/cli-run-headless.test.ts +173 -0
  349. package/test/integration/cli.test.ts +75 -0
  350. package/test/integration/config/merger.test.ts +465 -0
  351. package/test/integration/config/paths.test.ts +51 -0
  352. package/test/integration/config-loader.test.ts +265 -0
  353. package/test/integration/config.test.ts +444 -0
  354. package/test/integration/context-integration.test.ts +702 -0
  355. package/test/integration/context-provider-injection.test.ts +506 -0
  356. package/test/integration/context-verification-integration.test.ts +295 -0
  357. package/test/integration/e2e.test.ts +896 -0
  358. package/test/integration/execution.test.ts +625 -0
  359. package/test/integration/helpers.test.ts +295 -0
  360. package/test/integration/hooks.test.ts +361 -0
  361. package/test/integration/interaction-chain-pipeline.test.ts +464 -0
  362. package/test/integration/isolation.test.ts +143 -0
  363. package/test/integration/logger.test.ts +461 -0
  364. package/test/integration/parallel.test.ts +250 -0
  365. package/test/integration/path-security.test.ts +173 -0
  366. package/test/integration/pipeline-acceptance.test.ts +302 -0
  367. package/test/integration/pipeline-events.test.ts +475 -0
  368. package/test/integration/pipeline.test.ts +658 -0
  369. package/test/integration/plan.test.ts +157 -0
  370. package/test/integration/plugin-routing.test.ts +921 -0
  371. package/test/integration/plugins/config-integration.test.ts +172 -0
  372. package/test/integration/plugins/config-resolution.test.ts +522 -0
  373. package/test/integration/plugins/loader.test.ts +641 -0
  374. package/test/integration/plugins/registry.test.ts +746 -0
  375. package/test/integration/plugins/validator.test.ts +563 -0
  376. package/test/integration/prd-pause.test.ts +205 -0
  377. package/test/integration/prd-resolvers.test.ts +185 -0
  378. package/test/integration/precheck-integration.test.ts +468 -0
  379. package/test/integration/precheck.test.ts +805 -0
  380. package/test/integration/progress.test.ts +34 -0
  381. package/test/integration/rectification-flow.test.ts +512 -0
  382. package/test/integration/reporter-lifecycle.test.ts +860 -0
  383. package/test/integration/review-config-commands.test.ts +319 -0
  384. package/test/integration/review-config-schema.test.ts +116 -0
  385. package/test/integration/review-plugin-integration.test.ts +722 -0
  386. package/test/integration/review.test.ts +149 -0
  387. package/test/integration/routing-stage-bug-021.test.ts +274 -0
  388. package/test/integration/routing-stage-greenfield.test.ts +286 -0
  389. package/test/integration/runner-config-plugins.test.ts +461 -0
  390. package/test/integration/runner-fixes.test.ts +399 -0
  391. package/test/integration/runner-plugin-integration.test.ts +543 -0
  392. package/test/integration/runner.test.ts +1679 -0
  393. package/test/integration/s5-greenfield-fallback.test.ts +297 -0
  394. package/test/integration/status-file-integration.test.ts +325 -0
  395. package/test/integration/status-file.test.ts +379 -0
  396. package/test/integration/status-writer.test.ts +345 -0
  397. package/test/integration/story-id-in-events.test.ts +273 -0
  398. package/test/integration/tdd-cleanup.test.ts +246 -0
  399. package/test/integration/tdd-orchestrator.test.ts +1762 -0
  400. package/test/integration/test-scanner.test.ts +403 -0
  401. package/test/integration/verification-asset-check.test.ts +142 -0
  402. package/test/integration/verify-stage.test.ts +275 -0
  403. package/test/integration/worktree/manager.test.ts +218 -0
  404. package/test/integration/worktree/merge.test.ts +341 -0
  405. package/test/manual/logging-formatter-demo.ts +158 -0
  406. package/test/ui/tui-agent-panel.test.tsx +99 -0
  407. package/test/ui/tui-controls.test.ts +334 -0
  408. package/test/ui/tui-cost-and-pty.test.ts +189 -0
  409. package/test/ui/tui-layout.test.ts +378 -0
  410. package/test/ui/tui-pty-integration.test.tsx +159 -0
  411. package/test/ui/tui-stories.test.ts +332 -0
  412. package/test/unit/acceptance.test.ts +186 -0
  413. package/test/unit/agent-stderr-capture.test.ts +146 -0
  414. package/test/unit/analyze-classifier.test.ts +215 -0
  415. package/test/unit/analyze.test.ts +224 -0
  416. package/test/unit/auto-detect.test.ts +249 -0
  417. package/test/unit/cli-status.test.ts +417 -0
  418. package/test/unit/commands/common.test.ts +320 -0
  419. package/test/unit/commands/logs.test.ts +416 -0
  420. package/test/unit/commands/unlock.test.ts +319 -0
  421. package/test/unit/constitution-generators.test.ts +160 -0
  422. package/test/unit/constitution.test.ts +209 -0
  423. package/test/unit/context.test.ts +1722 -0
  424. package/test/unit/cost.test.ts +231 -0
  425. package/test/unit/crash-recovery.test.ts +308 -0
  426. package/test/unit/escalation.test.ts +126 -0
  427. package/test/unit/execution-logging-stderr.test.ts +156 -0
  428. package/test/unit/execution-stage.test.ts +122 -0
  429. package/test/unit/fix-generator.test.ts +275 -0
  430. package/test/unit/formatters.test.ts +469 -0
  431. package/test/unit/greenfield.test.ts +179 -0
  432. package/test/unit/helpers.test.ts +317 -0
  433. package/test/unit/interaction/human-review-trigger.test.ts +164 -0
  434. package/test/unit/interaction-network-failures.test.ts +389 -0
  435. package/test/unit/interaction-plugins.test.ts +164 -0
  436. package/test/unit/isolation.test.ts +134 -0
  437. package/test/unit/logging/formatter.test.ts +455 -0
  438. package/test/unit/merge.test.ts +268 -0
  439. package/test/unit/metrics.test.ts +276 -0
  440. package/test/unit/optimizer/noop.optimizer.test.ts +125 -0
  441. package/test/unit/optimizer/rule-based.optimizer.test.ts +358 -0
  442. package/test/unit/prd-auto-default.test.ts +290 -0
  443. package/test/unit/prd-failure-category.test.ts +176 -0
  444. package/test/unit/prd-get-next-story.test.ts +186 -0
  445. package/test/unit/precheck-checks.test.ts +840 -0
  446. package/test/unit/precheck-story-size-gate.test.ts +287 -0
  447. package/test/unit/precheck-types.test.ts +142 -0
  448. package/test/unit/prompts.test.ts +475 -0
  449. package/test/unit/queue.test.ts +237 -0
  450. package/test/unit/rectification.test.ts +284 -0
  451. package/test/unit/registry.test.ts +287 -0
  452. package/test/unit/routing.test.ts +937 -0
  453. package/test/unit/run-lifecycle.test.ts +140 -0
  454. package/test/unit/storyid-events.test.ts +224 -0
  455. package/test/unit/tdd-verdict.test.ts +492 -0
  456. package/test/unit/test-output-parser.test.ts +377 -0
  457. package/test/unit/verdict.test.ts +324 -0
  458. package/test/unit/worktree-manager.test.ts +158 -0
  459. 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
+ }