@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,24 @@
1
+ import type { IPromptOptimizer, PromptOptimizerInput, PromptOptimizerResult } from "./types.js";
2
+ import { estimateTokens } from "./types.js";
3
+
4
+ /**
5
+ * Passthrough optimizer that returns the prompt unchanged.
6
+ *
7
+ * Used as the default when optimization is disabled or
8
+ * when the configured strategy is unrecognized.
9
+ */
10
+ export class NoopOptimizer implements IPromptOptimizer {
11
+ public readonly name = "noop";
12
+
13
+ async optimize(input: PromptOptimizerInput): Promise<PromptOptimizerResult> {
14
+ const tokens = estimateTokens(input.prompt);
15
+
16
+ return {
17
+ prompt: input.prompt,
18
+ originalTokens: tokens,
19
+ optimizedTokens: tokens,
20
+ savings: 0,
21
+ appliedRules: [],
22
+ };
23
+ }
24
+ }
@@ -0,0 +1,248 @@
1
+ import type { IPromptOptimizer, PromptOptimizerInput, PromptOptimizerResult } from "./types.js";
2
+ import { estimateTokens } from "./types.js";
3
+
4
+ interface RuleBasedConfig {
5
+ stripWhitespace?: boolean;
6
+ compactCriteria?: boolean;
7
+ deduplicateContext?: boolean;
8
+ maxPromptTokens?: number;
9
+ }
10
+
11
+ const DEFAULT_CONFIG: RuleBasedConfig = {
12
+ stripWhitespace: true,
13
+ compactCriteria: true,
14
+ deduplicateContext: true,
15
+ maxPromptTokens: 8000,
16
+ };
17
+
18
+ /**
19
+ * Rule-based optimizer that applies deterministic transformations
20
+ * to reduce token usage without external dependencies.
21
+ */
22
+ export class RuleBasedOptimizer implements IPromptOptimizer {
23
+ public readonly name = "rule-based";
24
+
25
+ async optimize(input: PromptOptimizerInput): Promise<PromptOptimizerResult> {
26
+ const originalTokens = estimateTokens(input.prompt);
27
+ const appliedRules: string[] = [];
28
+
29
+ let optimized = input.prompt;
30
+
31
+ // Get config with defaults
32
+ const config = {
33
+ ...DEFAULT_CONFIG,
34
+ ...input.config.optimizer?.strategies?.["rule-based"],
35
+ };
36
+
37
+ // Rule 1: Strip whitespace
38
+ if (config.stripWhitespace) {
39
+ const before = optimized;
40
+ optimized = this.stripWhitespace(optimized);
41
+ if (optimized !== before) {
42
+ appliedRules.push("stripWhitespace");
43
+ }
44
+ }
45
+
46
+ // Rule 2: Compact acceptance criteria
47
+ if (config.compactCriteria) {
48
+ const before = optimized;
49
+ optimized = this.compactCriteria(optimized);
50
+ if (optimized !== before) {
51
+ appliedRules.push("compactCriteria");
52
+ }
53
+ }
54
+
55
+ // Rule 3: Deduplicate context
56
+ if (config.deduplicateContext && input.contextMarkdown) {
57
+ const before = optimized;
58
+ optimized = this.deduplicateContext(optimized, input.contextMarkdown);
59
+ if (optimized !== before) {
60
+ appliedRules.push("deduplicateContext");
61
+ }
62
+ }
63
+
64
+ // Rule 4: Enforce max prompt tokens
65
+ if (config.maxPromptTokens) {
66
+ const currentTokens = estimateTokens(optimized);
67
+ if (currentTokens > config.maxPromptTokens) {
68
+ optimized = this.trimToMaxTokens(optimized, config.maxPromptTokens);
69
+ appliedRules.push("maxPromptTokens");
70
+ }
71
+ }
72
+
73
+ const optimizedTokens = estimateTokens(optimized);
74
+ const savings = originalTokens > 0 ? (originalTokens - optimizedTokens) / originalTokens : 0;
75
+
76
+ return {
77
+ prompt: optimized,
78
+ originalTokens,
79
+ optimizedTokens,
80
+ savings,
81
+ appliedRules,
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Collapse multiple blank lines to single blank line and trim trailing whitespace.
87
+ */
88
+ private stripWhitespace(prompt: string): string {
89
+ return (
90
+ prompt
91
+ // Trim trailing whitespace from each line
92
+ .split("\n")
93
+ .map((line) => line.trimEnd())
94
+ .join("\n")
95
+ // Collapse 3+ consecutive newlines to 2
96
+ .replace(/\n{3,}/g, "\n\n")
97
+ );
98
+ }
99
+
100
+ /**
101
+ * Convert verbose acceptance criteria to terse bullet format.
102
+ */
103
+ private compactCriteria(prompt: string): string {
104
+ return (
105
+ prompt
106
+ // Remove verbose prefixes
107
+ .replace(/The user should be able to /gi, "")
108
+ .replace(/The system must /gi, "")
109
+ .replace(/The system should /gi, "")
110
+ .replace(/When the /gi, "")
111
+ .replace(/When a /gi, "")
112
+ // Compact common verbose patterns
113
+ .replace(/it should validate all fields/gi, "validate all fields")
114
+ .replace(/display an error message/gi, "show error")
115
+ .replace(/error message/gi, "error")
116
+ );
117
+ }
118
+
119
+ /**
120
+ * Remove context sections that duplicate constitution content.
121
+ */
122
+ private deduplicateContext(prompt: string, contextMarkdown: string): string {
123
+ // Find context section
124
+ const contextSectionMatch = prompt.match(/# Context\n([\s\S]*?)(?=\n#|$)/i);
125
+ if (!contextSectionMatch) {
126
+ return prompt;
127
+ }
128
+
129
+ const contextSection = contextSectionMatch[1];
130
+ const contextLines = contextSection.split("\n");
131
+
132
+ // Remove lines that appear in constitution
133
+ const dedupedLines = contextLines.filter((line) => {
134
+ const trimmed = line.trim();
135
+ if (!trimmed) return true; // Keep blank lines for now
136
+ // Check if this line appears in the context markdown (which may duplicate constitution)
137
+ return !contextMarkdown.includes(trimmed);
138
+ });
139
+
140
+ // If we removed content, replace the context section
141
+ if (dedupedLines.length < contextLines.length) {
142
+ const newContextSection = dedupedLines.join("\n");
143
+ return prompt.replace(contextSectionMatch[0], `# Context\n${newContextSection}`);
144
+ }
145
+
146
+ return prompt;
147
+ }
148
+
149
+ /**
150
+ * Trim context aggressively if prompt exceeds max tokens.
151
+ * Preserve Task and Acceptance Criteria sections.
152
+ */
153
+ private trimToMaxTokens(prompt: string, maxTokens: number): string {
154
+ const currentTokens = estimateTokens(prompt);
155
+ if (currentTokens <= maxTokens) {
156
+ return prompt;
157
+ }
158
+
159
+ // Extract sections
160
+ const sections = this.extractSections(prompt);
161
+ const targetChars = maxTokens * 4; // Reverse of token estimation
162
+ const trimmedMessage = "\n... (context trimmed)";
163
+
164
+ // Preserve task and AC, trim context
165
+ let result = "";
166
+ let remainingChars = targetChars;
167
+
168
+ // Add task section (always preserve)
169
+ if (sections.task) {
170
+ result += sections.task;
171
+ remainingChars -= sections.task.length;
172
+ }
173
+
174
+ // Add AC section (always preserve)
175
+ if (sections.acceptanceCriteria) {
176
+ result += sections.acceptanceCriteria;
177
+ remainingChars -= sections.acceptanceCriteria.length;
178
+ }
179
+
180
+ // Add as much context as fits
181
+ if (sections.context && remainingChars > 0) {
182
+ // Reserve space for the trimmed message if we're going to add it
183
+ const reserveForMessage = sections.context.length > remainingChars ? trimmedMessage.length : 0;
184
+ const maxContextChars = Math.max(0, remainingChars - reserveForMessage);
185
+ const trimmedContext = sections.context.substring(0, maxContextChars);
186
+ result += trimmedContext;
187
+ if (trimmedContext.length < sections.context.length) {
188
+ result += trimmedMessage;
189
+ }
190
+ }
191
+
192
+ // Add other sections if there's room
193
+ if (sections.other && remainingChars > sections.other.length) {
194
+ result += sections.other;
195
+ }
196
+
197
+ return result;
198
+ }
199
+
200
+ /**
201
+ * Extract common prompt sections for targeted trimming.
202
+ */
203
+ private extractSections(prompt: string): {
204
+ task?: string;
205
+ context?: string;
206
+ acceptanceCriteria?: string;
207
+ other?: string;
208
+ } {
209
+ const sections: {
210
+ task?: string;
211
+ context?: string;
212
+ acceptanceCriteria?: string;
213
+ other?: string;
214
+ } = {};
215
+
216
+ const taskMatch = prompt.match(/# Task\n([\s\S]*?)(?=\n#|$)/i);
217
+ if (taskMatch) {
218
+ sections.task = taskMatch[0];
219
+ }
220
+
221
+ const contextMatch = prompt.match(/# Context\n([\s\S]*?)(?=\n#|$)/i);
222
+ if (contextMatch) {
223
+ sections.context = contextMatch[0];
224
+ }
225
+
226
+ const acMatch = prompt.match(/# Acceptance Criteria\n([\s\S]*?)(?=\n#|$)/i);
227
+ if (acMatch) {
228
+ sections.acceptanceCriteria = acMatch[0];
229
+ }
230
+
231
+ // Collect everything else
232
+ let other = prompt;
233
+ if (sections.task) {
234
+ other = other.replace(sections.task, "");
235
+ }
236
+ if (sections.context) {
237
+ other = other.replace(sections.context, "");
238
+ }
239
+ if (sections.acceptanceCriteria) {
240
+ other = other.replace(sections.acceptanceCriteria, "");
241
+ }
242
+ if (other.trim()) {
243
+ sections.other = other;
244
+ }
245
+
246
+ return sections;
247
+ }
248
+ }
@@ -0,0 +1,53 @@
1
+ import type { NaxConfig } from "../config/schema.js";
2
+ import type { UserStory } from "../prd/types.js";
3
+
4
+ /**
5
+ * Interface for prompt optimizers.
6
+ *
7
+ * Optimizers transform assembled prompts to reduce token usage while
8
+ * preserving semantic meaning and all technical requirements.
9
+ */
10
+ export interface IPromptOptimizer {
11
+ /** Unique optimizer name */
12
+ name: string;
13
+
14
+ /**
15
+ * Optimize a prompt before it is sent to the coding agent.
16
+ *
17
+ * Implementations MUST preserve all technical requirements,
18
+ * acceptance criteria semantics, and code references.
19
+ */
20
+ optimize(input: PromptOptimizerInput): Promise<PromptOptimizerResult>;
21
+ }
22
+
23
+ export interface PromptOptimizerInput {
24
+ /** Assembled prompt from promptStage */
25
+ prompt: string;
26
+ /** Stories being executed (for context) */
27
+ stories: UserStory[];
28
+ /** Raw context markdown (pre-assembly, for dedup detection) */
29
+ contextMarkdown?: string;
30
+ /** Nax configuration */
31
+ config: NaxConfig;
32
+ }
33
+
34
+ export interface PromptOptimizerResult {
35
+ /** Optimized prompt */
36
+ prompt: string;
37
+ /** Estimated token count before optimization */
38
+ originalTokens: number;
39
+ /** Estimated token count after optimization */
40
+ optimizedTokens: number;
41
+ /** Savings percentage (0-1) */
42
+ savings: number;
43
+ /** List of applied optimization rules/passes */
44
+ appliedRules: string[];
45
+ }
46
+
47
+ /**
48
+ * Estimate token count using simple heuristic.
49
+ * ~4 chars per token for English text (rough estimate).
50
+ */
51
+ export function estimateTokens(text: string): number {
52
+ return Math.ceil(text.length / 4);
53
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Pipeline Event Emitter
3
+ *
4
+ * Typed event emitter for TUI integration. Emits lifecycle events during
5
+ * pipeline execution so the TUI can display real-time progress.
6
+ */
7
+
8
+ import { EventEmitter } from "node:events";
9
+ import type { UserStory } from "../prd/types";
10
+ import type { RoutingResult, StageResult } from "./types";
11
+
12
+ /**
13
+ * Summary of a completed run.
14
+ */
15
+ export interface RunSummary {
16
+ /** Total number of stories processed */
17
+ storiesProcessed: number;
18
+ /** Number of stories completed successfully */
19
+ storiesCompleted: number;
20
+ /** Number of stories failed */
21
+ storiesFailed: number;
22
+ /** Number of stories skipped */
23
+ storiesSkipped: number;
24
+ /** Total cost in USD */
25
+ totalCost: number;
26
+ /** Total duration in milliseconds */
27
+ durationMs: number;
28
+ }
29
+
30
+ /**
31
+ * Pipeline event types matching v0.6 spec.
32
+ *
33
+ * Events:
34
+ * - story:start — Story execution begins
35
+ * - story:complete — Story execution ends (success/fail/skip)
36
+ * - story:escalate — Story escalated to higher tier
37
+ * - stage:enter — Pipeline stage starts
38
+ * - stage:exit — Pipeline stage finishes
39
+ * - run:complete — Full run completes
40
+ */
41
+ export interface PipelineEvents {
42
+ "story:start": (story: UserStory, routing: RoutingResult) => void;
43
+ "story:complete": (story: UserStory, result: StageResult) => void;
44
+ "story:escalate": (story: UserStory, fromTier: string, toTier: string) => void;
45
+ "stage:enter": (stage: string, story: UserStory) => void;
46
+ "stage:exit": (stage: string, result: StageResult) => void;
47
+ "run:complete": (summary: RunSummary) => void;
48
+ }
49
+
50
+ /**
51
+ * Typed event emitter for pipeline events.
52
+ *
53
+ * Wraps Node.js EventEmitter with TypeScript types for pipeline lifecycle
54
+ * events. The TUI subscribes to these events to update UI state in real-time.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const emitter = new PipelineEventEmitter();
59
+ *
60
+ * emitter.on('story:start', (story, routing) => {
61
+ * // Handle story start: ${story.id} with ${routing.modelTier}
62
+ * });
63
+ *
64
+ * emitter.on('story:complete', (story, result) => {
65
+ * // Handle story completion: ${story.id} - ${result.action}
66
+ * });
67
+ *
68
+ * // In pipeline runner:
69
+ * emitter.emit('story:start', story, routing);
70
+ * ```
71
+ */
72
+ export class PipelineEventEmitter {
73
+ private emitter = new EventEmitter();
74
+
75
+ /**
76
+ * Subscribe to a pipeline event.
77
+ *
78
+ * @param event - Event name
79
+ * @param listener - Event handler
80
+ */
81
+ on<E extends keyof PipelineEvents>(event: E, listener: PipelineEvents[E]): void {
82
+ this.emitter.on(event, listener as (...args: unknown[]) => void);
83
+ }
84
+
85
+ /**
86
+ * Subscribe to an event once (auto-unsubscribe after first emission).
87
+ *
88
+ * @param event - Event name
89
+ * @param listener - Event handler
90
+ */
91
+ once<E extends keyof PipelineEvents>(event: E, listener: PipelineEvents[E]): void {
92
+ this.emitter.once(event, listener as (...args: unknown[]) => void);
93
+ }
94
+
95
+ /**
96
+ * Unsubscribe from an event.
97
+ *
98
+ * @param event - Event name
99
+ * @param listener - Event handler to remove
100
+ */
101
+ off<E extends keyof PipelineEvents>(event: E, listener: PipelineEvents[E]): void {
102
+ this.emitter.off(event, listener as (...args: unknown[]) => void);
103
+ }
104
+
105
+ /**
106
+ * Emit a pipeline event.
107
+ *
108
+ * Called internally by the pipeline runner. External code should only
109
+ * subscribe to events, not emit them.
110
+ *
111
+ * @param event - Event name
112
+ * @param args - Event arguments
113
+ */
114
+ emit<E extends keyof PipelineEvents>(event: E, ...args: Parameters<PipelineEvents[E]>): void {
115
+ this.emitter.emit(event, ...args);
116
+ }
117
+
118
+ /**
119
+ * Remove all listeners for a specific event or all events.
120
+ *
121
+ * @param event - Optional event name (if not provided, removes all listeners)
122
+ */
123
+ removeAllListeners(event?: keyof PipelineEvents): void {
124
+ if (event) {
125
+ this.emitter.removeAllListeners(event);
126
+ } else {
127
+ this.emitter.removeAllListeners();
128
+ }
129
+ }
130
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Pipeline Module
3
+ *
4
+ * Composable stage-based execution pipeline.
5
+ */
6
+
7
+ export type {
8
+ PipelineContext,
9
+ PipelineStage,
10
+ StageResult,
11
+ StageAction,
12
+ RoutingResult,
13
+ } from "./types";
14
+
15
+ export { runPipeline } from "./runner";
16
+ export type { PipelineRunResult } from "./runner";
17
+
18
+ export { PipelineEventEmitter } from "./events";
19
+ export type { PipelineEvents, RunSummary } from "./events";
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Pipeline Runner
3
+ *
4
+ * Executes a sequence of pipeline stages, handling stage results and
5
+ * controlling the flow (continue/skip/fail/escalate/pause).
6
+ */
7
+
8
+ import { getLogger } from "../logger";
9
+ import type { PipelineEventEmitter } from "./events";
10
+ import type { PipelineContext, PipelineStage, StageResult } from "./types";
11
+
12
+ /**
13
+ * Pipeline execution result.
14
+ */
15
+ export interface PipelineRunResult {
16
+ /** Whether the pipeline completed successfully (reached the end) */
17
+ success: boolean;
18
+ /** Final action taken (e.g., "skip", "fail", "escalate", "pause", "complete") */
19
+ finalAction: "complete" | "skip" | "fail" | "escalate" | "pause";
20
+ /** Reason for non-complete outcomes */
21
+ reason?: string;
22
+ /** Stage where the pipeline stopped (if not completed) */
23
+ stoppedAtStage?: string;
24
+ /** Updated context after pipeline execution */
25
+ context: PipelineContext;
26
+ }
27
+
28
+ /**
29
+ * Run a pipeline of stages against a context.
30
+ *
31
+ * Iterates through each enabled stage, executing them in sequence.
32
+ * Stops early if a stage returns skip/fail/escalate/pause.
33
+ *
34
+ * **IMPORTANT - Context Mutation Contract:**
35
+ * This function mutates the input context in-place. Stages modify the context
36
+ * object directly (e.g., `ctx.constitution = result`, `ctx.routing = routing`).
37
+ * The returned `context` in PipelineRunResult is the same object reference,
38
+ * not a clone. If you need immutability, clone the context before calling
39
+ * runPipeline.
40
+ *
41
+ * @param stages - Array of pipeline stages to execute
42
+ * @param context - Initial pipeline context (WILL BE MUTATED IN-PLACE)
43
+ * @param eventEmitter - Optional event emitter for TUI integration
44
+ * @returns Pipeline execution result with mutated context
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const stages = [routingStage, contextStage, executionStage];
49
+ * const ctx = createInitialContext(); // { config, prd, story, ... }
50
+ *
51
+ * const result = await runPipeline(stages, ctx);
52
+ *
53
+ * if (result.success) {
54
+ * // Pipeline completed successfully
55
+ * // ctx and result.context are the same object
56
+ * // ctx.agentResult === result.context.agentResult is true
57
+ * } else {
58
+ * // Pipeline stopped: ${result.finalAction} - ${result.reason}
59
+ * }
60
+ * ```
61
+ */
62
+ export async function runPipeline(
63
+ stages: PipelineStage[],
64
+ context: PipelineContext,
65
+ eventEmitter?: PipelineEventEmitter,
66
+ ): Promise<PipelineRunResult> {
67
+ const logger = getLogger();
68
+
69
+ for (const stage of stages) {
70
+ // Skip disabled stages
71
+ if (!stage.enabled(context)) {
72
+ logger.debug("pipeline", `Stage "${stage.name}" skipped (disabled)`);
73
+ continue;
74
+ }
75
+
76
+ // Emit stage:enter event
77
+ eventEmitter?.emit("stage:enter", stage.name, context.story);
78
+
79
+ // Execute the stage
80
+ let result: StageResult;
81
+ try {
82
+ result = await stage.execute(context);
83
+ } catch (error) {
84
+ // Stage execution failed with an exception
85
+ const failResult: StageResult = {
86
+ action: "fail",
87
+ reason: `Stage "${stage.name}" threw error: ${error instanceof Error ? error.message : String(error)}`,
88
+ };
89
+
90
+ // Emit stage:exit event
91
+ eventEmitter?.emit("stage:exit", stage.name, failResult);
92
+
93
+ return {
94
+ success: false,
95
+ finalAction: "fail",
96
+ reason: failResult.reason,
97
+ stoppedAtStage: stage.name,
98
+ context,
99
+ };
100
+ }
101
+
102
+ // Emit stage:exit event
103
+ eventEmitter?.emit("stage:exit", stage.name, result);
104
+
105
+ // Handle stage result
106
+ switch (result.action) {
107
+ case "continue":
108
+ // Proceed to next stage
109
+ continue;
110
+
111
+ case "skip":
112
+ return {
113
+ success: false,
114
+ finalAction: "skip",
115
+ reason: result.reason,
116
+ stoppedAtStage: stage.name,
117
+ context,
118
+ };
119
+
120
+ case "fail":
121
+ return {
122
+ success: false,
123
+ finalAction: "fail",
124
+ reason: result.reason,
125
+ stoppedAtStage: stage.name,
126
+ context,
127
+ };
128
+
129
+ case "escalate":
130
+ return {
131
+ success: false,
132
+ finalAction: "escalate",
133
+ reason: "Stage requested escalation to higher tier",
134
+ stoppedAtStage: stage.name,
135
+ context,
136
+ };
137
+
138
+ case "pause":
139
+ return {
140
+ success: false,
141
+ finalAction: "pause",
142
+ reason: result.reason,
143
+ stoppedAtStage: stage.name,
144
+ context,
145
+ };
146
+
147
+ default: {
148
+ // Exhaustiveness check
149
+ const _exhaustive: never = result;
150
+ throw new Error(`Unknown stage action: ${JSON.stringify(_exhaustive)}`);
151
+ }
152
+ }
153
+ }
154
+
155
+ // All stages completed successfully
156
+ return {
157
+ success: true,
158
+ finalAction: "complete",
159
+ context,
160
+ };
161
+ }