@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,59 +0,0 @@
1
- /**
2
- * Cost rate tables for all supported model tiers and specific models.
3
- */
4
-
5
- import type { ModelTier } from "../../config/schema";
6
- import type { ModelCostRates } from "./types";
7
-
8
- /** Model tier cost rates (as of 2025-01) */
9
- export const COST_RATES: Record<ModelTier, ModelCostRates> = {
10
- fast: {
11
- // Haiku 4.5
12
- inputPer1M: 0.8,
13
- outputPer1M: 4.0,
14
- },
15
- balanced: {
16
- // Sonnet 4.5
17
- inputPer1M: 3.0,
18
- outputPer1M: 15.0,
19
- },
20
- powerful: {
21
- // Opus 4
22
- inputPer1M: 15.0,
23
- outputPer1M: 75.0,
24
- },
25
- };
26
-
27
- /** Per-model pricing in $/1M tokens: { input, output } */
28
- export const MODEL_PRICING: Record<
29
- string,
30
- { input: number; output: number; cacheRead?: number; cacheCreation?: number }
31
- > = {
32
- // Anthropic Claude models (short aliases)
33
- sonnet: { input: 3, output: 15 },
34
- haiku: { input: 0.8, output: 4.0, cacheRead: 0.1, cacheCreation: 1.0 },
35
- opus: { input: 15, output: 75 },
36
-
37
- // Anthropic Claude models (full names)
38
- "claude-sonnet-4": { input: 3, output: 15 },
39
- "claude-sonnet-4-5": { input: 3, output: 15 },
40
- "claude-sonnet-4-6": { input: 3, output: 15 },
41
- "claude-haiku": { input: 0.8, output: 4.0, cacheRead: 0.1, cacheCreation: 1.0 },
42
- "claude-haiku-4-5": { input: 0.8, output: 4.0, cacheRead: 0.1, cacheCreation: 1.0 },
43
- "claude-opus": { input: 15, output: 75 },
44
- "claude-opus-4": { input: 15, output: 75 },
45
- "claude-opus-4-6": { input: 15, output: 75 },
46
-
47
- // OpenAI models
48
- "gpt-4.1": { input: 10, output: 30 },
49
- "gpt-4": { input: 30, output: 60 },
50
- "gpt-3.5-turbo": { input: 0.5, output: 1.5 },
51
-
52
- // Google Gemini
53
- "gemini-2.5-pro": { input: 0.075, output: 0.3 },
54
- "gemini-2-pro": { input: 0.075, output: 0.3 },
55
-
56
- // OpenAI Codex
57
- codex: { input: 0.02, output: 0.06 },
58
- "code-davinci-002": { input: 0.02, output: 0.06 },
59
- };
@@ -1,45 +0,0 @@
1
- /**
2
- * Cost tracking types — shared across all agent adapters.
3
- */
4
-
5
- import type { ModelTier } from "../../config/schema";
6
-
7
- export type { ModelTier };
8
-
9
- /** Cost rates per 1M tokens (USD) */
10
- export interface ModelCostRates {
11
- inputPer1M: number;
12
- outputPer1M: number;
13
- }
14
-
15
- /** Token usage data (camelCase — nax-internal representation) */
16
- export interface TokenUsage {
17
- inputTokens: number;
18
- outputTokens: number;
19
- }
20
-
21
- /** Cost estimate with confidence indicator */
22
- export interface CostEstimate {
23
- cost: number;
24
- confidence: "exact" | "estimated" | "fallback";
25
- }
26
-
27
- /** Token usage with confidence indicator */
28
- export interface TokenUsageWithConfidence {
29
- inputTokens: number;
30
- outputTokens: number;
31
- confidence: "exact" | "estimated";
32
- }
33
-
34
- /**
35
- * Token usage from an ACP session's cumulative_token_usage field.
36
- * Uses snake_case to match the ACP wire format.
37
- */
38
- export interface SessionTokenUsage {
39
- input_tokens: number;
40
- output_tokens: number;
41
- /** Cache read tokens — billed at a reduced rate */
42
- cache_read_input_tokens?: number;
43
- /** Cache creation tokens — billed at a higher creation rate */
44
- cache_creation_input_tokens?: number;
45
- }
@@ -1,177 +0,0 @@
1
- /**
2
- * Gemini CLI Agent Adapter — implements AgentAdapter interface
3
- *
4
- * Provides uniform interface for spawning Gemini CLI processes,
5
- * supporting one-shot completions via 'gemini -p' and Google auth detection.
6
- */
7
-
8
- import type {
9
- AgentAdapter,
10
- AgentCapabilities,
11
- AgentResult,
12
- AgentRunOptions,
13
- CompleteOptions,
14
- DecomposeOptions,
15
- DecomposeResult,
16
- PlanOptions,
17
- PlanResult,
18
- } from "../types";
19
- import { CompleteError } from "../types";
20
-
21
- // ─────────────────────────────────────────────────────────────────────────────
22
- // Injectable dependencies — follows the _deps pattern
23
- // Replaced in unit tests to intercept Bun.spawn/Bun.which calls.
24
- // ─────────────────────────────────────────────────────────────────────────────
25
-
26
- export const _geminiRunDeps = {
27
- which(name: string): string | null {
28
- return Bun.which(name);
29
- },
30
- spawn(
31
- cmd: string[],
32
- opts: { cwd?: string; stdout: "pipe"; stderr: "pipe" | "inherit"; env?: Record<string, string | undefined> },
33
- ): {
34
- stdout: ReadableStream<Uint8Array>;
35
- stderr: ReadableStream<Uint8Array>;
36
- exited: Promise<number>;
37
- pid: number;
38
- kill(signal?: number | NodeJS.Signals): void;
39
- } {
40
- return Bun.spawn(cmd, opts) as unknown as {
41
- stdout: ReadableStream<Uint8Array>;
42
- stderr: ReadableStream<Uint8Array>;
43
- exited: Promise<number>;
44
- pid: number;
45
- kill(signal?: number | NodeJS.Signals): void;
46
- };
47
- },
48
- };
49
-
50
- export const _geminiCompleteDeps = {
51
- spawn(
52
- cmd: string[],
53
- opts: { stdout: "pipe"; stderr: "pipe" | "inherit" },
54
- ): {
55
- stdout: ReadableStream<Uint8Array>;
56
- stderr: ReadableStream<Uint8Array>;
57
- exited: Promise<number>;
58
- pid: number;
59
- } {
60
- return Bun.spawn(cmd, opts) as unknown as {
61
- stdout: ReadableStream<Uint8Array>;
62
- stderr: ReadableStream<Uint8Array>;
63
- exited: Promise<number>;
64
- pid: number;
65
- };
66
- },
67
- };
68
-
69
- // ─────────────────────────────────────────────────────────────────────────────
70
- // GeminiAdapter implementation
71
- // ─────────────────────────────────────────────────────────────────────────────
72
-
73
- const MAX_AGENT_OUTPUT_CHARS = 5000;
74
-
75
- export class GeminiAdapter implements AgentAdapter {
76
- readonly name = "gemini";
77
- readonly displayName = "Gemini CLI";
78
- readonly binary = "gemini";
79
-
80
- readonly capabilities: AgentCapabilities = {
81
- supportedTiers: ["fast", "balanced", "powerful"],
82
- maxContextTokens: 1_000_000,
83
- features: new Set<"tdd" | "review" | "refactor" | "batch">(["tdd", "review", "refactor"]),
84
- };
85
-
86
- async isInstalled(): Promise<boolean> {
87
- const path = _geminiRunDeps.which("gemini");
88
- if (path === null) {
89
- return false;
90
- }
91
-
92
- // Check Google auth — run 'gemini' with a flag that shows auth status
93
- try {
94
- const proc = _geminiRunDeps.spawn(["gemini", "--version"], {
95
- stdout: "pipe",
96
- stderr: "pipe",
97
- });
98
-
99
- const exitCode = await proc.exited;
100
- if (exitCode !== 0) {
101
- return false;
102
- }
103
-
104
- const stdout = await new Response(proc.stdout).text();
105
- const lowerOut = stdout.toLowerCase();
106
-
107
- // If output explicitly says "not logged in", auth has failed
108
- if (lowerOut.includes("not logged in")) {
109
- return false;
110
- }
111
-
112
- return true;
113
- } catch {
114
- return false;
115
- }
116
- }
117
-
118
- buildCommand(options: AgentRunOptions): string[] {
119
- return ["gemini", "-p", options.prompt];
120
- }
121
-
122
- async run(options: AgentRunOptions): Promise<AgentResult> {
123
- const cmd = this.buildCommand(options);
124
- const startTime = Date.now();
125
-
126
- const proc = _geminiRunDeps.spawn(cmd, {
127
- cwd: options.workdir,
128
- stdout: "pipe",
129
- stderr: "inherit",
130
- });
131
-
132
- const exitCode = await proc.exited;
133
- const stdout = await new Response(proc.stdout).text();
134
- const durationMs = Date.now() - startTime;
135
-
136
- return {
137
- success: exitCode === 0,
138
- exitCode,
139
- output: stdout.slice(-MAX_AGENT_OUTPUT_CHARS),
140
- rateLimited: false,
141
- durationMs,
142
- estimatedCost: 0,
143
- pid: proc.pid,
144
- };
145
- }
146
-
147
- async complete(prompt: string, _options?: CompleteOptions): Promise<string> {
148
- const cmd = ["gemini", "-p", prompt];
149
-
150
- const proc = _geminiCompleteDeps.spawn(cmd, { stdout: "pipe", stderr: "pipe" });
151
- const exitCode = await proc.exited;
152
-
153
- const stdout = await new Response(proc.stdout).text();
154
- const stderr = await new Response(proc.stderr).text();
155
- const trimmed = stdout.trim();
156
-
157
- if (exitCode !== 0) {
158
- const errorDetails = stderr.trim() || trimmed;
159
- const errorMessage = errorDetails || `complete() failed with exit code ${exitCode}`;
160
- throw new CompleteError(errorMessage, exitCode);
161
- }
162
-
163
- if (!trimmed) {
164
- throw new CompleteError("complete() returned empty output");
165
- }
166
-
167
- return trimmed;
168
- }
169
-
170
- async plan(_options: PlanOptions): Promise<PlanResult> {
171
- throw new Error("GeminiAdapter.plan() not implemented");
172
- }
173
-
174
- async decompose(_options: DecomposeOptions): Promise<DecomposeResult> {
175
- throw new Error("GeminiAdapter.decompose() not implemented");
176
- }
177
- }
@@ -1,18 +0,0 @@
1
- export type { AgentAdapter, AgentCapabilities, AgentResult, AgentRunOptions, CompleteOptions } from "./types";
2
- export { CompleteError } from "./types";
3
- export { ClaudeCodeAdapter } from "./claude";
4
- export { getAllAgentNames, getAgent, getInstalledAgents, checkAgentHealth } from "./registry";
5
- export type { ModelCostRates, TokenUsage, CostEstimate, TokenUsageWithConfidence, SessionTokenUsage } from "./cost";
6
- export {
7
- COST_RATES,
8
- MODEL_PRICING,
9
- parseTokenUsage,
10
- estimateCost,
11
- estimateCostFromOutput,
12
- estimateCostByDuration,
13
- formatCostWithConfidence,
14
- estimateCostFromTokenUsage,
15
- } from "./cost";
16
- export { validateAgentForTier, validateAgentFeature, describeAgentCapabilities } from "./shared/validation";
17
- export type { AgentVersionInfo } from "./shared/version-detection";
18
- export { getAgentVersion, getAgentVersions } from "./shared/version-detection";
@@ -1,106 +0,0 @@
1
- /**
2
- * OpenCode Agent Adapter — implements AgentAdapter interface
3
- *
4
- * Provides uniform interface for spawning OpenCode agent processes,
5
- * supporting one-shot completions.
6
- */
7
-
8
- import type {
9
- AgentAdapter,
10
- AgentCapabilities,
11
- AgentResult,
12
- AgentRunOptions,
13
- CompleteOptions,
14
- DecomposeOptions,
15
- DecomposeResult,
16
- PlanOptions,
17
- PlanResult,
18
- } from "../types";
19
- import { CompleteError } from "../types";
20
-
21
- // ─────────────────────────────────────────────────────────────────────────────
22
- // Injectable dependencies — matches the _deps pattern used in claude.ts
23
- // These are replaced in unit tests to intercept Bun.spawn calls.
24
- // ─────────────────────────────────────────────────────────────────────────────
25
-
26
- export const _opencodeCompleteDeps = {
27
- which(name: string): string | null {
28
- return Bun.which(name);
29
- },
30
- spawn(
31
- cmd: string[],
32
- opts: { stdout: "pipe"; stderr: "pipe" | "inherit" },
33
- ): {
34
- stdout: ReadableStream<Uint8Array>;
35
- stderr: ReadableStream<Uint8Array>;
36
- exited: Promise<number>;
37
- pid: number;
38
- } {
39
- return Bun.spawn(cmd, opts) as unknown as {
40
- stdout: ReadableStream<Uint8Array>;
41
- stderr: ReadableStream<Uint8Array>;
42
- exited: Promise<number>;
43
- pid: number;
44
- };
45
- },
46
- };
47
-
48
- // ─────────────────────────────────────────────────────────────────────────────
49
- // OpenCodeAdapter implementation
50
- // ─────────────────────────────────────────────────────────────────────────────
51
-
52
- export class OpenCodeAdapter implements AgentAdapter {
53
- readonly name = "opencode";
54
- readonly displayName = "OpenCode";
55
- readonly binary = "opencode";
56
-
57
- readonly capabilities: AgentCapabilities = {
58
- supportedTiers: ["fast", "balanced"],
59
- maxContextTokens: 8_000,
60
- features: new Set<"tdd" | "review" | "refactor" | "batch">(["tdd", "refactor"]),
61
- };
62
-
63
- async isInstalled(): Promise<boolean> {
64
- const path = _opencodeCompleteDeps.which("opencode");
65
- return path !== null;
66
- }
67
-
68
- buildCommand(_options: AgentRunOptions): string[] {
69
- throw new Error("OpenCodeAdapter.buildCommand() not implemented");
70
- }
71
-
72
- async run(_options: AgentRunOptions): Promise<AgentResult> {
73
- throw new Error("OpenCodeAdapter.run() not implemented");
74
- }
75
-
76
- async complete(prompt: string, _options?: CompleteOptions): Promise<string> {
77
- const cmd = ["opencode", "--prompt", prompt];
78
-
79
- const proc = _opencodeCompleteDeps.spawn(cmd, { stdout: "pipe", stderr: "pipe" });
80
- const exitCode = await proc.exited;
81
-
82
- const stdout = await new Response(proc.stdout).text();
83
- const stderr = await new Response(proc.stderr).text();
84
- const trimmed = stdout.trim();
85
-
86
- if (exitCode !== 0) {
87
- const errorDetails = stderr.trim() || trimmed;
88
- const errorMessage = errorDetails || `complete() failed with exit code ${exitCode}`;
89
- throw new CompleteError(errorMessage, exitCode);
90
- }
91
-
92
- if (!trimmed) {
93
- throw new CompleteError("complete() returned empty output");
94
- }
95
-
96
- return trimmed;
97
- }
98
-
99
- async plan(_options: PlanOptions): Promise<PlanResult> {
100
- throw new Error("OpenCodeAdapter.plan() not implemented");
101
- }
102
-
103
- async decompose(_options: DecomposeOptions): Promise<DecomposeResult> {
104
- throw new Error("OpenCodeAdapter.decompose() not implemented");
105
- }
106
- }
@@ -1,136 +0,0 @@
1
- /**
2
- * Agent Registry
3
- *
4
- * Discovers and manages available coding agents.
5
- */
6
-
7
- import type { NaxConfig } from "../config/schema";
8
- import { getLogger } from "../logger";
9
- import { AcpAgentAdapter } from "./acp/adapter";
10
- import { AiderAdapter } from "./aider/adapter";
11
- import { ClaudeCodeAdapter } from "./claude/adapter";
12
- import { CodexAdapter } from "./codex/adapter";
13
- import { GeminiAdapter } from "./gemini/adapter";
14
- import { OpenCodeAdapter } from "./opencode/adapter";
15
- import type { AgentAdapter } from "./types";
16
-
17
- /** All known agent adapters */
18
- export const ALL_AGENTS: AgentAdapter[] = [
19
- new ClaudeCodeAdapter(),
20
- new CodexAdapter(),
21
- new OpenCodeAdapter(),
22
- new GeminiAdapter(),
23
- new AiderAdapter(),
24
- ];
25
-
26
- /** Get all registered agent names */
27
- export function getAllAgentNames(): string[] {
28
- return ALL_AGENTS.map((a) => a.name);
29
- }
30
-
31
- /** Get a specific agent by name */
32
- export function getAgent(name: string): AgentAdapter | undefined {
33
- return ALL_AGENTS.find((a) => a.name === name);
34
- }
35
-
36
- /** Get all installed agents on this machine */
37
- export async function getInstalledAgents(): Promise<AgentAdapter[]> {
38
- const results = await Promise.all(
39
- ALL_AGENTS.map(async (agent) => ({
40
- agent,
41
- installed: await agent.isInstalled(),
42
- })),
43
- );
44
- return results.filter((r) => r.installed).map((r) => r.agent);
45
- }
46
-
47
- /** Check health of all agents */
48
- export async function checkAgentHealth(): Promise<Array<{ name: string; displayName: string; installed: boolean }>> {
49
- return Promise.all(
50
- ALL_AGENTS.map(async (agent) => ({
51
- name: agent.name,
52
- displayName: agent.displayName,
53
- installed: await agent.isInstalled(),
54
- })),
55
- );
56
- }
57
-
58
- /** Protocol-aware agent registry returned by createAgentRegistry() */
59
- export interface AgentRegistry {
60
- /** Get a specific agent, respecting the configured protocol */
61
- getAgent(name: string): AgentAdapter | undefined;
62
- /** Get all installed agents */
63
- getInstalledAgents(): Promise<AgentAdapter[]>;
64
- /** Check health of all agents */
65
- checkAgentHealth(): Promise<Array<{ name: string; displayName: string; installed: boolean }>>;
66
- /** Active protocol ('acp' | 'cli') */
67
- protocol: "acp" | "cli";
68
- }
69
-
70
- /**
71
- * Create a protocol-aware agent registry.
72
- *
73
- * When config.agent.protocol is 'acp', returns AcpAgentAdapter instances.
74
- * When 'cli' (or unset), returns legacy CLI adapters.
75
- * AcpAgentAdapter instances are cached per agent name for the lifetime of the registry.
76
- */
77
- export function createAgentRegistry(config: NaxConfig): AgentRegistry {
78
- const protocol: "acp" | "cli" = config.agent?.protocol ?? "cli";
79
- const logger = getLogger();
80
- const acpCache = new Map<string, AcpAgentAdapter>();
81
-
82
- // Log which protocol is being used at startup
83
- logger?.info("agents", `Agent protocol: ${protocol}`, { protocol, hasConfig: !!config.agent });
84
-
85
- function getAgent(name: string): AgentAdapter | undefined {
86
- if (protocol === "acp") {
87
- const known = ALL_AGENTS.find((a) => a.name === name);
88
- if (!known) return undefined;
89
- if (!acpCache.has(name)) {
90
- acpCache.set(name, new AcpAgentAdapter(name));
91
- logger?.debug("agents", `Created AcpAgentAdapter for ${name}`, { name, protocol });
92
- }
93
- return acpCache.get(name);
94
- }
95
- const adapter = ALL_AGENTS.find((a) => a.name === name);
96
- if (adapter) {
97
- logger?.debug("agents", `Using CLI adapter for ${name}: ${adapter.constructor.name}`, { name });
98
- }
99
- return adapter;
100
- }
101
-
102
- async function getInstalledAgents(): Promise<AgentAdapter[]> {
103
- const agents =
104
- protocol === "acp"
105
- ? ALL_AGENTS.map((a) => {
106
- if (!acpCache.has(a.name)) {
107
- acpCache.set(a.name, new AcpAgentAdapter(a.name));
108
- }
109
- return acpCache.get(a.name) as AcpAgentAdapter;
110
- })
111
- : ALL_AGENTS;
112
- const results = await Promise.all(agents.map(async (agent) => ({ agent, installed: await agent.isInstalled() })));
113
- return results.filter((r) => r.installed).map((r) => r.agent);
114
- }
115
-
116
- async function checkAgentHealth(): Promise<Array<{ name: string; displayName: string; installed: boolean }>> {
117
- const agents =
118
- protocol === "acp"
119
- ? ALL_AGENTS.map((a) => {
120
- if (!acpCache.has(a.name)) {
121
- acpCache.set(a.name, new AcpAgentAdapter(a.name));
122
- }
123
- return acpCache.get(a.name) as AcpAgentAdapter;
124
- })
125
- : ALL_AGENTS;
126
- return Promise.all(
127
- agents.map(async (agent) => ({
128
- name: agent.name,
129
- displayName: agent.displayName,
130
- installed: await agent.isInstalled(),
131
- })),
132
- );
133
- }
134
-
135
- return { getAgent, getInstalledAgents, checkAgentHealth, protocol };
136
- }
@@ -1,154 +0,0 @@
1
- /**
2
- * Claude Code Decompose Logic
3
- *
4
- * Extracted from claude.ts: decompose(), buildDecomposePrompt(),
5
- * parseDecomposeOutput(), validateComplexity()
6
- */
7
-
8
- import { COMPLEXITY_GUIDE, GROUPING_RULES, TEST_STRATEGY_GUIDE, resolveTestStrategy } from "../../config/test-strategy";
9
- import type { DecomposeOptions, DecomposeResult, DecomposedStory } from "../types";
10
-
11
- /**
12
- * Build the decompose prompt combining spec content and codebase context.
13
- */
14
- export function buildDecomposePrompt(options: DecomposeOptions): string {
15
- return `You are a requirements analyst. Break down the following feature specification into user stories and classify each story's complexity.
16
-
17
- CODEBASE CONTEXT:
18
- ${options.codebaseContext}
19
-
20
- FEATURE SPECIFICATION:
21
- ${options.specContent}
22
-
23
- Decompose this spec into user stories. For each story, provide:
24
- 1. id: Story ID (e.g., "US-001")
25
- 2. title: Concise story title
26
- 3. description: What needs to be implemented
27
- 4. acceptanceCriteria: Array of testable criteria
28
- 5. tags: Array of routing tags (e.g., ["security", "api"])
29
- 6. dependencies: Array of story IDs this depends on (e.g., ["US-001"])
30
- 7. complexity: "simple" | "medium" | "complex" | "expert"
31
- 8. contextFiles: Array of file paths to inject into agent prompt before execution
32
- 9. reasoning: Why this complexity level
33
- 10. estimatedLOC: Estimated lines of code to change
34
- 11. risks: Array of implementation risks
35
- 12. testStrategy: "test-after" | "tdd-simple" | "three-session-tdd" | "three-session-tdd-lite"
36
-
37
- ${COMPLEXITY_GUIDE}
38
-
39
- ${TEST_STRATEGY_GUIDE}
40
-
41
- ${GROUPING_RULES}
42
-
43
- Consider:
44
- 1. Does infrastructure exist? (e.g., "add caching" when no cache layer exists = complex)
45
- 2. How many files will be touched?
46
- 3. Are there cross-cutting concerns (auth, validation, error handling)?
47
- 4. Does it require new dependencies or architectural decisions?
48
-
49
- Respond with ONLY a JSON array (no markdown code fences):
50
- [{
51
- "id": "US-001",
52
- "title": "Story title",
53
- "description": "Story description",
54
- "acceptanceCriteria": ["Criterion 1", "Criterion 2"],
55
- "tags": ["tag1"],
56
- "dependencies": [],
57
- "complexity": "medium",
58
- "contextFiles": ["src/path/to/file.ts"],
59
- "reasoning": "Why this complexity level",
60
- "estimatedLOC": 150,
61
- "risks": ["Risk 1"],
62
- "testStrategy": "test-after"
63
- }]`;
64
- }
65
-
66
- /**
67
- * Parse decompose output from agent stdout.
68
- *
69
- * Extracts JSON array from output, handles markdown code fences,
70
- * and validates structure.
71
- */
72
- export function parseDecomposeOutput(output: string): DecomposedStory[] {
73
- // Extract JSON from output (handles markdown code fences)
74
- const jsonMatch = output.match(/```(?:json)?\s*(\[[\s\S]*?\])\s*```/);
75
- let jsonText = jsonMatch ? jsonMatch[1] : output;
76
-
77
- // Try to find JSON array directly if no code fence
78
- if (!jsonMatch) {
79
- const arrayMatch = output.match(/\[[\s\S]*\]/);
80
- if (arrayMatch) {
81
- jsonText = arrayMatch[0];
82
- }
83
- }
84
-
85
- // Parse JSON
86
- let parsed: unknown;
87
- try {
88
- parsed = JSON.parse(jsonText.trim());
89
- } catch (error) {
90
- throw new Error(
91
- `Failed to parse decompose output as JSON: ${(error as Error).message}\n\nOutput:\n${output.slice(0, 500)}`,
92
- );
93
- }
94
-
95
- // Validate structure
96
- if (!Array.isArray(parsed)) {
97
- throw new Error("Decompose output is not an array");
98
- }
99
-
100
- // Map to DecomposedStory[] with validation
101
- const stories: DecomposedStory[] = parsed.map((item: unknown, index: number) => {
102
- // Type guard: ensure item is an object
103
- if (typeof item !== "object" || item === null) {
104
- throw new Error(`Story at index ${index} is not an object`);
105
- }
106
- const record = item as Record<string, unknown>;
107
- if (!record.id || typeof record.id !== "string") {
108
- throw new Error(`Story at index ${index} missing valid 'id' field`);
109
- }
110
- if (!record.title || typeof record.title !== "string") {
111
- throw new Error(`Story ${record.id} missing valid 'title' field`);
112
- }
113
-
114
- return {
115
- id: record.id,
116
- title: record.title,
117
- description: String(record.description || record.title),
118
- acceptanceCriteria: Array.isArray(record.acceptanceCriteria)
119
- ? record.acceptanceCriteria
120
- : ["Implementation complete"],
121
- tags: Array.isArray(record.tags) ? record.tags : [],
122
- dependencies: Array.isArray(record.dependencies) ? record.dependencies : [],
123
- complexity: coerceComplexity(record.complexity),
124
- // contextFiles: prefer the new field; fall back to legacy relevantFiles from older LLM responses
125
- contextFiles: Array.isArray(record.contextFiles)
126
- ? record.contextFiles
127
- : Array.isArray(record.relevantFiles)
128
- ? record.relevantFiles
129
- : [],
130
- relevantFiles: Array.isArray(record.relevantFiles) ? record.relevantFiles : [],
131
- reasoning: String(record.reasoning || "No reasoning provided"),
132
- estimatedLOC: Number(record.estimatedLOC) || 0,
133
- risks: Array.isArray(record.risks) ? record.risks : [],
134
- testStrategy: resolveTestStrategy(typeof record.testStrategy === "string" ? record.testStrategy : undefined),
135
- };
136
- });
137
-
138
- if (stories.length === 0) {
139
- throw new Error("Decompose returned empty story array");
140
- }
141
-
142
- return stories;
143
- }
144
-
145
- /**
146
- * Coerce complexity value from decompose output.
147
- */
148
- export function coerceComplexity(value: unknown): "simple" | "medium" | "complex" | "expert" {
149
- if (value === "simple" || value === "medium" || value === "complex" || value === "expert") {
150
- return value;
151
- }
152
- // Default to medium if invalid
153
- return "medium";
154
- }