@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,371 @@
1
+ /**
2
+ * Integration tests for CLI precheck command
3
+ *
4
+ * Tests:
5
+ * - Command registration and flag parsing
6
+ * - Directory resolution via resolveProject()
7
+ * - Human and JSON output formats
8
+ * - Exit codes (0=pass, 1=blocker, 2=invalid PRD)
9
+ * - Error handling for missing feature/prd.json
10
+ */
11
+
12
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
13
+ import { mkdirSync, rmSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ import { precheckCommand } from "../../src/commands/precheck";
16
+ import type { PRD } from "../../src/prd/types";
17
+ import { EXIT_CODES } from "../../src/precheck";
18
+
19
+ const TEMP_DIR = join(import.meta.dir, "tmp-precheck-cli");
20
+
21
+ /**
22
+ * Helper to create a test project structure
23
+ */
24
+ function setupTestProject(name: string): {
25
+ projectDir: string;
26
+ naxDir: string;
27
+ featureDir: string;
28
+ prdPath: string;
29
+ } {
30
+ const projectDir = join(TEMP_DIR, name);
31
+ const naxDir = join(projectDir, "nax");
32
+ const featureDir = join(naxDir, "features", "test-feature");
33
+ const prdPath = join(featureDir, "prd.json");
34
+
35
+ mkdirSync(featureDir, { recursive: true });
36
+
37
+ // Write minimal config.json
38
+ Bun.write(
39
+ join(naxDir, "config.json"),
40
+ JSON.stringify(
41
+ {
42
+ feature: "test-feature",
43
+ routing: { enabled: true, tierLabels: { fast: 1, balanced: 2, powerful: 3 } },
44
+ quality: { test: { enabled: true, command: "echo test" } },
45
+ },
46
+ null,
47
+ 2,
48
+ ),
49
+ );
50
+
51
+ // Initialize git repo to satisfy checks
52
+ Bun.spawnSync(["git", "init", "-q"], { cwd: projectDir });
53
+ Bun.spawnSync(["git", "config", "user.name", "Test"], { cwd: projectDir });
54
+ Bun.spawnSync(["git", "config", "user.email", "test@example.com"], { cwd: projectDir });
55
+
56
+ // Create node_modules to satisfy dependencies check
57
+ mkdirSync(join(projectDir, "node_modules"), { recursive: true });
58
+
59
+ return { projectDir, naxDir, featureDir, prdPath };
60
+ }
61
+
62
+ /**
63
+ * Helper to create a valid PRD
64
+ */
65
+ function createValidPRD(): PRD {
66
+ return {
67
+ version: "0.1.0",
68
+ project: "test-project",
69
+ feature: "test-feature",
70
+ branch: "feat/test-feature",
71
+ branchName: "feat/test-feature",
72
+ userStories: [
73
+ {
74
+ id: "US-001",
75
+ title: "Test Story",
76
+ description: "Test description",
77
+ acceptanceCriteria: [{ id: "AC-1", criterion: "Test criterion", testStrategy: "integration" }],
78
+ tags: [],
79
+ routing: {
80
+ tier: "fast",
81
+ complexity: "simple",
82
+ estimatedCost: 0.01,
83
+ security: false,
84
+ thinkingBudget: 1000,
85
+ },
86
+ dependencies: [],
87
+ },
88
+ ],
89
+ totalStories: 1,
90
+ completedStories: 0,
91
+ progress: 0,
92
+ };
93
+ }
94
+
95
+ describe("CLI precheck command", () => {
96
+ beforeEach(() => {
97
+ rmSync(TEMP_DIR, { recursive: true, force: true });
98
+ mkdirSync(TEMP_DIR, { recursive: true });
99
+ });
100
+
101
+ afterEach(() => {
102
+ rmSync(TEMP_DIR, { recursive: true, force: true });
103
+ });
104
+
105
+ test("should resolve project directory with -d flag", async () => {
106
+ const { projectDir, prdPath } = setupTestProject("test-d-flag");
107
+
108
+ // Write valid PRD
109
+ await Bun.write(prdPath, JSON.stringify(createValidPRD()));
110
+
111
+ // Commit everything to satisfy working-tree-clean check
112
+ Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
113
+ Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
114
+
115
+ // Mock process.exit to capture exit code
116
+ let exitCode: number | undefined;
117
+ const originalExit = process.exit;
118
+ process.exit = ((code?: number) => {
119
+ exitCode = code;
120
+ // Don't actually exit in tests
121
+ }) as never;
122
+
123
+ try {
124
+ await precheckCommand({
125
+ feature: "test-feature",
126
+ dir: projectDir,
127
+ json: false,
128
+ });
129
+ } catch (err) {
130
+ // Expected - command calls process.exit
131
+ } finally {
132
+ process.exit = originalExit;
133
+ }
134
+
135
+ // Should exit with code 0 (success) or 1 (warning)
136
+ expect(exitCode).toBeDefined();
137
+ expect([EXIT_CODES.SUCCESS, EXIT_CODES.BLOCKER]).toContain(exitCode);
138
+ });
139
+
140
+ test("should accept -f flag for feature name", async () => {
141
+ const { projectDir, prdPath } = setupTestProject("test-f-flag");
142
+
143
+ // Write valid PRD
144
+ await Bun.write(prdPath, JSON.stringify(createValidPRD()));
145
+
146
+ // Commit to satisfy checks
147
+ Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
148
+ Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
149
+
150
+ let exitCode: number | undefined;
151
+ const originalExit = process.exit;
152
+ process.exit = ((code?: number) => {
153
+ exitCode = code;
154
+ }) as never;
155
+
156
+ try {
157
+ await precheckCommand({
158
+ feature: "test-feature",
159
+ dir: projectDir,
160
+ json: false,
161
+ });
162
+ } catch (err) {
163
+ // Expected
164
+ } finally {
165
+ process.exit = originalExit;
166
+ }
167
+
168
+ expect(exitCode).toBeDefined();
169
+ });
170
+
171
+ test("should output JSON format with --json flag", async () => {
172
+ const { projectDir, prdPath } = setupTestProject("test-json-flag");
173
+
174
+ // Write valid PRD
175
+ await Bun.write(prdPath, JSON.stringify(createValidPRD()));
176
+
177
+ // Commit to satisfy checks
178
+ Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
179
+ Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
180
+
181
+ // Capture console.log output
182
+ const logs: string[] = [];
183
+ const originalLog = console.log;
184
+ console.log = (msg: string) => {
185
+ logs.push(msg);
186
+ };
187
+
188
+ let exitCode: number | undefined;
189
+ const originalExit = process.exit;
190
+ process.exit = ((code?: number) => {
191
+ exitCode = code;
192
+ }) as never;
193
+
194
+ try {
195
+ await precheckCommand({
196
+ feature: "test-feature",
197
+ dir: projectDir,
198
+ json: true,
199
+ });
200
+ } catch (err) {
201
+ // Expected
202
+ } finally {
203
+ console.log = originalLog;
204
+ process.exit = originalExit;
205
+ }
206
+
207
+ // Should have JSON output
208
+ expect(logs.length).toBeGreaterThan(0);
209
+
210
+ // Try to parse first log as JSON
211
+ const jsonOutput = JSON.parse(logs[0]);
212
+ expect(jsonOutput).toHaveProperty("passed");
213
+ expect(jsonOutput).toHaveProperty("blockers");
214
+ expect(jsonOutput).toHaveProperty("warnings");
215
+ expect(jsonOutput).toHaveProperty("summary");
216
+ expect(jsonOutput).toHaveProperty("feature");
217
+ expect(jsonOutput.feature).toBe("test-feature");
218
+ });
219
+
220
+ test("should exit with code 2 for invalid PRD", async () => {
221
+ const { projectDir, prdPath } = setupTestProject("test-invalid-prd");
222
+
223
+ // Write PRD that will pass loading but fail validation
224
+ await Bun.write(
225
+ prdPath,
226
+ JSON.stringify({
227
+ version: "0.1.0",
228
+ // Missing required fields: project, feature, branchName
229
+ userStories: [],
230
+ totalStories: 0,
231
+ completedStories: 0,
232
+ progress: 0,
233
+ }),
234
+ );
235
+
236
+ // Commit to satisfy git checks
237
+ Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
238
+ Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
239
+
240
+ let exitCode: number | undefined;
241
+ const originalExit = process.exit;
242
+ const originalError = console.error;
243
+ const originalLog = console.log;
244
+ console.error = () => {}; // Suppress error output
245
+ console.log = () => {}; // Suppress check output
246
+
247
+ process.exit = ((code?: number) => {
248
+ exitCode = code;
249
+ }) as never;
250
+
251
+ try {
252
+ await precheckCommand({
253
+ feature: "test-feature",
254
+ dir: projectDir,
255
+ json: false,
256
+ });
257
+ } catch (err) {
258
+ // Expected
259
+ } finally {
260
+ process.exit = originalExit;
261
+ console.error = originalError;
262
+ console.log = originalLog;
263
+ }
264
+
265
+ expect(exitCode).toBe(EXIT_CODES.INVALID_PRD);
266
+ });
267
+
268
+ test("should exit with code 2 when prd.json is missing", async () => {
269
+ const { projectDir } = setupTestProject("test-missing-prd");
270
+
271
+ // Don't create prd.json
272
+
273
+ let exitCode: number | undefined;
274
+ const originalExit = process.exit;
275
+ const originalError = console.error;
276
+ console.error = () => {}; // Suppress error output
277
+
278
+ process.exit = ((code?: number) => {
279
+ exitCode = code;
280
+ }) as never;
281
+
282
+ try {
283
+ await precheckCommand({
284
+ feature: "test-feature",
285
+ dir: projectDir,
286
+ json: false,
287
+ });
288
+ } catch (err) {
289
+ // Expected
290
+ } finally {
291
+ process.exit = originalExit;
292
+ console.error = originalError;
293
+ }
294
+
295
+ expect(exitCode).toBe(EXIT_CODES.INVALID_PRD);
296
+ });
297
+
298
+ test("should handle missing feature flag with error", async () => {
299
+ const { projectDir, naxDir } = setupTestProject("test-no-feature");
300
+
301
+ // Remove feature from config
302
+ await Bun.write(
303
+ join(naxDir, "config.json"),
304
+ JSON.stringify(
305
+ {
306
+ routing: { enabled: true },
307
+ quality: { test: { enabled: true } },
308
+ },
309
+ null,
310
+ 2,
311
+ ),
312
+ );
313
+
314
+ let exitCode: number | undefined;
315
+ const originalExit = process.exit;
316
+ const originalError = console.error;
317
+ console.error = () => {}; // Suppress error output
318
+
319
+ process.exit = ((code?: number) => {
320
+ exitCode = code;
321
+ }) as never;
322
+
323
+ try {
324
+ await precheckCommand({
325
+ dir: projectDir,
326
+ json: false,
327
+ });
328
+ } catch (err) {
329
+ // Expected
330
+ } finally {
331
+ process.exit = originalExit;
332
+ console.error = originalError;
333
+ }
334
+
335
+ expect(exitCode).toBe(1);
336
+ });
337
+
338
+ test("should use resolveProject() for directory resolution", async () => {
339
+ const { projectDir, prdPath } = setupTestProject("test-resolve-project");
340
+
341
+ // Write valid PRD
342
+ await Bun.write(prdPath, JSON.stringify(createValidPRD()));
343
+
344
+ // Commit to satisfy checks
345
+ Bun.spawnSync(["git", "add", "."], { cwd: projectDir });
346
+ Bun.spawnSync(["git", "commit", "-m", "init", "-q"], { cwd: projectDir });
347
+
348
+ let exitCode: number | undefined;
349
+ const originalExit = process.exit;
350
+ process.exit = ((code?: number) => {
351
+ exitCode = code;
352
+ }) as never;
353
+
354
+ try {
355
+ // Should resolve project from explicit -d flag
356
+ await precheckCommand({
357
+ feature: "test-feature",
358
+ dir: projectDir,
359
+ json: false,
360
+ });
361
+ } catch (err) {
362
+ // Expected
363
+ } finally {
364
+ process.exit = originalExit;
365
+ }
366
+
367
+ // Should succeed (or have blockers, but not fail to resolve)
368
+ expect(exitCode).toBeDefined();
369
+ expect(exitCode).not.toBe(undefined);
370
+ });
371
+ });
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Integration test for headless mode with formatter
3
+ *
4
+ * Verifies that `nax run` uses formatted output in headless mode
5
+ * instead of raw JSONL, while still writing JSONL to disk.
6
+ */
7
+
8
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
9
+ import { existsSync, mkdirSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { initLogger, resetLogger } from "../../src/logger";
12
+
13
+ describe("Headless mode formatter integration", () => {
14
+ const testDir = join(import.meta.dir, "..", "tmp", "headless-test");
15
+ const logFile = join(testDir, "test.jsonl");
16
+
17
+ beforeEach(() => {
18
+ // Clean up any existing logger
19
+ resetLogger();
20
+
21
+ // Create test directory
22
+ mkdirSync(testDir, { recursive: true });
23
+ });
24
+
25
+ afterEach(() => {
26
+ resetLogger();
27
+ });
28
+
29
+ test("logger uses formatter in headless mode with normal verbosity", async () => {
30
+ // Initialize logger in headless mode with normal verbosity
31
+ const logger = initLogger({
32
+ level: "info",
33
+ filePath: logFile,
34
+ useChalk: false, // Disable colors for test output
35
+ formatterMode: "normal",
36
+ headless: true,
37
+ });
38
+
39
+ // Capture console output
40
+ const originalLog = console.log;
41
+ const outputs: string[] = [];
42
+ console.log = (msg: string) => {
43
+ outputs.push(msg);
44
+ };
45
+
46
+ try {
47
+ // Log a test message
48
+ logger.info("test.stage", "Test message", { foo: "bar" });
49
+
50
+ // Verify console output uses formatter (not raw JSONL)
51
+ expect(outputs.length).toBeGreaterThan(0);
52
+ const output = outputs[0];
53
+
54
+ // Should NOT be raw JSON
55
+ expect(output.startsWith("{")).toBe(false);
56
+
57
+ // Should contain formatted elements
58
+ expect(output).toContain("test.stage");
59
+ expect(output).toContain("Test message");
60
+ } finally {
61
+ console.log = originalLog;
62
+ }
63
+
64
+ // Verify JSONL file was written
65
+ expect(existsSync(logFile)).toBe(true);
66
+ const fileContent = await Bun.file(logFile).text();
67
+ expect(fileContent).toContain('"stage":"test.stage"');
68
+ expect(fileContent).toContain('"message":"Test message"');
69
+ });
70
+
71
+ test("logger outputs raw JSONL in json mode", () => {
72
+ // Initialize logger in headless mode with json verbosity
73
+ const logger = initLogger({
74
+ level: "info",
75
+ filePath: logFile,
76
+ useChalk: false,
77
+ formatterMode: "json",
78
+ headless: true,
79
+ });
80
+
81
+ // Capture console output
82
+ const originalLog = console.log;
83
+ const outputs: string[] = [];
84
+ console.log = (msg: string) => {
85
+ outputs.push(msg);
86
+ };
87
+
88
+ try {
89
+ // Log a test message
90
+ logger.info("test.stage", "Test message", { foo: "bar" });
91
+
92
+ // Verify console output is raw JSONL
93
+ expect(outputs.length).toBe(1);
94
+ const output = outputs[0];
95
+
96
+ // Should be valid JSON
97
+ const parsed = JSON.parse(output);
98
+ expect(parsed.stage).toBe("test.stage");
99
+ expect(parsed.message).toBe("Test message");
100
+ expect(parsed.data.foo).toBe("bar");
101
+ } finally {
102
+ console.log = originalLog;
103
+ }
104
+ });
105
+
106
+ test("logger suppresses debug logs in quiet mode", () => {
107
+ // Initialize logger in quiet mode
108
+ const logger = initLogger({
109
+ level: "debug", // Log level allows everything through
110
+ filePath: logFile,
111
+ useChalk: false,
112
+ formatterMode: "quiet", // Formatter filters what's displayed
113
+ headless: true,
114
+ });
115
+
116
+ // Capture console output
117
+ const originalLog = console.log;
118
+ const outputs: string[] = [];
119
+ console.log = (msg: string) => {
120
+ outputs.push(msg);
121
+ };
122
+
123
+ try {
124
+ // Log debug and info messages
125
+ logger.debug("test.stage", "Debug message");
126
+ logger.info("test.stage", "Info message");
127
+
128
+ // In quiet mode, info logs should be filtered out
129
+ // (unless they're critical events like run.start/run.end)
130
+ expect(outputs.length).toBe(0);
131
+
132
+ // But errors should still show (reset outputs first)
133
+ outputs.length = 0;
134
+ logger.error("test.stage", "Error message");
135
+ expect(outputs.length).toBe(1);
136
+ expect(outputs[0]).toContain("Error message");
137
+ } finally {
138
+ console.log = originalLog;
139
+ }
140
+ });
141
+
142
+ test("logger uses default console formatter when not in headless mode", () => {
143
+ // Initialize logger WITHOUT headless mode
144
+ const logger = initLogger({
145
+ level: "info",
146
+ filePath: logFile,
147
+ useChalk: false,
148
+ headless: false, // Not headless
149
+ });
150
+
151
+ // Capture console output
152
+ const originalLog = console.log;
153
+ const outputs: string[] = [];
154
+ console.log = (msg: string) => {
155
+ outputs.push(msg);
156
+ };
157
+
158
+ try {
159
+ // Log a test message
160
+ logger.info("test.stage", "Test message", { foo: "bar" });
161
+
162
+ // Verify console output uses default console formatter (not formatter)
163
+ expect(outputs.length).toBeGreaterThan(0);
164
+ const output = outputs[0];
165
+
166
+ // Default console format includes [timestamp] [stage] message
167
+ expect(output).toContain("[test.stage]");
168
+ expect(output).toContain("Test message");
169
+ } finally {
170
+ console.log = originalLog;
171
+ }
172
+ });
173
+ });
@@ -0,0 +1,75 @@
1
+ /**
2
+ * CLI --parallel flag tests
3
+ *
4
+ * Validates that the --parallel flag is correctly parsed and passed to RunOptions.
5
+ */
6
+
7
+ import { describe, expect, test } from "bun:test";
8
+ import type { RunOptions } from "../../src/execution/runner";
9
+
10
+ describe("CLI --parallel flag parsing", () => {
11
+ test("parses --parallel 4 correctly", () => {
12
+ // Simulate parsing --parallel 4
13
+ const parallelArg = "4";
14
+ const parallel = Number.parseInt(parallelArg, 10);
15
+
16
+ expect(parallel).toBe(4);
17
+ expect(Number.isNaN(parallel)).toBe(false);
18
+ expect(parallel).toBeGreaterThanOrEqual(0);
19
+ });
20
+
21
+ test("parses --parallel 0 (auto-detect mode) correctly", () => {
22
+ const parallelArg = "0";
23
+ const parallel = Number.parseInt(parallelArg, 10);
24
+
25
+ expect(parallel).toBe(0);
26
+ expect(Number.isNaN(parallel)).toBe(false);
27
+ });
28
+
29
+ test("omitted --parallel defaults to undefined (sequential)", () => {
30
+ // When flag is not provided, parallel should be undefined
31
+ const parallel: number | undefined = undefined;
32
+
33
+ expect(parallel).toBeUndefined();
34
+ });
35
+
36
+ test("rejects negative --parallel values", () => {
37
+ const parallelArg = "-1";
38
+ const parallel = Number.parseInt(parallelArg, 10);
39
+
40
+ expect(parallel).toBe(-1);
41
+ expect(parallel).toBeLessThan(0);
42
+ });
43
+
44
+ test("rejects non-numeric --parallel values", () => {
45
+ const parallelArg = "abc";
46
+ const parallel = Number.parseInt(parallelArg, 10);
47
+
48
+ expect(Number.isNaN(parallel)).toBe(true);
49
+ });
50
+
51
+ test("RunOptions accepts parallel field", () => {
52
+ // Type-check that RunOptions accepts parallel field
53
+ const options: Partial<RunOptions> = {
54
+ parallel: 4,
55
+ };
56
+
57
+ expect(options.parallel).toBe(4);
58
+ });
59
+
60
+ test("RunOptions accepts parallel=0 (auto-detect)", () => {
61
+ const options: Partial<RunOptions> = {
62
+ parallel: 0,
63
+ };
64
+
65
+ expect(options.parallel).toBe(0);
66
+ });
67
+
68
+ test("RunOptions accepts parallel=undefined (sequential)", () => {
69
+ const options: Partial<RunOptions> = {
70
+ parallel: undefined,
71
+ };
72
+
73
+ expect(options.parallel).toBeUndefined();
74
+ });
75
+ });