@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,301 @@
1
+ import { getSafeLogger } from "../logger";
2
+ import type { WorktreeManager } from "./manager";
3
+
4
+ export interface MergeResult {
5
+ success: boolean;
6
+ storyId: string;
7
+ conflictFiles?: string[];
8
+ retryCount?: number;
9
+ }
10
+
11
+ export interface StoryDependencies {
12
+ [storyId: string]: string[];
13
+ }
14
+
15
+ export class MergeEngine {
16
+ constructor(private worktreeManager: WorktreeManager) {}
17
+
18
+ /**
19
+ * Merges branch nax/<storyId> into current branch with --no-ff
20
+ * Returns { success: true } on clean merge
21
+ * Returns { success: false, conflictFiles: [...] } on conflict
22
+ * Cleans up worktree after successful merge
23
+ */
24
+ async merge(projectRoot: string, storyId: string): Promise<Omit<MergeResult, "storyId">> {
25
+ const branchName = `nax/${storyId}`;
26
+
27
+ try {
28
+ // Perform merge with --no-ff
29
+ const mergeProc = Bun.spawn(["git", "merge", "--no-ff", branchName, "-m", `Merge branch '${branchName}'`], {
30
+ cwd: projectRoot,
31
+ stdout: "pipe",
32
+ stderr: "pipe",
33
+ });
34
+
35
+ const exitCode = await mergeProc.exited;
36
+ const stderr = await new Response(mergeProc.stderr).text();
37
+ const stdout = await new Response(mergeProc.stdout).text();
38
+
39
+ if (exitCode === 0) {
40
+ // Clean merge - cleanup worktree
41
+ try {
42
+ await this.worktreeManager.remove(projectRoot, storyId);
43
+ } catch (error) {
44
+ // Log warning but don't fail the merge
45
+ const logger = getSafeLogger();
46
+ logger?.warn("worktree", `Failed to cleanup worktree for ${storyId}`, {
47
+ error: error instanceof Error ? error.message : String(error),
48
+ });
49
+ }
50
+
51
+ return { success: true };
52
+ }
53
+
54
+ // Merge failed - check for conflicts
55
+ const output = `${stdout}\n${stderr}`;
56
+ if (output.includes("CONFLICT") || output.includes("conflict") || output.includes("Automatic merge failed")) {
57
+ // Extract conflict files
58
+ const conflictFiles = await this.getConflictFiles(projectRoot);
59
+
60
+ // Abort the merge
61
+ await this.abortMerge(projectRoot);
62
+
63
+ return {
64
+ success: false,
65
+ conflictFiles,
66
+ };
67
+ }
68
+
69
+ // Other error
70
+ throw new Error(`Merge failed: ${stderr || stdout || "unknown error"}`);
71
+ } catch (error) {
72
+ if (error instanceof Error) {
73
+ throw error;
74
+ }
75
+ throw new Error(`Failed to merge branch ${branchName}: ${String(error)}`);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Merges stories in topological order based on dependencies
81
+ * On conflict: retries once after rebasing worktree on updated base
82
+ * On 2nd conflict: marks story as failed, continues with remaining stories
83
+ */
84
+ async mergeAll(projectRoot: string, storyIds: string[], dependencies: StoryDependencies): Promise<MergeResult[]> {
85
+ // Sort stories in topological order
86
+ const orderedStories = this.topologicalSort(storyIds, dependencies);
87
+ const results: MergeResult[] = [];
88
+ const failedStories = new Set<string>();
89
+
90
+ for (const storyId of orderedStories) {
91
+ // Check if any dependencies failed
92
+ const deps = dependencies[storyId] || [];
93
+ const hasFailedDeps = deps.some((dep) => failedStories.has(dep));
94
+
95
+ if (hasFailedDeps) {
96
+ results.push({
97
+ success: false,
98
+ storyId,
99
+ conflictFiles: [],
100
+ });
101
+ failedStories.add(storyId);
102
+ continue;
103
+ }
104
+
105
+ // Try to merge
106
+ let result = await this.merge(projectRoot, storyId);
107
+
108
+ // If conflict, retry once after rebasing
109
+ if (!result.success && result.conflictFiles) {
110
+ try {
111
+ // Rebase worktree on updated base
112
+ await this.rebaseWorktree(projectRoot, storyId);
113
+
114
+ // Retry merge
115
+ result = await this.merge(projectRoot, storyId);
116
+
117
+ // If still fails, mark as failed
118
+ if (!result.success) {
119
+ results.push({
120
+ success: false,
121
+ storyId,
122
+ conflictFiles: result.conflictFiles,
123
+ retryCount: 1,
124
+ });
125
+ failedStories.add(storyId);
126
+ continue;
127
+ }
128
+
129
+ // Success after retry
130
+ results.push({
131
+ success: true,
132
+ storyId,
133
+ retryCount: 1,
134
+ });
135
+ } catch (error) {
136
+ // Rebase failed, mark as failed
137
+ results.push({
138
+ success: false,
139
+ storyId,
140
+ conflictFiles: result.conflictFiles,
141
+ retryCount: 1,
142
+ });
143
+ failedStories.add(storyId);
144
+ }
145
+ } else if (result.success) {
146
+ // First attempt succeeded
147
+ results.push({
148
+ success: true,
149
+ storyId,
150
+ retryCount: 0,
151
+ });
152
+ } else {
153
+ // Failed without conflicts (shouldn't happen normally)
154
+ results.push({
155
+ success: false,
156
+ storyId,
157
+ retryCount: 0,
158
+ });
159
+ failedStories.add(storyId);
160
+ }
161
+ }
162
+
163
+ return results;
164
+ }
165
+
166
+ /**
167
+ * Topological sort of stories based on dependencies
168
+ * Returns stories in order where dependencies come before dependents
169
+ */
170
+ private topologicalSort(storyIds: string[], dependencies: StoryDependencies): string[] {
171
+ const visited = new Set<string>();
172
+ const sorted: string[] = [];
173
+ const visiting = new Set<string>();
174
+
175
+ const visit = (storyId: string) => {
176
+ if (visited.has(storyId)) {
177
+ return;
178
+ }
179
+
180
+ if (visiting.has(storyId)) {
181
+ throw new Error(`Circular dependency detected involving ${storyId}`);
182
+ }
183
+
184
+ visiting.add(storyId);
185
+
186
+ // Visit dependencies first
187
+ const deps = dependencies[storyId] || [];
188
+ for (const dep of deps) {
189
+ if (storyIds.includes(dep)) {
190
+ visit(dep);
191
+ }
192
+ }
193
+
194
+ visiting.delete(storyId);
195
+ visited.add(storyId);
196
+ sorted.push(storyId);
197
+ };
198
+
199
+ for (const storyId of storyIds) {
200
+ visit(storyId);
201
+ }
202
+
203
+ return sorted;
204
+ }
205
+
206
+ /**
207
+ * Rebases worktree on current base branch
208
+ */
209
+ private async rebaseWorktree(projectRoot: string, storyId: string): Promise<void> {
210
+ const worktreePath = `${projectRoot}/.nax-wt/${storyId}`;
211
+
212
+ try {
213
+ // Get current branch name from main repo
214
+ const currentBranchProc = Bun.spawn(["git", "rev-parse", "--abbrev-ref", "HEAD"], {
215
+ cwd: projectRoot,
216
+ stdout: "pipe",
217
+ stderr: "pipe",
218
+ });
219
+
220
+ const exitCode = await currentBranchProc.exited;
221
+ if (exitCode !== 0) {
222
+ throw new Error("Failed to get current branch");
223
+ }
224
+
225
+ const currentBranch = (await new Response(currentBranchProc.stdout).text()).trim();
226
+
227
+ // Rebase worktree branch onto current branch
228
+ const rebaseProc = Bun.spawn(["git", "rebase", currentBranch], {
229
+ cwd: worktreePath,
230
+ stdout: "pipe",
231
+ stderr: "pipe",
232
+ });
233
+
234
+ const rebaseExitCode = await rebaseProc.exited;
235
+ if (rebaseExitCode !== 0) {
236
+ const stderr = await new Response(rebaseProc.stderr).text();
237
+
238
+ // Abort rebase on failure
239
+ await Bun.spawn(["git", "rebase", "--abort"], {
240
+ cwd: worktreePath,
241
+ stdout: "pipe",
242
+ stderr: "pipe",
243
+ }).exited;
244
+
245
+ throw new Error(`Rebase failed: ${stderr || "unknown error"}`);
246
+ }
247
+ } catch (error) {
248
+ if (error instanceof Error) {
249
+ throw error;
250
+ }
251
+ throw new Error(`Failed to rebase worktree ${storyId}: ${String(error)}`);
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Gets list of conflicted files
257
+ */
258
+ private async getConflictFiles(projectRoot: string): Promise<string[]> {
259
+ try {
260
+ const proc = Bun.spawn(["git", "diff", "--name-only", "--diff-filter=U"], {
261
+ cwd: projectRoot,
262
+ stdout: "pipe",
263
+ stderr: "pipe",
264
+ });
265
+
266
+ const exitCode = await proc.exited;
267
+ if (exitCode !== 0) {
268
+ return [];
269
+ }
270
+
271
+ const stdout = await new Response(proc.stdout).text();
272
+ return stdout
273
+ .trim()
274
+ .split("\n")
275
+ .filter((line) => line.length > 0);
276
+ } catch {
277
+ return [];
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Aborts an in-progress merge
283
+ */
284
+ private async abortMerge(projectRoot: string): Promise<void> {
285
+ try {
286
+ const proc = Bun.spawn(["git", "merge", "--abort"], {
287
+ cwd: projectRoot,
288
+ stdout: "pipe",
289
+ stderr: "pipe",
290
+ });
291
+
292
+ await proc.exited;
293
+ } catch (error) {
294
+ // Log warning but don't throw - merge might already be aborted
295
+ const logger = getSafeLogger();
296
+ logger?.warn("worktree", "Failed to abort merge", {
297
+ error: error instanceof Error ? error.message : String(error),
298
+ });
299
+ }
300
+ }
301
+ }
@@ -0,0 +1,4 @@
1
+ export interface WorktreeInfo {
2
+ path: string;
3
+ branch: string;
4
+ }
@@ -0,0 +1,217 @@
1
+ # Test Coverage for US-001: Precheck types and check implementations
2
+
3
+ ## Summary
4
+
5
+ Created comprehensive failing tests for the precheck system. All tests fail with "Not implemented" errors as expected.
6
+
7
+ ## Test Files Created/Verified
8
+
9
+ ### 1. `test/unit/precheck-types.test.ts` (13 tests) ✅ PASSING
10
+ Tests the type definitions only - these pass because TypeScript validates structure at compile time.
11
+
12
+ **Coverage:**
13
+ - PrecheckResult type structure (blockers[], warnings[] arrays)
14
+ - Check type structure (name, tier, passed, message fields)
15
+ - CheckTier type values ("blocker", "warning")
16
+ - CheckStatus type values ("passed", "failed", "skipped")
17
+
18
+ ### 2. `test/unit/precheck-checks.test.ts` (55 tests) ❌ FAILING (as expected)
19
+ Tests individual check implementations.
20
+
21
+ #### Tier 1 Blocker Tests (33 tests):
22
+ 1. **checkGitRepoExists** (3 tests)
23
+ - ✅ Passes when .git directory exists
24
+ - ✅ Fails when .git directory does not exist
25
+ - ✅ Uses git rev-parse --git-dir command
26
+
27
+ 2. **checkWorkingTreeClean** (3 tests)
28
+ - ✅ Uses git status --porcelain command
29
+ - ✅ Returns blocker tier
30
+ - ✅ Includes helpful message
31
+
32
+ 3. **checkStaleLock** (4 tests)
33
+ - ✅ Passes when no lock file exists
34
+ - ✅ Passes when lock file is fresh (< 2 hours old)
35
+ - ✅ Fails when lock file is stale (> 2 hours old)
36
+ - ✅ Detects exactly 2 hours as the threshold
37
+
38
+ 4. **checkPRDValid** (6 tests)
39
+ - ✅ Passes when all stories have required fields
40
+ - ✅ Fails when story is missing id
41
+ - ✅ Fails when story is missing title
42
+ - ✅ Fails when story is missing description
43
+ - ✅ Auto-defaults missing tags to empty array in-memory
44
+ - ✅ Auto-defaults missing status to pending in-memory
45
+ - ✅ Auto-defaults missing storyPoints to 1 in-memory
46
+ - ✅ Checks all required fields per story
47
+
48
+ 5. **checkClaudeCLI** (3 tests)
49
+ - ✅ Runs claude --version command
50
+ - ✅ Returns blocker tier
51
+ - ✅ Provides helpful error message on failure
52
+
53
+ 6. **checkDependenciesInstalled** (6 tests)
54
+ - ✅ Detects Node.js dependencies via node_modules
55
+ - ✅ Detects Rust dependencies via target directory
56
+ - ✅ Detects Python dependencies via venv directory
57
+ - ✅ Detects PHP dependencies via vendor directory
58
+ - ✅ Fails when no dependency directories exist
59
+ - ✅ Is language-aware and checks all supported package managers
60
+
61
+ 7. **checkTestCommand** (4 tests)
62
+ - ✅ Passes when test command is configured
63
+ - ✅ Skips silently when test command is null
64
+ - ✅ Skips silently when test command is false
65
+ - ✅ Reads command from config.execution
66
+
67
+ 8. **checkLintCommand** (4 tests)
68
+ - ✅ Passes when lint command is configured
69
+ - ✅ Skips silently when lint command is null
70
+ - ✅ Skips silently when lint command is false
71
+ - ✅ Reads command from config.execution
72
+
73
+ 9. **checkTypecheckCommand** (4 tests)
74
+ - ✅ Passes when typecheck command is configured
75
+ - ✅ Skips silently when typecheck command is null
76
+ - ✅ Skips silently when typecheck command is false
77
+ - ✅ Reads command from config.execution
78
+
79
+ 10. **checkGitUserConfigured** (3 tests)
80
+ - ✅ Checks git config user.name and user.email
81
+ - ✅ Returns blocker tier
82
+ - ✅ Provides helpful message
83
+
84
+ #### Tier 2 Warning Tests (22 tests):
85
+ 1. **checkClaudeMdExists** (3 tests)
86
+ - ✅ Passes when CLAUDE.md exists
87
+ - ✅ Fails when CLAUDE.md does not exist
88
+ - ✅ Returns warning tier not blocker
89
+
90
+ 2. **checkDiskSpace** (4 tests)
91
+ - ✅ Passes when disk space is above 1GB
92
+ - ✅ Fails when disk space is below 1GB
93
+ - ✅ Triggers warning below 1GB threshold
94
+ - ✅ Provides disk space information in message
95
+
96
+ 3. **checkPendingStories** (3 tests)
97
+ - ✅ Passes when there are pending stories
98
+ - ✅ Warns when all stories are passed
99
+ - ✅ Counts pending and in-progress as actionable
100
+
101
+ 4. **checkOptionalCommands** (3 tests)
102
+ - ✅ Warns when optional commands are missing
103
+ - ✅ Passes when all optional commands are configured
104
+ - ✅ Lists which commands are missing
105
+
106
+ 5. **checkGitignoreCoversNax** (6 tests)
107
+ - ✅ Passes when .gitignore exists and covers nax runtime files
108
+ - ✅ Fails when .gitignore does not exist
109
+ - ✅ Fails when .gitignore exists but does not cover nax.lock
110
+ - ✅ Fails when .gitignore exists but does not cover runs directories
111
+ - ✅ Fails when .gitignore exists but does not cover test/tmp
112
+ - ✅ Checks all three nax runtime file patterns
113
+
114
+ ### 3. `test/integration/precheck.test.ts` (25 tests) ❌ FAILING (as expected)
115
+ Integration tests for the complete precheck workflow.
116
+
117
+ **Coverage:**
118
+ - ✅ Returns PrecheckResult with blockers and warnings arrays
119
+ - ✅ Separates blocker checks from warning checks
120
+ - ✅ Includes all 10 blocker checks
121
+ - ✅ Includes all 5 warning checks
122
+ - ✅ Auto-defaults missing PRD fields in-memory during validation
123
+ - ✅ Handles PRD with multiple stories
124
+ - ✅ Detects invalid PRD with missing required fields
125
+ - ✅ Skips command checks when commands are set to null
126
+ - ✅ Completes all checks even if some fail
127
+ - ✅ Provides detailed messages for each check
128
+ - ✅ Stale lock detection (2 tests)
129
+ - ✅ .gitignore validation (4 tests)
130
+
131
+ ## Source Files Created
132
+
133
+ ### 1. `src/precheck/types.ts`
134
+ Type definitions for:
135
+ - `CheckTier` = "blocker" | "warning"
136
+ - `CheckStatus` = "passed" | "failed" | "skipped"
137
+ - `Check` interface (name, tier, passed, message)
138
+ - `PrecheckResult` interface (blockers[], warnings[])
139
+
140
+ ### 2. `src/precheck/checks.ts`
141
+ Stub implementations for all check functions:
142
+ - 10 Tier 1 blocker checks
143
+ - 5 Tier 2 warning checks
144
+ - All throw "Not implemented" errors
145
+
146
+ ### 3. `src/precheck/index.ts`
147
+ Stub for runPrecheck orchestrator (US-002):
148
+ - `runPrecheck(config, prd)` - throws "Not implemented" with note about US-002
149
+
150
+ ## Acceptance Criteria Coverage
151
+
152
+ ✅ **AC1:** PrecheckResult type includes blockers[] and warnings[] arrays
153
+ - Verified in test/unit/precheck-types.test.ts
154
+
155
+ ✅ **AC2:** Git repo check uses git rev-parse --git-dir
156
+ - Verified in test/unit/precheck-checks.test.ts
157
+
158
+ ✅ **AC3:** Working tree check uses git status --porcelain
159
+ - Verified in test/unit/precheck-checks.test.ts
160
+
161
+ ✅ **AC4:** Stale lock detection: nax.lock older than 2 hours
162
+ - Verified in test/unit/precheck-checks.test.ts (4 tests)
163
+
164
+ ✅ **AC5:** PRD validation checks id, title, description per story
165
+ - Verified in test/unit/precheck-checks.test.ts (8 tests)
166
+
167
+ ✅ **AC6:** PRD auto-defaults missing optional fields in-memory
168
+ - Verified in test/unit/precheck-checks.test.ts (3 tests)
169
+ - tags=[], status=pending, storyPoints=1
170
+
171
+ ✅ **AC7:** Claude CLI check runs claude --version
172
+ - Verified in test/unit/precheck-checks.test.ts
173
+
174
+ ✅ **AC8:** Dependency detection is language-aware
175
+ - Verified in test/unit/precheck-checks.test.ts (6 tests)
176
+ - node_modules, target, venv, vendor
177
+
178
+ ✅ **AC9:** Test/lint/typecheck commands read from config.execution
179
+ - Verified in test/unit/precheck-checks.test.ts (12 tests)
180
+
181
+ ✅ **AC10:** Commands set to null/false are skipped silently
182
+ - Verified in test/unit/precheck-checks.test.ts (6 tests)
183
+
184
+ ✅ **AC11:** Disk space warning triggers below 1GB
185
+ - Verified in test/unit/precheck-checks.test.ts (4 tests)
186
+
187
+ ✅ **AC12:** .gitignore warning if missing or does not cover nax runtime files
188
+ - Verified in test/unit/precheck-checks.test.ts (6 tests)
189
+ - Checks: nax.lock, nax/features/*/runs/, test/tmp/
190
+
191
+ ## Test Execution Results
192
+
193
+ ### Unit Tests - Types
194
+ ```
195
+ bun test ./test/unit/precheck-types.test.ts
196
+ ✅ 13 pass, 0 fail, 20 expect() calls
197
+ ```
198
+
199
+ ### Unit Tests - Checks
200
+ ```
201
+ bun test ./test/unit/precheck-checks.test.ts
202
+ ❌ All tests fail with "Not implemented" errors (expected behavior)
203
+ ```
204
+
205
+ ### Integration Tests
206
+ ```
207
+ bun test ./test/integration/precheck.test.ts
208
+ ❌ All tests fail with "Not implemented" errors (expected behavior)
209
+ ```
210
+
211
+ ## Next Steps
212
+
213
+ The implementer (Session 2) should now implement:
214
+ 1. All check functions in `src/precheck/checks.ts`
215
+ 2. The `runPrecheck` orchestrator in `src/precheck/index.ts` (for US-002)
216
+
217
+ All tests are ready and will validate correct implementation behavior.
@@ -0,0 +1,84 @@
1
+ # Test Coverage: US-003 - CLI nax precheck command
2
+
3
+ ## Story: US-003
4
+ CLI nax precheck command with --json flag
5
+
6
+ ## Test File
7
+ `test/integration/cli-precheck.test.ts` - 7 tests
8
+
9
+ ## Coverage
10
+
11
+ ### 1. Command Registration
12
+ ✅ Command is registered as `nax precheck`
13
+ ✅ Supports `-f, --feature <name>` flag
14
+ ✅ Supports `-d, --dir <path>` flag
15
+ ✅ Supports `--json` flag
16
+
17
+ ### 2. Project Resolution
18
+ ✅ Uses `resolveProject()` from common.ts (US-001)
19
+ ✅ Resolves project directory with `-d` flag
20
+ ✅ Resolves feature directory from `-f` flag or config.json
21
+ ✅ Validates nax/ directory exists
22
+ ✅ Validates prd.json exists
23
+
24
+ ### 3. Output Formats
25
+ ✅ Human-readable format (default) - emoji indicators (✓/✗/⚠)
26
+ ✅ Machine-readable JSON format (--json flag)
27
+ ✅ JSON includes: passed, blockers, warnings, summary, feature
28
+
29
+ ### 4. Exit Codes
30
+ ✅ Exit code 0 - All checks passed (or warnings only)
31
+ ✅ Exit code 1 - Blocker detected
32
+ ✅ Exit code 2 - Invalid PRD (missing prd.json or invalid structure)
33
+
34
+ ### 5. Error Handling
35
+ ✅ Missing feature flag with no config.json feature - exit 1
36
+ ✅ Missing prd.json - exit 2
37
+ ✅ Invalid PRD structure - exit 2
38
+ ✅ Missing feature directory - proper error message
39
+
40
+ ## Test Structure
41
+ - Uses temp directories for isolation
42
+ - Sets up minimal git repo to satisfy checks
43
+ - Mocks process.exit to capture exit codes
44
+ - Tests both human and JSON output formats
45
+
46
+ ## Integration Points
47
+ - ✅ Uses resolveProject() from src/commands/common.ts
48
+ - ✅ Uses runPrecheck() from src/precheck/index.ts
49
+ - ✅ Uses loadConfig() from src/config
50
+ - ✅ Uses loadPRD() from src/prd
51
+ - ✅ Respects EXIT_CODES from src/precheck
52
+
53
+ ## Verified Behavior
54
+ 1. Command registered in bin/nax.ts
55
+ 2. Exported from src/commands/index.ts
56
+ 3. Uses same project resolution as `nax status` and `nax logs`
57
+ 4. Fail-fast on Tier 1 blockers
58
+ 5. Collects all Tier 2 warnings
59
+ 6. Proper exit codes for automation/CI
60
+
61
+ ## Manual Testing
62
+ ```bash
63
+ # Human format (default)
64
+ nax precheck -f precheck
65
+ # Exit code: 0 (warnings only)
66
+
67
+ # JSON format
68
+ nax precheck -f precheck --json
69
+ # Output: {"passed":true,"feature":"precheck","summary":{...}}
70
+
71
+ # Explicit directory
72
+ nax precheck -f precheck -d /path/to/project
73
+
74
+ # Missing feature
75
+ nax precheck
76
+ # Error: No feature specified
77
+ ```
78
+
79
+ ## Coverage Summary
80
+ - 7 integration tests
81
+ - All acceptance criteria verified
82
+ - All flags tested
83
+ - All exit codes tested
84
+ - Error paths covered
@@ -0,0 +1,86 @@
1
+ # Test Coverage: US-005 Config-Driven Review Commands
2
+
3
+ ## Story
4
+ Config-driven review commands replacing hardcoded lint
5
+
6
+ ## Implementation Summary
7
+
8
+ ### Files Modified
9
+ 1. **src/config/schema.ts**
10
+ - Added `lintCommand?: string | null` to `ExecutionConfig`
11
+ - Added `typecheckCommand?: string | null` to `ExecutionConfig`
12
+ - Updated `ExecutionConfigSchema` to validate these fields
13
+
14
+ 2. **src/review/runner.ts**
15
+ - Added `loadPackageJson()` - loads package.json from workdir
16
+ - Added `hasScript()` - checks if package.json has a script
17
+ - Added `resolveCommand()` - implements resolution strategy
18
+ - Modified `runReview()` - accepts optional `executionConfig` parameter
19
+ - Implements command resolution order:
20
+ 1. `executionConfig.lintCommand` / `executionConfig.typecheckCommand` (null = disabled)
21
+ 2. `config.review.commands[check]` (legacy, backwards compat)
22
+ 3. package.json scripts -> `bun run <script>`
23
+ 4. Not found -> skip with warning
24
+
25
+ 3. **src/pipeline/stages/review.ts**
26
+ - Updated `runReview()` call to pass `ctx.config.execution`
27
+
28
+ ### Test Coverage
29
+
30
+ **New Tests: test/integration/review-config-commands.test.ts (12 tests)**
31
+ - ✅ uses explicit executionConfig.lintCommand when provided
32
+ - ✅ uses explicit executionConfig.typecheckCommand when provided
33
+ - ✅ skips check when executionConfig command is null (explicitly disabled)
34
+ - ✅ uses package.json script when no executionConfig override
35
+ - ✅ skips check when package.json script not found
36
+ - ✅ executionConfig takes precedence over package.json
37
+ - ✅ reviewConfig.commands takes precedence over package.json (backwards compat)
38
+ - ✅ executionConfig takes precedence over reviewConfig.commands
39
+ - ✅ handles missing package.json gracefully
40
+ - ✅ handles invalid package.json gracefully
41
+ - ✅ resolution order: executionConfig > reviewConfig > package.json
42
+ - ✅ test command ignores executionConfig (not affected by this story)
43
+
44
+ **Updated Tests: test/integration/review.test.ts**
45
+ - ✅ Modified "uses default commands when not specified" test to match new behavior
46
+
47
+ ## Acceptance Criteria Coverage
48
+
49
+ | Criterion | Status | Evidence |
50
+ |-----------|--------|----------|
51
+ | Review stage reads lintCommand from config.execution | ✅ | `test/integration/review-config-commands.test.ts:23-37` |
52
+ | Review stage reads typecheckCommand from config.execution | ✅ | `test/integration/review-config-commands.test.ts:39-53` |
53
+ | Resolution order: config -> package.json -> skip | ✅ | `test/integration/review-config-commands.test.ts:185-214` |
54
+ | Setting command to null/false explicitly disables it | ✅ | `test/integration/review-config-commands.test.ts:55-71` |
55
+ | Missing command logs warning instead of failing | ✅ | `src/review/runner.ts:140-143` + test output shows warnings |
56
+ | Config schema updated with lintCommand and typecheckCommand fields | ✅ | `src/config/schema.ts:113-114` |
57
+ | BUG-005 (hardcoded bun run lint) is resolved | ✅ | No hardcoded commands, all resolved via strategy |
58
+
59
+ ## Behavior Changes
60
+
61
+ ### Before
62
+ - Always used hardcoded defaults: `bun run lint`, `bun run typecheck`, `bun test`
63
+ - Commands from `config.review.commands` could override defaults
64
+ - No way to explicitly disable a check without removing it from `checks` array
65
+
66
+ ### After
67
+ - Command resolution follows priority:
68
+ 1. `config.execution.lintCommand` / `typecheckCommand` (highest priority)
69
+ 2. `config.review.commands[check]` (legacy, for backwards compatibility)
70
+ 3. package.json scripts (auto-detected)
71
+ 4. Skip with warning (no command found)
72
+ - Setting `lintCommand: null` explicitly disables lint check
73
+ - Missing commands no longer fail - they skip with a warning
74
+
75
+ ## Backwards Compatibility
76
+
77
+ ✅ **Fully backwards compatible**
78
+ - Existing configs using `config.review.commands` continue to work
79
+ - Projects without explicit config fall back to package.json detection
80
+ - No breaking changes to existing APIs
81
+
82
+ ## Notes
83
+
84
+ - `test` command intentionally NOT added to `ExecutionConfig` (not part of this story scope)
85
+ - Resolution order ensures maximum flexibility: explicit config > legacy config > auto-detect > skip
86
+ - Warning messages logged when commands are skipped for debugging visibility