@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,506 @@
1
+ /**
2
+ * Context Provider Injection Tests (US-002)
3
+ *
4
+ * Tests that context providers are called before agent execution
5
+ * and their content is injected into the agent prompt with proper
6
+ * token budget management and error handling.
7
+ */
8
+
9
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
10
+ import { DEFAULT_CONFIG } from "../../src/config/schema";
11
+ import { contextStage } from "../../src/pipeline/stages/context";
12
+ import type { PipelineContext } from "../../src/pipeline/types";
13
+ import { PluginRegistry } from "../../src/plugins/registry";
14
+ import type { IContextProvider, NaxPlugin } from "../../src/plugins/types";
15
+ import type { PRD, UserStory } from "../../src/prd/types";
16
+
17
+ /**
18
+ * Create a minimal test context for context stage testing
19
+ */
20
+ function createTestContext(overrides?: Partial<PipelineContext>): PipelineContext {
21
+ const story: UserStory = {
22
+ id: "US-002",
23
+ title: "Test Story",
24
+ description: "Test story for context provider injection",
25
+ acceptanceCriteria: ["AC1", "AC2"],
26
+ status: "pending",
27
+ dependencies: [],
28
+ reasoning: "test",
29
+ estimatedComplexity: "simple",
30
+ tags: [],
31
+ metadata: {},
32
+ };
33
+
34
+ const prd: PRD = {
35
+ version: 1,
36
+ feature: "test-feature",
37
+ description: "Test feature",
38
+ stories: [story],
39
+ acceptanceCriteria: [],
40
+ technicalNotes: "",
41
+ contextFiles: [],
42
+ dependencies: {},
43
+ codebaseSummary: "",
44
+ };
45
+
46
+ return {
47
+ config: DEFAULT_CONFIG,
48
+ prd,
49
+ story,
50
+ stories: [story],
51
+ routing: {
52
+ complexity: "simple",
53
+ modelTier: "fast",
54
+ testStrategy: "test-after",
55
+ reasoning: "test",
56
+ },
57
+ workdir: "/test/workdir",
58
+ hooks: { hooks: {} },
59
+ ...overrides,
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Create a mock context provider for testing
65
+ */
66
+ function createMockProvider(
67
+ name: string,
68
+ content: string,
69
+ estimatedTokens: number,
70
+ label: string,
71
+ shouldThrow = false,
72
+ ): IContextProvider {
73
+ return {
74
+ name,
75
+ async getContext(story: UserStory) {
76
+ if (shouldThrow) {
77
+ throw new Error(`Provider ${name} failed`);
78
+ }
79
+ return {
80
+ content,
81
+ estimatedTokens,
82
+ label,
83
+ };
84
+ },
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Create a mock plugin with a context provider
90
+ */
91
+ function createMockPlugin(provider: IContextProvider): NaxPlugin {
92
+ return {
93
+ name: `plugin-${provider.name}`,
94
+ version: "1.0.0",
95
+ provides: ["context-provider"],
96
+ extensions: {
97
+ contextProvider: provider,
98
+ },
99
+ };
100
+ }
101
+
102
+ describe("US-002: Context Provider Injection", () => {
103
+ describe("AC1: All registered context providers are called before agent execution", () => {
104
+ test("calls all registered context providers", async () => {
105
+ const provider1 = createMockProvider("jira", "Jira ticket data", 100, "Jira Context");
106
+ const provider2 = createMockProvider("linear", "Linear issue data", 150, "Linear Context");
107
+
108
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2)];
109
+ const registry = new PluginRegistry(plugins);
110
+
111
+ const ctx = createTestContext({ plugins: registry });
112
+
113
+ const result = await contextStage.execute(ctx);
114
+
115
+ expect(result.action).toBe("continue");
116
+ expect(ctx.contextMarkdown).toContain("Jira Context");
117
+ expect(ctx.contextMarkdown).toContain("Jira ticket data");
118
+ expect(ctx.contextMarkdown).toContain("Linear Context");
119
+ expect(ctx.contextMarkdown).toContain("Linear issue data");
120
+ });
121
+
122
+ test("providers are called with the current story", async () => {
123
+ let capturedStory: UserStory | undefined;
124
+ const provider = createMockProvider("test", "content", 100, "Test");
125
+ provider.getContext = async (story: UserStory) => {
126
+ capturedStory = story;
127
+ return { content: "test", estimatedTokens: 100, label: "Test" };
128
+ };
129
+
130
+ const registry = new PluginRegistry([createMockPlugin(provider)]);
131
+ const ctx = createTestContext({ plugins: registry });
132
+
133
+ await contextStage.execute(ctx);
134
+
135
+ expect(capturedStory).toBeDefined();
136
+ expect(capturedStory?.id).toBe("US-002");
137
+ });
138
+
139
+ test("works with no context providers registered", async () => {
140
+ const registry = new PluginRegistry([]);
141
+ const ctx = createTestContext({ plugins: registry });
142
+
143
+ const result = await contextStage.execute(ctx);
144
+
145
+ expect(result.action).toBe("continue");
146
+ });
147
+ });
148
+
149
+ describe("AC2: Provider content is appended under markdown section with provider's label", () => {
150
+ test("appends provider content under labeled markdown section", async () => {
151
+ const provider = createMockProvider("jira", "Ticket details here", 100, "Jira Context");
152
+
153
+ const registry = new PluginRegistry([createMockPlugin(provider)]);
154
+ const ctx = createTestContext({ plugins: registry });
155
+
156
+ await contextStage.execute(ctx);
157
+
158
+ expect(ctx.contextMarkdown).toContain("## Jira Context");
159
+ expect(ctx.contextMarkdown).toContain("Ticket details here");
160
+ });
161
+
162
+ test("multiple providers create separate labeled sections", async () => {
163
+ const provider1 = createMockProvider("jira", "Jira data", 100, "Jira Context");
164
+ const provider2 = createMockProvider("confluence", "Confluence data", 150, "Confluence Docs");
165
+
166
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2)];
167
+ const registry = new PluginRegistry(plugins);
168
+
169
+ const ctx = createTestContext({ plugins: registry });
170
+
171
+ await contextStage.execute(ctx);
172
+
173
+ expect(ctx.contextMarkdown).toContain("## Jira Context");
174
+ expect(ctx.contextMarkdown).toContain("Jira data");
175
+ expect(ctx.contextMarkdown).toContain("## Confluence Docs");
176
+ expect(ctx.contextMarkdown).toContain("Confluence data");
177
+ });
178
+
179
+ test("provider content is appended to existing context markdown", async () => {
180
+ const provider = createMockProvider("jira", "New context", 100, "Jira Context");
181
+ const registry = new PluginRegistry([createMockPlugin(provider)]);
182
+
183
+ const ctx = createTestContext({
184
+ plugins: registry,
185
+ contextMarkdown: "Existing context\n\n## Dependencies",
186
+ });
187
+
188
+ await contextStage.execute(ctx);
189
+
190
+ expect(ctx.contextMarkdown).toContain("Existing context");
191
+ expect(ctx.contextMarkdown).toContain("## Dependencies");
192
+ expect(ctx.contextMarkdown).toContain("## Jira Context");
193
+ expect(ctx.contextMarkdown).toContain("New context");
194
+ });
195
+ });
196
+
197
+ describe("AC3: Total injected tokens respect the token budget", () => {
198
+ test("respects default token budget of 2000 tokens when not configured", async () => {
199
+ // This test expects the implementation to use config.execution.contextProviderTokenBudget
200
+ // Currently uses hardcoded 20_000, which is why this test will FAIL
201
+ const provider1 = createMockProvider("provider1", "content1", 1000, "Provider 1");
202
+ const provider2 = createMockProvider("provider2", "content2", 1500, "Provider 2");
203
+ const provider3 = createMockProvider("provider3", "content3", 500, "Provider 3");
204
+
205
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2), createMockPlugin(provider3)];
206
+ const registry = new PluginRegistry(plugins);
207
+
208
+ // Create config with default token budget (2000)
209
+ const configWithBudget = {
210
+ ...DEFAULT_CONFIG,
211
+ execution: {
212
+ ...DEFAULT_CONFIG.execution,
213
+ contextProviderTokenBudget: 2000,
214
+ },
215
+ };
216
+
217
+ const ctx = createTestContext({
218
+ plugins: registry,
219
+ config: configWithBudget,
220
+ });
221
+
222
+ await contextStage.execute(ctx);
223
+
224
+ // Should include provider1 (1000) and provider2 (1500) = 2500 total
225
+ // But should stop before adding all due to budget
226
+ // With 2000 budget, only provider1 should be added
227
+ expect(ctx.contextMarkdown).toContain("Provider 1");
228
+ expect(ctx.contextMarkdown).not.toContain("Provider 2"); // Would exceed budget
229
+ expect(ctx.contextMarkdown).not.toContain("Provider 3");
230
+ });
231
+
232
+ test("respects custom token budget from config", async () => {
233
+ const provider1 = createMockProvider("provider1", "content1", 500, "Provider 1");
234
+ const provider2 = createMockProvider("provider2", "content2", 400, "Provider 2");
235
+ const provider3 = createMockProvider("provider3", "content3", 300, "Provider 3");
236
+
237
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2), createMockPlugin(provider3)];
238
+ const registry = new PluginRegistry(plugins);
239
+
240
+ // Set budget to 1000 tokens
241
+ const configWithBudget = {
242
+ ...DEFAULT_CONFIG,
243
+ execution: {
244
+ ...DEFAULT_CONFIG.execution,
245
+ contextProviderTokenBudget: 1000,
246
+ },
247
+ };
248
+
249
+ const ctx = createTestContext({
250
+ plugins: registry,
251
+ config: configWithBudget,
252
+ });
253
+
254
+ await contextStage.execute(ctx);
255
+
256
+ // Should include provider1 (500) and provider2 (400) = 900 total
257
+ // Should skip provider3 (would make total 1200, exceeding 1000 budget)
258
+ expect(ctx.contextMarkdown).toContain("Provider 1");
259
+ expect(ctx.contextMarkdown).toContain("Provider 2");
260
+ expect(ctx.contextMarkdown).not.toContain("Provider 3");
261
+ });
262
+
263
+ test("providers added in order until budget exhausted", async () => {
264
+ const provider1 = createMockProvider("provider1", "content1", 800, "Provider 1");
265
+ const provider2 = createMockProvider("provider2", "content2", 800, "Provider 2");
266
+ const provider3 = createMockProvider("provider3", "content3", 100, "Provider 3");
267
+
268
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2), createMockPlugin(provider3)];
269
+ const registry = new PluginRegistry(plugins);
270
+
271
+ const configWithBudget = {
272
+ ...DEFAULT_CONFIG,
273
+ execution: {
274
+ ...DEFAULT_CONFIG.execution,
275
+ contextProviderTokenBudget: 1000,
276
+ },
277
+ };
278
+
279
+ const ctx = createTestContext({
280
+ plugins: registry,
281
+ config: configWithBudget,
282
+ });
283
+
284
+ await contextStage.execute(ctx);
285
+
286
+ // Should only include provider1 (800 tokens)
287
+ // provider2 would exceed budget (800 + 800 = 1600 > 1000)
288
+ expect(ctx.contextMarkdown).toContain("Provider 1");
289
+ expect(ctx.contextMarkdown).not.toContain("Provider 2");
290
+ expect(ctx.contextMarkdown).not.toContain("Provider 3");
291
+ });
292
+
293
+ test("single provider exceeding budget is included if it's the first", async () => {
294
+ const provider1 = createMockProvider("provider1", "large content", 3000, "Provider 1");
295
+ const provider2 = createMockProvider("provider2", "content2", 100, "Provider 2");
296
+
297
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2)];
298
+ const registry = new PluginRegistry(plugins);
299
+
300
+ const configWithBudget = {
301
+ ...DEFAULT_CONFIG,
302
+ execution: {
303
+ ...DEFAULT_CONFIG.execution,
304
+ contextProviderTokenBudget: 2000,
305
+ },
306
+ };
307
+
308
+ const ctx = createTestContext({
309
+ plugins: registry,
310
+ config: configWithBudget,
311
+ });
312
+
313
+ await contextStage.execute(ctx);
314
+
315
+ // First provider should be skipped as it exceeds budget alone
316
+ // Implementation should skip providers that would exceed budget
317
+ expect(ctx.contextMarkdown).not.toContain("Provider 1");
318
+ expect(ctx.contextMarkdown).not.toContain("Provider 2");
319
+ });
320
+ });
321
+
322
+ describe("AC4: Provider errors are caught, logged, and skipped", () => {
323
+ test("continues when a provider throws an error", async () => {
324
+ const provider1 = createMockProvider("failing", "content", 100, "Failing Provider", true);
325
+ const provider2 = createMockProvider("working", "content2", 100, "Working Provider");
326
+
327
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2)];
328
+ const registry = new PluginRegistry(plugins);
329
+
330
+ const ctx = createTestContext({ plugins: registry });
331
+
332
+ const result = await contextStage.execute(ctx);
333
+
334
+ // Should continue despite provider1 failing
335
+ expect(result.action).toBe("continue");
336
+ expect(ctx.contextMarkdown).not.toContain("Failing Provider");
337
+ expect(ctx.contextMarkdown).toContain("Working Provider");
338
+ expect(ctx.contextMarkdown).toContain("content2");
339
+ });
340
+
341
+ test("handles all providers failing gracefully", async () => {
342
+ const provider1 = createMockProvider("failing1", "content", 100, "Provider 1", true);
343
+ const provider2 = createMockProvider("failing2", "content", 100, "Provider 2", true);
344
+
345
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2)];
346
+ const registry = new PluginRegistry(plugins);
347
+
348
+ const ctx = createTestContext({ plugins: registry });
349
+
350
+ const result = await contextStage.execute(ctx);
351
+
352
+ expect(result.action).toBe("continue");
353
+ // Context markdown should be empty or contain only base context
354
+ });
355
+
356
+ test("error in one provider does not affect others", async () => {
357
+ const provider1 = createMockProvider("provider1", "content1", 100, "Provider 1");
358
+ const provider2 = createMockProvider("failing", "content", 100, "Failing Provider", true);
359
+ const provider3 = createMockProvider("provider3", "content3", 100, "Provider 3");
360
+
361
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2), createMockPlugin(provider3)];
362
+ const registry = new PluginRegistry(plugins);
363
+
364
+ const ctx = createTestContext({ plugins: registry });
365
+
366
+ await contextStage.execute(ctx);
367
+
368
+ expect(ctx.contextMarkdown).toContain("Provider 1");
369
+ expect(ctx.contextMarkdown).toContain("content1");
370
+ expect(ctx.contextMarkdown).not.toContain("Failing Provider");
371
+ expect(ctx.contextMarkdown).toContain("Provider 3");
372
+ expect(ctx.contextMarkdown).toContain("content3");
373
+ });
374
+ });
375
+
376
+ describe("AC5: Token budget is configurable via execution.contextProviderTokenBudget", () => {
377
+ test("config schema includes contextProviderTokenBudget field", () => {
378
+ // This test will FAIL because the schema doesn't have this field yet
379
+ const config = {
380
+ ...DEFAULT_CONFIG,
381
+ execution: {
382
+ ...DEFAULT_CONFIG.execution,
383
+ contextProviderTokenBudget: 5000,
384
+ },
385
+ };
386
+
387
+ // Should not throw when accessing the field
388
+ expect(config.execution.contextProviderTokenBudget).toBe(5000);
389
+ });
390
+
391
+ test("default config includes contextProviderTokenBudget with default of 2000", () => {
392
+ // Verify DEFAULT_CONFIG has the field with default value
393
+ // This will FAIL until ExecutionConfig type is updated
394
+ expect(DEFAULT_CONFIG.execution).toHaveProperty("contextProviderTokenBudget");
395
+ expect(DEFAULT_CONFIG.execution.contextProviderTokenBudget).toBe(2000);
396
+ });
397
+
398
+ test("uses configured token budget instead of hardcoded value", async () => {
399
+ const provider1 = createMockProvider("provider1", "content1", 3000, "Provider 1");
400
+ const provider2 = createMockProvider("provider2", "content2", 2000, "Provider 2");
401
+
402
+ const plugins = [createMockPlugin(provider1), createMockPlugin(provider2)];
403
+ const registry = new PluginRegistry(plugins);
404
+
405
+ // Set custom budget of 5000 tokens
406
+ const configWithBudget = {
407
+ ...DEFAULT_CONFIG,
408
+ execution: {
409
+ ...DEFAULT_CONFIG.execution,
410
+ contextProviderTokenBudget: 5000,
411
+ },
412
+ };
413
+
414
+ const ctx = createTestContext({
415
+ plugins: registry,
416
+ config: configWithBudget,
417
+ });
418
+
419
+ await contextStage.execute(ctx);
420
+
421
+ // Both providers should be included (3000 + 2000 = 5000)
422
+ expect(ctx.contextMarkdown).toContain("Provider 1");
423
+ expect(ctx.contextMarkdown).toContain("Provider 2");
424
+ });
425
+
426
+ test("different projects can have different token budgets", async () => {
427
+ const provider = createMockProvider("provider", "content", 2500, "Provider");
428
+ const registry = new PluginRegistry([createMockPlugin(provider)]);
429
+
430
+ // Project 1: low budget
431
+ const ctx1 = createTestContext({
432
+ plugins: registry,
433
+ config: {
434
+ ...DEFAULT_CONFIG,
435
+ execution: {
436
+ ...DEFAULT_CONFIG.execution,
437
+ contextProviderTokenBudget: 2000,
438
+ },
439
+ },
440
+ });
441
+
442
+ await contextStage.execute(ctx1);
443
+ expect(ctx1.contextMarkdown).not.toContain("Provider"); // Exceeds budget
444
+
445
+ // Project 2: high budget
446
+ const ctx2 = createTestContext({
447
+ plugins: registry,
448
+ config: {
449
+ ...DEFAULT_CONFIG,
450
+ execution: {
451
+ ...DEFAULT_CONFIG.execution,
452
+ contextProviderTokenBudget: 3000,
453
+ },
454
+ },
455
+ });
456
+
457
+ await contextStage.execute(ctx2);
458
+ expect(ctx2.contextMarkdown).toContain("Provider"); // Within budget
459
+ });
460
+ });
461
+
462
+ describe("Integration: Context providers inject into full pipeline", () => {
463
+ test("context markdown is available to prompt stage", async () => {
464
+ const provider = createMockProvider("jira", "Ticket ABC-123", 100, "Jira Context");
465
+ const registry = new PluginRegistry([createMockPlugin(provider)]);
466
+
467
+ const ctx = createTestContext({ plugins: registry });
468
+
469
+ // Run context stage
470
+ await contextStage.execute(ctx);
471
+
472
+ // Verify context markdown is set and available for prompt stage
473
+ expect(ctx.contextMarkdown).toBeDefined();
474
+ expect(ctx.contextMarkdown).toContain("Jira Context");
475
+ expect(ctx.contextMarkdown).toContain("Ticket ABC-123");
476
+ });
477
+
478
+ test("built context tracks plugin elements", async () => {
479
+ const provider = createMockProvider("jira", "content", 150, "Jira Context");
480
+ const registry = new PluginRegistry([createMockPlugin(provider)]);
481
+
482
+ const ctx = createTestContext({ plugins: registry });
483
+
484
+ await contextStage.execute(ctx);
485
+
486
+ // After running context stage, built context should include plugin elements
487
+ // This test expects the implementation to populate builtContext
488
+ });
489
+
490
+ test("context providers work alongside PRD context", async () => {
491
+ const provider = createMockProvider("jira", "External context", 100, "External");
492
+ const registry = new PluginRegistry([createMockPlugin(provider)]);
493
+
494
+ const ctx = createTestContext({
495
+ plugins: registry,
496
+ contextMarkdown: "# Story Context\n\nPRD-based context here",
497
+ });
498
+
499
+ await contextStage.execute(ctx);
500
+
501
+ // Should preserve existing context and append plugin context
502
+ expect(ctx.contextMarkdown).toContain("PRD-based context");
503
+ expect(ctx.contextMarkdown).toContain("External");
504
+ });
505
+ });
506
+ });