@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,274 @@
1
+ /**
2
+ * Post-Agent Verification (ADR-003)
3
+ *
4
+ * Runs verification after the agent completes, reverts story state on failure.
5
+ */
6
+
7
+ import { spawn } from "bun";
8
+ import type { NaxConfig } from "../config";
9
+ import { getSafeLogger } from "../logger";
10
+ import type { StoryMetrics } from "../metrics";
11
+ import type { PRD, UserStory } from "../prd";
12
+ import { getExpectedFiles, savePRD } from "../prd";
13
+ import { getTierConfig } from "./escalation";
14
+ import { revertStoriesOnFailure, runRectificationLoop } from "./post-verify-rectification";
15
+ import { appendProgress } from "./progress";
16
+ import { getEnvironmentalEscalationThreshold, parseTestOutput, runVerification } from "./verification";
17
+
18
+ /** Get test files changed since a git ref. Returns empty array if detection fails. */
19
+ async function getChangedTestFiles(workdir: string, gitRef?: string): Promise<string[]> {
20
+ if (!gitRef) return [];
21
+ try {
22
+ const proc = spawn({
23
+ cmd: ["git", "diff", "--name-only", gitRef, "HEAD"],
24
+ cwd: workdir,
25
+ stdout: "pipe",
26
+ stderr: "pipe",
27
+ });
28
+ const exitCode = await proc.exited;
29
+ if (exitCode !== 0) return [];
30
+ const stdout = await new Response(proc.stdout).text();
31
+ return stdout
32
+ .trim()
33
+ .split("\n")
34
+ .filter(
35
+ (f) =>
36
+ f && (f.includes("test/") || f.includes("__tests__/") || f.endsWith(".test.ts") || f.endsWith(".spec.ts")),
37
+ );
38
+ } catch {
39
+ return [];
40
+ }
41
+ }
42
+
43
+ /** Scope a test command to only run specific test files. */
44
+ function scopeTestCommand(baseCommand: string, testFiles: string[]): string {
45
+ if (testFiles.length === 0) return baseCommand;
46
+ return `${baseCommand} ${testFiles.join(" ")}`;
47
+ }
48
+
49
+ export interface PostVerifyOptions {
50
+ config: NaxConfig;
51
+ prd: PRD;
52
+ prdPath: string;
53
+ workdir: string;
54
+ featureDir?: string;
55
+ story: UserStory;
56
+ storiesToExecute: UserStory[];
57
+ allStoryMetrics: StoryMetrics[];
58
+ timeoutRetryCountMap: Map<string, number>;
59
+ storyGitRef?: string;
60
+ }
61
+
62
+ export interface PostVerifyResult {
63
+ passed: boolean;
64
+ prd: PRD;
65
+ }
66
+
67
+ /**
68
+ * Run post-agent verification and handle failure state.
69
+ *
70
+ * @design Shell command in config.quality.commands.test is operator-controlled,
71
+ * not user/PRD input. No shell injection risk from untrusted sources.
72
+ */
73
+ export async function runPostAgentVerification(opts: PostVerifyOptions): Promise<PostVerifyResult> {
74
+ const {
75
+ config,
76
+ prd,
77
+ prdPath,
78
+ workdir,
79
+ featureDir,
80
+ story,
81
+ storiesToExecute,
82
+ allStoryMetrics,
83
+ timeoutRetryCountMap,
84
+ storyGitRef,
85
+ } = opts;
86
+ const logger = getSafeLogger();
87
+
88
+ if (!config.quality.commands.test) return { passed: true, prd };
89
+
90
+ // Scoped verification: only run test files changed by this story
91
+ const changedTestFiles = await getChangedTestFiles(workdir, storyGitRef);
92
+ const testCommand = scopeTestCommand(config.quality.commands.test, changedTestFiles);
93
+ const timeoutRetryCount = timeoutRetryCountMap.get(story.id) || 0;
94
+
95
+ const verificationResult = await runVerification({
96
+ workingDirectory: workdir,
97
+ expectedFiles: getExpectedFiles(story),
98
+ command: testCommand,
99
+ timeoutSeconds: config.execution.verificationTimeoutSeconds,
100
+ forceExit: config.quality.forceExit,
101
+ detectOpenHandles: config.quality.detectOpenHandles,
102
+ detectOpenHandlesRetries: config.quality.detectOpenHandlesRetries,
103
+ timeoutRetryCount,
104
+ gracePeriodMs: config.quality.gracePeriodMs,
105
+ drainTimeoutMs: config.quality.drainTimeoutMs,
106
+ shell: config.quality.shell,
107
+ stripEnvVars: config.quality.stripEnvVars,
108
+ });
109
+
110
+ const rectificationEnabled = config.execution.rectification?.enabled ?? false;
111
+
112
+ if (verificationResult.success) {
113
+ logger?.info("verification", "Scoped verification passed");
114
+ if (verificationResult.output) {
115
+ const analysis = parseTestOutput(verificationResult.output, 0);
116
+ if (analysis.passCount > 0) {
117
+ logger?.debug("verification", "Scoped test results", {
118
+ passCount: analysis.passCount,
119
+ failCount: analysis.failCount,
120
+ });
121
+ }
122
+ }
123
+
124
+ // Regression Gate (BUG-009): run full suite after scoped tests pass
125
+ const regressionResult = await runRegressionGate(config, workdir, story, changedTestFiles, rectificationEnabled);
126
+ if (regressionResult === "passed" || regressionResult === "skipped") {
127
+ return { passed: true, prd };
128
+ }
129
+
130
+ // Regression failed -- revert stories
131
+ const updatedPrd = await revertStoriesOnFailure({
132
+ prd,
133
+ prdPath,
134
+ story,
135
+ storiesToExecute,
136
+ allStoryMetrics,
137
+ featureDir,
138
+ diagnosticContext: "REGRESSION: full-suite regression detected",
139
+ countsTowardEscalation: true,
140
+ });
141
+ return { passed: false, prd: updatedPrd };
142
+ }
143
+
144
+ // --- Verification failed ---
145
+ // Attempt rectification if enabled and tests failed (not timeout/env)
146
+ const isTestFailure = verificationResult.status === "TEST_FAILURE" && verificationResult.output;
147
+ if (rectificationEnabled && isTestFailure && verificationResult.output) {
148
+ const fixed = await runRectificationLoop({
149
+ config,
150
+ workdir,
151
+ story,
152
+ testCommand,
153
+ timeoutSeconds: config.execution.verificationTimeoutSeconds,
154
+ testOutput: verificationResult.output,
155
+ });
156
+ if (fixed) return { passed: true, prd };
157
+ }
158
+
159
+ // Track timeout retries for --detectOpenHandles escalation
160
+ if (verificationResult.status === "TIMEOUT") {
161
+ timeoutRetryCountMap.set(story.id, timeoutRetryCount + 1);
162
+ }
163
+
164
+ logger?.warn("verification", `Verification ${verificationResult.status}`, {
165
+ status: verificationResult.status,
166
+ error: verificationResult.error?.split("\n")[0],
167
+ });
168
+
169
+ // Handle environmental failure escalation
170
+ if (verificationResult.countsTowardEscalation && verificationResult.status === "ENVIRONMENTAL_FAILURE") {
171
+ checkEnvironmentalEscalation(config, story, prd, logger);
172
+ }
173
+
174
+ // Revert stories and save
175
+ const diagnosticContext = verificationResult.error || `Verification failed: ${verificationResult.status}`;
176
+ const updatedPrd = await revertStoriesOnFailure({
177
+ prd,
178
+ prdPath,
179
+ story,
180
+ storiesToExecute,
181
+ allStoryMetrics,
182
+ featureDir,
183
+ diagnosticContext,
184
+ countsTowardEscalation: verificationResult.countsTowardEscalation ?? false,
185
+ });
186
+
187
+ return { passed: false, prd: updatedPrd };
188
+ }
189
+
190
+ /** Run regression gate (full suite) after scoped tests pass. */
191
+ async function runRegressionGate(
192
+ config: NaxConfig,
193
+ workdir: string,
194
+ story: UserStory,
195
+ changedTestFiles: string[],
196
+ rectificationEnabled: boolean,
197
+ ): Promise<"passed" | "skipped" | "failed"> {
198
+ const logger = getSafeLogger();
199
+ const regressionGateEnabled = config.execution.regressionGate?.enabled ?? true;
200
+ const scopedTestsWereRun = changedTestFiles.length > 0;
201
+
202
+ if (!regressionGateEnabled || !scopedTestsWereRun) {
203
+ if (regressionGateEnabled && !scopedTestsWereRun) {
204
+ logger?.debug("regression-gate", "Skipping regression gate (full suite already run in scoped verification)");
205
+ }
206
+ return "skipped";
207
+ }
208
+
209
+ logger?.info("regression-gate", "Running full-suite regression gate");
210
+ const fullSuiteCommand = config.quality.commands.test ?? "bun test";
211
+ const regressionResult = await runVerification({
212
+ workingDirectory: workdir,
213
+ expectedFiles: getExpectedFiles(story),
214
+ command: fullSuiteCommand,
215
+ timeoutSeconds: config.execution.regressionGate.timeoutSeconds,
216
+ forceExit: config.quality.forceExit,
217
+ detectOpenHandles: config.quality.detectOpenHandles,
218
+ detectOpenHandlesRetries: config.quality.detectOpenHandlesRetries,
219
+ timeoutRetryCount: 0,
220
+ gracePeriodMs: config.quality.gracePeriodMs,
221
+ drainTimeoutMs: config.quality.drainTimeoutMs,
222
+ shell: config.quality.shell,
223
+ stripEnvVars: config.quality.stripEnvVars,
224
+ });
225
+
226
+ if (regressionResult.success) {
227
+ logger?.info("regression-gate", "Full-suite regression gate passed");
228
+ return "passed";
229
+ }
230
+
231
+ logger?.warn("regression-gate", "Full-suite regression detected", { status: regressionResult.status });
232
+
233
+ // Attempt rectification on regression failures
234
+ const isTestFailure = regressionResult.status === "TEST_FAILURE" && regressionResult.output;
235
+ if (rectificationEnabled && isTestFailure && regressionResult.output) {
236
+ const fixed = await runRectificationLoop({
237
+ config,
238
+ workdir,
239
+ story,
240
+ testCommand: fullSuiteCommand,
241
+ timeoutSeconds: config.execution.regressionGate.timeoutSeconds,
242
+ testOutput: regressionResult.output,
243
+ promptPrefix:
244
+ "# REGRESSION: Cross-Story Test Failures\n\nYour changes passed scoped tests but broke unrelated tests. Fix these regressions.",
245
+ });
246
+ if (fixed) return "passed";
247
+ }
248
+
249
+ return "failed";
250
+ }
251
+
252
+ /** Check if environmental failure should trigger early escalation. */
253
+ function checkEnvironmentalEscalation(
254
+ config: NaxConfig,
255
+ story: UserStory,
256
+ prd: PRD,
257
+ logger: ReturnType<typeof getSafeLogger>,
258
+ ): void {
259
+ const currentTier = story.routing?.modelTier || config.autoMode.escalation.tierOrder[0]?.tier;
260
+ const tierCfg = currentTier ? getTierConfig(currentTier, config.autoMode.escalation.tierOrder) : undefined;
261
+ if (!tierCfg) return;
262
+
263
+ const threshold = getEnvironmentalEscalationThreshold(
264
+ tierCfg.attempts,
265
+ config.quality.environmentalEscalationDivisor,
266
+ );
267
+ const currentAttempts = prd.userStories.find((s) => s.id === story.id)?.attempts ?? 0;
268
+ if (currentAttempts >= threshold) {
269
+ logger?.warn("verification", "Environmental failure hit early escalation threshold", {
270
+ currentAttempts,
271
+ threshold,
272
+ });
273
+ }
274
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Progress Logging
3
+ *
4
+ * Append timestamped entries to progress.txt after story completion.
5
+ */
6
+
7
+ import { join } from "node:path";
8
+ import type { StoryStatus } from "../prd";
9
+
10
+ /** Append a progress entry to progress.txt */
11
+ export async function appendProgress(
12
+ featureDir: string,
13
+ storyId: string,
14
+ status: StoryStatus,
15
+ message: string,
16
+ ): Promise<void> {
17
+ const progressPath = join(featureDir, "progress.txt");
18
+ const timestamp = new Date().toISOString();
19
+ const entry = `[${timestamp}] ${storyId} — ${status.toUpperCase()} — ${message}\n`;
20
+
21
+ // Append to file (creates if doesn't exist)
22
+ const file = Bun.file(progressPath);
23
+ const existing = (await file.exists()) ? await file.text() : "";
24
+ await Bun.write(progressPath, existing + entry);
25
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Prompt builders for agent sessions
3
+ *
4
+ * Constructs prompts for single-session and batch execution modes.
5
+ * Supports constitution injection for project-level governance.
6
+ */
7
+
8
+ import type { ConstitutionResult } from "../constitution";
9
+ import type { UserStory } from "../prd";
10
+
11
+ /**
12
+ * Build prompt for single-session (test-after) execution
13
+ *
14
+ * Priority order: Constitution (95) → Story prompt (100) → Context (90)
15
+ *
16
+ * @param story - User story to execute
17
+ * @param contextMarkdown - Optional context markdown from context builder
18
+ * @param constitution - Optional constitution result
19
+ * @returns Formatted prompt string
20
+ */
21
+ export function buildSingleSessionPrompt(
22
+ story: UserStory,
23
+ contextMarkdown?: string,
24
+ constitution?: ConstitutionResult,
25
+ ): string {
26
+ const basePrompt = `# Task: ${story.title}
27
+
28
+ **Description:**
29
+ ${story.description}
30
+
31
+ **Acceptance Criteria:**
32
+ ${story.acceptanceCriteria.map((ac, i) => `${i + 1}. ${ac}`).join("\n")}
33
+
34
+ **Instructions:**
35
+ 1. Implement the functionality described above
36
+ 2. Write tests to verify all acceptance criteria are met
37
+ 3. Ensure all tests pass
38
+ 4. Follow existing code patterns and conventions
39
+ 5. If existing test coverage is listed below, do NOT duplicate those tests — only test NEW behavior
40
+ 6. Commit your changes when done
41
+
42
+ Use test-after approach: implement first, then add tests to verify.`;
43
+
44
+ // Build sections in priority order
45
+ const sections: string[] = [];
46
+
47
+ // Priority 95: Constitution
48
+ if (constitution) {
49
+ sections.push(`# CONSTITUTION (follow these rules strictly)
50
+
51
+ ${constitution.content}`);
52
+ }
53
+
54
+ // Priority 100: Story prompt (always first in display order)
55
+ sections.push(basePrompt);
56
+
57
+ // Priority 90: Context
58
+ if (contextMarkdown) {
59
+ sections.push(contextMarkdown);
60
+ }
61
+
62
+ return sections.join("\n\n---\n\n");
63
+ }
64
+
65
+ /**
66
+ * Build prompt for batched stories (multiple simple stories in one session)
67
+ *
68
+ * Priority order: Constitution (95) → Story prompt (100) → Context (90)
69
+ *
70
+ * @param stories - Array of user stories to execute in batch
71
+ * @param contextMarkdown - Optional context markdown from context builder
72
+ * @param constitution - Optional constitution result
73
+ * @returns Formatted prompt string
74
+ */
75
+ export function buildBatchPrompt(
76
+ stories: UserStory[],
77
+ contextMarkdown?: string,
78
+ constitution?: ConstitutionResult,
79
+ ): string {
80
+ const storyPrompts = stories
81
+ .map((story, idx) => {
82
+ return `## Story ${idx + 1}: ${story.id} — ${story.title}
83
+
84
+ **Description:**
85
+ ${story.description}
86
+
87
+ **Acceptance Criteria:**
88
+ ${story.acceptanceCriteria.map((ac, i) => `${i + 1}. ${ac}`).join("\n")}`;
89
+ })
90
+ .join("\n\n");
91
+
92
+ const basePrompt = `# Batch Task: ${stories.length} Stories
93
+
94
+ You are assigned ${stories.length} related stories to implement in sequence. Each story should be implemented, tested, and committed separately.
95
+
96
+ ${storyPrompts}
97
+
98
+ **Instructions:**
99
+ 1. Implement each story in order
100
+ 2. Write tests to verify all acceptance criteria are met for each story
101
+ 3. Ensure all tests pass for each story
102
+ 4. **Commit each story separately** with a clear commit message referencing the story ID
103
+ 5. Follow existing code patterns and conventions
104
+ 6. If existing test coverage is listed below, do NOT duplicate those tests — only test NEW behavior
105
+
106
+ Use test-after approach: implement first, then add tests to verify.`;
107
+
108
+ // Build sections in priority order
109
+ const sections: string[] = [];
110
+
111
+ // Priority 95: Constitution
112
+ if (constitution) {
113
+ sections.push(`# CONSTITUTION (follow these rules strictly)
114
+
115
+ ${constitution.content}`);
116
+ }
117
+
118
+ // Priority 100: Story prompt (always first in display order)
119
+ sections.push(basePrompt);
120
+
121
+ // Priority 90: Context
122
+ if (contextMarkdown) {
123
+ sections.push(contextMarkdown);
124
+ }
125
+
126
+ return sections.join("\n\n---\n\n");
127
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Queue File Handler
3
+ *
4
+ * Provides atomic read/write operations for .queue.txt command files.
5
+ * Uses rename-before-read pattern to prevent race conditions.
6
+ */
7
+
8
+ import path from "node:path";
9
+ import { getLogger } from "../logger";
10
+ import { parseQueueFile } from "../queue";
11
+ import type { QueueCommand } from "../queue";
12
+
13
+ /**
14
+ * Safely get logger instance, returns null if not initialized
15
+ */
16
+ function getSafeLogger() {
17
+ try {
18
+ return getLogger();
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Read and parse queue file atomically.
26
+ * Uses rename-before-read pattern to prevent race conditions:
27
+ * 1. Rename .queue.txt → .queue.txt.processing (atomic operation)
28
+ * 2. Read from .queue.txt.processing
29
+ * 3. Delete .queue.txt.processing after processing
30
+ *
31
+ * This ensures commands written during processing aren't lost.
32
+ *
33
+ * @param workdir - Working directory containing .queue.txt
34
+ * @returns Array of parsed queue commands, or empty array if no queue file
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const commands = await readQueueFile("/path/to/project");
39
+ * for (const cmd of commands) {
40
+ * if (cmd.type === "PAUSE") {
41
+ * // Handle pause
42
+ * }
43
+ * }
44
+ * await clearQueueFile("/path/to/project");
45
+ * ```
46
+ */
47
+ export async function readQueueFile(workdir: string): Promise<QueueCommand[]> {
48
+ const queuePath = path.join(workdir, ".queue.txt");
49
+ const processingPath = path.join(workdir, ".queue.txt.processing");
50
+ const logger = getSafeLogger();
51
+
52
+ try {
53
+ // Check if queue file exists
54
+ const file = Bun.file(queuePath);
55
+ const exists = await file.exists();
56
+ if (!exists) {
57
+ return [];
58
+ }
59
+
60
+ // Atomically rename to .processing (prevents concurrent reads)
61
+ try {
62
+ await Bun.spawn(["mv", queuePath, processingPath], { stdout: "pipe" }).exited;
63
+ } catch (error) {
64
+ // File was already moved by another process, or doesn't exist anymore
65
+ return [];
66
+ }
67
+
68
+ // Read from processing file
69
+ const processingFile = Bun.file(processingPath);
70
+ const content = await processingFile.text();
71
+ const result = parseQueueFile(content);
72
+
73
+ return result.commands;
74
+ } catch (error) {
75
+ logger?.warn("queue", "Failed to read queue file", {
76
+ error: (error as Error).message,
77
+ });
78
+ return [];
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Clear queue file after processing commands.
84
+ * Deletes .queue.txt.processing file.
85
+ *
86
+ * @param workdir - Working directory containing .queue.txt.processing
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const commands = await readQueueFile("/path/to/project");
91
+ * // Process commands...
92
+ * await clearQueueFile("/path/to/project");
93
+ * ```
94
+ */
95
+ export async function clearQueueFile(workdir: string): Promise<void> {
96
+ const processingPath = path.join(workdir, ".queue.txt.processing");
97
+ const logger = getSafeLogger();
98
+ try {
99
+ const file = Bun.file(processingPath);
100
+ const exists = await file.exists();
101
+ if (exists) {
102
+ await Bun.spawn(["rm", processingPath], { stdout: "pipe" }).exited;
103
+ }
104
+ } catch (error) {
105
+ logger?.warn("queue", "Failed to clear queue file", {
106
+ error: (error as Error).message,
107
+ });
108
+ }
109
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Rectification Core Logic (v0.11)
3
+ *
4
+ * DEPRECATED: Use src/verification/rectification.ts instead.
5
+ * This file is kept for backward compatibility only.
6
+ */
7
+
8
+ // Re-export from unified verification layer
9
+ export {
10
+ type RectificationState,
11
+ shouldRetryRectification,
12
+ createRectificationPrompt,
13
+ } from "../verification/rectification";