@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,468 @@
1
+ /**
2
+ * Integration tests for precheck integration with nax run
3
+ *
4
+ * Tests US-004: Integrate precheck into nax run
5
+ * - AC1: Precheck runs automatically before first story
6
+ * - AC2: Tier 1 blocker aborts run with descriptive error
7
+ * - AC3: Tier 2 warnings logged but don't block execution
8
+ * - AC4: --skip-precheck flag bypasses all checks
9
+ * - AC5: Precheck results included in run JSONL log
10
+ * - AC6: Failed precheck updates status.json with precheck-failed status
11
+ */
12
+
13
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
14
+
15
+ // Skip in CI: these tests call run() which invokes the full nax execution pipeline
16
+ // including spawning real agent subprocesses. CI runners lack the claude binary and
17
+ // have restricted process/file system environments. These are end-to-end smoke tests
18
+ // that must run in a properly configured dev environment (local, Mac01, or VPS).
19
+ const skipInCI = process.env.CI ? test.skip : test;
20
+ import { mkdirSync, rmSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ import type { NaxConfig } from "../../src/config";
23
+ import { DEFAULT_CONFIG } from "../../src/config";
24
+ import { run } from "../../src/execution";
25
+ import type { PRD } from "../../src/prd";
26
+ import { loadPRD } from "../../src/prd";
27
+
28
+ describe("Precheck Integration with nax run", () => {
29
+ let testDir: string;
30
+ let savedSkipPrecheck: string | undefined;
31
+
32
+ beforeEach(async () => {
33
+ // Temporarily remove NAX_SKIP_PRECHECK so precheck actually runs in these tests
34
+ savedSkipPrecheck = process.env.NAX_SKIP_PRECHECK;
35
+ delete process.env.NAX_SKIP_PRECHECK;
36
+
37
+ testDir = join(import.meta.dir, "..", "..", ".tmp", `precheck-integration-${Date.now()}`);
38
+ mkdirSync(testDir, { recursive: true });
39
+
40
+ // Initialize as git repo to pass git checks
41
+ const { spawnSync } = await import("bun");
42
+ spawnSync(["git", "init"], { cwd: testDir });
43
+ spawnSync(["git", "config", "user.name", "Test User"], { cwd: testDir });
44
+ spawnSync(["git", "config", "user.email", "test@example.com"], { cwd: testDir });
45
+ });
46
+
47
+ afterEach(() => {
48
+ // Restore NAX_SKIP_PRECHECK to its original value
49
+ if (savedSkipPrecheck !== undefined) {
50
+ process.env.NAX_SKIP_PRECHECK = savedSkipPrecheck;
51
+ } else {
52
+ delete process.env.NAX_SKIP_PRECHECK;
53
+ }
54
+
55
+ try {
56
+ rmSync(testDir, { recursive: true, force: true });
57
+ } catch (error) {
58
+ // Ignore cleanup errors
59
+ }
60
+ });
61
+
62
+ /**
63
+ * Helper to create a basic PRD with one simple story
64
+ */
65
+ function createBasicPRD(feature: string): PRD {
66
+ return {
67
+ feature,
68
+ project: "test-project",
69
+ branchName: `feat/${feature}`,
70
+ userStories: [
71
+ {
72
+ id: "US-001",
73
+ title: "Test Story",
74
+ description: "A test story",
75
+ acceptanceCriteria: ["Story works"],
76
+ status: "pending",
77
+ dependencies: [],
78
+ tags: [],
79
+ estimatedComplexity: "simple",
80
+ },
81
+ ],
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Helper to create feature directory and PRD file
87
+ */
88
+ async function setupFeature(feature: string): Promise<string> {
89
+ const naxDir = join(testDir, "nax");
90
+ const featuresDir = join(naxDir, "features");
91
+ const featureDir = join(featuresDir, feature);
92
+ mkdirSync(featureDir, { recursive: true });
93
+
94
+ // Create .gitignore to exclude nax runtime files
95
+ await Bun.write(join(testDir, ".gitignore"), "nax.lock\n*.jsonl\nstatus.json\n.nax-wt/\n");
96
+
97
+ // Create dummy package.json and node_modules to pass dependency check
98
+ await Bun.write(join(testDir, "package.json"), JSON.stringify({ name: "test", version: "1.0.0" }, null, 2));
99
+ mkdirSync(join(testDir, "node_modules"), { recursive: true });
100
+
101
+ const prd = createBasicPRD(feature);
102
+ const prdPath = join(featureDir, "prd.json");
103
+ await Bun.write(prdPath, JSON.stringify(prd, null, 2));
104
+
105
+ // Commit the PRD file and .gitignore to avoid "working tree not clean" errors
106
+ const { spawnSync } = await import("bun");
107
+ spawnSync(["git", "add", "."], { cwd: testDir });
108
+ spawnSync(["git", "commit", "-m", `Setup ${feature} feature`], { cwd: testDir });
109
+
110
+ return prdPath;
111
+ }
112
+
113
+ /**
114
+ * Helper to read JSONL log and parse precheck entry
115
+ */
116
+ async function readPrecheckLog(logFilePath: string): Promise<any | null> {
117
+ const logFile = Bun.file(logFilePath);
118
+ if (!(await logFile.exists())) {
119
+ return null;
120
+ }
121
+
122
+ const content = await logFile.text();
123
+ const lines = content.trim().split("\n");
124
+
125
+ for (const line of lines) {
126
+ const entry = JSON.parse(line);
127
+ if (entry.type === "precheck") {
128
+ return entry;
129
+ }
130
+ }
131
+
132
+ return null;
133
+ }
134
+
135
+ /**
136
+ * Helper to read status.json
137
+ */
138
+ async function readStatusFile(statusFilePath: string): Promise<any | null> {
139
+ const statusFile = Bun.file(statusFilePath);
140
+ if (!(await statusFile.exists())) {
141
+ return null;
142
+ }
143
+
144
+ return await statusFile.json();
145
+ }
146
+
147
+ // ────────────────────────────────────────────────────────────────────────────
148
+ // AC4: --skip-precheck flag bypasses all checks
149
+ // ────────────────────────────────────────────────────────────────────────────
150
+
151
+ test("AC4: --skip-precheck bypasses precheck validations", async () => {
152
+ // Create non-git temp directory (will fail precheck)
153
+ const nonGitDir = join(import.meta.dir, "..", "..", ".tmp", `non-git-${Date.now()}`);
154
+ mkdirSync(nonGitDir, { recursive: true });
155
+
156
+ try {
157
+ const prdPath = await setupFeature("skip-test");
158
+ const logFilePath = join(nonGitDir, "nax", "features", "skip-test", "runs", "test.jsonl");
159
+ const statusFilePath = join(nonGitDir, "nax", "features", "skip-test", "status.json");
160
+
161
+ const config: NaxConfig = {
162
+ ...DEFAULT_CONFIG,
163
+ execution: {
164
+ ...DEFAULT_CONFIG.execution,
165
+ maxIterations: 1,
166
+ },
167
+ };
168
+
169
+ // Run with skipPrecheck: true (should succeed even without git repo)
170
+ const result = await run({
171
+ prdPath,
172
+ workdir: nonGitDir,
173
+ config,
174
+ hooks: { hooks: {} },
175
+ feature: "skip-test",
176
+ dryRun: true, // Use dry-run to avoid actual agent execution
177
+ skipPrecheck: true,
178
+ logFilePath,
179
+ statusFile: statusFilePath,
180
+ });
181
+
182
+ // Should complete without error
183
+ expect(result.success).toBe(true);
184
+
185
+ // Verify precheck was NOT logged to JSONL
186
+ const precheckLog = await readPrecheckLog(logFilePath);
187
+ expect(precheckLog).toBeNull();
188
+ } finally {
189
+ rmSync(nonGitDir, { recursive: true, force: true });
190
+ }
191
+ });
192
+
193
+ // ────────────────────────────────────────────────────────────────────────────
194
+ // AC1: Precheck runs automatically before first story
195
+ // ────────────────────────────────────────────────────────────────────────────
196
+
197
+ skipInCI("AC1: precheck runs automatically before first story", async () => {
198
+ const prdPath = await setupFeature("auto-test");
199
+ const logFilePath = join(testDir, "nax", "features", "auto-test", "runs", "test.jsonl");
200
+ const runsDir = join(testDir, "nax", "features", "auto-test", "runs");
201
+
202
+ // Pre-create and commit the runs directory to avoid uncommitted changes during test
203
+ mkdirSync(runsDir, { recursive: true });
204
+ const { spawnSync } = await import("bun");
205
+ spawnSync(["git", "add", "."], { cwd: testDir });
206
+ spawnSync(["git", "commit", "-m", "Add runs dir"], { cwd: testDir });
207
+
208
+ const config: NaxConfig = {
209
+ ...DEFAULT_CONFIG,
210
+ execution: {
211
+ ...DEFAULT_CONFIG.execution,
212
+ maxIterations: 1,
213
+ },
214
+ };
215
+
216
+ // Run without skipPrecheck (default behavior)
217
+ await run({
218
+ prdPath,
219
+ workdir: testDir,
220
+ config,
221
+ hooks: { hooks: {} },
222
+ feature: "auto-test",
223
+ dryRun: true,
224
+ logFilePath,
225
+ });
226
+
227
+ // Verify precheck was logged to JSONL (AC5)
228
+ const precheckLog = await readPrecheckLog(logFilePath);
229
+ expect(precheckLog).not.toBeNull();
230
+ expect(precheckLog.type).toBe("precheck");
231
+ expect(precheckLog.passed).toBeDefined();
232
+ expect(precheckLog.summary).toBeDefined();
233
+ });
234
+
235
+ // ────────────────────────────────────────────────────────────────────────────
236
+ // AC2: Tier 1 blocker aborts run with descriptive error
237
+ // ────────────────────────────────────────────────────────────────────────────
238
+
239
+ test("AC2: Tier 1 blocker aborts run with descriptive error", async () => {
240
+ // Create directory with uncommitted changes (will fail working-tree-clean check)
241
+ const dirtyDir = join(import.meta.dir, "..", "..", ".tmp", `dirty-${Date.now()}`);
242
+ mkdirSync(dirtyDir, { recursive: true });
243
+
244
+ try {
245
+ // Initialize git and create a dirty state
246
+ const { spawnSync } = await import("bun");
247
+ spawnSync(["git", "init"], { cwd: dirtyDir });
248
+ spawnSync(["git", "config", "user.name", "Test User"], { cwd: dirtyDir });
249
+ spawnSync(["git", "config", "user.email", "test@example.com"], { cwd: dirtyDir });
250
+
251
+ // Create a file, add it, then modify it (creating uncommitted changes)
252
+ await Bun.write(join(dirtyDir, "test.txt"), "initial");
253
+ spawnSync(["git", "add", "test.txt"], { cwd: dirtyDir });
254
+ spawnSync(["git", "commit", "-m", "initial"], { cwd: dirtyDir });
255
+ await Bun.write(join(dirtyDir, "test.txt"), "modified");
256
+
257
+ // Setup feature
258
+ const naxDir = join(dirtyDir, "nax");
259
+ const featuresDir = join(naxDir, "features");
260
+ const featureDir = join(featuresDir, "blocker-test");
261
+ mkdirSync(featureDir, { recursive: true });
262
+
263
+ const prd = createBasicPRD("blocker-test");
264
+ const prdPath = join(featureDir, "prd.json");
265
+ await Bun.write(prdPath, JSON.stringify(prd, null, 2));
266
+
267
+ // Commit the PRD file
268
+ spawnSync(["git", "add", "."], { cwd: dirtyDir });
269
+ spawnSync(["git", "commit", "-m", "Add PRD"], { cwd: dirtyDir });
270
+
271
+ // Create a new dirty file AFTER the commit so working tree is actually dirty
272
+ await Bun.write(join(dirtyDir, "dirty.txt"), "uncommitted change");
273
+
274
+ const logFilePath = join(featureDir, "runs", "test.jsonl");
275
+ const statusFilePath = join(featureDir, "status.json");
276
+
277
+ const config: NaxConfig = {
278
+ ...DEFAULT_CONFIG,
279
+ execution: {
280
+ ...DEFAULT_CONFIG.execution,
281
+ maxIterations: 1,
282
+ },
283
+ };
284
+
285
+ // Run should throw error due to precheck failure
286
+ try {
287
+ await run({
288
+ prdPath,
289
+ workdir: dirtyDir,
290
+ config,
291
+ hooks: { hooks: {} },
292
+ feature: "blocker-test",
293
+ dryRun: true,
294
+ logFilePath,
295
+ statusFile: statusFilePath,
296
+ });
297
+ expect(true).toBe(false); // Should not reach here
298
+ } catch (error) {
299
+ // Verify error message is descriptive
300
+ expect((error as Error).message).toContain("Precheck failed");
301
+ expect((error as Error).message).toContain("working-tree-clean");
302
+ }
303
+
304
+ // Verify precheck failure was logged (AC5)
305
+ const precheckLog = await readPrecheckLog(logFilePath);
306
+ expect(precheckLog).not.toBeNull();
307
+ expect(precheckLog.passed).toBe(false);
308
+ expect(precheckLog.blockers.length).toBeGreaterThan(0);
309
+
310
+ // Verify status.json shows precheck-failed (AC6)
311
+ const status = await readStatusFile(statusFilePath);
312
+ expect(status).not.toBeNull();
313
+ expect(status.run.status).toBe("precheck-failed");
314
+ } finally {
315
+ rmSync(dirtyDir, { recursive: true, force: true });
316
+ }
317
+ });
318
+
319
+ // ────────────────────────────────────────────────────────────────────────────
320
+ // AC3: Tier 2 warnings logged but don't block execution
321
+ // ────────────────────────────────────────────────────────────────────────────
322
+
323
+ skipInCI("AC3: Tier 2 warnings don't block execution", async () => {
324
+ // Setup feature (clean git repo should pass all Tier 1 but may have Tier 2 warnings)
325
+ const prdPath = await setupFeature("warning-test");
326
+ const logFilePath = join(testDir, "nax", "features", "warning-test", "runs", "test.jsonl");
327
+ const runsDir = join(testDir, "nax", "features", "warning-test", "runs");
328
+
329
+ // Pre-create and commit the runs directory to avoid uncommitted changes during test
330
+ mkdirSync(runsDir, { recursive: true });
331
+ const { spawnSync } = await import("bun");
332
+ spawnSync(["git", "add", "."], { cwd: testDir });
333
+ spawnSync(["git", "commit", "-m", "Add runs dir"], { cwd: testDir });
334
+
335
+ const config: NaxConfig = {
336
+ ...DEFAULT_CONFIG,
337
+ execution: {
338
+ ...DEFAULT_CONFIG.execution,
339
+ maxIterations: 1,
340
+ },
341
+ };
342
+
343
+ // Run should succeed even with warnings
344
+ const result = await run({
345
+ prdPath,
346
+ workdir: testDir,
347
+ config,
348
+ hooks: { hooks: {} },
349
+ feature: "warning-test",
350
+ dryRun: true,
351
+ logFilePath,
352
+ });
353
+
354
+ // Should complete successfully
355
+ expect(result.success).toBe(true);
356
+
357
+ // Verify precheck passed (may have warnings)
358
+ const precheckLog = await readPrecheckLog(logFilePath);
359
+ expect(precheckLog).not.toBeNull();
360
+ expect(precheckLog.passed).toBe(true);
361
+ // Warnings are OK (don't block execution)
362
+ expect(precheckLog.warnings).toBeDefined();
363
+ });
364
+
365
+ // ────────────────────────────────────────────────────────────────────────────
366
+ // AC5: Precheck results included in run JSONL log
367
+ // ────────────────────────────────────────────────────────────────────────────
368
+
369
+ skipInCI("AC5: precheck results logged to JSONL", async () => {
370
+ const prdPath = await setupFeature("log-test");
371
+ const logFilePath = join(testDir, "nax", "features", "log-test", "runs", "test.jsonl");
372
+ const runsDir = join(testDir, "nax", "features", "log-test", "runs");
373
+
374
+ // Pre-create and commit the runs directory to avoid uncommitted changes during test
375
+ mkdirSync(runsDir, { recursive: true });
376
+ const { spawnSync } = await import("bun");
377
+ spawnSync(["git", "add", "."], { cwd: testDir });
378
+ spawnSync(["git", "commit", "-m", "Add runs dir"], { cwd: testDir });
379
+
380
+ const config: NaxConfig = {
381
+ ...DEFAULT_CONFIG,
382
+ execution: {
383
+ ...DEFAULT_CONFIG.execution,
384
+ maxIterations: 1,
385
+ },
386
+ };
387
+
388
+ await run({
389
+ prdPath,
390
+ workdir: testDir,
391
+ config,
392
+ hooks: { hooks: {} },
393
+ feature: "log-test",
394
+ dryRun: true,
395
+ logFilePath,
396
+ });
397
+
398
+ // Verify precheck entry structure
399
+ const precheckLog = await readPrecheckLog(logFilePath);
400
+ expect(precheckLog).not.toBeNull();
401
+ expect(precheckLog.type).toBe("precheck");
402
+ expect(precheckLog.timestamp).toBeDefined();
403
+ expect(precheckLog.passed).toBeDefined();
404
+ expect(precheckLog.blockers).toBeDefined();
405
+ expect(precheckLog.warnings).toBeDefined();
406
+ expect(precheckLog.summary).toBeDefined();
407
+ expect(precheckLog.summary.total).toBeGreaterThan(0);
408
+ expect(precheckLog.summary.passed).toBeGreaterThan(0);
409
+ });
410
+
411
+ // ────────────────────────────────────────────────────────────────────────────
412
+ // AC6: Failed precheck updates status.json with precheck-failed status
413
+ // ────────────────────────────────────────────────────────────────────────────
414
+
415
+ test("AC6: failed precheck updates status.json", async () => {
416
+ // Create non-git directory (will fail precheck)
417
+ const nonGitDir = join(import.meta.dir, "..", "..", ".tmp", `non-git-status-${Date.now()}`);
418
+ mkdirSync(nonGitDir, { recursive: true });
419
+
420
+ try {
421
+ // Setup feature (intentionally no git repo to fail precheck)
422
+ const naxDir = join(nonGitDir, "nax");
423
+ const featuresDir = join(naxDir, "features");
424
+ const featureDir = join(featuresDir, "status-test");
425
+ mkdirSync(featureDir, { recursive: true });
426
+
427
+ const prd = createBasicPRD("status-test");
428
+ const prdPath = join(featureDir, "prd.json");
429
+ await Bun.write(prdPath, JSON.stringify(prd, null, 2));
430
+
431
+ // Note: NOT committing to git since this test needs to verify precheck failure
432
+
433
+ const statusFilePath = join(featureDir, "status.json");
434
+
435
+ const config: NaxConfig = {
436
+ ...DEFAULT_CONFIG,
437
+ execution: {
438
+ ...DEFAULT_CONFIG.execution,
439
+ maxIterations: 1,
440
+ },
441
+ };
442
+
443
+ // Run should fail due to precheck
444
+ try {
445
+ await run({
446
+ prdPath,
447
+ workdir: nonGitDir,
448
+ config,
449
+ hooks: { hooks: {} },
450
+ feature: "status-test",
451
+ dryRun: true,
452
+ statusFile: statusFilePath,
453
+ });
454
+ } catch (error) {
455
+ // Expected failure
456
+ }
457
+
458
+ // Verify status.json exists and has precheck-failed status
459
+ const status = await readStatusFile(statusFilePath);
460
+ expect(status).not.toBeNull();
461
+ expect(status.run).toBeDefined();
462
+ expect(status.run.status).toBe("precheck-failed");
463
+ expect(status.run.feature).toBe("status-test");
464
+ } finally {
465
+ rmSync(nonGitDir, { recursive: true, force: true });
466
+ }
467
+ });
468
+ });