@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,133 @@
1
+ /**
2
+ * Extended Agent Type Definitions
3
+ *
4
+ * Types for plan mode, decompose mode, and interactive PTY sessions.
5
+ * Separated from core types to keep each file under 400 lines.
6
+ */
7
+
8
+ import type { ModelDef, ModelTier } from "../config/schema";
9
+
10
+ /**
11
+ * Configuration options for running an agent in plan mode.
12
+ *
13
+ * Plan mode spawns the agent interactively (or non-interactively with input file)
14
+ * to gather requirements, ask clarifying questions, and produce a structured spec.
15
+ */
16
+ export interface PlanOptions {
17
+ /** The initial planning prompt or task description */
18
+ prompt: string;
19
+ /** Working directory */
20
+ workdir: string;
21
+ /** Whether to run in interactive mode (agent takes over terminal) */
22
+ interactive: boolean;
23
+ /** Optional codebase context (file tree, dependencies, test patterns) */
24
+ codebaseContext?: string;
25
+ /** Optional input file path for non-interactive mode */
26
+ inputFile?: string;
27
+ /** Model tier to use for planning (default: "balanced") */
28
+ modelTier?: ModelTier;
29
+ /** Resolved model definition */
30
+ modelDef?: ModelDef;
31
+ }
32
+
33
+ /**
34
+ * Result from running an agent in plan mode.
35
+ *
36
+ * Contains the generated specification content and optional conversation log.
37
+ */
38
+ export interface PlanResult {
39
+ /** The generated specification markdown content */
40
+ specContent: string;
41
+ /** Optional conversation log (for debugging/review) */
42
+ conversationLog?: string;
43
+ }
44
+
45
+ /**
46
+ * Configuration options for running an agent in decompose mode.
47
+ *
48
+ * Decompose mode reads a spec document and breaks it down into classified user stories
49
+ * in a single LLM call (decompose + classify combined).
50
+ */
51
+ export interface DecomposeOptions {
52
+ /** The spec document content to decompose */
53
+ specContent: string;
54
+ /** Working directory */
55
+ workdir: string;
56
+ /** Codebase context (file tree, dependencies, test patterns) */
57
+ codebaseContext: string;
58
+ /** Model tier to use for decomposition (default: "balanced") */
59
+ modelTier?: ModelTier;
60
+ /** Resolved model definition */
61
+ modelDef?: ModelDef;
62
+ }
63
+
64
+ /** A single classified user story from decompose result. */
65
+ export interface DecomposedStory {
66
+ /** Story ID (e.g., "US-001") */
67
+ id: string;
68
+ /** Story title */
69
+ title: string;
70
+ /** Story description */
71
+ description: string;
72
+ /** Acceptance criteria */
73
+ acceptanceCriteria: string[];
74
+ /** Tags for routing */
75
+ tags: string[];
76
+ /** Dependencies (story IDs) */
77
+ dependencies: string[];
78
+ /** Classified complexity */
79
+ complexity: "simple" | "medium" | "complex" | "expert";
80
+ /** Context files to inject into agent prompt before execution */
81
+ contextFiles: string[];
82
+ /** Classification reasoning */
83
+ reasoning: string;
84
+ /** Estimated lines of code */
85
+ estimatedLOC: number;
86
+ /** Implementation risks */
87
+ risks: string[];
88
+ /** Test strategy recommendation from LLM */
89
+ testStrategy?: "three-session-tdd" | "test-after";
90
+ }
91
+
92
+ /**
93
+ * Result from running an agent in decompose mode.
94
+ *
95
+ * Contains the decomposed and classified user stories.
96
+ */
97
+ export interface DecomposeResult {
98
+ /** The decomposed and classified user stories */
99
+ stories: DecomposedStory[];
100
+ }
101
+
102
+ /**
103
+ * PTY handle interface for managing spawned PTY process.
104
+ *
105
+ * Provides methods to write input, resize terminal, and kill process.
106
+ * Returned by runInteractive() for TUI integration.
107
+ */
108
+ export interface PtyHandle {
109
+ /** Write input to PTY stdin */
110
+ write(data: string): void;
111
+ /** Resize PTY terminal */
112
+ resize(cols: number, rows: number): void;
113
+ /** Kill PTY process */
114
+ kill(): void;
115
+ /** Process ID */
116
+ pid: number;
117
+ }
118
+
119
+ /**
120
+ * Configuration options for running an agent in interactive PTY mode.
121
+ *
122
+ * Extends AgentRunOptions with PTY-specific callbacks for output streaming
123
+ * and exit handling. Used by TUI to embed agent sessions.
124
+ */
125
+ export interface InteractiveRunOptions extends AgentRunOptions {
126
+ /** Callback fired when PTY outputs data */
127
+ onOutput: (data: Buffer) => void;
128
+ /** Callback fired when PTY process exits */
129
+ onExit: (code: number) => void;
130
+ }
131
+
132
+ // Re-import for the extends clause
133
+ import type { AgentRunOptions } from "./types";
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Agent Adapter Interface
3
+ *
4
+ * Every coding agent (Claude Code, Codex, OpenCode, etc.)
5
+ * implements this interface so nax can spawn, monitor, and
6
+ * collect results from them uniformly.
7
+ */
8
+
9
+ import type { ModelDef, ModelTier } from "../config/schema";
10
+
11
+ // Re-export extended types for backward compatibility
12
+ export type {
13
+ PlanOptions,
14
+ PlanResult,
15
+ DecomposeOptions,
16
+ DecomposeResult,
17
+ DecomposedStory,
18
+ PtyHandle,
19
+ InteractiveRunOptions,
20
+ } from "./types-extended";
21
+
22
+ /**
23
+ * Agent execution result returned after running a coding agent.
24
+ */
25
+ export interface AgentResult {
26
+ /** Whether the agent completed successfully */
27
+ success: boolean;
28
+ /** Exit code from the process */
29
+ exitCode: number;
30
+ /** stdout output (last N lines) */
31
+ output: string;
32
+ /** stderr output tail (last N lines) — useful for diagnosing failures */
33
+ stderr?: string;
34
+ /** Whether the agent hit a rate limit */
35
+ rateLimited: boolean;
36
+ /** Duration in milliseconds */
37
+ durationMs: number;
38
+ /** Estimated cost for this run (USD) */
39
+ estimatedCost: number;
40
+ /** Process ID of the spawned agent (for cleanup on failure) */
41
+ pid?: number;
42
+ }
43
+
44
+ /**
45
+ * Configuration options for running a coding agent session.
46
+ */
47
+ export interface AgentRunOptions {
48
+ /** The prompt to send to the agent */
49
+ prompt: string;
50
+ /** Working directory */
51
+ workdir: string;
52
+ /** Model tier (for cost estimation) */
53
+ modelTier: ModelTier;
54
+ /** Resolved model definition */
55
+ modelDef: ModelDef;
56
+ /** Maximum runtime in seconds */
57
+ timeoutSeconds: number;
58
+ /** Environment variables to pass */
59
+ env?: Record<string, string>;
60
+ /** Use --dangerously-skip-permissions flag (default: true) */
61
+ dangerouslySkipPermissions?: boolean;
62
+ }
63
+
64
+ /**
65
+ * Agent capability metadata describing what features and tiers the agent supports.
66
+ */
67
+ export interface AgentCapabilities {
68
+ /** Model tiers this agent supports (e.g., fast/balanced/powerful) */
69
+ readonly supportedTiers: readonly ModelTier[];
70
+ /** Maximum context window size in tokens */
71
+ readonly maxContextTokens: number;
72
+ /** Feature flags — what workflows this agent can handle */
73
+ readonly features: ReadonlySet<"tdd" | "review" | "refactor" | "batch">;
74
+ }
75
+
76
+ /**
77
+ * Agent adapter interface — one implementation per supported coding agent.
78
+ *
79
+ * Provides uniform interface for checking installation, running agents,
80
+ * and building CLI commands across different coding agent tools.
81
+ */
82
+ export interface AgentAdapter {
83
+ /** Unique agent name (e.g., "claude", "codex", "opencode") */
84
+ readonly name: string;
85
+ /** Human-readable display name */
86
+ readonly displayName: string;
87
+ /** Binary command to check if agent is installed */
88
+ readonly binary: string;
89
+ /** Capability metadata describing supported tiers and features */
90
+ readonly capabilities: AgentCapabilities;
91
+
92
+ /** Check if the agent binary is available on this machine. */
93
+ isInstalled(): Promise<boolean>;
94
+
95
+ /** Run the agent with a prompt and return the result. */
96
+ run(options: AgentRunOptions): Promise<AgentResult>;
97
+
98
+ /** Build the CLI command for a given run (for dry-run display). */
99
+ buildCommand(options: AgentRunOptions): string[];
100
+
101
+ /** Run the agent in plan mode to generate a feature specification. */
102
+ plan(options: import("./types-extended").PlanOptions): Promise<import("./types-extended").PlanResult>;
103
+
104
+ /** Run the agent in decompose mode to break spec into classified stories. */
105
+ decompose(options: import("./types-extended").DecomposeOptions): Promise<import("./types-extended").DecomposeResult>;
106
+
107
+ /**
108
+ * Run the agent in interactive PTY mode for TUI embedding.
109
+ * This method is optional — only implemented by agents that support
110
+ * interactive terminal sessions (e.g., Claude Code).
111
+ */
112
+ runInteractive?(options: import("./types-extended").InteractiveRunOptions): import("./types-extended").PtyHandle;
113
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Agent Validation Helpers
3
+ *
4
+ * Runtime validation for agent capabilities and tier compatibility.
5
+ */
6
+
7
+ import type { ModelTier } from "../config/schema";
8
+ import type { AgentAdapter } from "./types";
9
+
10
+ /**
11
+ * Check if an agent supports a given model tier.
12
+ *
13
+ * Used to validate routing decisions at runtime — ensures the orchestrator
14
+ * doesn't try to use a tier the agent doesn't support.
15
+ *
16
+ * @param agent - The agent adapter to validate
17
+ * @param tier - The model tier to check (fast/balanced/powerful)
18
+ * @returns true if the agent declares support for this tier
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const agent = new ClaudeCodeAdapter();
23
+ * if (!validateAgentForTier(agent, "powerful")) {
24
+ * console.warn(`Agent ${agent.name} does not support powerful tier`);
25
+ * }
26
+ * ```
27
+ */
28
+ export function validateAgentForTier(agent: AgentAdapter, tier: ModelTier): boolean {
29
+ return agent.capabilities.supportedTiers.includes(tier);
30
+ }
31
+
32
+ /**
33
+ * Check if an agent supports a specific feature.
34
+ *
35
+ * @param agent - The agent adapter to validate
36
+ * @param feature - The feature to check (tdd/review/refactor/batch)
37
+ * @returns true if the agent declares support for this feature
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const agent = new ClaudeCodeAdapter();
42
+ * if (!validateAgentFeature(agent, "tdd")) {
43
+ * throw new Error("Agent does not support TDD workflow");
44
+ * }
45
+ * ```
46
+ */
47
+ export function validateAgentFeature(agent: AgentAdapter, feature: "tdd" | "review" | "refactor" | "batch"): boolean {
48
+ return agent.capabilities.features.has(feature);
49
+ }
50
+
51
+ /**
52
+ * Get a human-readable description of agent capabilities.
53
+ *
54
+ * @param agent - The agent adapter to describe
55
+ * @returns Formatted capability summary
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const agent = new ClaudeCodeAdapter();
60
+ * console.log(describeAgentCapabilities(agent));
61
+ * // "claude: tiers=[fast,balanced,powerful], maxTokens=200000, features=[tdd,review,refactor,batch]"
62
+ * ```
63
+ */
64
+ export function describeAgentCapabilities(agent: AgentAdapter): string {
65
+ const tiers = agent.capabilities.supportedTiers.join(",");
66
+ const features = Array.from(agent.capabilities.features).join(",");
67
+ const maxTokens = agent.capabilities.maxContextTokens;
68
+ return `${agent.name}: tiers=[${tiers}], maxTokens=${maxTokens}, features=[${features}]`;
69
+ }
@@ -0,0 +1,305 @@
1
+ /**
2
+ * LLM-Enhanced Classifier
3
+ *
4
+ * Uses a single cheap LLM call (haiku) to classify all stories in one shot.
5
+ * Falls back to keyword matching if LLM call fails.
6
+ */
7
+
8
+ import { Anthropic } from "@anthropic-ai/sdk";
9
+ import type { NaxConfig } from "../config";
10
+ import { getLogger } from "../logger";
11
+ import type { UserStory } from "../prd";
12
+ import { classifyComplexity } from "../routing";
13
+ import type { ClassificationResult, CodebaseScan, StoryClassification } from "./types";
14
+
15
+ /**
16
+ * Raw LLM classification item (before validation)
17
+ */
18
+ interface LLMClassificationItem {
19
+ storyId: unknown;
20
+ complexity: unknown;
21
+ relevantFiles: unknown;
22
+ reasoning: unknown;
23
+ estimatedLOC: unknown;
24
+ risks: unknown;
25
+ }
26
+
27
+ /**
28
+ * Classify stories using LLM-enhanced analysis with fallback to keyword matching.
29
+ *
30
+ * Makes a single Anthropic API call (haiku tier) to classify all stories.
31
+ * If the LLM call fails or returns invalid JSON, falls back to keyword matching.
32
+ *
33
+ * @param stories - User stories to classify
34
+ * @param scan - Codebase scan result
35
+ * @param config - Ngent configuration
36
+ * @returns Classification result with method used
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const result = await classifyStories(stories, scan, config);
41
+ * if (result.method === "keyword-fallback") {
42
+ * console.warn("LLM classification failed:", result.fallbackReason);
43
+ * }
44
+ * console.log(result.classifications);
45
+ * ```
46
+ */
47
+ export async function classifyStories(
48
+ stories: UserStory[],
49
+ scan: CodebaseScan,
50
+ config: NaxConfig,
51
+ ): Promise<ClassificationResult> {
52
+ // Check if LLM-enhanced analysis is enabled
53
+ if (!config.analyze?.llmEnhanced) {
54
+ return {
55
+ classifications: stories.map((story) => fallbackClassification(story)),
56
+ method: "keyword-fallback",
57
+ fallbackReason: "LLM-enhanced analysis disabled in config",
58
+ };
59
+ }
60
+
61
+ // Try LLM classification
62
+ try {
63
+ const classifications = await classifyWithLLM(stories, scan, config);
64
+ return {
65
+ classifications,
66
+ method: "llm",
67
+ };
68
+ } catch (error) {
69
+ // Fall back to keyword matching
70
+ const reason = error instanceof Error ? error.message : String(error);
71
+ const logger = getLogger();
72
+ logger.warn("analyze", "LLM classification failed, falling back to keyword matching", { error: reason });
73
+
74
+ return {
75
+ classifications: stories.map((story) => fallbackClassification(story)),
76
+ method: "keyword-fallback",
77
+ fallbackReason: reason,
78
+ };
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Classify stories using LLM with structured JSON output.
84
+ *
85
+ * @param stories - User stories to classify
86
+ * @param scan - Codebase scan result
87
+ * @param config - Ngent configuration
88
+ * @returns Array of story classifications
89
+ */
90
+ async function classifyWithLLM(
91
+ stories: UserStory[],
92
+ scan: CodebaseScan,
93
+ config: NaxConfig,
94
+ ): Promise<StoryClassification[]> {
95
+ // Check API key
96
+ const apiKey = process.env.ANTHROPIC_API_KEY;
97
+ if (!apiKey) {
98
+ throw new Error("ANTHROPIC_API_KEY not set");
99
+ }
100
+
101
+ const client = new Anthropic({ apiKey });
102
+
103
+ // Build prompt
104
+ const prompt = buildClassificationPrompt(stories, scan, config);
105
+
106
+ // Make API call (use haiku for cheap classification)
107
+ const response = await client.messages.create({
108
+ model: "claude-haiku-4-20250514",
109
+ max_tokens: 4096,
110
+ messages: [
111
+ {
112
+ role: "user",
113
+ content: prompt,
114
+ },
115
+ ],
116
+ });
117
+
118
+ // Extract text from response
119
+ const textContent = response.content.find((c) => c.type === "text");
120
+ if (!textContent || textContent.type !== "text") {
121
+ throw new Error("No text response from LLM");
122
+ }
123
+
124
+ // Parse JSON response
125
+ const jsonText = extractJSON(textContent.text);
126
+ const parsed: unknown = JSON.parse(jsonText);
127
+
128
+ // Validate structure
129
+ if (!Array.isArray(parsed)) {
130
+ throw new Error("LLM response is not an array");
131
+ }
132
+
133
+ // Map to StoryClassification[]
134
+ const classifications: StoryClassification[] = parsed.map((item: unknown) => {
135
+ const rawItem = item as LLMClassificationItem;
136
+ return {
137
+ storyId: String(rawItem.storyId),
138
+ complexity: validateComplexity(rawItem.complexity),
139
+ contextFiles: Array.isArray(rawItem.relevantFiles) ? rawItem.relevantFiles.map(String) : [],
140
+ reasoning: String(rawItem.reasoning || "No reasoning provided"),
141
+ estimatedLOC: Number(rawItem.estimatedLOC) || 0,
142
+ risks: Array.isArray(rawItem.risks) ? rawItem.risks.map(String) : [],
143
+ };
144
+ });
145
+
146
+ // Ensure all stories are classified
147
+ const classifiedIds = new Set(classifications.map((c) => c.storyId));
148
+ for (const story of stories) {
149
+ if (!classifiedIds.has(story.id)) {
150
+ throw new Error(`Story ${story.id} not classified by LLM`);
151
+ }
152
+ }
153
+
154
+ return classifications;
155
+ }
156
+
157
+ /**
158
+ * Build classification prompt for LLM.
159
+ *
160
+ * @param stories - User stories to classify
161
+ * @param scan - Codebase scan result
162
+ * @param config - Ngent configuration
163
+ * @returns Formatted prompt string
164
+ */
165
+ function buildClassificationPrompt(stories: UserStory[], scan: CodebaseScan, config: NaxConfig): string {
166
+ // Format codebase summary
167
+ const codebaseSummary = `
168
+ FILE TREE:
169
+ ${scan.fileTree}
170
+
171
+ DEPENDENCIES:
172
+ ${Object.entries(scan.dependencies)
173
+ .map(([name, version]) => `- ${name}: ${version}`)
174
+ .join("\n")}
175
+
176
+ DEV DEPENDENCIES:
177
+ ${Object.entries(scan.devDependencies)
178
+ .map(([name, version]) => `- ${name}: ${version}`)
179
+ .join("\n")}
180
+
181
+ TEST PATTERNS:
182
+ ${scan.testPatterns.map((p) => `- ${p}`).join("\n")}
183
+ `.trim();
184
+
185
+ // Format stories as JSON for LLM
186
+ const storiesJson = JSON.stringify(
187
+ stories.map((s) => ({
188
+ id: s.id,
189
+ title: s.title,
190
+ description: s.description,
191
+ acceptanceCriteria: s.acceptanceCriteria,
192
+ tags: s.tags,
193
+ })),
194
+ null,
195
+ 2,
196
+ );
197
+
198
+ return `You are a code complexity classifier. Given a codebase summary and user stories,
199
+ classify each story's implementation complexity.
200
+
201
+ CODEBASE:
202
+ ${codebaseSummary}
203
+
204
+ STORIES:
205
+ ${storiesJson}
206
+
207
+ For each story, respond with a JSON array (and ONLY the JSON array, no markdown code fences):
208
+ [{
209
+ "storyId": "US-001",
210
+ "complexity": "simple|medium|complex|expert",
211
+ "relevantFiles": ["src/path/to/file.ts"],
212
+ "reasoning": "Why this complexity level",
213
+ "estimatedLOC": 50,
214
+ "risks": ["No existing cache layer"]
215
+ }]
216
+
217
+ Classification rules:
218
+ - simple: 1-3 files, <100 LOC, straightforward implementation, existing patterns
219
+ - medium: 3-6 files, 100-300 LOC, moderate logic, some new patterns
220
+ - complex: 6+ files, 300-800 LOC, architectural changes, cross-cutting concerns
221
+ - expert: Security/crypto/real-time/distributed systems, >800 LOC, new infrastructure
222
+
223
+ Consider:
224
+ 1. Does infrastructure exist? (e.g., "add caching" when no cache layer exists = complex)
225
+ 2. How many files will be touched?
226
+ 3. Are there cross-cutting concerns (auth, validation, error handling)?
227
+ 4. Does it require new dependencies or architectural decisions?
228
+
229
+ Respond with ONLY the JSON array.`;
230
+ }
231
+
232
+ /**
233
+ * Extract JSON from LLM response (handles markdown code fences).
234
+ *
235
+ * @param text - LLM response text
236
+ * @returns JSON string
237
+ */
238
+ function extractJSON(text: string): string {
239
+ // Remove markdown code fences if present
240
+ const jsonMatch = text.match(/```(?:json)?\s*(\[[\s\S]*?\])\s*```/);
241
+ if (jsonMatch) {
242
+ return jsonMatch[1];
243
+ }
244
+
245
+ // Try to find JSON array directly
246
+ const arrayMatch = text.match(/\[[\s\S]*\]/);
247
+ if (arrayMatch) {
248
+ return arrayMatch[0];
249
+ }
250
+
251
+ // Return as-is if no special formatting detected
252
+ return text.trim();
253
+ }
254
+
255
+ /**
256
+ * Validate complexity value from LLM response.
257
+ *
258
+ * @param value - Complexity value from LLM
259
+ * @returns Valid Complexity type
260
+ */
261
+ function validateComplexity(value: unknown): "simple" | "medium" | "complex" | "expert" {
262
+ if (value === "simple" || value === "medium" || value === "complex" || value === "expert") {
263
+ return value;
264
+ }
265
+ // Default to medium if invalid
266
+ return "medium";
267
+ }
268
+
269
+ /**
270
+ * Fallback classification using keyword matching.
271
+ *
272
+ * @param story - User story to classify
273
+ * @returns Story classification using keyword-based complexity
274
+ */
275
+ function fallbackClassification(story: UserStory): StoryClassification {
276
+ const complexity = classifyComplexity(story.title, story.description, story.acceptanceCriteria, story.tags);
277
+
278
+ return {
279
+ storyId: story.id,
280
+ complexity,
281
+ contextFiles: [],
282
+ reasoning: `Keyword-based classification: ${complexity}`,
283
+ estimatedLOC: estimateLOCFromComplexity(complexity),
284
+ risks: [],
285
+ };
286
+ }
287
+
288
+ /**
289
+ * Estimate LOC from complexity level (rough heuristic).
290
+ *
291
+ * @param complexity - Complexity level
292
+ * @returns Estimated lines of code
293
+ */
294
+ function estimateLOCFromComplexity(complexity: "simple" | "medium" | "complex" | "expert"): number {
295
+ switch (complexity) {
296
+ case "simple":
297
+ return 50;
298
+ case "medium":
299
+ return 150;
300
+ case "complex":
301
+ return 400;
302
+ case "expert":
303
+ return 800;
304
+ }
305
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Analyze Module
3
+ *
4
+ * LLM-enhanced story classification with codebase scanning.
5
+ */
6
+
7
+ export type {
8
+ CodebaseScan,
9
+ StoryClassification,
10
+ ClassifierResponse,
11
+ ClassificationMethod,
12
+ ClassificationResult,
13
+ } from "./types";
14
+
15
+ export { scanCodebase } from "./scanner";
16
+ export { classifyStories } from "./classifier";