@nathapp/nax 0.50.3 → 0.51.0

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 (352) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/nax.js +393 -197
  3. package/package.json +1 -3
  4. package/bin/nax.ts +0 -1195
  5. package/src/acceptance/fix-generator.ts +0 -322
  6. package/src/acceptance/generator.ts +0 -415
  7. package/src/acceptance/index.ts +0 -42
  8. package/src/acceptance/refinement.ts +0 -224
  9. package/src/acceptance/templates/cli.ts +0 -47
  10. package/src/acceptance/templates/component.ts +0 -78
  11. package/src/acceptance/templates/e2e.ts +0 -43
  12. package/src/acceptance/templates/index.ts +0 -21
  13. package/src/acceptance/templates/snapshot.ts +0 -50
  14. package/src/acceptance/templates/unit.ts +0 -48
  15. package/src/acceptance/types.ts +0 -138
  16. package/src/agents/acp/adapter.ts +0 -888
  17. package/src/agents/acp/cost.ts +0 -9
  18. package/src/agents/acp/index.ts +0 -7
  19. package/src/agents/acp/interaction-bridge.ts +0 -126
  20. package/src/agents/acp/parser.ts +0 -119
  21. package/src/agents/acp/spawn-client.ts +0 -373
  22. package/src/agents/acp/types.ts +0 -22
  23. package/src/agents/aider/adapter.ts +0 -135
  24. package/src/agents/claude/adapter.ts +0 -258
  25. package/src/agents/claude/complete.ts +0 -80
  26. package/src/agents/claude/cost.ts +0 -16
  27. package/src/agents/claude/execution.ts +0 -215
  28. package/src/agents/claude/index.ts +0 -3
  29. package/src/agents/claude/interactive.ts +0 -77
  30. package/src/agents/claude/plan.ts +0 -179
  31. package/src/agents/codex/adapter.ts +0 -153
  32. package/src/agents/cost/calculate.ts +0 -154
  33. package/src/agents/cost/index.ts +0 -10
  34. package/src/agents/cost/parse.ts +0 -97
  35. package/src/agents/cost/pricing.ts +0 -59
  36. package/src/agents/cost/types.ts +0 -45
  37. package/src/agents/gemini/adapter.ts +0 -177
  38. package/src/agents/index.ts +0 -18
  39. package/src/agents/opencode/adapter.ts +0 -106
  40. package/src/agents/registry.ts +0 -136
  41. package/src/agents/shared/decompose.ts +0 -154
  42. package/src/agents/shared/model-resolution.ts +0 -43
  43. package/src/agents/shared/types-extended.ts +0 -164
  44. package/src/agents/shared/validation.ts +0 -69
  45. package/src/agents/shared/version-detection.ts +0 -109
  46. package/src/agents/types.ts +0 -205
  47. package/src/analyze/classifier.ts +0 -282
  48. package/src/analyze/index.ts +0 -16
  49. package/src/analyze/scanner.ts +0 -171
  50. package/src/analyze/types.ts +0 -51
  51. package/src/cli/accept.ts +0 -108
  52. package/src/cli/agents.ts +0 -87
  53. package/src/cli/analyze-parser.ts +0 -291
  54. package/src/cli/analyze.ts +0 -352
  55. package/src/cli/config-descriptions.ts +0 -219
  56. package/src/cli/config-diff.ts +0 -103
  57. package/src/cli/config-display.ts +0 -285
  58. package/src/cli/config-get.ts +0 -55
  59. package/src/cli/config.ts +0 -14
  60. package/src/cli/constitution.ts +0 -17
  61. package/src/cli/diagnose-analysis.ts +0 -159
  62. package/src/cli/diagnose-formatter.ts +0 -87
  63. package/src/cli/diagnose.ts +0 -203
  64. package/src/cli/generate.ts +0 -250
  65. package/src/cli/index.ts +0 -42
  66. package/src/cli/init-context.ts +0 -405
  67. package/src/cli/init-detect.ts +0 -303
  68. package/src/cli/init.ts +0 -296
  69. package/src/cli/interact.ts +0 -295
  70. package/src/cli/plan.ts +0 -509
  71. package/src/cli/plugins.ts +0 -122
  72. package/src/cli/prompts-export.ts +0 -58
  73. package/src/cli/prompts-init.ts +0 -200
  74. package/src/cli/prompts-main.ts +0 -183
  75. package/src/cli/prompts-shared.ts +0 -70
  76. package/src/cli/prompts-tdd.ts +0 -88
  77. package/src/cli/prompts.ts +0 -17
  78. package/src/cli/runs.ts +0 -174
  79. package/src/cli/status-cost.ts +0 -151
  80. package/src/cli/status-features.ts +0 -405
  81. package/src/cli/status.ts +0 -13
  82. package/src/commands/common.ts +0 -171
  83. package/src/commands/diagnose.ts +0 -17
  84. package/src/commands/index.ts +0 -9
  85. package/src/commands/logs-formatter.ts +0 -201
  86. package/src/commands/logs-reader.ts +0 -171
  87. package/src/commands/logs.ts +0 -103
  88. package/src/commands/precheck.ts +0 -86
  89. package/src/commands/runs.ts +0 -220
  90. package/src/commands/unlock.ts +0 -96
  91. package/src/config/defaults.ts +0 -218
  92. package/src/config/index.ts +0 -22
  93. package/src/config/loader.ts +0 -143
  94. package/src/config/merge.ts +0 -106
  95. package/src/config/merger.ts +0 -147
  96. package/src/config/path-security.ts +0 -121
  97. package/src/config/paths.ts +0 -27
  98. package/src/config/permissions.ts +0 -63
  99. package/src/config/runtime-types.ts +0 -522
  100. package/src/config/schema-types.ts +0 -53
  101. package/src/config/schema.ts +0 -60
  102. package/src/config/schemas.ts +0 -426
  103. package/src/config/test-strategy.ts +0 -71
  104. package/src/config/types.ts +0 -57
  105. package/src/config/validate.ts +0 -103
  106. package/src/constitution/generator.ts +0 -158
  107. package/src/constitution/generators/aider.ts +0 -41
  108. package/src/constitution/generators/claude.ts +0 -35
  109. package/src/constitution/generators/cursor.ts +0 -36
  110. package/src/constitution/generators/opencode.ts +0 -38
  111. package/src/constitution/generators/types.ts +0 -33
  112. package/src/constitution/generators/windsurf.ts +0 -36
  113. package/src/constitution/index.ts +0 -11
  114. package/src/constitution/loader.ts +0 -121
  115. package/src/constitution/types.ts +0 -31
  116. package/src/context/auto-detect.ts +0 -228
  117. package/src/context/builder.ts +0 -299
  118. package/src/context/elements.ts +0 -122
  119. package/src/context/formatter.ts +0 -107
  120. package/src/context/generator.ts +0 -343
  121. package/src/context/generators/aider.ts +0 -34
  122. package/src/context/generators/claude.ts +0 -28
  123. package/src/context/generators/codex.ts +0 -28
  124. package/src/context/generators/cursor.ts +0 -28
  125. package/src/context/generators/gemini.ts +0 -28
  126. package/src/context/generators/opencode.ts +0 -30
  127. package/src/context/generators/windsurf.ts +0 -28
  128. package/src/context/greenfield.ts +0 -114
  129. package/src/context/index.ts +0 -34
  130. package/src/context/injector.ts +0 -279
  131. package/src/context/parent-context.ts +0 -39
  132. package/src/context/test-scanner.ts +0 -370
  133. package/src/context/types.ts +0 -98
  134. package/src/decompose/apply.ts +0 -50
  135. package/src/decompose/builder.ts +0 -181
  136. package/src/decompose/index.ts +0 -8
  137. package/src/decompose/sections/codebase.ts +0 -26
  138. package/src/decompose/sections/constraints.ts +0 -32
  139. package/src/decompose/sections/index.ts +0 -4
  140. package/src/decompose/sections/sibling-stories.ts +0 -25
  141. package/src/decompose/sections/target-story.ts +0 -31
  142. package/src/decompose/types.ts +0 -55
  143. package/src/decompose/validators/complexity.ts +0 -45
  144. package/src/decompose/validators/coverage.ts +0 -134
  145. package/src/decompose/validators/dependency.ts +0 -91
  146. package/src/decompose/validators/index.ts +0 -35
  147. package/src/decompose/validators/overlap.ts +0 -128
  148. package/src/errors.ts +0 -67
  149. package/src/execution/batching.ts +0 -157
  150. package/src/execution/crash-heartbeat.ts +0 -77
  151. package/src/execution/crash-recovery.ts +0 -79
  152. package/src/execution/crash-signals.ts +0 -165
  153. package/src/execution/crash-writer.ts +0 -154
  154. package/src/execution/deferred-review.ts +0 -105
  155. package/src/execution/dry-run.ts +0 -81
  156. package/src/execution/escalation/escalation.ts +0 -46
  157. package/src/execution/escalation/index.ts +0 -13
  158. package/src/execution/escalation/tier-escalation.ts +0 -346
  159. package/src/execution/escalation/tier-outcome.ts +0 -143
  160. package/src/execution/executor-types.ts +0 -73
  161. package/src/execution/helpers.ts +0 -38
  162. package/src/execution/index.ts +0 -27
  163. package/src/execution/iteration-runner.ts +0 -160
  164. package/src/execution/lifecycle/acceptance-loop.ts +0 -309
  165. package/src/execution/lifecycle/headless-formatter.ts +0 -83
  166. package/src/execution/lifecycle/index.ts +0 -11
  167. package/src/execution/lifecycle/parallel-lifecycle.ts +0 -101
  168. package/src/execution/lifecycle/precheck-runner.ts +0 -140
  169. package/src/execution/lifecycle/run-cleanup.ts +0 -81
  170. package/src/execution/lifecycle/run-completion.ts +0 -247
  171. package/src/execution/lifecycle/run-initialization.ts +0 -187
  172. package/src/execution/lifecycle/run-regression.ts +0 -305
  173. package/src/execution/lifecycle/run-setup.ts +0 -240
  174. package/src/execution/lifecycle/story-size-prompts.ts +0 -123
  175. package/src/execution/lock.ts +0 -129
  176. package/src/execution/parallel-coordinator.ts +0 -281
  177. package/src/execution/parallel-executor-rectification-pass.ts +0 -117
  178. package/src/execution/parallel-executor-rectify.ts +0 -136
  179. package/src/execution/parallel-executor.ts +0 -330
  180. package/src/execution/parallel-worker.ts +0 -149
  181. package/src/execution/parallel.ts +0 -13
  182. package/src/execution/pid-registry.ts +0 -275
  183. package/src/execution/pipeline-result-handler.ts +0 -221
  184. package/src/execution/progress.ts +0 -27
  185. package/src/execution/queue-handler.ts +0 -109
  186. package/src/execution/runner-completion.ts +0 -171
  187. package/src/execution/runner-execution.ts +0 -243
  188. package/src/execution/runner-setup.ts +0 -86
  189. package/src/execution/runner.ts +0 -265
  190. package/src/execution/sequential-executor.ts +0 -219
  191. package/src/execution/status-file.ts +0 -264
  192. package/src/execution/status-writer.ts +0 -181
  193. package/src/execution/story-context.ts +0 -266
  194. package/src/execution/story-selector.ts +0 -76
  195. package/src/execution/test-output-parser.ts +0 -14
  196. package/src/execution/timeout-handler.ts +0 -100
  197. package/src/hooks/index.ts +0 -2
  198. package/src/hooks/runner.ts +0 -280
  199. package/src/hooks/types.ts +0 -79
  200. package/src/interaction/chain.ts +0 -170
  201. package/src/interaction/index.ts +0 -61
  202. package/src/interaction/init.ts +0 -84
  203. package/src/interaction/plugins/auto.ts +0 -243
  204. package/src/interaction/plugins/cli.ts +0 -300
  205. package/src/interaction/plugins/telegram.ts +0 -384
  206. package/src/interaction/plugins/webhook.ts +0 -286
  207. package/src/interaction/state.ts +0 -171
  208. package/src/interaction/triggers.ts +0 -250
  209. package/src/interaction/types.ts +0 -170
  210. package/src/logger/formatters.ts +0 -84
  211. package/src/logger/index.ts +0 -16
  212. package/src/logger/logger.ts +0 -296
  213. package/src/logger/types.ts +0 -48
  214. package/src/logging/formatter.ts +0 -355
  215. package/src/logging/index.ts +0 -22
  216. package/src/logging/types.ts +0 -93
  217. package/src/metrics/aggregator.ts +0 -191
  218. package/src/metrics/index.ts +0 -14
  219. package/src/metrics/tracker.ts +0 -200
  220. package/src/metrics/types.ts +0 -115
  221. package/src/optimizer/index.ts +0 -63
  222. package/src/optimizer/noop.optimizer.ts +0 -24
  223. package/src/optimizer/rule-based.optimizer.ts +0 -248
  224. package/src/optimizer/types.ts +0 -53
  225. package/src/pipeline/event-bus.ts +0 -297
  226. package/src/pipeline/events.ts +0 -130
  227. package/src/pipeline/index.ts +0 -19
  228. package/src/pipeline/runner.ts +0 -149
  229. package/src/pipeline/stages/acceptance-setup.ts +0 -144
  230. package/src/pipeline/stages/acceptance.ts +0 -215
  231. package/src/pipeline/stages/autofix.ts +0 -262
  232. package/src/pipeline/stages/completion.ts +0 -110
  233. package/src/pipeline/stages/constitution.ts +0 -63
  234. package/src/pipeline/stages/context.ts +0 -122
  235. package/src/pipeline/stages/execution.ts +0 -359
  236. package/src/pipeline/stages/index.ts +0 -86
  237. package/src/pipeline/stages/optimizer.ts +0 -74
  238. package/src/pipeline/stages/prompt.ts +0 -79
  239. package/src/pipeline/stages/queue-check.ts +0 -103
  240. package/src/pipeline/stages/rectify.ts +0 -101
  241. package/src/pipeline/stages/regression.ts +0 -99
  242. package/src/pipeline/stages/review.ts +0 -94
  243. package/src/pipeline/stages/routing.ts +0 -276
  244. package/src/pipeline/stages/verify.ts +0 -286
  245. package/src/pipeline/subscribers/events-writer.ts +0 -135
  246. package/src/pipeline/subscribers/hooks.ts +0 -179
  247. package/src/pipeline/subscribers/interaction.ts +0 -103
  248. package/src/pipeline/subscribers/registry.ts +0 -73
  249. package/src/pipeline/subscribers/reporters.ts +0 -174
  250. package/src/pipeline/types.ts +0 -220
  251. package/src/plugins/extensions.ts +0 -225
  252. package/src/plugins/index.ts +0 -33
  253. package/src/plugins/loader.ts +0 -352
  254. package/src/plugins/plugin-logger.ts +0 -41
  255. package/src/plugins/registry.ts +0 -168
  256. package/src/plugins/types.ts +0 -206
  257. package/src/plugins/validator.ts +0 -352
  258. package/src/prd/index.ts +0 -220
  259. package/src/prd/schema.ts +0 -268
  260. package/src/prd/types.ts +0 -273
  261. package/src/prd/validate.ts +0 -41
  262. package/src/precheck/checks-agents.ts +0 -63
  263. package/src/precheck/checks-blockers.ts +0 -23
  264. package/src/precheck/checks-cli.ts +0 -68
  265. package/src/precheck/checks-config.ts +0 -102
  266. package/src/precheck/checks-git.ts +0 -117
  267. package/src/precheck/checks-system.ts +0 -101
  268. package/src/precheck/checks-warnings.ts +0 -221
  269. package/src/precheck/checks.ts +0 -36
  270. package/src/precheck/index.ts +0 -374
  271. package/src/precheck/story-size-gate.ts +0 -144
  272. package/src/precheck/types.ts +0 -31
  273. package/src/prompts/builder.ts +0 -166
  274. package/src/prompts/index.ts +0 -2
  275. package/src/prompts/loader.ts +0 -43
  276. package/src/prompts/sections/conventions.ts +0 -19
  277. package/src/prompts/sections/hermetic.ts +0 -41
  278. package/src/prompts/sections/index.ts +0 -12
  279. package/src/prompts/sections/isolation.ts +0 -70
  280. package/src/prompts/sections/role-task.ts +0 -182
  281. package/src/prompts/sections/story.ts +0 -55
  282. package/src/prompts/sections/verdict.ts +0 -70
  283. package/src/prompts/types.ts +0 -21
  284. package/src/queue/index.ts +0 -2
  285. package/src/queue/manager.ts +0 -254
  286. package/src/queue/types.ts +0 -54
  287. package/src/review/index.ts +0 -8
  288. package/src/review/orchestrator.ts +0 -154
  289. package/src/review/runner.ts +0 -303
  290. package/src/review/types.ts +0 -70
  291. package/src/routing/batch-route.ts +0 -35
  292. package/src/routing/builder.ts +0 -81
  293. package/src/routing/chain.ts +0 -75
  294. package/src/routing/content-hash.ts +0 -25
  295. package/src/routing/index.ts +0 -20
  296. package/src/routing/loader.ts +0 -62
  297. package/src/routing/router.ts +0 -305
  298. package/src/routing/strategies/adaptive.ts +0 -215
  299. package/src/routing/strategies/index.ts +0 -8
  300. package/src/routing/strategies/keyword.ts +0 -180
  301. package/src/routing/strategies/llm-prompts.ts +0 -224
  302. package/src/routing/strategies/llm.ts +0 -320
  303. package/src/routing/strategies/manual.ts +0 -50
  304. package/src/routing/strategy.ts +0 -102
  305. package/src/tdd/cleanup.ts +0 -120
  306. package/src/tdd/index.ts +0 -22
  307. package/src/tdd/isolation.ts +0 -117
  308. package/src/tdd/orchestrator.ts +0 -406
  309. package/src/tdd/prompts.ts +0 -40
  310. package/src/tdd/rectification-gate.ts +0 -274
  311. package/src/tdd/session-runner.ts +0 -263
  312. package/src/tdd/types.ts +0 -84
  313. package/src/tdd/verdict-reader.ts +0 -266
  314. package/src/tdd/verdict.ts +0 -152
  315. package/src/tui/App.tsx +0 -265
  316. package/src/tui/components/AgentPanel.tsx +0 -75
  317. package/src/tui/components/CostOverlay.tsx +0 -118
  318. package/src/tui/components/HelpOverlay.tsx +0 -107
  319. package/src/tui/components/StatusBar.tsx +0 -63
  320. package/src/tui/components/StoriesPanel.tsx +0 -177
  321. package/src/tui/hooks/useKeyboard.ts +0 -142
  322. package/src/tui/hooks/useLayout.ts +0 -137
  323. package/src/tui/hooks/usePipelineEvents.ts +0 -183
  324. package/src/tui/hooks/usePty.ts +0 -189
  325. package/src/tui/index.tsx +0 -38
  326. package/src/tui/types.ts +0 -76
  327. package/src/utils/errors.ts +0 -12
  328. package/src/utils/git.ts +0 -245
  329. package/src/utils/json-file.ts +0 -72
  330. package/src/utils/log-test-output.ts +0 -25
  331. package/src/utils/path-security.ts +0 -73
  332. package/src/utils/queue-writer.ts +0 -54
  333. package/src/verification/crash-detector.ts +0 -34
  334. package/src/verification/executor.ts +0 -250
  335. package/src/verification/index.ts +0 -12
  336. package/src/verification/orchestrator-types.ts +0 -154
  337. package/src/verification/orchestrator.ts +0 -76
  338. package/src/verification/parser.ts +0 -220
  339. package/src/verification/rectification-loop.ts +0 -172
  340. package/src/verification/rectification.ts +0 -108
  341. package/src/verification/runners.ts +0 -129
  342. package/src/verification/smart-runner.ts +0 -307
  343. package/src/verification/strategies/acceptance.ts +0 -136
  344. package/src/verification/strategies/regression.ts +0 -90
  345. package/src/verification/strategies/scoped.ts +0 -154
  346. package/src/verification/types.ts +0 -117
  347. package/src/version.ts +0 -40
  348. package/src/worktree/dispatcher.ts +0 -6
  349. package/src/worktree/index.ts +0 -2
  350. package/src/worktree/manager.ts +0 -193
  351. package/src/worktree/merge.ts +0 -302
  352. package/src/worktree/types.ts +0 -4
@@ -1,105 +0,0 @@
1
- /**
2
- * Deferred Plugin Review (DR-003)
3
- *
4
- * Captures the run-start git ref and runs all plugin reviewers once after
5
- * all stories complete, using the full diff from run-start to HEAD.
6
- */
7
-
8
- import { spawn } from "bun";
9
- import type { PluginRegistry } from "../plugins";
10
- import type { ReviewConfig } from "../review/types";
11
-
12
- /** Injectable deps for testing */
13
- export const _deferredReviewDeps = { spawn };
14
-
15
- export interface DeferredReviewResult {
16
- runStartRef: string;
17
- changedFiles: string[];
18
- reviewerResults: Array<{
19
- name: string;
20
- passed: boolean;
21
- output: string;
22
- exitCode?: number;
23
- error?: string;
24
- }>;
25
- anyFailed: boolean;
26
- }
27
-
28
- /** Capture the current HEAD git ref. Returns "" on failure. */
29
- export async function captureRunStartRef(workdir: string): Promise<string> {
30
- try {
31
- const proc = _deferredReviewDeps.spawn({
32
- cmd: ["git", "rev-parse", "HEAD"],
33
- cwd: workdir,
34
- stdout: "pipe",
35
- stderr: "pipe",
36
- });
37
- const [, stdout] = await Promise.all([proc.exited, new Response(proc.stdout).text()]);
38
- return stdout.trim();
39
- } catch {
40
- return "";
41
- }
42
- }
43
-
44
- async function getChangedFilesForDeferred(workdir: string, baseRef: string): Promise<string[]> {
45
- try {
46
- const proc = _deferredReviewDeps.spawn({
47
- cmd: ["git", "diff", "--name-only", `${baseRef}...HEAD`],
48
- cwd: workdir,
49
- stdout: "pipe",
50
- stderr: "pipe",
51
- });
52
- const [, stdout] = await Promise.all([proc.exited, new Response(proc.stdout).text()]);
53
- return stdout.trim().split("\n").filter(Boolean);
54
- } catch {
55
- return [];
56
- }
57
- }
58
-
59
- /** Run all plugin reviewers once with the full diff since runStartRef. */
60
- export async function runDeferredReview(
61
- workdir: string,
62
- reviewConfig: ReviewConfig,
63
- plugins: PluginRegistry,
64
- runStartRef: string,
65
- ): Promise<DeferredReviewResult | undefined> {
66
- if (!reviewConfig || reviewConfig.pluginMode !== "deferred") {
67
- return undefined;
68
- }
69
-
70
- const reviewers = plugins.getReviewers();
71
- if (reviewers.length === 0) {
72
- return undefined;
73
- }
74
-
75
- const changedFiles = await getChangedFilesForDeferred(workdir, runStartRef);
76
-
77
- const reviewerResults: DeferredReviewResult["reviewerResults"] = [];
78
- let anyFailed = false;
79
-
80
- for (const reviewer of reviewers) {
81
- try {
82
- const result = await reviewer.check(workdir, changedFiles);
83
- reviewerResults.push({
84
- name: reviewer.name,
85
- passed: result.passed,
86
- output: result.output,
87
- exitCode: result.exitCode,
88
- });
89
- if (!result.passed) {
90
- anyFailed = true;
91
- }
92
- } catch (error) {
93
- const errorMsg = error instanceof Error ? error.message : String(error);
94
- reviewerResults.push({
95
- name: reviewer.name,
96
- passed: false,
97
- output: "",
98
- error: errorMsg,
99
- });
100
- anyFailed = true;
101
- }
102
- }
103
-
104
- return { runStartRef, changedFiles, reviewerResults, anyFailed };
105
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * Dry Run Handler (ADR-005, Phase 4)
3
- *
4
- * Extracted from pipeline-result-handler.ts to slim that file below 200 lines.
5
- */
6
-
7
- import { getSafeLogger } from "../logger";
8
- import { pipelineEventBus } from "../pipeline/event-bus";
9
- import type { PluginRegistry } from "../plugins";
10
- import { markStoryPassed, savePRD } from "../prd";
11
- import type { PRD, UserStory } from "../prd/types";
12
- import type { routeTask } from "../routing";
13
- import type { StatusWriter } from "./status-writer";
14
-
15
- export interface DryRunContext {
16
- prd: PRD;
17
- prdPath: string;
18
- storiesToExecute: UserStory[];
19
- routing: ReturnType<typeof routeTask>;
20
- statusWriter: StatusWriter;
21
- pluginRegistry: PluginRegistry;
22
- runId: string;
23
- totalCost: number;
24
- iterations: number;
25
- }
26
-
27
- export interface DryRunResult {
28
- storiesCompletedDelta: number;
29
- prdDirty: boolean;
30
- }
31
-
32
- /** Handle dry-run iteration: log what would happen, mark stories passed. */
33
- export async function handleDryRun(ctx: DryRunContext): Promise<DryRunResult> {
34
- const logger = getSafeLogger();
35
-
36
- ctx.statusWriter.setPrd(ctx.prd);
37
- ctx.statusWriter.setCurrentStory({
38
- storyId: ctx.storiesToExecute[0].id,
39
- title: ctx.storiesToExecute[0].title,
40
- complexity: ctx.routing.complexity,
41
- tddStrategy: ctx.routing.testStrategy,
42
- model: ctx.routing.modelTier,
43
- attempt: (ctx.storiesToExecute[0].attempts ?? 0) + 1,
44
- phase: "routing",
45
- });
46
- await ctx.statusWriter.update(ctx.totalCost, ctx.iterations);
47
-
48
- for (const s of ctx.storiesToExecute) {
49
- logger?.info("execution", "[DRY RUN] Would execute agent here", {
50
- storyId: s.id,
51
- storyTitle: s.title,
52
- modelTier: ctx.routing.modelTier,
53
- complexity: ctx.routing.complexity,
54
- testStrategy: ctx.routing.testStrategy,
55
- });
56
- }
57
-
58
- for (const s of ctx.storiesToExecute) {
59
- markStoryPassed(ctx.prd, s.id);
60
- }
61
- await savePRD(ctx.prd, ctx.prdPath);
62
-
63
- for (const s of ctx.storiesToExecute) {
64
- pipelineEventBus.emit({
65
- type: "story:completed",
66
- storyId: s.id,
67
- story: s,
68
- passed: true,
69
- runElapsedMs: 0,
70
- cost: 0,
71
- modelTier: ctx.routing.modelTier,
72
- testStrategy: ctx.routing.testStrategy,
73
- });
74
- }
75
-
76
- ctx.statusWriter.setPrd(ctx.prd);
77
- ctx.statusWriter.setCurrentStory(null);
78
- await ctx.statusWriter.update(ctx.totalCost, ctx.iterations);
79
-
80
- return { storiesCompletedDelta: ctx.storiesToExecute.length, prdDirty: true };
81
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * Model Tier Escalation (ADR-003)
3
- *
4
- * Handles escalating model tiers through configurable tier chain
5
- * with per-tier attempt budgets.
6
- */
7
-
8
- import type { TierConfig } from "../../config";
9
-
10
- /**
11
- * Escalate to the next tier in the configured order.
12
- *
13
- * @param currentTier - Current tier name
14
- * @param tierOrder - Ordered tier config array from config (e.g., [{tier:"fast",attempts:5}, ...])
15
- * @returns Next tier name, or null if at max tier
16
- *
17
- * @example
18
- * ```typescript
19
- * const tiers = [{tier:"fast",attempts:5}, {tier:"balanced",attempts:3}, {tier:"powerful",attempts:2}];
20
- * escalateTier("fast", tiers); // => "balanced"
21
- * escalateTier("powerful", tiers); // => null
22
- * ```
23
- */
24
- export function escalateTier(currentTier: string, tierOrder: TierConfig[]): string | null {
25
- const getName = (t: TierConfig) => t.tier ?? (t as unknown as { name?: string }).name ?? null;
26
- const currentIndex = tierOrder.findIndex((t) => getName(t) === currentTier);
27
- if (currentIndex === -1 || currentIndex === tierOrder.length - 1) {
28
- return null;
29
- }
30
- return getName(tierOrder[currentIndex + 1]);
31
- }
32
-
33
- /**
34
- * Get the tier config for a given tier name.
35
- */
36
- export function getTierConfig(tierName: string, tierOrder: TierConfig[]): TierConfig | undefined {
37
- const getName = (t: TierConfig) => t.tier ?? (t as unknown as { name?: string }).name ?? null;
38
- return tierOrder.find((t) => getName(t) === tierName);
39
- }
40
-
41
- /**
42
- * Calculate total max iterations from tier order (sum of all attempts).
43
- */
44
- export function calculateMaxIterations(tierOrder: TierConfig[]): number {
45
- return tierOrder.reduce((sum, t) => sum + t.attempts, 0);
46
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Escalation module exports
3
- */
4
-
5
- export { escalateTier, getTierConfig, calculateMaxIterations } from "./escalation";
6
- export {
7
- resolveMaxAttemptsOutcome,
8
- preIterationTierCheck,
9
- handleTierEscalation,
10
- type PreIterationCheckResult,
11
- type EscalationHandlerContext,
12
- type EscalationHandlerResult,
13
- } from "./tier-escalation";
@@ -1,346 +0,0 @@
1
- /**
2
- * Tier Escalation Logic
3
- *
4
- * Handles model tier escalation when stories fail:
5
- * - Pre-iteration tier budget checks
6
- * - Tier escalation with attempt counter reset
7
- * - Max attempts outcome resolution (pause vs fail)
8
- */
9
-
10
- import type { NaxConfig } from "../../config";
11
- import { type LoadedHooksConfig, fireHook } from "../../hooks";
12
- import { getSafeLogger } from "../../logger";
13
- import type { PRD, StructuredFailure, UserStory } from "../../prd";
14
- import { markStoryFailed, savePRD } from "../../prd";
15
- import { tryLlmBatchRoute } from "../../routing/batch-route";
16
- import { clearCacheForStory } from "../../routing/strategies/llm";
17
- import type { FailureCategory } from "../../tdd/types";
18
- import { calculateMaxIterations, escalateTier, getTierConfig } from "../escalation";
19
- import { hookCtx } from "../helpers";
20
- import { appendProgress } from "../progress";
21
- import { handleMaxAttemptsReached, handleNoTierAvailable } from "./tier-outcome";
22
-
23
- /** Build a StructuredFailure for tier escalation. */
24
- function buildEscalationFailure(
25
- story: UserStory,
26
- currentTier: string,
27
- reviewFindings?: import("../../plugins/types").ReviewFinding[],
28
- cost?: number,
29
- ): StructuredFailure {
30
- return {
31
- attempt: (story.attempts ?? 0) + 1,
32
- modelTier: currentTier,
33
- stage: "escalation" as const,
34
- summary: `Failed with tier ${currentTier}, escalating to next tier`,
35
- reviewFindings: reviewFindings && reviewFindings.length > 0 ? reviewFindings : undefined,
36
- cost: cost ?? 0,
37
- timestamp: new Date().toISOString(),
38
- };
39
- }
40
-
41
- /**
42
- * Determine the outcome when max attempts are reached for an escalation.
43
- *
44
- * Returns 'pause' if the failure category requires human review
45
- * (isolation-violation or verifier-rejected). For all other categories
46
- * (session-failure, tests-failing, or no category) returns 'fail'.
47
- *
48
- * Exported for unit-testing without running the full runner loop.
49
- */
50
- export function resolveMaxAttemptsOutcome(failureCategory?: FailureCategory): "pause" | "fail" {
51
- if (!failureCategory) {
52
- return "fail";
53
- }
54
-
55
- switch (failureCategory) {
56
- case "isolation-violation":
57
- case "verifier-rejected":
58
- case "greenfield-no-tests":
59
- return "pause";
60
- case "runtime-crash":
61
- return "pause";
62
- case "session-failure":
63
- case "tests-failing":
64
- return "fail";
65
- default:
66
- // Exhaustive check: if a new FailureCategory is added, this will error
67
- failureCategory satisfies never;
68
- return "fail";
69
- }
70
- }
71
-
72
- export interface PreIterationCheckResult {
73
- shouldSkipIteration: boolean;
74
- prdDirty: boolean;
75
- prd: PRD;
76
- }
77
-
78
- /**
79
- * Pre-iteration tier escalation check (BUG-16 + BUG-17 fix)
80
- *
81
- * Check if story has exceeded current tier's attempt budget BEFORE spawning agent.
82
- * If exceeded, escalate to next tier or mark as failed.
83
- */
84
- export async function preIterationTierCheck(
85
- story: UserStory,
86
- routing: { modelTier: string },
87
- config: NaxConfig,
88
- prd: PRD,
89
- prdPath: string,
90
- featureDir: string | undefined,
91
- hooks: LoadedHooksConfig,
92
- feature: string,
93
- totalCost: number,
94
- workdir: string,
95
- ): Promise<PreIterationCheckResult> {
96
- const logger = getSafeLogger();
97
- const currentTier = story.routing?.modelTier ?? routing.modelTier;
98
- const tierOrder = config.autoMode.escalation?.tierOrder || [];
99
- const tierCfg = tierOrder.length > 0 ? getTierConfig(currentTier, tierOrder) : undefined;
100
-
101
- if (!tierCfg || (story.attempts ?? 0) < tierCfg.attempts) {
102
- // Story still has budget in current tier
103
- return { shouldSkipIteration: false, prdDirty: false, prd };
104
- }
105
-
106
- // Exceeded current tier budget — try to escalate
107
- const nextTier = escalateTier(currentTier, tierOrder);
108
- const routingMode = config.routing.llm?.mode ?? "hybrid";
109
-
110
- if (nextTier && config.autoMode.escalation.enabled) {
111
- logger?.warn("escalation", "Story exceeded tier budget, escalating", {
112
- storyId: story.id,
113
- attempts: story.attempts,
114
- tierAttempts: tierCfg.attempts,
115
- currentTier,
116
- nextTier,
117
- });
118
-
119
- // Update story routing in PRD and reset attempts for new tier
120
- const updatedPrd = {
121
- ...prd,
122
- userStories: prd.userStories.map((s) =>
123
- s.id === story.id
124
- ? {
125
- ...s,
126
- attempts: 0, // Reset attempts for new tier
127
- routing: s.routing ? { ...s.routing, modelTier: nextTier } : { ...routing, modelTier: nextTier },
128
- }
129
- : s,
130
- ) as PRD["userStories"],
131
- } as PRD;
132
- await savePRD(updatedPrd, prdPath);
133
-
134
- // Clear routing cache for story to avoid returning old cached decision
135
- clearCacheForStory(story.id);
136
-
137
- // Hybrid mode: re-route story after escalation
138
- if (routingMode === "hybrid") {
139
- await tryLlmBatchRoute(config, [story], "hybrid-re-route");
140
- }
141
-
142
- // Skip to next iteration (will reload PRD and use new tier)
143
- return { shouldSkipIteration: true, prdDirty: true, prd: updatedPrd };
144
- }
145
-
146
- // No next tier or escalation disabled — mark story as failed
147
- logger?.error("execution", "Story failed - all tiers exhausted", {
148
- storyId: story.id,
149
- attempts: story.attempts,
150
- });
151
-
152
- const failedPrd = { ...prd };
153
- markStoryFailed(failedPrd, story.id, undefined, undefined);
154
- await savePRD(failedPrd, prdPath);
155
-
156
- if (featureDir) {
157
- await appendProgress(featureDir, story.id, "failed", `${story.title} — All tiers exhausted`);
158
- }
159
-
160
- await fireHook(
161
- hooks,
162
- "on-story-fail",
163
- hookCtx(feature, {
164
- storyId: story.id,
165
- status: "failed",
166
- reason: `All tiers exhausted (${story.attempts} attempts)`,
167
- cost: totalCost,
168
- }),
169
- workdir,
170
- );
171
-
172
- // Skip to next iteration (will pick next story)
173
- return { shouldSkipIteration: true, prdDirty: true, prd: failedPrd };
174
- }
175
-
176
- export interface EscalationHandlerContext {
177
- story: UserStory;
178
- storiesToExecute: UserStory[];
179
- isBatchExecution: boolean;
180
- routing: { modelTier: string; testStrategy: string };
181
- pipelineResult: {
182
- reason?: string;
183
- context: {
184
- retryAsLite?: boolean;
185
- tddFailureCategory?: FailureCategory;
186
- reviewFindings?: import("../../plugins/types").ReviewFinding[];
187
- };
188
- };
189
- config: NaxConfig;
190
- prd: PRD;
191
- prdPath: string;
192
- featureDir?: string;
193
- hooks: LoadedHooksConfig;
194
- feature: string;
195
- totalCost: number;
196
- workdir: string;
197
- /** Verify result from the pipeline verify stage — used to detect RUNTIME_CRASH (BUG-070) */
198
- verifyResult?: { status: string; success: boolean };
199
- /** Cost of the failed attempt being escalated (BUG-067: accumulated across escalations) */
200
- attemptCost?: number;
201
- }
202
-
203
- export interface EscalationHandlerResult {
204
- outcome: "escalated" | "paused" | "failed" | "retry-same";
205
- prdDirty: boolean;
206
- prd: PRD;
207
- }
208
-
209
- /**
210
- * Determine if the pipeline should retry the same tier due to a transient runtime crash.
211
- *
212
- * Returns true when the verify result status is RUNTIME_CRASH — these are Bun
213
- * runtime-level failures, not code quality issues, so escalating the model tier
214
- * would not help. Instead the same tier should be retried.
215
- *
216
- * @param verifyResult - Verify result from the pipeline verify stage
217
- */
218
- export function shouldRetrySameTier(verifyResult: { status: string; success: boolean } | undefined): boolean {
219
- return verifyResult?.status === "RUNTIME_CRASH";
220
- }
221
-
222
- /**
223
- * Swappable dependencies for testing (avoids mock.module() which leaks in Bun 1.x).
224
- */
225
- export const _tierEscalationDeps = {
226
- savePRD,
227
- };
228
-
229
- /**
230
- * Handle tier escalation after pipeline escalation action
231
- *
232
- * Escalates to next tier or marks story as paused/failed based on failure category.
233
- */
234
- export async function handleTierEscalation(ctx: EscalationHandlerContext): Promise<EscalationHandlerResult> {
235
- const logger = getSafeLogger();
236
-
237
- // BUG-070: Runtime crashes are transient — retry same tier, do NOT escalate
238
- if (shouldRetrySameTier(ctx.verifyResult)) {
239
- logger?.warn("escalation", "Runtime crash detected — retrying same tier (transient, not a code issue)", {
240
- storyId: ctx.story.id,
241
- });
242
- return { outcome: "retry-same", prdDirty: false, prd: ctx.prd };
243
- }
244
-
245
- const nextTier = escalateTier(ctx.routing.modelTier, ctx.config.autoMode.escalation.tierOrder);
246
- const escalateWholeBatch = ctx.config.autoMode.escalation.escalateEntireBatch ?? true;
247
- const storiesToEscalate = ctx.isBatchExecution && escalateWholeBatch ? ctx.storiesToExecute : [ctx.story];
248
-
249
- // Retrieve TDD-specific context flags set by executionStage
250
- const escalateRetryAsLite = ctx.pipelineResult.context.retryAsLite === true;
251
- const escalateFailureCategory = ctx.pipelineResult.context.tddFailureCategory;
252
- const escalateReviewFindings = ctx.pipelineResult.context.reviewFindings;
253
- // S5: Auto-switch to test-after on greenfield-no-tests
254
- const escalateRetryAsTestAfter = escalateFailureCategory === "greenfield-no-tests";
255
- const routingMode = ctx.config.routing.llm?.mode ?? "hybrid";
256
-
257
- if (!nextTier || !ctx.config.autoMode.escalation.enabled) {
258
- // No next tier or escalation disabled — pause or fail based on failure category
259
- return await handleNoTierAvailable(ctx, escalateFailureCategory);
260
- }
261
-
262
- const maxAttempts = calculateMaxIterations(ctx.config.autoMode.escalation.tierOrder);
263
- const canEscalate = storiesToEscalate.every((s) => (s.attempts ?? 0) < maxAttempts);
264
-
265
- if (!canEscalate) {
266
- // Max attempts reached — pause or fail based on failure category
267
- return await handleMaxAttemptsReached(ctx, escalateFailureCategory);
268
- }
269
-
270
- // Can escalate — log and update stories
271
- for (const s of storiesToEscalate) {
272
- const currentTestStrategy = s.routing?.testStrategy ?? ctx.routing.testStrategy;
273
- const shouldSwitchToTestAfter = escalateRetryAsTestAfter && currentTestStrategy !== "test-after";
274
-
275
- if (shouldSwitchToTestAfter) {
276
- logger?.warn("escalation", "Switching strategy to test-after (greenfield-no-tests fallback)", {
277
- storyId: s.id,
278
- fromStrategy: currentTestStrategy,
279
- toStrategy: "test-after",
280
- });
281
- } else {
282
- logger?.warn("escalation", "Escalating story to next tier", {
283
- storyId: s.id,
284
- nextTier,
285
- retryAsLite: escalateRetryAsLite,
286
- });
287
- }
288
- }
289
-
290
- const pipelineReason = ctx.pipelineResult.reason ? `: ${ctx.pipelineResult.reason}` : "";
291
- const errorMessage = `Attempt ${ctx.story.attempts + 1} failed with model tier: ${ctx.routing.modelTier}${ctx.isBatchExecution ? " (in batch)" : ""}${pipelineReason}`;
292
-
293
- const updatedPrd = {
294
- ...ctx.prd,
295
- userStories: ctx.prd.userStories.map((s) => {
296
- const shouldEscalate = storiesToEscalate.some((story) => story.id === s.id);
297
- if (!shouldEscalate) return s;
298
-
299
- // S5: Check if this is a one-time test-after switch
300
- const currentTestStrategy = s.routing?.testStrategy ?? ctx.routing.testStrategy;
301
- const shouldSwitchToTestAfter = escalateRetryAsTestAfter && currentTestStrategy !== "test-after";
302
-
303
- const baseRouting = s.routing ?? { ...ctx.routing };
304
- const updatedRouting = {
305
- ...baseRouting,
306
- modelTier: shouldSwitchToTestAfter ? baseRouting.modelTier : nextTier,
307
- ...(escalateRetryAsLite ? { testStrategy: "three-session-tdd-lite" as const } : {}),
308
- ...(shouldSwitchToTestAfter ? { testStrategy: "test-after" as const } : {}),
309
- };
310
-
311
- // BUG-011: Reset attempt counter on tier escalation
312
- const currentStoryTier = s.routing?.modelTier ?? ctx.routing.modelTier;
313
- const isChangingTier = currentStoryTier !== nextTier;
314
- const shouldResetAttempts = isChangingTier || shouldSwitchToTestAfter;
315
-
316
- // Build escalation failure (BUG-067: include cost for accumulatedAttemptCost in metrics)
317
- const escalationFailure = buildEscalationFailure(s, currentStoryTier, escalateReviewFindings, ctx.attemptCost);
318
-
319
- return {
320
- ...s,
321
- attempts: shouldResetAttempts ? 0 : (s.attempts ?? 0) + 1,
322
- routing: updatedRouting,
323
- priorErrors: [...(s.priorErrors || []), errorMessage],
324
- priorFailures: [...(s.priorFailures || []), escalationFailure],
325
- } as UserStory;
326
- }) as PRD["userStories"],
327
- } as PRD;
328
-
329
- await _tierEscalationDeps.savePRD(updatedPrd, ctx.prdPath);
330
-
331
- // Clear routing cache for all escalated stories to avoid returning old cached decisions
332
- for (const story of storiesToEscalate) {
333
- clearCacheForStory(story.id);
334
- }
335
-
336
- // Hybrid mode: re-route escalated stories
337
- if (routingMode === "hybrid") {
338
- await tryLlmBatchRoute(ctx.config, storiesToEscalate, "hybrid-re-route-pipeline");
339
- }
340
-
341
- return {
342
- outcome: "escalated",
343
- prdDirty: true,
344
- prd: updatedPrd,
345
- };
346
- }