@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,261 @@
1
+ /**
2
+ * Integration Tests for Analyze Command
3
+ */
4
+
5
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
6
+ import { existsSync, mkdirSync, rmSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import { analyzeFeature } from "../../src/cli/analyze";
9
+ import { DEFAULT_CONFIG } from "../../src/config";
10
+
11
+ describe("analyzeFeature integration", () => {
12
+ const testDir = "/tmp/nax-analyze-test";
13
+ const featureDir = join(testDir, "nax/features/test-feature");
14
+
15
+ beforeAll(() => {
16
+ // Create test directory structure
17
+ if (existsSync(testDir)) {
18
+ rmSync(testDir, { recursive: true });
19
+ }
20
+ mkdirSync(featureDir, { recursive: true });
21
+
22
+ // Create test spec.md
23
+ const specContent = `# Test Feature
24
+
25
+ ## US-001: Add user authentication
26
+
27
+ ### Description
28
+ Implement JWT-based authentication with refresh tokens.
29
+
30
+ ### Acceptance Criteria
31
+ - [ ] User can log in with email/password
32
+ - [ ] JWT token is generated and stored
33
+ - [ ] Refresh token logic works
34
+ - [ ] Token expiry is handled
35
+
36
+ Tags: security, auth
37
+ Dependencies: none
38
+
39
+ ## US-002: Update homepage UI
40
+
41
+ ### Description
42
+ Refresh the homepage design with new color scheme.
43
+
44
+ ### Acceptance Criteria
45
+ - [ ] New colors applied
46
+ - [ ] Layout is responsive
47
+
48
+ Tags: ui
49
+ Dependencies: none
50
+ `;
51
+
52
+ Bun.write(join(featureDir, "spec.md"), specContent);
53
+
54
+ // Create mock src/ directory
55
+ mkdirSync(join(testDir, "src"), { recursive: true });
56
+ Bun.write(join(testDir, "src/index.ts"), "export {}");
57
+
58
+ // Create mock package.json
59
+ Bun.write(
60
+ join(testDir, "package.json"),
61
+ JSON.stringify({
62
+ name: "test-project",
63
+ dependencies: { zod: "^4.0.0" },
64
+ devDependencies: { typescript: "^5.0.0" },
65
+ }),
66
+ );
67
+ });
68
+
69
+ afterAll(() => {
70
+ // Cleanup
71
+ if (existsSync(testDir)) {
72
+ rmSync(testDir, { recursive: true });
73
+ }
74
+ });
75
+
76
+ test("parses spec.md into PRD structure", async () => {
77
+ const config = {
78
+ ...DEFAULT_CONFIG,
79
+ analyze: {
80
+ llmEnhanced: false, // Disable LLM for predictable tests
81
+ model: "fast" as const,
82
+ fallbackToKeywords: true,
83
+ maxCodebaseSummaryTokens: 5000,
84
+ },
85
+ };
86
+
87
+ const prd = await analyzeFeature({
88
+ featureDir,
89
+ featureName: "test-feature",
90
+ branchName: "feat/test-feature",
91
+ config,
92
+ });
93
+
94
+ expect(prd.project).toBe("nax");
95
+ expect(prd.feature).toBe("test-feature");
96
+ expect(prd.branchName).toBe("feat/test-feature");
97
+ expect(prd.userStories).toHaveLength(2);
98
+ });
99
+
100
+ test("extracts story metadata correctly", async () => {
101
+ const config = {
102
+ ...DEFAULT_CONFIG,
103
+ analyze: {
104
+ llmEnhanced: false,
105
+ model: "fast" as const,
106
+ fallbackToKeywords: true,
107
+ maxCodebaseSummaryTokens: 5000,
108
+ },
109
+ };
110
+
111
+ const prd = await analyzeFeature({
112
+ featureDir,
113
+ featureName: "test-feature",
114
+ branchName: "feat/test-feature",
115
+ config,
116
+ });
117
+
118
+ const story1 = prd.userStories[0];
119
+ expect(story1.id).toBe("US-001");
120
+ expect(story1.title).toBe("Add user authentication");
121
+ expect(story1.description).toContain("JWT-based authentication");
122
+ expect(story1.acceptanceCriteria).toHaveLength(4);
123
+ expect(story1.tags).toContain("security");
124
+ expect(story1.tags).toContain("auth");
125
+ expect(story1.status).toBe("pending");
126
+ expect(story1.passes).toBe(false);
127
+ });
128
+
129
+ test("applies routing when LLM disabled (keyword fallback)", async () => {
130
+ const config = {
131
+ ...DEFAULT_CONFIG,
132
+ analyze: {
133
+ llmEnhanced: false,
134
+ model: "fast" as const,
135
+ fallbackToKeywords: true,
136
+ maxCodebaseSummaryTokens: 5000,
137
+ },
138
+ };
139
+
140
+ const prd = await analyzeFeature({
141
+ featureDir,
142
+ featureName: "test-feature",
143
+ branchName: "feat/test-feature",
144
+ config,
145
+ });
146
+
147
+ // Routing should be applied with keyword classification
148
+ expect(prd.userStories[0].routing).toBeDefined();
149
+ expect(prd.userStories[1].routing).toBeDefined();
150
+ });
151
+
152
+ test.skip("scans codebase when LLM enabled", async () => {
153
+ // Skipped: This test would require a real agent installation and API key
154
+ // The LLM decompose flow is tested in unit tests with mocked agents
155
+ const config = {
156
+ ...DEFAULT_CONFIG,
157
+ analyze: {
158
+ llmEnhanced: true,
159
+ model: "fast" as const,
160
+ fallbackToKeywords: true,
161
+ maxCodebaseSummaryTokens: 5000,
162
+ },
163
+ };
164
+
165
+ // This will trigger LLM decompose (will fall back due to no agent in test)
166
+ const prd = await analyzeFeature({
167
+ featureDir,
168
+ featureName: "test-feature",
169
+ branchName: "feat/test-feature",
170
+ config,
171
+ });
172
+
173
+ // Should have routing metadata from keyword fallback
174
+ expect(prd.userStories[0].routing).toBeDefined();
175
+ expect(prd.userStories[1].routing).toBeDefined();
176
+
177
+ // First story should be complex (security keywords)
178
+ expect(prd.userStories[0].routing?.complexity).toBe("complex");
179
+
180
+ // Second story should be simple
181
+ expect(prd.userStories[1].routing?.complexity).toBe("simple");
182
+ });
183
+
184
+ test("throws error when spec.md missing", async () => {
185
+ const emptyDir = "/tmp/nax-empty-test";
186
+ mkdirSync(emptyDir, { recursive: true });
187
+
188
+ try {
189
+ await expect(
190
+ analyzeFeature({
191
+ featureDir: emptyDir,
192
+ featureName: "empty",
193
+ branchName: "feat/empty",
194
+ }),
195
+ ).rejects.toThrow("spec.md not found");
196
+ } finally {
197
+ rmSync(emptyDir, { recursive: true });
198
+ }
199
+ });
200
+
201
+ test("throws error when no stories found", async () => {
202
+ const noStoriesDir = "/tmp/nax-no-stories-test";
203
+ const featurePath = join(noStoriesDir, "nax/features/test");
204
+ mkdirSync(featurePath, { recursive: true });
205
+
206
+ // Create empty spec.md
207
+ await Bun.write(join(featurePath, "spec.md"), "# Empty\n\nNo stories here.");
208
+
209
+ try {
210
+ await expect(
211
+ analyzeFeature({
212
+ featureDir: featurePath,
213
+ featureName: "test",
214
+ branchName: "feat/test",
215
+ }),
216
+ ).rejects.toThrow("No user stories found");
217
+ } finally {
218
+ rmSync(noStoriesDir, { recursive: true });
219
+ }
220
+ });
221
+
222
+ test("warns but succeeds when story count exceeds maxStoriesPerFeature limit", async () => {
223
+ const manyStoriesDir = "/tmp/nax-many-stories-test";
224
+ const featurePath = join(manyStoriesDir, "nax/features/test");
225
+ mkdirSync(featurePath, { recursive: true });
226
+
227
+ // Create spec.md with 6 stories (exceeds limit of 5)
228
+ let specContent = "# Many Stories\n\n";
229
+ for (let i = 1; i <= 6; i++) {
230
+ specContent += `## US-${String(i).padStart(3, "0")}: Story ${i}\n\n`;
231
+ specContent += `### Description\nStory ${i}\n\n`;
232
+ specContent += `### Acceptance Criteria\n- [ ] Done\n\n`;
233
+ }
234
+ await Bun.write(join(featurePath, "spec.md"), specContent);
235
+
236
+ const config = {
237
+ ...DEFAULT_CONFIG,
238
+ execution: {
239
+ ...DEFAULT_CONFIG.execution,
240
+ maxStoriesPerFeature: 5,
241
+ },
242
+ analyze: {
243
+ ...DEFAULT_CONFIG.analyze,
244
+ llmEnhanced: false,
245
+ },
246
+ };
247
+
248
+ try {
249
+ // Should warn but not throw (changed from hard error to warning)
250
+ const prd = await analyzeFeature({
251
+ featureDir: featurePath,
252
+ featureName: "test",
253
+ branchName: "feat/test",
254
+ config,
255
+ });
256
+ expect(prd.userStories.length).toBe(6);
257
+ } finally {
258
+ rmSync(manyStoriesDir, { recursive: true });
259
+ }
260
+ });
261
+ });
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Tests for Codebase Scanner
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+ import { existsSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import { scanCodebase } from "../../src/analyze/scanner";
9
+
10
+ describe("scanCodebase", () => {
11
+ test("scans project codebase successfully", async () => {
12
+ // Use the nax project itself as test data
13
+ const workdir = join(import.meta.dir, "..");
14
+
15
+ const scan = await scanCodebase(workdir);
16
+
17
+ // Should have file tree
18
+ expect(scan.fileTree).toBeTruthy();
19
+ expect(typeof scan.fileTree).toBe("string");
20
+ expect(scan.fileTree.length).toBeGreaterThan(0);
21
+
22
+ // Should have dependencies
23
+ expect(scan.dependencies).toBeDefined();
24
+ expect(typeof scan.dependencies).toBe("object");
25
+
26
+ // Should have dev dependencies
27
+ expect(scan.devDependencies).toBeDefined();
28
+ expect(typeof scan.devDependencies).toBe("object");
29
+
30
+ // Should detect test patterns
31
+ expect(scan.testPatterns).toBeDefined();
32
+ expect(Array.isArray(scan.testPatterns)).toBe(true);
33
+ expect(scan.testPatterns.length).toBeGreaterThan(0);
34
+ });
35
+
36
+ test("handles missing src directory", async () => {
37
+ const workdir = "/tmp/nax-test-no-src";
38
+
39
+ // Create temp dir without src/
40
+ await Bun.write(join(workdir, "package.json"), JSON.stringify({}));
41
+
42
+ const scan = await scanCodebase(workdir);
43
+
44
+ // Should return placeholder for missing src
45
+ expect(scan.fileTree).toBe("No src/ directory");
46
+ expect(scan.dependencies).toEqual({});
47
+ expect(scan.devDependencies).toEqual({});
48
+ });
49
+
50
+ test(
51
+ "extracts dependencies from package.json",
52
+ async () => {
53
+ const workdir = join(import.meta.dir, "../..");
54
+
55
+ const scan = await scanCodebase(workdir);
56
+
57
+ // Should have zod dependency (from real package.json)
58
+ expect(scan.dependencies.zod).toBeTruthy();
59
+ expect(scan.dependencies.commander).toBeTruthy();
60
+ },
61
+ 30000,
62
+ );
63
+
64
+ test(
65
+ "detects test framework",
66
+ async () => {
67
+ const workdir = join(import.meta.dir, "../..");
68
+
69
+ const scan = await scanCodebase(workdir);
70
+
71
+ // Should detect bun:test (no framework in package.json)
72
+ const hasBunTest = scan.testPatterns.some((p) => p.includes("bun:test"));
73
+ expect(hasBunTest).toBe(true);
74
+ },
75
+ 30000,
76
+ );
77
+
78
+ test(
79
+ "detects test directory",
80
+ async () => {
81
+ const workdir = join(import.meta.dir, "../..");
82
+
83
+ const scan = await scanCodebase(workdir);
84
+
85
+ // Should detect test/ directory
86
+ const hasTestDir = scan.testPatterns.some((p) => p.includes("test/"));
87
+ expect(hasTestDir).toBe(true);
88
+ },
89
+ 30000,
90
+ );
91
+
92
+ test(
93
+ "file tree respects max depth",
94
+ async () => {
95
+ const workdir = join(import.meta.dir, "../..");
96
+
97
+ const scan = await scanCodebase(workdir);
98
+
99
+ // File tree should not be excessively deep (max depth 3)
100
+ const lines = scan.fileTree.split("\n");
101
+ const maxIndent = Math.max(
102
+ ...lines.map((line) => {
103
+ const match = line.match(/^(│ {3}| {4})*/);
104
+ return match ? match[0].length / 4 : 0;
105
+ }),
106
+ );
107
+
108
+ // Max depth 3 means max indent of 2 (0-indexed)
109
+ expect(maxIndent).toBeLessThanOrEqual(3);
110
+ },
111
+ 30000,
112
+ );
113
+
114
+ test(
115
+ "file tree includes directories and files",
116
+ async () => {
117
+ const workdir = join(import.meta.dir, "../..");
118
+
119
+ const scan = await scanCodebase(workdir);
120
+
121
+ // Should contain directories (marked with trailing /)
122
+ const hasDirectories = scan.fileTree.includes("/");
123
+ expect(hasDirectories).toBe(true);
124
+
125
+ // Should contain some TypeScript files
126
+ const hasTsFiles = scan.fileTree.includes(".ts");
127
+ expect(hasTsFiles).toBe(true);
128
+ },
129
+ 30000,
130
+ );
131
+ });
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Edge Case Tests for `nax config` Default View
3
+ *
4
+ * Tests edge cases and regression scenarios for the default view.
5
+ * These tests ensure the feature handles unusual scenarios correctly.
6
+ */
7
+
8
+ import { describe, test, expect, beforeEach, afterEach } from "bun:test";
9
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
10
+ import { tmpdir } from "node:os";
11
+ import { join } from "node:path";
12
+
13
+ describe("nax config (default view) - edge cases", () => {
14
+ let tempDir: string;
15
+ let originalCwd: string;
16
+
17
+ beforeEach(() => {
18
+ tempDir = mkdtempSync(join(tmpdir(), "nax-config-edge-test-"));
19
+ originalCwd = process.cwd();
20
+ });
21
+
22
+ afterEach(() => {
23
+ process.chdir(originalCwd);
24
+ rmSync(tempDir, { recursive: true, force: true });
25
+ });
26
+
27
+ // NOTE: Error handling tests removed - those belong in a separate error handling story
28
+ // The current story (CM-003) focuses on the happy path: displaying config when files are valid
29
+
30
+ test("handles project config with only comments (valid but empty JSON)", async () => {
31
+ // Create project config with only {}
32
+ const naxDir = join(tempDir, "nax");
33
+ mkdirSync(naxDir, { recursive: true });
34
+ writeFileSync(join(naxDir, "config.json"), "{}");
35
+
36
+ process.chdir(tempDir);
37
+
38
+ const proc = Bun.spawn(["bun", join(import.meta.dir, "../../bin/nax.ts"), "config"], {
39
+ cwd: tempDir,
40
+ stdout: "pipe",
41
+ stderr: "pipe",
42
+ });
43
+
44
+ const output = await new Response(proc.stdout).text();
45
+ const exitCode = await proc.exited;
46
+
47
+ expect(exitCode).toBe(0);
48
+
49
+ // Should show project config as found (even though it's empty)
50
+ expect(output).toContain("// Project config:");
51
+ expect(output).toContain("config.json");
52
+
53
+ // Should still output valid JSON (merged with defaults)
54
+ const lines = output.split("\n");
55
+ const jsonStartIndex = lines.findIndex((line) => line.startsWith("{"));
56
+ const jsonOutput = lines.slice(jsonStartIndex).join("\n");
57
+ const parsed = JSON.parse(jsonOutput);
58
+ expect(parsed.version).toBe(1);
59
+ });
60
+
61
+ test("handles deep nesting when walking up directory tree", async () => {
62
+ // Create project config at root
63
+ const naxDir = join(tempDir, "nax");
64
+ mkdirSync(naxDir, { recursive: true });
65
+ writeFileSync(
66
+ join(naxDir, "config.json"),
67
+ JSON.stringify({
68
+ execution: {
69
+ maxIterations: 50,
70
+ },
71
+ }),
72
+ );
73
+
74
+ // Create deeply nested subdirectory
75
+ const deepDir = join(tempDir, "a", "b", "c", "d", "e", "f");
76
+ mkdirSync(deepDir, { recursive: true });
77
+ process.chdir(deepDir);
78
+
79
+ const proc = Bun.spawn(["bun", join(import.meta.dir, "../../bin/nax.ts"), "config"], {
80
+ cwd: deepDir,
81
+ stdout: "pipe",
82
+ stderr: "pipe",
83
+ });
84
+
85
+ const output = await new Response(proc.stdout).text();
86
+ const exitCode = await proc.exited;
87
+
88
+ expect(exitCode).toBe(0);
89
+
90
+ // Should find project config by walking up
91
+ expect(output).toContain("// Project config:");
92
+ expect(output).toContain("config.json");
93
+
94
+ // Should reflect merged config
95
+ const lines = output.split("\n");
96
+ const jsonStartIndex = lines.findIndex((line) => line.startsWith("{"));
97
+ const jsonOutput = lines.slice(jsonStartIndex).join("\n");
98
+ const parsed = JSON.parse(jsonOutput);
99
+ expect(parsed.execution.maxIterations).toBe(50);
100
+ });
101
+
102
+ test("outputs complete config structure with all top-level keys", async () => {
103
+ process.chdir(tempDir);
104
+
105
+ const proc = Bun.spawn(["bun", join(import.meta.dir, "../../bin/nax.ts"), "config"], {
106
+ cwd: tempDir,
107
+ stdout: "pipe",
108
+ stderr: "pipe",
109
+ });
110
+
111
+ const output = await new Response(proc.stdout).text();
112
+ const exitCode = await proc.exited;
113
+
114
+ expect(exitCode).toBe(0);
115
+
116
+ const lines = output.split("\n");
117
+ const jsonStartIndex = lines.findIndex((line) => line.startsWith("{"));
118
+ const jsonOutput = lines.slice(jsonStartIndex).join("\n");
119
+ const parsed = JSON.parse(jsonOutput);
120
+
121
+ // Verify all required top-level keys are present
122
+ expect(parsed).toHaveProperty("version");
123
+ expect(parsed).toHaveProperty("models");
124
+ expect(parsed).toHaveProperty("autoMode");
125
+ expect(parsed).toHaveProperty("routing");
126
+ expect(parsed).toHaveProperty("execution");
127
+ expect(parsed).toHaveProperty("quality");
128
+ expect(parsed).toHaveProperty("tdd");
129
+ expect(parsed).toHaveProperty("constitution");
130
+ expect(parsed).toHaveProperty("analyze");
131
+ expect(parsed).toHaveProperty("review");
132
+ expect(parsed).toHaveProperty("plan");
133
+ expect(parsed).toHaveProperty("acceptance");
134
+ expect(parsed).toHaveProperty("context");
135
+ expect(parsed).toHaveProperty("interaction");
136
+ expect(parsed).toHaveProperty("precheck");
137
+ });
138
+
139
+ test("merges nested config overrides correctly", async () => {
140
+ // Create project config with nested overrides
141
+ const naxDir = join(tempDir, "nax");
142
+ mkdirSync(naxDir, { recursive: true });
143
+ writeFileSync(
144
+ join(naxDir, "config.json"),
145
+ JSON.stringify({
146
+ execution: {
147
+ maxIterations: 15,
148
+ rectification: {
149
+ enabled: false,
150
+ maxRetries: 5,
151
+ },
152
+ },
153
+ }),
154
+ );
155
+
156
+ process.chdir(tempDir);
157
+
158
+ const proc = Bun.spawn(["bun", join(import.meta.dir, "../../bin/nax.ts"), "config"], {
159
+ cwd: tempDir,
160
+ stdout: "pipe",
161
+ stderr: "pipe",
162
+ });
163
+
164
+ const output = await new Response(proc.stdout).text();
165
+ const exitCode = await proc.exited;
166
+
167
+ expect(exitCode).toBe(0);
168
+
169
+ const lines = output.split("\n");
170
+ const jsonStartIndex = lines.findIndex((line) => line.startsWith("{"));
171
+ const jsonOutput = lines.slice(jsonStartIndex).join("\n");
172
+ const parsed = JSON.parse(jsonOutput);
173
+
174
+ // Verify nested overrides
175
+ expect(parsed.execution.maxIterations).toBe(15);
176
+ expect(parsed.execution.rectification.enabled).toBe(false);
177
+ expect(parsed.execution.rectification.maxRetries).toBe(5);
178
+
179
+ // Verify non-overridden fields are preserved
180
+ expect(parsed.execution.iterationDelayMs).toBeDefined();
181
+ expect(parsed.execution.rectification.fullSuiteTimeoutSeconds).toBeDefined();
182
+ });
183
+
184
+ test("handles project config with schema version mismatch", async () => {
185
+ // Create project config with future schema version
186
+ const naxDir = join(tempDir, "nax");
187
+ mkdirSync(naxDir, { recursive: true });
188
+ writeFileSync(
189
+ join(naxDir, "config.json"),
190
+ JSON.stringify({
191
+ version: 999, // Future version
192
+ execution: {
193
+ maxIterations: 25,
194
+ },
195
+ }),
196
+ );
197
+
198
+ process.chdir(tempDir);
199
+
200
+ const proc = Bun.spawn(["bun", join(import.meta.dir, "../../bin/nax.ts"), "config"], {
201
+ cwd: tempDir,
202
+ stdout: "pipe",
203
+ stderr: "pipe",
204
+ });
205
+
206
+ const output = await new Response(proc.stdout).text();
207
+ const stderr = await new Response(proc.stderr).text();
208
+ const exitCode = await proc.exited;
209
+
210
+ // Should either succeed with warning or fail gracefully
211
+ if (exitCode !== 0) {
212
+ expect(stderr.toLowerCase()).toMatch(/error|invalid|version/);
213
+ } else {
214
+ // If it succeeds, verify output is valid
215
+ const lines = output.split("\n");
216
+ const jsonStartIndex = lines.findIndex((line) => line.startsWith("{"));
217
+ expect(jsonStartIndex).toBeGreaterThan(0);
218
+ const jsonOutput = lines.slice(jsonStartIndex).join("\n");
219
+ expect(() => JSON.parse(jsonOutput)).not.toThrow();
220
+ }
221
+ });
222
+ });