@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,399 @@
1
+ /**
2
+ * Tests for BUG-2 (queue race condition) and PERF-1 (batching optimization)
3
+ * Tests for PERF-2 (PRD dirty-flag reload optimization) and MEM-1 (file size limit)
4
+ */
5
+
6
+ import { beforeEach, describe, expect, test } from "bun:test";
7
+ import path from "node:path";
8
+ import { groupStoriesIntoBatches } from "../../src/execution/runner";
9
+ import type { PRD, UserStory } from "../../src/prd";
10
+ import { PRD_MAX_FILE_SIZE, loadPRD } from "../../src/prd";
11
+
12
+ // Helper to create test stories
13
+ function createStory(
14
+ id: string,
15
+ complexity: "simple" | "medium" | "complex" | "expert" = "simple",
16
+ testStrategy: "test-after" | "three-session-tdd" = "test-after",
17
+ ): UserStory {
18
+ return {
19
+ id,
20
+ title: `Story ${id}`,
21
+ description: "Test story",
22
+ acceptanceCriteria: ["AC1"],
23
+ dependencies: [],
24
+ tags: [],
25
+ status: "pending",
26
+ passes: false,
27
+ escalations: [],
28
+ attempts: 0,
29
+ routing: {
30
+ complexity,
31
+ modelTier: "fast",
32
+ testStrategy,
33
+ reasoning: "Test routing",
34
+ },
35
+ };
36
+ }
37
+
38
+ describe("BUG-2: Queue race condition", () => {
39
+ let tmpDir: string;
40
+
41
+ beforeEach(async () => {
42
+ tmpDir = `/tmp/nax-race-test-${Date.now()}`;
43
+ await Bun.spawn(["mkdir", "-p", tmpDir], { stdout: "pipe" }).exited;
44
+ });
45
+
46
+ test("atomic read-and-rename prevents race condition", async () => {
47
+ const queuePath = path.join(tmpDir, ".queue.txt");
48
+ const processingPath = path.join(tmpDir, ".queue.txt.processing");
49
+
50
+ // Write initial commands
51
+ await Bun.write(queuePath, "PAUSE\n");
52
+
53
+ // Simulate reader starting (rename to processing)
54
+ await Bun.spawn(["mv", queuePath, processingPath], { stdout: "pipe" }).exited;
55
+
56
+ // Simulate concurrent writer adding commands (should create new .queue.txt)
57
+ await Bun.write(queuePath, "SKIP US-001\n");
58
+
59
+ // Verify processing file exists
60
+ const processingFile = Bun.file(processingPath);
61
+ expect(await processingFile.exists()).toBe(true);
62
+ const processingContent = await processingFile.text();
63
+ expect(processingContent).toBe("PAUSE\n");
64
+
65
+ // Verify new queue file exists with new content
66
+ const newQueueFile = Bun.file(queuePath);
67
+ expect(await newQueueFile.exists()).toBe(true);
68
+ const newContent = await newQueueFile.text();
69
+ expect(newContent).toBe("SKIP US-001\n");
70
+
71
+ // Cleanup
72
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
73
+ });
74
+
75
+ test("processing file is deleted after reading", async () => {
76
+ const queuePath = path.join(tmpDir, ".queue.txt");
77
+ const processingPath = path.join(tmpDir, ".queue.txt.processing");
78
+
79
+ // Write commands
80
+ await Bun.write(queuePath, "PAUSE\n");
81
+
82
+ // Rename to processing
83
+ await Bun.spawn(["mv", queuePath, processingPath], { stdout: "pipe" }).exited;
84
+
85
+ // Verify processing file exists
86
+ expect(await Bun.file(processingPath).exists()).toBe(true);
87
+
88
+ // Simulate cleanup (delete processing file)
89
+ await Bun.spawn(["rm", processingPath], { stdout: "pipe" }).exited;
90
+
91
+ // Verify processing file is deleted
92
+ expect(await Bun.file(processingPath).exists()).toBe(false);
93
+
94
+ // Cleanup
95
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
96
+ });
97
+
98
+ test("concurrent writes during processing don't lose commands", async () => {
99
+ const queuePath = path.join(tmpDir, ".queue.txt");
100
+ const processingPath = path.join(tmpDir, ".queue.txt.processing");
101
+
102
+ // Write initial batch
103
+ await Bun.write(queuePath, "PAUSE\nSKIP US-001\n");
104
+
105
+ // Reader: rename to processing
106
+ await Bun.spawn(["mv", queuePath, processingPath], { stdout: "pipe" }).exited;
107
+
108
+ // Writer: add new commands (creates new .queue.txt)
109
+ await Bun.write(queuePath, "SKIP US-002\nSKIP US-003\n");
110
+
111
+ // Reader: read processing file
112
+ const processingContent = await Bun.file(processingPath).text();
113
+ const processedLines = processingContent.trim().split("\n");
114
+
115
+ // Reader: delete processing file
116
+ await Bun.spawn(["rm", processingPath], { stdout: "pipe" }).exited;
117
+
118
+ // Verify original commands were processed
119
+ expect(processedLines).toEqual(["PAUSE", "SKIP US-001"]);
120
+
121
+ // Verify new commands are in queue
122
+ const newContent = await Bun.file(queuePath).text();
123
+ const newLines = newContent.trim().split("\n");
124
+ expect(newLines).toEqual(["SKIP US-002", "SKIP US-003"]);
125
+
126
+ // Cleanup
127
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
128
+ });
129
+ });
130
+
131
+ describe("BUG-2: File locking", () => {
132
+ let tmpDir: string;
133
+
134
+ beforeEach(async () => {
135
+ tmpDir = `/tmp/nax-lock-test-${Date.now()}`;
136
+ await Bun.spawn(["mkdir", "-p", tmpDir], { stdout: "pipe" }).exited;
137
+ });
138
+
139
+ test("lock file prevents concurrent execution", async () => {
140
+ const lockPath = path.join(tmpDir, "nax.lock");
141
+
142
+ // Create lock
143
+ const lockData = {
144
+ pid: process.pid,
145
+ timestamp: Date.now(),
146
+ };
147
+ await Bun.write(lockPath, JSON.stringify(lockData));
148
+
149
+ // Verify lock exists
150
+ const lockFile = Bun.file(lockPath);
151
+ expect(await lockFile.exists()).toBe(true);
152
+
153
+ // Verify lock content
154
+ const content = await lockFile.text();
155
+ const parsed = JSON.parse(content);
156
+ expect(parsed.pid).toBe(process.pid);
157
+ expect(parsed.timestamp).toBeGreaterThan(0);
158
+
159
+ // Cleanup
160
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
161
+ });
162
+
163
+ test("stale lock is removed after 1 hour", async () => {
164
+ const lockPath = path.join(tmpDir, "nax.lock");
165
+
166
+ // Create stale lock (2 hours old)
167
+ const staleLockData = {
168
+ pid: 99999,
169
+ timestamp: Date.now() - 2 * 60 * 60 * 1000, // 2 hours ago
170
+ };
171
+ await Bun.write(lockPath, JSON.stringify(staleLockData));
172
+
173
+ // Verify lock is stale
174
+ const lockContent = await Bun.file(lockPath).text();
175
+ const lockData = JSON.parse(lockContent);
176
+ const lockAge = Date.now() - lockData.timestamp;
177
+ const ONE_HOUR = 60 * 60 * 1000;
178
+ expect(lockAge).toBeGreaterThan(ONE_HOUR);
179
+
180
+ // Cleanup
181
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
182
+ });
183
+
184
+ test("lock is released after execution", async () => {
185
+ const lockPath = path.join(tmpDir, "nax.lock");
186
+
187
+ // Create lock
188
+ const lockData = {
189
+ pid: process.pid,
190
+ timestamp: Date.now(),
191
+ };
192
+ await Bun.write(lockPath, JSON.stringify(lockData));
193
+
194
+ // Verify lock exists
195
+ expect(await Bun.file(lockPath).exists()).toBe(true);
196
+
197
+ // Simulate release (delete lock)
198
+ await Bun.spawn(["rm", lockPath], { stdout: "pipe" }).exited;
199
+
200
+ // Verify lock is removed
201
+ expect(await Bun.file(lockPath).exists()).toBe(false);
202
+
203
+ // Cleanup
204
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
205
+ });
206
+ });
207
+
208
+ describe("PERF-1: Batch optimization", () => {
209
+ test("groups consecutive simple stories correctly", () => {
210
+ const stories: UserStory[] = [
211
+ createStory("US-001", "simple", "test-after"),
212
+ createStory("US-002", "simple", "test-after"),
213
+ createStory("US-003", "simple", "test-after"),
214
+ createStory("US-004", "medium", "test-after"),
215
+ createStory("US-005", "simple", "test-after"),
216
+ ];
217
+
218
+ const batches = groupStoriesIntoBatches(stories, 4);
219
+
220
+ expect(batches).toHaveLength(3);
221
+ expect(batches[0].stories).toHaveLength(3); // US-001, US-002, US-003
222
+ expect(batches[0].isBatch).toBe(true);
223
+ expect(batches[1].stories).toHaveLength(1); // US-004 (medium)
224
+ expect(batches[1].isBatch).toBe(false);
225
+ expect(batches[2].stories).toHaveLength(1); // US-005 (simple, but alone)
226
+ expect(batches[2].isBatch).toBe(false);
227
+ });
228
+
229
+ test("respects max batch size", () => {
230
+ const stories: UserStory[] = [
231
+ createStory("US-001", "simple", "test-after"),
232
+ createStory("US-002", "simple", "test-after"),
233
+ createStory("US-003", "simple", "test-after"),
234
+ createStory("US-004", "simple", "test-after"),
235
+ createStory("US-005", "simple", "test-after"),
236
+ createStory("US-006", "simple", "test-after"),
237
+ ];
238
+
239
+ const batches = groupStoriesIntoBatches(stories, 4);
240
+
241
+ expect(batches).toHaveLength(2);
242
+ expect(batches[0].stories).toHaveLength(4); // US-001 to US-004
243
+ expect(batches[0].isBatch).toBe(true);
244
+ expect(batches[1].stories).toHaveLength(2); // US-005, US-006
245
+ expect(batches[1].isBatch).toBe(true);
246
+ });
247
+
248
+ test("handles mixed complexity correctly", () => {
249
+ const stories: UserStory[] = [
250
+ createStory("US-001", "simple", "test-after"),
251
+ createStory("US-002", "medium", "test-after"),
252
+ createStory("US-003", "simple", "test-after"),
253
+ createStory("US-004", "complex", "three-session-tdd"),
254
+ createStory("US-005", "simple", "test-after"),
255
+ ];
256
+
257
+ const batches = groupStoriesIntoBatches(stories, 4);
258
+
259
+ expect(batches).toHaveLength(5);
260
+ // Each non-simple story creates its own batch
261
+ expect(batches[0].stories).toHaveLength(1); // US-001
262
+ expect(batches[1].stories).toHaveLength(1); // US-002
263
+ expect(batches[2].stories).toHaveLength(1); // US-003
264
+ expect(batches[3].stories).toHaveLength(1); // US-004
265
+ expect(batches[4].stories).toHaveLength(1); // US-005
266
+ });
267
+
268
+ test("large story list performance", () => {
269
+ // Create 1000 stories
270
+ const stories: UserStory[] = [];
271
+ for (let i = 0; i < 1000; i++) {
272
+ const complexity = i % 3 === 0 ? "simple" : "medium";
273
+ stories.push(createStory(`US-${String(i + 1).padStart(4, "0")}`, complexity, "test-after"));
274
+ }
275
+
276
+ const startTime = Date.now();
277
+ const batches = groupStoriesIntoBatches(stories, 4);
278
+ const duration = Date.now() - startTime;
279
+
280
+ // Should complete in under 100ms for 1000 stories
281
+ expect(duration).toBeLessThan(100);
282
+
283
+ // Verify batches were created
284
+ expect(batches.length).toBeGreaterThan(0);
285
+ });
286
+
287
+ test("uses pre-computed routing", () => {
288
+ // Stories with routing already set (from analyze phase)
289
+ const stories: UserStory[] = [
290
+ createStory("US-001", "simple", "test-after"),
291
+ createStory("US-002", "simple", "test-after"),
292
+ ];
293
+
294
+ const batches = groupStoriesIntoBatches(stories, 4);
295
+
296
+ // Should use routing from story.routing, not re-compute
297
+ expect(batches).toHaveLength(1);
298
+ expect(batches[0].stories).toHaveLength(2);
299
+ expect(batches[0].isBatch).toBe(true);
300
+ });
301
+ });
302
+
303
+ describe("PERF-2 & MEM-1: PRD file size limit and dirty-flag optimization", () => {
304
+ let tmpDir: string;
305
+
306
+ beforeEach(async () => {
307
+ tmpDir = `/tmp/nax-prd-test-${Date.now()}`;
308
+ await Bun.spawn(["mkdir", "-p", tmpDir], { stdout: "pipe" }).exited;
309
+ });
310
+
311
+ test("rejects PRD files exceeding size limit", async () => {
312
+ const prdPath = path.join(tmpDir, "prd.json");
313
+
314
+ // Create a minimal PRD structure
315
+ const largePRD: PRD = {
316
+ project: "test-project",
317
+ feature: "test-feature",
318
+ branchName: "test-branch",
319
+ createdAt: new Date().toISOString(),
320
+ updatedAt: new Date().toISOString(),
321
+ userStories: [],
322
+ };
323
+
324
+ // Add enough stories to exceed 5MB limit
325
+ // Each story is roughly 500 bytes, so we need ~10,000 stories
326
+ const storyTemplate = {
327
+ title: "Test Story with long description and multiple acceptance criteria",
328
+ description: "A".repeat(200), // 200 character description
329
+ acceptanceCriteria: Array.from({ length: 5 }, (_, i) => `Acceptance criterion ${i}: ${"x".repeat(50)}`),
330
+ dependencies: [],
331
+ tags: ["test", "performance", "large-prd"],
332
+ status: "pending" as const,
333
+ passes: false,
334
+ escalations: [],
335
+ attempts: 0,
336
+ };
337
+
338
+ for (let i = 0; i < 11000; i++) {
339
+ largePRD.userStories.push({
340
+ ...storyTemplate,
341
+ id: `US-${String(i + 1).padStart(5, "0")}`,
342
+ });
343
+ }
344
+
345
+ // Write large PRD
346
+ await Bun.write(prdPath, JSON.stringify(largePRD, null, 2));
347
+
348
+ // Verify file size exceeds limit
349
+ const stats = await Bun.file(prdPath).stat();
350
+ expect(stats.size).toBeGreaterThan(PRD_MAX_FILE_SIZE);
351
+
352
+ // Try to load — should throw error
353
+ try {
354
+ await loadPRD(prdPath);
355
+ expect(true).toBe(false); // Should not reach here
356
+ } catch (error) {
357
+ expect(error).toBeInstanceOf(Error);
358
+ expect((error as Error).message).toContain("too large");
359
+ expect((error as Error).message).toContain("exceeds");
360
+ expect((error as Error).message).toContain("MB");
361
+ }
362
+
363
+ // Cleanup
364
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
365
+ });
366
+
367
+ test("accepts PRD files within size limit", async () => {
368
+ const prdPath = path.join(tmpDir, "prd.json");
369
+
370
+ // Create a normal-sized PRD
371
+ const prd: PRD = {
372
+ project: "test-project",
373
+ feature: "test-feature",
374
+ branchName: "test-branch",
375
+ createdAt: new Date().toISOString(),
376
+ updatedAt: new Date().toISOString(),
377
+ userStories: [createStory("US-001", "simple", "test-after"), createStory("US-002", "simple", "test-after")],
378
+ };
379
+
380
+ // Write PRD
381
+ await Bun.write(prdPath, JSON.stringify(prd, null, 2));
382
+
383
+ // Verify file size is within limit
384
+ const stats = await Bun.file(prdPath).stat();
385
+ expect(stats.size).toBeLessThan(PRD_MAX_FILE_SIZE);
386
+
387
+ // Should load successfully
388
+ const loaded = await loadPRD(prdPath);
389
+ expect(loaded.userStories).toHaveLength(2);
390
+ expect(loaded.project).toBe("test-project");
391
+
392
+ // Cleanup
393
+ await Bun.spawn(["rm", "-rf", tmpDir], { stdout: "pipe" }).exited;
394
+ });
395
+
396
+ test("PRD_MAX_FILE_SIZE constant is 5MB", () => {
397
+ expect(PRD_MAX_FILE_SIZE).toBe(5 * 1024 * 1024);
398
+ });
399
+ });