@nathapp/nax 0.50.2 → 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 +579 -373
  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 -423
  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 -135
  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 -218
  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 -217
  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 -520
  100. package/src/config/schema-types.ts +0 -53
  101. package/src/config/schema.ts +0 -60
  102. package/src/config/schemas.ts +0 -425
  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 -280
  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 -140
  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,140 +0,0 @@
1
- /**
2
- * Acceptance Setup Stage
3
- *
4
- * Pre-run pipeline stage that generates acceptance tests from PRD criteria
5
- * and validates them with a RED gate before story execution begins.
6
- *
7
- * RED gate behavior:
8
- * - exit != 0 (tests fail) → valid RED, continue
9
- * - exit == 0 (all tests pass) → tests are not testing new behavior, warn and skip
10
- *
11
- * Stores results in ctx.acceptanceSetup = { totalCriteria, testableCount, redFailCount }.
12
- */
13
-
14
- import path from "node:path";
15
- import type { RefinedCriterion } from "../../acceptance/types";
16
- import { resolveModel } from "../../config";
17
- import type { UserStory } from "../../prd/types";
18
- import type { PipelineContext, PipelineStage, StageResult } from "../types";
19
-
20
- /**
21
- * Injectable dependencies for acceptance-setup stage.
22
- * Allows tests to mock bun test execution, file I/O, and LLM calls.
23
- * @internal
24
- */
25
- export const _acceptanceSetupDeps = {
26
- fileExists: async (_path: string): Promise<boolean> => {
27
- const f = Bun.file(_path);
28
- return f.exists();
29
- },
30
- writeFile: async (filePath: string, content: string): Promise<void> => {
31
- await Bun.write(filePath, content);
32
- },
33
- runTest: async (_testPath: string, _workdir: string): Promise<{ exitCode: number; output: string }> => {
34
- const proc = Bun.spawn(["bun", "test", _testPath], {
35
- cwd: _workdir,
36
- stdout: "pipe",
37
- stderr: "pipe",
38
- });
39
- const [exitCode, stdout, stderr] = await Promise.all([
40
- proc.exited,
41
- new Response(proc.stdout).text(),
42
- new Response(proc.stderr).text(),
43
- ]);
44
- return { exitCode, output: `${stdout}\n${stderr}` };
45
- },
46
- refine: async (
47
- _criteria: string[],
48
- _context: import("../../acceptance/types").RefinementContext,
49
- ): Promise<RefinedCriterion[]> => {
50
- const { refineAcceptanceCriteria } = await import("../../acceptance/refinement");
51
- return refineAcceptanceCriteria(_criteria, _context);
52
- },
53
- generate: async (
54
- _stories: UserStory[],
55
- _refined: RefinedCriterion[],
56
- _options: import("../../acceptance/types").GenerateFromPRDOptions,
57
- ): Promise<import("../../acceptance/types").AcceptanceTestResult> => {
58
- const { generateFromPRD } = await import("../../acceptance/generator");
59
- return generateFromPRD(_stories, _refined, _options);
60
- },
61
- };
62
-
63
- export const acceptanceSetupStage: PipelineStage = {
64
- name: "acceptance-setup",
65
-
66
- enabled(ctx: PipelineContext): boolean {
67
- return ctx.config.acceptance.enabled && !!ctx.featureDir;
68
- },
69
-
70
- async execute(ctx: PipelineContext): Promise<StageResult> {
71
- if (!ctx.featureDir) {
72
- return { action: "fail", reason: "[acceptance-setup] featureDir is not set" };
73
- }
74
-
75
- const testPath = path.join(ctx.featureDir, "acceptance.test.ts");
76
- const fileExists = await _acceptanceSetupDeps.fileExists(testPath);
77
-
78
- let totalCriteria = 0;
79
- let testableCount = 0;
80
-
81
- if (!fileExists) {
82
- const allCriteria: string[] = ctx.prd.userStories.flatMap((s) => s.acceptanceCriteria);
83
- totalCriteria = allCriteria.length;
84
-
85
- let refinedCriteria: RefinedCriterion[];
86
-
87
- if (ctx.config.acceptance.refinement) {
88
- refinedCriteria = await _acceptanceSetupDeps.refine(allCriteria, {
89
- storyId: ctx.prd.userStories[0]?.id ?? "US-001",
90
- codebaseContext: "",
91
- config: ctx.config,
92
- testStrategy: ctx.config.acceptance.testStrategy,
93
- testFramework: ctx.config.acceptance.testFramework,
94
- });
95
- } else {
96
- refinedCriteria = allCriteria.map((c) => ({
97
- original: c,
98
- refined: c,
99
- testable: true,
100
- storyId: ctx.prd.userStories[0]?.id ?? "US-001",
101
- }));
102
- }
103
-
104
- testableCount = refinedCriteria.filter((r) => r.testable).length;
105
-
106
- const result = await _acceptanceSetupDeps.generate(ctx.prd.userStories, refinedCriteria, {
107
- featureName: ctx.prd.feature,
108
- workdir: ctx.workdir,
109
- featureDir: ctx.featureDir,
110
- codebaseContext: "",
111
- modelTier: ctx.config.acceptance.model ?? "fast",
112
- modelDef: resolveModel(ctx.config.models[ctx.config.acceptance.model ?? "fast"]),
113
- config: ctx.config,
114
- testStrategy: ctx.config.acceptance.testStrategy,
115
- testFramework: ctx.config.acceptance.testFramework,
116
- });
117
-
118
- await _acceptanceSetupDeps.writeFile(testPath, result.testCode);
119
- }
120
-
121
- if (ctx.config.acceptance.redGate === false) {
122
- ctx.acceptanceSetup = { totalCriteria, testableCount, redFailCount: 0 };
123
- return { action: "continue" };
124
- }
125
-
126
- const { exitCode } = await _acceptanceSetupDeps.runTest(testPath, ctx.workdir);
127
-
128
- if (exitCode === 0) {
129
- ctx.acceptanceSetup = { totalCriteria, testableCount, redFailCount: 0 };
130
- return {
131
- action: "skip",
132
- reason:
133
- "[acceptance-setup] Acceptance tests already pass — they are not testing new behavior. Skipping acceptance gate.",
134
- };
135
- }
136
-
137
- ctx.acceptanceSetup = { totalCriteria, testableCount, redFailCount: 1 };
138
- return { action: "continue" };
139
- },
140
- };
@@ -1,215 +0,0 @@
1
- /**
2
- * Acceptance Stage
3
- *
4
- * Runs acceptance tests when all stories are complete.
5
- * Validates the feature against acceptance criteria from spec.md.
6
- *
7
- * Only executes when:
8
- * - All stories in the PRD are complete (status: passed/failed/skipped, not pending/in-progress)
9
- * - Acceptance validation is enabled in config
10
- *
11
- * @returns
12
- * - `continue`: All acceptance tests pass
13
- * - `fail`: One or more acceptance tests failed
14
- *
15
- * @example
16
- * ```ts
17
- * // All stories complete, acceptance tests pass
18
- * await acceptanceStage.execute(ctx);
19
- * // Returns: { action: "continue" }
20
- *
21
- * // All stories complete, acceptance tests fail
22
- * await acceptanceStage.execute(ctx);
23
- * // Returns: { action: "fail", reason: "Acceptance tests failed: AC-2, AC-5" }
24
- * ```
25
- */
26
-
27
- import path from "node:path";
28
- import { getLogger } from "../../logger";
29
- import { countStories } from "../../prd";
30
- import { logTestOutput } from "../../utils/log-test-output";
31
- import type { PipelineContext, PipelineStage, StageResult } from "../types";
32
-
33
- /**
34
- * Parse bun test output to extract failed test names.
35
- *
36
- * Looks for lines containing "AC-N:" to identify which acceptance criteria failed.
37
- *
38
- * @param output - stdout/stderr from bun test
39
- * @returns Array of failed AC IDs (e.g., ["AC-2", "AC-5"])
40
- *
41
- * @example
42
- * ```ts
43
- * const output = `
44
- * ✓ AC-1: TTL expiry
45
- * ✗ AC-2: handles empty input
46
- * ✓ AC-3: validates format
47
- * `;
48
- * const failed = parseTestFailures(output);
49
- * // Returns: ["AC-2"]
50
- * ```
51
- */
52
- function parseTestFailures(output: string): string[] {
53
- const failedACs: string[] = [];
54
- const lines = output.split("\n");
55
-
56
- for (const line of lines) {
57
- // Look for Bun's (fail) marker followed by AC-N pattern
58
- // Pattern: (fail) ... > AC-N: description
59
- if (line.includes("(fail)")) {
60
- const acMatch = line.match(/(AC-\d+):/i);
61
- if (acMatch) {
62
- const acId = acMatch[1].toUpperCase();
63
- if (!failedACs.includes(acId)) {
64
- failedACs.push(acId);
65
- }
66
- }
67
- }
68
- }
69
-
70
- return failedACs;
71
- }
72
-
73
- /**
74
- * Check if all stories in the PRD are complete.
75
- *
76
- * Stories are complete if their status is passed, failed, or skipped.
77
- * Pending or in-progress stories are not complete.
78
- *
79
- * @param ctx - Pipeline context
80
- * @returns true if all stories complete, false otherwise
81
- */
82
- function areAllStoriesComplete(ctx: PipelineContext): boolean {
83
- const counts = countStories(ctx.prd);
84
- const totalComplete = counts.passed + counts.failed + counts.skipped;
85
- return totalComplete === counts.total;
86
- }
87
-
88
- export const acceptanceStage: PipelineStage = {
89
- name: "acceptance",
90
-
91
- enabled(ctx: PipelineContext): boolean {
92
- // Only run when:
93
- // 1. Acceptance validation is enabled
94
- // 2. All stories are complete
95
- const effectiveConfig = ctx.effectiveConfig ?? ctx.config;
96
- if (!effectiveConfig.acceptance.enabled) {
97
- return false;
98
- }
99
-
100
- if (!areAllStoriesComplete(ctx)) {
101
- return false;
102
- }
103
-
104
- return true;
105
- },
106
-
107
- async execute(ctx: PipelineContext): Promise<StageResult> {
108
- const logger = getLogger();
109
-
110
- // PKG-004: use centrally resolved effective config
111
- const effectiveConfig = ctx.effectiveConfig ?? ctx.config;
112
-
113
- logger.info("acceptance", "Running acceptance tests");
114
-
115
- // Build path to acceptance test file
116
- if (!ctx.featureDir) {
117
- logger.warn("acceptance", "No feature directory — skipping acceptance tests");
118
- return { action: "continue" };
119
- }
120
-
121
- const testPath = path.join(ctx.featureDir, effectiveConfig.acceptance.testPath);
122
-
123
- // Check if test file exists
124
- const testFile = Bun.file(testPath);
125
- const exists = await testFile.exists();
126
-
127
- if (!exists) {
128
- logger.warn("acceptance", "Acceptance test file not found — skipping", {
129
- testPath,
130
- });
131
- return { action: "continue" };
132
- }
133
-
134
- // Run bun test on the acceptance test file
135
- const proc = Bun.spawn(["bun", "test", testPath], {
136
- cwd: ctx.workdir,
137
- stdout: "pipe",
138
- stderr: "pipe",
139
- });
140
-
141
- const [exitCode, stdout, stderr] = await Promise.all([
142
- proc.exited,
143
- new Response(proc.stdout).text(),
144
- new Response(proc.stderr).text(),
145
- ]);
146
-
147
- // Combine stdout and stderr for parsing
148
- const output = `${stdout}\n${stderr}`;
149
-
150
- // Parse test results
151
- const failedACs = parseTestFailures(output);
152
-
153
- // Check for overridden ACs (skip those)
154
- const overrides = ctx.prd.acceptanceOverrides || {};
155
- const actualFailures = failedACs.filter((acId) => !overrides[acId]);
156
-
157
- // If all tests passed cleanly
158
- if (actualFailures.length === 0 && exitCode === 0) {
159
- logger.info("acceptance", "All acceptance tests passed");
160
- return { action: "continue" };
161
- }
162
-
163
- // All parsed AC failures are overridden — treat as success even with non-zero exit
164
- if (failedACs.length > 0 && actualFailures.length === 0) {
165
- logger.info("acceptance", "All failed ACs are overridden — treating as pass");
166
- return { action: "continue" };
167
- }
168
-
169
- // Non-zero exit but no AC failures parsed at all — test crashed (syntax error, import failure, etc.)
170
- if (failedACs.length === 0 && exitCode !== 0) {
171
- logger.error("acceptance", "Tests errored with no AC failures parsed", { exitCode });
172
- logTestOutput(logger, "acceptance", output);
173
-
174
- ctx.acceptanceFailures = {
175
- failedACs: ["AC-ERROR"],
176
- testOutput: output,
177
- };
178
-
179
- return {
180
- action: "fail",
181
- reason: `Acceptance tests errored (exit code ${exitCode}): syntax error, import failure, or unhandled exception`,
182
- };
183
- }
184
-
185
- // If we have actual failures, report them
186
- if (actualFailures.length > 0) {
187
- // Log overridden failures (if any)
188
- const overriddenFailures = failedACs.filter((acId) => overrides[acId]);
189
- if (overriddenFailures.length > 0) {
190
- logger.warn("acceptance", "Skipped failures (overridden)", {
191
- overriddenFailures,
192
- overrides: overriddenFailures.map((acId) => ({ acId, reason: overrides[acId] })),
193
- });
194
- }
195
-
196
- logger.error("acceptance", "Acceptance tests failed", { failedACs: actualFailures });
197
- logTestOutput(logger, "acceptance", output);
198
-
199
- // Store failed ACs and test output in context for fix generation
200
- ctx.acceptanceFailures = {
201
- failedACs: actualFailures,
202
- testOutput: output,
203
- };
204
-
205
- return {
206
- action: "fail",
207
- reason: `Acceptance tests failed: ${actualFailures.join(", ")}`,
208
- };
209
- }
210
-
211
- // All tests passed
212
- logger.info("acceptance", "All acceptance tests passed");
213
- return { action: "continue" };
214
- },
215
- };
@@ -1,262 +0,0 @@
1
- // RE-ARCH: keep
2
- /**
3
- * Autofix Stage (ADR-005, Phase 2)
4
- *
5
- * Runs after a failed review stage. Attempts to fix quality issues
6
- * automatically before escalating:
7
- *
8
- * Phase 1 — Mechanical fix: runs lintFix / formatFix commands (if configured)
9
- * Phase 2 — Agent rectification: spawns an agent session with the review error
10
- * output as context (reuses the pattern from rectification-loop.ts)
11
- *
12
- * Language-agnostic: uses quality.commands.lintFix / formatFix from config.
13
- * No hardcoded tool names.
14
- *
15
- * Enabled only when ctx.reviewResult?.passed === false AND autofix is enabled.
16
- *
17
- * Returns:
18
- * - `retry` fromStage:"review" — autofix resolved the failures
19
- * - `escalate` — max attempts exhausted or agent unavailable
20
- */
21
-
22
- import { join } from "node:path";
23
- import { getAgent } from "../../agents";
24
- import { resolveModel } from "../../config";
25
- import { loadConfigForWorkdir } from "../../config/loader";
26
- import { resolvePermissions } from "../../config/permissions";
27
- import { getLogger } from "../../logger";
28
- import type { UserStory } from "../../prd";
29
- import type { ReviewCheckResult } from "../../review/types";
30
- import { pipelineEventBus } from "../event-bus";
31
- import type { PipelineContext, PipelineStage, StageResult } from "../types";
32
-
33
- export const autofixStage: PipelineStage = {
34
- name: "autofix",
35
-
36
- enabled(ctx: PipelineContext): boolean {
37
- if (!ctx.reviewResult) return false;
38
- if (ctx.reviewResult.success) return false;
39
- const autofixEnabled = (ctx.effectiveConfig ?? ctx.config).quality.autofix?.enabled ?? true;
40
- return autofixEnabled;
41
- },
42
-
43
- skipReason(ctx: PipelineContext): string {
44
- if (!ctx.reviewResult || ctx.reviewResult.success) return "not needed (review passed)";
45
- return "disabled (autofix not enabled in config)";
46
- },
47
-
48
- async execute(ctx: PipelineContext): Promise<StageResult> {
49
- const logger = getLogger();
50
- const { reviewResult } = ctx;
51
-
52
- if (!reviewResult || reviewResult.success) {
53
- return { action: "continue" };
54
- }
55
-
56
- // PKG-004: use centrally resolved effective config (ctx.effectiveConfig set once per story)
57
- const effectiveConfig = ctx.effectiveConfig ?? ctx.config;
58
- const lintFixCmd = effectiveConfig.quality.commands.lintFix;
59
- const formatFixCmd = effectiveConfig.quality.commands.formatFix;
60
-
61
- // Effective workdir for running commands (scoped to package if monorepo)
62
- const effectiveWorkdir = ctx.story.workdir ? join(ctx.workdir, ctx.story.workdir) : ctx.workdir;
63
-
64
- // Identify which checks failed
65
- const failedCheckNames = new Set((reviewResult.checks ?? []).filter((c) => !c.success).map((c) => c.check));
66
- const hasLintFailure = failedCheckNames.has("lint");
67
-
68
- logger.info("autofix", "Starting autofix", {
69
- storyId: ctx.story.id,
70
- failedChecks: [...failedCheckNames],
71
- workdir: effectiveWorkdir,
72
- });
73
-
74
- // Phase 1: Mechanical fix — only for lint failures (lintFix/formatFix cannot fix typecheck errors)
75
- if (hasLintFailure && (lintFixCmd || formatFixCmd)) {
76
- if (lintFixCmd) {
77
- pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: lintFixCmd });
78
- const lintResult = await _autofixDeps.runCommand(lintFixCmd, effectiveWorkdir);
79
- logger.debug("autofix", `lintFix exit=${lintResult.exitCode}`, { storyId: ctx.story.id, command: lintFixCmd });
80
- if (lintResult.exitCode !== 0) {
81
- logger.warn("autofix", "lintFix command failed — may not have fixed all issues", {
82
- storyId: ctx.story.id,
83
- exitCode: lintResult.exitCode,
84
- });
85
- }
86
- }
87
-
88
- if (formatFixCmd) {
89
- pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: formatFixCmd });
90
- const fmtResult = await _autofixDeps.runCommand(formatFixCmd, effectiveWorkdir);
91
- logger.debug("autofix", `formatFix exit=${fmtResult.exitCode}`, {
92
- storyId: ctx.story.id,
93
- command: formatFixCmd,
94
- });
95
- if (fmtResult.exitCode !== 0) {
96
- logger.warn("autofix", "formatFix command failed — may not have fixed all issues", {
97
- storyId: ctx.story.id,
98
- exitCode: fmtResult.exitCode,
99
- });
100
- }
101
- }
102
-
103
- const recheckPassed = await _autofixDeps.recheckReview(ctx);
104
- pipelineEventBus.emit({ type: "autofix:completed", storyId: ctx.story.id, fixed: recheckPassed });
105
-
106
- if (recheckPassed) {
107
- logger.info("autofix", "Mechanical autofix succeeded — retrying review", { storyId: ctx.story.id });
108
- return { action: "retry", fromStage: "review" };
109
- }
110
-
111
- logger.info("autofix", "Mechanical autofix did not resolve all failures — proceeding to agent rectification", {
112
- storyId: ctx.story.id,
113
- });
114
- }
115
-
116
- // Phase 2: Agent rectification — spawn agent with review error context
117
- const agentFixed = await _autofixDeps.runAgentRectification(ctx);
118
- if (agentFixed) {
119
- if (ctx.reviewResult) ctx.reviewResult = { ...ctx.reviewResult, success: true };
120
- logger.info("autofix", "Agent rectification succeeded — retrying review", { storyId: ctx.story.id });
121
- return { action: "retry", fromStage: "review" };
122
- }
123
-
124
- logger.warn("autofix", "Autofix exhausted — escalating", { storyId: ctx.story.id });
125
- return { action: "escalate", reason: "Autofix exhausted: review still failing after fix attempts" };
126
- },
127
- };
128
-
129
- // ---------------------------------------------------------------------------
130
- // Helpers
131
- // ---------------------------------------------------------------------------
132
-
133
- interface CommandResult {
134
- exitCode: number;
135
- output: string;
136
- }
137
-
138
- async function runCommand(cmd: string, cwd: string): Promise<CommandResult> {
139
- const parts = cmd.split(/\s+/);
140
- const proc = Bun.spawn(parts, { cwd, stdout: "pipe", stderr: "pipe" });
141
- const [exitCode, stdout, stderr] = await Promise.all([
142
- proc.exited,
143
- new Response(proc.stdout).text(),
144
- new Response(proc.stderr).text(),
145
- ]);
146
- return { exitCode, output: `${stdout}\n${stderr}` };
147
- }
148
-
149
- async function recheckReview(ctx: PipelineContext): Promise<boolean> {
150
- // Import reviewStage lazily to avoid circular deps
151
- const { reviewStage } = await import("./review");
152
- if (!reviewStage.enabled(ctx)) return true;
153
- // reviewStage.execute updates ctx.reviewResult in place.
154
- // We cannot use result.action here because review returns "continue" for BOTH
155
- // pass and built-in-check-failure (to hand off to autofix). Check success directly.
156
- await reviewStage.execute(ctx);
157
- return ctx.reviewResult?.success === true;
158
- }
159
-
160
- function collectFailedChecks(ctx: PipelineContext): ReviewCheckResult[] {
161
- return (ctx.reviewResult?.checks ?? []).filter((c) => !c.success);
162
- }
163
-
164
- export function buildReviewRectificationPrompt(failedChecks: ReviewCheckResult[], story: UserStory): string {
165
- const errors = failedChecks
166
- .map((c) => `## ${c.check} errors (exit code ${c.exitCode})\n\`\`\`\n${c.output}\n\`\`\``)
167
- .join("\n\n");
168
-
169
- // ENH-008: Scope constraint for monorepo stories — prevent out-of-package changes
170
- const scopeConstraint = story.workdir
171
- ? `\n\nIMPORTANT: Only modify files within \`${story.workdir}/\`. Do NOT touch files outside this directory.`
172
- : "";
173
-
174
- return `You are fixing lint/typecheck errors from a code review.
175
-
176
- Story: ${story.title} (${story.id})
177
-
178
- The following quality checks failed after implementation:
179
-
180
- ${errors}
181
-
182
- Fix ALL errors listed above. Do NOT change test files or test behavior.
183
- Do NOT add new features — only fix the quality check errors.
184
- Commit your fixes when done.${scopeConstraint}`;
185
- }
186
-
187
- async function runAgentRectification(ctx: PipelineContext): Promise<boolean> {
188
- const logger = getLogger();
189
- const effectiveConfig = ctx.effectiveConfig ?? ctx.config;
190
- const maxAttempts = effectiveConfig.quality.autofix?.maxAttempts ?? 2;
191
- const failedChecks = collectFailedChecks(ctx);
192
-
193
- if (failedChecks.length === 0) {
194
- logger.debug("autofix", "No failed checks found — skipping agent rectification", { storyId: ctx.story.id });
195
- return false;
196
- }
197
-
198
- logger.info("autofix", "Starting agent rectification for review failures", {
199
- storyId: ctx.story.id,
200
- failedChecks: failedChecks.map((c) => c.check),
201
- maxAttempts,
202
- });
203
-
204
- const agentGetFn = ctx.agentGetFn ?? getAgent;
205
-
206
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
207
- logger.info("autofix", `Agent rectification attempt ${attempt}/${maxAttempts}`, { storyId: ctx.story.id });
208
-
209
- const agent = agentGetFn(ctx.config.autoMode.defaultAgent);
210
- if (!agent) {
211
- logger.error("autofix", "Agent not found — cannot run agent rectification", { storyId: ctx.story.id });
212
- return false;
213
- }
214
-
215
- const prompt = buildReviewRectificationPrompt(failedChecks, ctx.story);
216
- const modelTier = ctx.story.routing?.modelTier ?? ctx.config.autoMode.escalation.tierOrder[0]?.tier ?? "balanced";
217
- const modelDef = resolveModel(ctx.config.models[modelTier]);
218
-
219
- // ENH-008: Scope agent to story.workdir for monorepo — prevents out-of-package changes
220
- const rectificationWorkdir = ctx.story.workdir ? join(ctx.workdir, ctx.story.workdir) : ctx.workdir;
221
-
222
- await agent.run({
223
- prompt,
224
- workdir: rectificationWorkdir,
225
- modelTier,
226
- modelDef,
227
- timeoutSeconds: ctx.config.execution.sessionTimeoutSeconds,
228
- dangerouslySkipPermissions: resolvePermissions(ctx.config, "rectification").skipPermissions,
229
- pipelineStage: "rectification",
230
- config: ctx.config,
231
- maxInteractionTurns: ctx.config.agent?.maxInteractionTurns,
232
- storyId: ctx.story.id,
233
- sessionRole: "implementer",
234
- });
235
-
236
- const passed = await _autofixDeps.recheckReview(ctx);
237
- if (passed) {
238
- logger.info("autofix", `[OK] Agent rectification succeeded on attempt ${attempt}`, {
239
- storyId: ctx.story.id,
240
- });
241
- return true;
242
- }
243
-
244
- // Refresh failed checks for next attempt
245
- const updatedFailed = collectFailedChecks(ctx);
246
- if (updatedFailed.length > 0) {
247
- failedChecks.splice(0, failedChecks.length, ...updatedFailed);
248
- }
249
-
250
- logger.warn("autofix", `Agent rectification still failing after attempt ${attempt}`, {
251
- storyId: ctx.story.id,
252
- });
253
- }
254
-
255
- logger.warn("autofix", "Agent rectification exhausted", { storyId: ctx.story.id });
256
- return false;
257
- }
258
-
259
- /**
260
- * Injectable deps for testing.
261
- */
262
- export const _autofixDeps = { runCommand, recheckReview, runAgentRectification, loadConfigForWorkdir };