@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,543 @@
1
+ /**
2
+ * Runner Plugin Integration Tests
3
+ *
4
+ * Tests for US-001: Wire plugin loading into the runner startup
5
+ *
6
+ * Acceptance Criteria:
7
+ * 1. Runner calls loadPlugins() during initialization before story loop starts
8
+ * 2. PluginRegistry is accessible from pipeline context (RunContext or similar)
9
+ * 3. registry.teardownAll() is called on both success and failure paths
10
+ * 4. If no plugins are found, an empty registry is used (no error)
11
+ * 5. Plugin loading errors are logged but do not abort the run
12
+ */
13
+
14
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
15
+ import * as fs from "node:fs/promises";
16
+ import * as os from "node:os";
17
+ import * as path from "node:path";
18
+ import * as agentModule from "../../src/agents";
19
+ import type { NaxConfig } from "../../src/config/schema";
20
+ import { run } from "../../src/execution/runner";
21
+ import type { LoadedHooksConfig } from "../../src/hooks";
22
+ import type { NaxPlugin } from "../../src/plugins/types";
23
+
24
+ // Test fixture helpers
25
+ async function createTempDir(): Promise<string> {
26
+ const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "nax-runner-plugin-test-"));
27
+ return tmpDir;
28
+ }
29
+
30
+ async function cleanupTempDir(dir: string): Promise<void> {
31
+ try {
32
+ await fs.rm(dir, { recursive: true, force: true });
33
+ } catch {
34
+ // Ignore cleanup errors
35
+ }
36
+ }
37
+
38
+ async function createMinimalPRD(workdir: string, feature: string): Promise<string> {
39
+ const featureDir = path.join(workdir, "nax", "features", feature);
40
+ await fs.mkdir(featureDir, { recursive: true });
41
+
42
+ const prdPath = path.join(featureDir, "prd.json");
43
+ const prd = {
44
+ featureName: feature,
45
+ userStories: [
46
+ {
47
+ id: "US-001",
48
+ title: "Test story",
49
+ description: "A test story",
50
+ acceptanceCriteria: [],
51
+ dependencies: [],
52
+ tags: [],
53
+ status: "pending",
54
+ },
55
+ ],
56
+ };
57
+
58
+ await fs.writeFile(prdPath, JSON.stringify(prd, null, 2));
59
+ return prdPath;
60
+ }
61
+
62
+ async function createMinimalConfig(): Promise<NaxConfig> {
63
+ return {
64
+ autoMode: {
65
+ defaultAgent: "claude-code",
66
+ complexityRouting: {
67
+ simple: "fast",
68
+ medium: "balanced",
69
+ complex: "powerful",
70
+ expert: "powerful",
71
+ },
72
+ escalation: {
73
+ enabled: true,
74
+ tierOrder: [
75
+ { tier: "fast", attempts: 1 },
76
+ { tier: "balanced", attempts: 1 },
77
+ ],
78
+ },
79
+ },
80
+ models: {
81
+ fast: { provider: "anthropic", modelName: "claude-3-5-haiku-20241022" },
82
+ balanced: { provider: "anthropic", modelName: "claude-3-5-sonnet-20241022" },
83
+ powerful: { provider: "anthropic", modelName: "claude-3-7-sonnet-20250219" },
84
+ },
85
+ execution: {
86
+ maxIterations: 2,
87
+ costLimit: 100,
88
+ iterationDelayMs: 0,
89
+ maxStoriesPerFeature: 100,
90
+ },
91
+ routing: {
92
+ strategy: "simple",
93
+ },
94
+ tdd: {
95
+ mode: "standard",
96
+ testStrategy: "test-after",
97
+ testCommand: "echo 'tests pass'",
98
+ },
99
+ quality: {
100
+ commands: {},
101
+ },
102
+ acceptance: {
103
+ enabled: false,
104
+ testCommand: "",
105
+ maxRetries: 0,
106
+ },
107
+ analyze: {
108
+ model: "balanced",
109
+ maxContextTokens: 100000,
110
+ },
111
+ plugins: [],
112
+ } as NaxConfig;
113
+ }
114
+
115
+ async function createPluginFile(dir: string, filename: string, plugin: NaxPlugin): Promise<void> {
116
+ const setupCode = plugin.setup ? "async setup(config) { }," : "";
117
+ const teardownCode = plugin.teardown ? "async teardown() { }," : "";
118
+
119
+ let extensionsCode = "";
120
+ if (plugin.extensions.reporter) {
121
+ extensionsCode = `
122
+ reporter: {
123
+ name: "${plugin.extensions.reporter.name}",
124
+ async onRunStart(event) {},
125
+ async onStoryComplete(event) {},
126
+ async onRunEnd(event) {}
127
+ }`;
128
+ }
129
+
130
+ const pluginCode = `
131
+ export default {
132
+ name: "${plugin.name}",
133
+ version: "${plugin.version}",
134
+ provides: ${JSON.stringify(plugin.provides)},
135
+ ${setupCode}
136
+ ${teardownCode}
137
+ extensions: {${extensionsCode}
138
+ }
139
+ };
140
+ `;
141
+ await fs.writeFile(path.join(dir, filename), pluginCode, "utf-8");
142
+ }
143
+
144
+ describe("Runner Plugin Integration (US-001)", () => {
145
+ let tempDir: string;
146
+ let getAgentSpy: any;
147
+
148
+ beforeEach(async () => {
149
+ tempDir = await createTempDir();
150
+
151
+ // Mock getAgent to return a valid agent
152
+ getAgentSpy = spyOn(agentModule, "getAgent").mockReturnValue({
153
+ name: "claude-code",
154
+ binary: "claude",
155
+ isInstalled: async () => true,
156
+ spawn: async () => ({
157
+ success: true,
158
+ estimatedCost: 0,
159
+ transcript: "",
160
+ }),
161
+ } as any);
162
+ });
163
+
164
+ afterEach(async () => {
165
+ await cleanupTempDir(tempDir);
166
+ getAgentSpy?.mockRestore();
167
+ });
168
+
169
+ test("AC1: Runner calls loadPlugins() during initialization before story loop starts", async () => {
170
+ // Create a minimal PRD
171
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
172
+ const config = await createMinimalConfig();
173
+
174
+ // Create a plugin in the global directory
175
+ const globalPluginsDir = path.join(tempDir, ".nax", "plugins");
176
+ await fs.mkdir(globalPluginsDir, { recursive: true });
177
+
178
+ const plugin: NaxPlugin = {
179
+ name: "test-reporter",
180
+ version: "1.0.0",
181
+ provides: ["reporter"],
182
+ extensions: {
183
+ reporter: {
184
+ name: "test-reporter",
185
+ async onRunStart(event) {
186
+ // This proves the plugin was loaded before the run started
187
+ },
188
+ },
189
+ },
190
+ };
191
+
192
+ await createPluginFile(globalPluginsDir, "reporter.ts", plugin);
193
+
194
+ // Override HOME to use our temp directory
195
+ const originalHome = process.env.HOME;
196
+ process.env.HOME = tempDir;
197
+
198
+ try {
199
+ // Run with dry-run to avoid actual agent execution
200
+ const result = await run({
201
+ prdPath,
202
+ workdir: tempDir,
203
+ config,
204
+ hooks: { hooks: [] },
205
+ feature: "test-feature",
206
+ dryRun: true,
207
+ skipPrecheck: true,
208
+ });
209
+
210
+ // If we get here, plugins were loaded successfully
211
+ expect(result.success).toBe(true);
212
+ } finally {
213
+ process.env.HOME = originalHome;
214
+ }
215
+ });
216
+
217
+ test("AC2: PluginRegistry is accessible from pipeline context", async () => {
218
+ // This is verified by checking that pipeline stages can access ctx.plugins
219
+ // The implementation already passes plugins to PipelineContext (runner.ts:706)
220
+ // We verify this indirectly by confirming no errors occur when plugins are used
221
+
222
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
223
+ const config = await createMinimalConfig();
224
+
225
+ // Create a plugin
226
+ const projectPluginsDir = path.join(tempDir, "nax", "plugins");
227
+ await fs.mkdir(projectPluginsDir, { recursive: true });
228
+
229
+ const plugin: NaxPlugin = {
230
+ name: "test-plugin",
231
+ version: "1.0.0",
232
+ provides: ["reporter"],
233
+ extensions: {
234
+ reporter: {
235
+ name: "test",
236
+ async onRunStart(event) {},
237
+ },
238
+ },
239
+ };
240
+
241
+ await createPluginFile(projectPluginsDir, "test.ts", plugin);
242
+
243
+ // Run with dry-run
244
+ const result = await run({
245
+ prdPath,
246
+ workdir: tempDir,
247
+ config,
248
+ hooks: { hooks: [] },
249
+ feature: "test-feature",
250
+ dryRun: true,
251
+ skipPrecheck: true,
252
+ });
253
+
254
+ expect(result.success).toBe(true);
255
+ });
256
+
257
+ test("AC3: registry.teardownAll() is called on success path", async () => {
258
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
259
+ const config = await createMinimalConfig();
260
+
261
+ // Create a plugin with teardown
262
+ const projectPluginsDir = path.join(tempDir, "nax", "plugins");
263
+ await fs.mkdir(projectPluginsDir, { recursive: true });
264
+
265
+ // Use a file to track teardown calls
266
+ const teardownMarkerPath = path.join(tempDir, "teardown-called.txt");
267
+
268
+ const pluginCode = `
269
+ let teardownCalled = false;
270
+
271
+ export default {
272
+ name: "teardown-test",
273
+ version: "1.0.0",
274
+ provides: ["reporter"],
275
+ async setup(config) {},
276
+ async teardown() {
277
+ const fs = require("node:fs/promises");
278
+ await fs.writeFile("${teardownMarkerPath.replace(/\\/g, "\\\\")}", "teardown-called", "utf-8");
279
+ },
280
+ extensions: {
281
+ reporter: {
282
+ name: "test",
283
+ async onRunStart(event) {}
284
+ }
285
+ }
286
+ };
287
+ `;
288
+ await fs.writeFile(path.join(projectPluginsDir, "teardown.ts"), pluginCode, "utf-8");
289
+
290
+ // Run successfully
291
+ await run({
292
+ prdPath,
293
+ workdir: tempDir,
294
+ config,
295
+ hooks: { hooks: [] },
296
+ feature: "test-feature",
297
+ dryRun: true,
298
+ skipPrecheck: true,
299
+ });
300
+
301
+ // Check that teardown was called
302
+ const teardownContent = await fs.readFile(teardownMarkerPath, "utf-8");
303
+ expect(teardownContent).toBe("teardown-called");
304
+ });
305
+
306
+ test("AC3: registry.teardownAll() is called on failure path", async () => {
307
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
308
+ const config = await createMinimalConfig();
309
+
310
+ // Create a plugin with teardown
311
+ const projectPluginsDir = path.join(tempDir, "nax", "plugins");
312
+ await fs.mkdir(projectPluginsDir, { recursive: true });
313
+
314
+ const teardownMarkerPath = path.join(tempDir, "teardown-called-fail.txt");
315
+
316
+ const pluginCode = `
317
+ export default {
318
+ name: "teardown-fail-test",
319
+ version: "1.0.0",
320
+ provides: ["reporter"],
321
+ async setup(config) {},
322
+ async teardown() {
323
+ const fs = require("node:fs/promises");
324
+ await fs.writeFile("${teardownMarkerPath.replace(/\\/g, "\\\\")}", "teardown-called", "utf-8");
325
+ },
326
+ extensions: {
327
+ reporter: {
328
+ name: "test",
329
+ async onRunStart(event) {}
330
+ }
331
+ }
332
+ };
333
+ `;
334
+ await fs.writeFile(path.join(projectPluginsDir, "teardown-fail.ts"), pluginCode, "utf-8");
335
+
336
+ // Create an invalid PRD to trigger failure
337
+ const invalidPrd = {
338
+ featureName: "test-feature",
339
+ userStories: [], // Empty stories should cause early exit
340
+ };
341
+ await fs.writeFile(prdPath, JSON.stringify(invalidPrd, null, 2));
342
+
343
+ // Run and expect failure/early exit
344
+ try {
345
+ await run({
346
+ prdPath,
347
+ workdir: tempDir,
348
+ config,
349
+ hooks: { hooks: [] },
350
+ feature: "test-feature",
351
+ dryRun: true,
352
+ skipPrecheck: true,
353
+ });
354
+ } catch (error) {
355
+ // May throw or return early
356
+ }
357
+
358
+ // Check that teardown was called even on failure
359
+ const teardownContent = await fs.readFile(teardownMarkerPath, "utf-8");
360
+ expect(teardownContent).toBe("teardown-called");
361
+ });
362
+
363
+ test("AC4: If no plugins are found, an empty registry is used (no error)", async () => {
364
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
365
+ const config = await createMinimalConfig();
366
+
367
+ // Ensure no plugins exist
368
+ const globalPluginsDir = path.join(tempDir, ".nax", "plugins");
369
+ const projectPluginsDir = path.join(tempDir, "nax", "plugins");
370
+
371
+ // Don't create these directories - test with non-existent plugin dirs
372
+
373
+ const originalHome = process.env.HOME;
374
+ process.env.HOME = tempDir;
375
+
376
+ try {
377
+ // Run with no plugins
378
+ const result = await run({
379
+ prdPath,
380
+ workdir: tempDir,
381
+ config,
382
+ hooks: { hooks: [] },
383
+ feature: "test-feature",
384
+ dryRun: true,
385
+ skipPrecheck: true,
386
+ });
387
+
388
+ // Should succeed with empty registry
389
+ expect(result.success).toBe(true);
390
+ } finally {
391
+ process.env.HOME = originalHome;
392
+ }
393
+ });
394
+
395
+ test("AC5: Plugin loading errors are logged but do not abort the run", async () => {
396
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
397
+ const config = await createMinimalConfig();
398
+
399
+ // Create a malformed plugin file
400
+ const projectPluginsDir = path.join(tempDir, "nax", "plugins");
401
+ await fs.mkdir(projectPluginsDir, { recursive: true });
402
+
403
+ const malformedPlugin = `
404
+ export default {
405
+ // Missing required fields (name, version)
406
+ provides: ["reporter"],
407
+ extensions: {}
408
+ };
409
+ `;
410
+ await fs.writeFile(path.join(projectPluginsDir, "malformed.ts"), malformedPlugin, "utf-8");
411
+
412
+ // Create a valid plugin as well
413
+ const validPlugin: NaxPlugin = {
414
+ name: "valid-plugin",
415
+ version: "1.0.0",
416
+ provides: ["reporter"],
417
+ extensions: {
418
+ reporter: {
419
+ name: "valid",
420
+ async onRunStart(event) {},
421
+ },
422
+ },
423
+ };
424
+ await createPluginFile(projectPluginsDir, "valid.ts", validPlugin);
425
+
426
+ // Run should succeed despite malformed plugin
427
+ const result = await run({
428
+ prdPath,
429
+ workdir: tempDir,
430
+ config,
431
+ hooks: { hooks: [] },
432
+ feature: "test-feature",
433
+ dryRun: true,
434
+ skipPrecheck: true,
435
+ });
436
+
437
+ // Should succeed - malformed plugin is skipped, valid plugin is loaded
438
+ expect(result.success).toBe(true);
439
+ });
440
+
441
+ test("Plugin loading resolves correct directory paths", async () => {
442
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
443
+ const config = await createMinimalConfig();
444
+
445
+ // Create plugins in both global and project directories
446
+ const globalPluginsDir = path.join(tempDir, ".nax", "plugins");
447
+ const projectPluginsDir = path.join(tempDir, "nax", "plugins");
448
+ await fs.mkdir(globalPluginsDir, { recursive: true });
449
+ await fs.mkdir(projectPluginsDir, { recursive: true });
450
+
451
+ const globalPlugin: NaxPlugin = {
452
+ name: "global-plugin",
453
+ version: "1.0.0",
454
+ provides: ["reporter"],
455
+ extensions: {
456
+ reporter: {
457
+ name: "global",
458
+ async onRunStart(event) {},
459
+ },
460
+ },
461
+ };
462
+
463
+ const projectPlugin: NaxPlugin = {
464
+ name: "project-plugin",
465
+ version: "1.0.0",
466
+ provides: ["reporter"],
467
+ extensions: {
468
+ reporter: {
469
+ name: "project",
470
+ async onRunStart(event) {},
471
+ },
472
+ },
473
+ };
474
+
475
+ await createPluginFile(globalPluginsDir, "global.ts", globalPlugin);
476
+ await createPluginFile(projectPluginsDir, "project.ts", projectPlugin);
477
+
478
+ const originalHome = process.env.HOME;
479
+ process.env.HOME = tempDir;
480
+
481
+ try {
482
+ // Run
483
+ const result = await run({
484
+ prdPath,
485
+ workdir: tempDir,
486
+ config,
487
+ hooks: { hooks: [] },
488
+ feature: "test-feature",
489
+ dryRun: true,
490
+ skipPrecheck: true,
491
+ });
492
+
493
+ // Should load both plugins successfully
494
+ expect(result.success).toBe(true);
495
+ } finally {
496
+ process.env.HOME = originalHome;
497
+ }
498
+ });
499
+
500
+ test("Config plugins are loaded alongside directory plugins", async () => {
501
+ const prdPath = await createMinimalPRD(tempDir, "test-feature");
502
+ const config = await createMinimalConfig();
503
+
504
+ // Create a config plugin
505
+ const configPluginDir = path.join(tempDir, "custom-plugin");
506
+ await fs.mkdir(configPluginDir, { recursive: true });
507
+
508
+ const configPlugin: NaxPlugin = {
509
+ name: "config-plugin",
510
+ version: "1.0.0",
511
+ provides: ["reporter"],
512
+ extensions: {
513
+ reporter: {
514
+ name: "config",
515
+ async onRunStart(event) {},
516
+ },
517
+ },
518
+ };
519
+
520
+ await createPluginFile(configPluginDir, "index.ts", configPlugin);
521
+
522
+ // Add plugin to config
523
+ config.plugins = [
524
+ {
525
+ module: path.join(configPluginDir, "index.ts"),
526
+ config: {},
527
+ },
528
+ ];
529
+
530
+ // Run
531
+ const result = await run({
532
+ prdPath,
533
+ workdir: tempDir,
534
+ config,
535
+ hooks: { hooks: [] },
536
+ feature: "test-feature",
537
+ dryRun: true,
538
+ skipPrecheck: true,
539
+ });
540
+
541
+ expect(result.success).toBe(true);
542
+ });
543
+ });