@nathapp/nax 0.50.3 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/nax.js +393 -197
  3. package/package.json +1 -3
  4. package/bin/nax.ts +0 -1195
  5. package/src/acceptance/fix-generator.ts +0 -322
  6. package/src/acceptance/generator.ts +0 -415
  7. package/src/acceptance/index.ts +0 -42
  8. package/src/acceptance/refinement.ts +0 -224
  9. package/src/acceptance/templates/cli.ts +0 -47
  10. package/src/acceptance/templates/component.ts +0 -78
  11. package/src/acceptance/templates/e2e.ts +0 -43
  12. package/src/acceptance/templates/index.ts +0 -21
  13. package/src/acceptance/templates/snapshot.ts +0 -50
  14. package/src/acceptance/templates/unit.ts +0 -48
  15. package/src/acceptance/types.ts +0 -138
  16. package/src/agents/acp/adapter.ts +0 -888
  17. package/src/agents/acp/cost.ts +0 -9
  18. package/src/agents/acp/index.ts +0 -7
  19. package/src/agents/acp/interaction-bridge.ts +0 -126
  20. package/src/agents/acp/parser.ts +0 -119
  21. package/src/agents/acp/spawn-client.ts +0 -373
  22. package/src/agents/acp/types.ts +0 -22
  23. package/src/agents/aider/adapter.ts +0 -135
  24. package/src/agents/claude/adapter.ts +0 -258
  25. package/src/agents/claude/complete.ts +0 -80
  26. package/src/agents/claude/cost.ts +0 -16
  27. package/src/agents/claude/execution.ts +0 -215
  28. package/src/agents/claude/index.ts +0 -3
  29. package/src/agents/claude/interactive.ts +0 -77
  30. package/src/agents/claude/plan.ts +0 -179
  31. package/src/agents/codex/adapter.ts +0 -153
  32. package/src/agents/cost/calculate.ts +0 -154
  33. package/src/agents/cost/index.ts +0 -10
  34. package/src/agents/cost/parse.ts +0 -97
  35. package/src/agents/cost/pricing.ts +0 -59
  36. package/src/agents/cost/types.ts +0 -45
  37. package/src/agents/gemini/adapter.ts +0 -177
  38. package/src/agents/index.ts +0 -18
  39. package/src/agents/opencode/adapter.ts +0 -106
  40. package/src/agents/registry.ts +0 -136
  41. package/src/agents/shared/decompose.ts +0 -154
  42. package/src/agents/shared/model-resolution.ts +0 -43
  43. package/src/agents/shared/types-extended.ts +0 -164
  44. package/src/agents/shared/validation.ts +0 -69
  45. package/src/agents/shared/version-detection.ts +0 -109
  46. package/src/agents/types.ts +0 -205
  47. package/src/analyze/classifier.ts +0 -282
  48. package/src/analyze/index.ts +0 -16
  49. package/src/analyze/scanner.ts +0 -171
  50. package/src/analyze/types.ts +0 -51
  51. package/src/cli/accept.ts +0 -108
  52. package/src/cli/agents.ts +0 -87
  53. package/src/cli/analyze-parser.ts +0 -291
  54. package/src/cli/analyze.ts +0 -352
  55. package/src/cli/config-descriptions.ts +0 -219
  56. package/src/cli/config-diff.ts +0 -103
  57. package/src/cli/config-display.ts +0 -285
  58. package/src/cli/config-get.ts +0 -55
  59. package/src/cli/config.ts +0 -14
  60. package/src/cli/constitution.ts +0 -17
  61. package/src/cli/diagnose-analysis.ts +0 -159
  62. package/src/cli/diagnose-formatter.ts +0 -87
  63. package/src/cli/diagnose.ts +0 -203
  64. package/src/cli/generate.ts +0 -250
  65. package/src/cli/index.ts +0 -42
  66. package/src/cli/init-context.ts +0 -405
  67. package/src/cli/init-detect.ts +0 -303
  68. package/src/cli/init.ts +0 -296
  69. package/src/cli/interact.ts +0 -295
  70. package/src/cli/plan.ts +0 -509
  71. package/src/cli/plugins.ts +0 -122
  72. package/src/cli/prompts-export.ts +0 -58
  73. package/src/cli/prompts-init.ts +0 -200
  74. package/src/cli/prompts-main.ts +0 -183
  75. package/src/cli/prompts-shared.ts +0 -70
  76. package/src/cli/prompts-tdd.ts +0 -88
  77. package/src/cli/prompts.ts +0 -17
  78. package/src/cli/runs.ts +0 -174
  79. package/src/cli/status-cost.ts +0 -151
  80. package/src/cli/status-features.ts +0 -405
  81. package/src/cli/status.ts +0 -13
  82. package/src/commands/common.ts +0 -171
  83. package/src/commands/diagnose.ts +0 -17
  84. package/src/commands/index.ts +0 -9
  85. package/src/commands/logs-formatter.ts +0 -201
  86. package/src/commands/logs-reader.ts +0 -171
  87. package/src/commands/logs.ts +0 -103
  88. package/src/commands/precheck.ts +0 -86
  89. package/src/commands/runs.ts +0 -220
  90. package/src/commands/unlock.ts +0 -96
  91. package/src/config/defaults.ts +0 -218
  92. package/src/config/index.ts +0 -22
  93. package/src/config/loader.ts +0 -143
  94. package/src/config/merge.ts +0 -106
  95. package/src/config/merger.ts +0 -147
  96. package/src/config/path-security.ts +0 -121
  97. package/src/config/paths.ts +0 -27
  98. package/src/config/permissions.ts +0 -63
  99. package/src/config/runtime-types.ts +0 -522
  100. package/src/config/schema-types.ts +0 -53
  101. package/src/config/schema.ts +0 -60
  102. package/src/config/schemas.ts +0 -426
  103. package/src/config/test-strategy.ts +0 -71
  104. package/src/config/types.ts +0 -57
  105. package/src/config/validate.ts +0 -103
  106. package/src/constitution/generator.ts +0 -158
  107. package/src/constitution/generators/aider.ts +0 -41
  108. package/src/constitution/generators/claude.ts +0 -35
  109. package/src/constitution/generators/cursor.ts +0 -36
  110. package/src/constitution/generators/opencode.ts +0 -38
  111. package/src/constitution/generators/types.ts +0 -33
  112. package/src/constitution/generators/windsurf.ts +0 -36
  113. package/src/constitution/index.ts +0 -11
  114. package/src/constitution/loader.ts +0 -121
  115. package/src/constitution/types.ts +0 -31
  116. package/src/context/auto-detect.ts +0 -228
  117. package/src/context/builder.ts +0 -299
  118. package/src/context/elements.ts +0 -122
  119. package/src/context/formatter.ts +0 -107
  120. package/src/context/generator.ts +0 -343
  121. package/src/context/generators/aider.ts +0 -34
  122. package/src/context/generators/claude.ts +0 -28
  123. package/src/context/generators/codex.ts +0 -28
  124. package/src/context/generators/cursor.ts +0 -28
  125. package/src/context/generators/gemini.ts +0 -28
  126. package/src/context/generators/opencode.ts +0 -30
  127. package/src/context/generators/windsurf.ts +0 -28
  128. package/src/context/greenfield.ts +0 -114
  129. package/src/context/index.ts +0 -34
  130. package/src/context/injector.ts +0 -279
  131. package/src/context/parent-context.ts +0 -39
  132. package/src/context/test-scanner.ts +0 -370
  133. package/src/context/types.ts +0 -98
  134. package/src/decompose/apply.ts +0 -50
  135. package/src/decompose/builder.ts +0 -181
  136. package/src/decompose/index.ts +0 -8
  137. package/src/decompose/sections/codebase.ts +0 -26
  138. package/src/decompose/sections/constraints.ts +0 -32
  139. package/src/decompose/sections/index.ts +0 -4
  140. package/src/decompose/sections/sibling-stories.ts +0 -25
  141. package/src/decompose/sections/target-story.ts +0 -31
  142. package/src/decompose/types.ts +0 -55
  143. package/src/decompose/validators/complexity.ts +0 -45
  144. package/src/decompose/validators/coverage.ts +0 -134
  145. package/src/decompose/validators/dependency.ts +0 -91
  146. package/src/decompose/validators/index.ts +0 -35
  147. package/src/decompose/validators/overlap.ts +0 -128
  148. package/src/errors.ts +0 -67
  149. package/src/execution/batching.ts +0 -157
  150. package/src/execution/crash-heartbeat.ts +0 -77
  151. package/src/execution/crash-recovery.ts +0 -79
  152. package/src/execution/crash-signals.ts +0 -165
  153. package/src/execution/crash-writer.ts +0 -154
  154. package/src/execution/deferred-review.ts +0 -105
  155. package/src/execution/dry-run.ts +0 -81
  156. package/src/execution/escalation/escalation.ts +0 -46
  157. package/src/execution/escalation/index.ts +0 -13
  158. package/src/execution/escalation/tier-escalation.ts +0 -346
  159. package/src/execution/escalation/tier-outcome.ts +0 -143
  160. package/src/execution/executor-types.ts +0 -73
  161. package/src/execution/helpers.ts +0 -38
  162. package/src/execution/index.ts +0 -27
  163. package/src/execution/iteration-runner.ts +0 -160
  164. package/src/execution/lifecycle/acceptance-loop.ts +0 -309
  165. package/src/execution/lifecycle/headless-formatter.ts +0 -83
  166. package/src/execution/lifecycle/index.ts +0 -11
  167. package/src/execution/lifecycle/parallel-lifecycle.ts +0 -101
  168. package/src/execution/lifecycle/precheck-runner.ts +0 -140
  169. package/src/execution/lifecycle/run-cleanup.ts +0 -81
  170. package/src/execution/lifecycle/run-completion.ts +0 -247
  171. package/src/execution/lifecycle/run-initialization.ts +0 -187
  172. package/src/execution/lifecycle/run-regression.ts +0 -305
  173. package/src/execution/lifecycle/run-setup.ts +0 -240
  174. package/src/execution/lifecycle/story-size-prompts.ts +0 -123
  175. package/src/execution/lock.ts +0 -129
  176. package/src/execution/parallel-coordinator.ts +0 -281
  177. package/src/execution/parallel-executor-rectification-pass.ts +0 -117
  178. package/src/execution/parallel-executor-rectify.ts +0 -136
  179. package/src/execution/parallel-executor.ts +0 -330
  180. package/src/execution/parallel-worker.ts +0 -149
  181. package/src/execution/parallel.ts +0 -13
  182. package/src/execution/pid-registry.ts +0 -275
  183. package/src/execution/pipeline-result-handler.ts +0 -221
  184. package/src/execution/progress.ts +0 -27
  185. package/src/execution/queue-handler.ts +0 -109
  186. package/src/execution/runner-completion.ts +0 -171
  187. package/src/execution/runner-execution.ts +0 -243
  188. package/src/execution/runner-setup.ts +0 -86
  189. package/src/execution/runner.ts +0 -265
  190. package/src/execution/sequential-executor.ts +0 -219
  191. package/src/execution/status-file.ts +0 -264
  192. package/src/execution/status-writer.ts +0 -181
  193. package/src/execution/story-context.ts +0 -266
  194. package/src/execution/story-selector.ts +0 -76
  195. package/src/execution/test-output-parser.ts +0 -14
  196. package/src/execution/timeout-handler.ts +0 -100
  197. package/src/hooks/index.ts +0 -2
  198. package/src/hooks/runner.ts +0 -280
  199. package/src/hooks/types.ts +0 -79
  200. package/src/interaction/chain.ts +0 -170
  201. package/src/interaction/index.ts +0 -61
  202. package/src/interaction/init.ts +0 -84
  203. package/src/interaction/plugins/auto.ts +0 -243
  204. package/src/interaction/plugins/cli.ts +0 -300
  205. package/src/interaction/plugins/telegram.ts +0 -384
  206. package/src/interaction/plugins/webhook.ts +0 -286
  207. package/src/interaction/state.ts +0 -171
  208. package/src/interaction/triggers.ts +0 -250
  209. package/src/interaction/types.ts +0 -170
  210. package/src/logger/formatters.ts +0 -84
  211. package/src/logger/index.ts +0 -16
  212. package/src/logger/logger.ts +0 -296
  213. package/src/logger/types.ts +0 -48
  214. package/src/logging/formatter.ts +0 -355
  215. package/src/logging/index.ts +0 -22
  216. package/src/logging/types.ts +0 -93
  217. package/src/metrics/aggregator.ts +0 -191
  218. package/src/metrics/index.ts +0 -14
  219. package/src/metrics/tracker.ts +0 -200
  220. package/src/metrics/types.ts +0 -115
  221. package/src/optimizer/index.ts +0 -63
  222. package/src/optimizer/noop.optimizer.ts +0 -24
  223. package/src/optimizer/rule-based.optimizer.ts +0 -248
  224. package/src/optimizer/types.ts +0 -53
  225. package/src/pipeline/event-bus.ts +0 -297
  226. package/src/pipeline/events.ts +0 -130
  227. package/src/pipeline/index.ts +0 -19
  228. package/src/pipeline/runner.ts +0 -149
  229. package/src/pipeline/stages/acceptance-setup.ts +0 -144
  230. package/src/pipeline/stages/acceptance.ts +0 -215
  231. package/src/pipeline/stages/autofix.ts +0 -262
  232. package/src/pipeline/stages/completion.ts +0 -110
  233. package/src/pipeline/stages/constitution.ts +0 -63
  234. package/src/pipeline/stages/context.ts +0 -122
  235. package/src/pipeline/stages/execution.ts +0 -359
  236. package/src/pipeline/stages/index.ts +0 -86
  237. package/src/pipeline/stages/optimizer.ts +0 -74
  238. package/src/pipeline/stages/prompt.ts +0 -79
  239. package/src/pipeline/stages/queue-check.ts +0 -103
  240. package/src/pipeline/stages/rectify.ts +0 -101
  241. package/src/pipeline/stages/regression.ts +0 -99
  242. package/src/pipeline/stages/review.ts +0 -94
  243. package/src/pipeline/stages/routing.ts +0 -276
  244. package/src/pipeline/stages/verify.ts +0 -286
  245. package/src/pipeline/subscribers/events-writer.ts +0 -135
  246. package/src/pipeline/subscribers/hooks.ts +0 -179
  247. package/src/pipeline/subscribers/interaction.ts +0 -103
  248. package/src/pipeline/subscribers/registry.ts +0 -73
  249. package/src/pipeline/subscribers/reporters.ts +0 -174
  250. package/src/pipeline/types.ts +0 -220
  251. package/src/plugins/extensions.ts +0 -225
  252. package/src/plugins/index.ts +0 -33
  253. package/src/plugins/loader.ts +0 -352
  254. package/src/plugins/plugin-logger.ts +0 -41
  255. package/src/plugins/registry.ts +0 -168
  256. package/src/plugins/types.ts +0 -206
  257. package/src/plugins/validator.ts +0 -352
  258. package/src/prd/index.ts +0 -220
  259. package/src/prd/schema.ts +0 -268
  260. package/src/prd/types.ts +0 -273
  261. package/src/prd/validate.ts +0 -41
  262. package/src/precheck/checks-agents.ts +0 -63
  263. package/src/precheck/checks-blockers.ts +0 -23
  264. package/src/precheck/checks-cli.ts +0 -68
  265. package/src/precheck/checks-config.ts +0 -102
  266. package/src/precheck/checks-git.ts +0 -117
  267. package/src/precheck/checks-system.ts +0 -101
  268. package/src/precheck/checks-warnings.ts +0 -221
  269. package/src/precheck/checks.ts +0 -36
  270. package/src/precheck/index.ts +0 -374
  271. package/src/precheck/story-size-gate.ts +0 -144
  272. package/src/precheck/types.ts +0 -31
  273. package/src/prompts/builder.ts +0 -166
  274. package/src/prompts/index.ts +0 -2
  275. package/src/prompts/loader.ts +0 -43
  276. package/src/prompts/sections/conventions.ts +0 -19
  277. package/src/prompts/sections/hermetic.ts +0 -41
  278. package/src/prompts/sections/index.ts +0 -12
  279. package/src/prompts/sections/isolation.ts +0 -70
  280. package/src/prompts/sections/role-task.ts +0 -182
  281. package/src/prompts/sections/story.ts +0 -55
  282. package/src/prompts/sections/verdict.ts +0 -70
  283. package/src/prompts/types.ts +0 -21
  284. package/src/queue/index.ts +0 -2
  285. package/src/queue/manager.ts +0 -254
  286. package/src/queue/types.ts +0 -54
  287. package/src/review/index.ts +0 -8
  288. package/src/review/orchestrator.ts +0 -154
  289. package/src/review/runner.ts +0 -303
  290. package/src/review/types.ts +0 -70
  291. package/src/routing/batch-route.ts +0 -35
  292. package/src/routing/builder.ts +0 -81
  293. package/src/routing/chain.ts +0 -75
  294. package/src/routing/content-hash.ts +0 -25
  295. package/src/routing/index.ts +0 -20
  296. package/src/routing/loader.ts +0 -62
  297. package/src/routing/router.ts +0 -305
  298. package/src/routing/strategies/adaptive.ts +0 -215
  299. package/src/routing/strategies/index.ts +0 -8
  300. package/src/routing/strategies/keyword.ts +0 -180
  301. package/src/routing/strategies/llm-prompts.ts +0 -224
  302. package/src/routing/strategies/llm.ts +0 -320
  303. package/src/routing/strategies/manual.ts +0 -50
  304. package/src/routing/strategy.ts +0 -102
  305. package/src/tdd/cleanup.ts +0 -120
  306. package/src/tdd/index.ts +0 -22
  307. package/src/tdd/isolation.ts +0 -117
  308. package/src/tdd/orchestrator.ts +0 -406
  309. package/src/tdd/prompts.ts +0 -40
  310. package/src/tdd/rectification-gate.ts +0 -274
  311. package/src/tdd/session-runner.ts +0 -263
  312. package/src/tdd/types.ts +0 -84
  313. package/src/tdd/verdict-reader.ts +0 -266
  314. package/src/tdd/verdict.ts +0 -152
  315. package/src/tui/App.tsx +0 -265
  316. package/src/tui/components/AgentPanel.tsx +0 -75
  317. package/src/tui/components/CostOverlay.tsx +0 -118
  318. package/src/tui/components/HelpOverlay.tsx +0 -107
  319. package/src/tui/components/StatusBar.tsx +0 -63
  320. package/src/tui/components/StoriesPanel.tsx +0 -177
  321. package/src/tui/hooks/useKeyboard.ts +0 -142
  322. package/src/tui/hooks/useLayout.ts +0 -137
  323. package/src/tui/hooks/usePipelineEvents.ts +0 -183
  324. package/src/tui/hooks/usePty.ts +0 -189
  325. package/src/tui/index.tsx +0 -38
  326. package/src/tui/types.ts +0 -76
  327. package/src/utils/errors.ts +0 -12
  328. package/src/utils/git.ts +0 -245
  329. package/src/utils/json-file.ts +0 -72
  330. package/src/utils/log-test-output.ts +0 -25
  331. package/src/utils/path-security.ts +0 -73
  332. package/src/utils/queue-writer.ts +0 -54
  333. package/src/verification/crash-detector.ts +0 -34
  334. package/src/verification/executor.ts +0 -250
  335. package/src/verification/index.ts +0 -12
  336. package/src/verification/orchestrator-types.ts +0 -154
  337. package/src/verification/orchestrator.ts +0 -76
  338. package/src/verification/parser.ts +0 -220
  339. package/src/verification/rectification-loop.ts +0 -172
  340. package/src/verification/rectification.ts +0 -108
  341. package/src/verification/runners.ts +0 -129
  342. package/src/verification/smart-runner.ts +0 -307
  343. package/src/verification/strategies/acceptance.ts +0 -136
  344. package/src/verification/strategies/regression.ts +0 -90
  345. package/src/verification/strategies/scoped.ts +0 -154
  346. package/src/verification/types.ts +0 -117
  347. package/src/version.ts +0 -40
  348. package/src/worktree/dispatcher.ts +0 -6
  349. package/src/worktree/index.ts +0 -2
  350. package/src/worktree/manager.ts +0 -193
  351. package/src/worktree/merge.ts +0 -302
  352. package/src/worktree/types.ts +0 -4
@@ -1,405 +0,0 @@
1
- /**
2
- * Status Feature Display
3
- *
4
- * Extracted from status.ts: feature status display (all-features table and single-feature details).
5
- */
6
-
7
- import { existsSync, readdirSync } from "node:fs";
8
- import { join } from "node:path";
9
- import chalk from "chalk";
10
- import { resolveProject } from "../commands/common";
11
- import type { NaxStatusFile } from "../execution/status-file";
12
- import { listPendingInteractions, loadPendingInteraction } from "../interaction";
13
- import { countStories, loadPRD } from "../prd";
14
-
15
- /** Options for feature status command */
16
- export interface FeatureStatusOptions {
17
- /** Feature name (from -f flag) */
18
- feature?: string;
19
- /** Explicit project directory (from -d flag) */
20
- dir?: string;
21
- }
22
-
23
- /** Feature summary for the all-features table */
24
- interface FeatureSummary {
25
- name: string;
26
- done: number;
27
- failed: number;
28
- pending: number;
29
- total: number;
30
- lastRun?: string;
31
- cost?: number;
32
- activeRun?: {
33
- runId: string;
34
- pid: number;
35
- startedAt: string;
36
- };
37
- crashedRun?: {
38
- runId: string;
39
- pid: number;
40
- crashedAt?: string;
41
- };
42
- }
43
-
44
- /** Check if a process is alive via POSIX signal 0 (portable, no subprocess) */
45
- function isPidAlive(pid: number): boolean {
46
- try {
47
- process.kill(pid, 0);
48
- return true;
49
- } catch {
50
- return false;
51
- }
52
- }
53
-
54
- /** Load status.json for a feature (if it exists) */
55
- async function loadStatusFile(featureDir: string): Promise<NaxStatusFile | null> {
56
- const statusPath = join(featureDir, "status.json");
57
- if (!existsSync(statusPath)) {
58
- return null;
59
- }
60
-
61
- try {
62
- const content = Bun.file(statusPath);
63
- return (await content.json()) as NaxStatusFile;
64
- } catch {
65
- return null;
66
- }
67
- }
68
-
69
- /** Load project-level status.json (if it exists) */
70
- async function loadProjectStatusFile(projectDir: string): Promise<NaxStatusFile | null> {
71
- const statusPath = join(projectDir, "nax", "status.json");
72
- if (!existsSync(statusPath)) {
73
- return null;
74
- }
75
-
76
- try {
77
- const content = Bun.file(statusPath);
78
- return (await content.json()) as NaxStatusFile;
79
- } catch {
80
- return null;
81
- }
82
- }
83
-
84
- /** Get feature summary from prd.json and optional status.json */
85
- async function getFeatureSummary(featureName: string, featureDir: string): Promise<FeatureSummary> {
86
- const prdPath = join(featureDir, "prd.json");
87
-
88
- // Guard: prd.json may not exist (e.g. plan failed before writing it)
89
- if (!existsSync(prdPath)) {
90
- return {
91
- name: featureName,
92
- done: 0,
93
- failed: 0,
94
- pending: 0,
95
- total: 0,
96
- };
97
- }
98
-
99
- // Load PRD for story counts
100
- const prd = await loadPRD(prdPath);
101
- const counts = countStories(prd);
102
-
103
- const summary: FeatureSummary = {
104
- name: featureName,
105
- done: counts.passed,
106
- failed: counts.failed,
107
- pending: counts.pending,
108
- total: counts.total,
109
- };
110
-
111
- // Load status.json if available
112
- const status = await loadStatusFile(featureDir);
113
- if (status) {
114
- summary.cost = status.cost.spent;
115
-
116
- // Check if run is active or crashed
117
- const pidAlive = isPidAlive(status.run.pid);
118
-
119
- if (status.run.status === "running" && pidAlive) {
120
- summary.activeRun = {
121
- runId: status.run.id,
122
- pid: status.run.pid,
123
- startedAt: status.run.startedAt,
124
- };
125
- } else if (status.run.status === "running" && !pidAlive) {
126
- // Run is marked "running" but PID is dead — crashed
127
- summary.crashedRun = {
128
- runId: status.run.id,
129
- pid: status.run.pid,
130
- crashedAt: status.run.crashedAt,
131
- };
132
- } else if (status.run.status === "crashed") {
133
- // Run explicitly marked as crashed
134
- summary.crashedRun = {
135
- runId: status.run.id,
136
- pid: status.run.pid,
137
- crashedAt: status.run.crashedAt,
138
- };
139
- }
140
- }
141
-
142
- // Get last run timestamp from runs/ directory
143
- const runsDir = join(featureDir, "runs");
144
- if (existsSync(runsDir)) {
145
- const runs = readdirSync(runsDir, { withFileTypes: true })
146
- .filter((e) => e.isFile() && e.name.endsWith(".jsonl") && e.name !== "latest.jsonl")
147
- .map((e) => e.name)
148
- .sort()
149
- .reverse();
150
-
151
- if (runs.length > 0) {
152
- // Extract timestamp from filename (YYYY-MM-DDTHH-MM-SS.jsonl)
153
- const latestRun = runs[0].replace(".jsonl", "");
154
- summary.lastRun = latestRun;
155
- }
156
- }
157
-
158
- return summary;
159
- }
160
-
161
- /** Display all features table */
162
- async function displayAllFeatures(projectDir: string): Promise<void> {
163
- const featuresDir = join(projectDir, "nax", "features");
164
-
165
- if (!existsSync(featuresDir)) {
166
- console.log(chalk.dim("No features found."));
167
- return;
168
- }
169
-
170
- const features = readdirSync(featuresDir, { withFileTypes: true })
171
- .filter((e) => e.isDirectory())
172
- .map((e) => e.name)
173
- .sort();
174
-
175
- if (features.length === 0) {
176
- console.log(chalk.dim("No features found."));
177
- return;
178
- }
179
-
180
- // Load project-level status if available (current run info)
181
- const projectStatus = await loadProjectStatusFile(projectDir);
182
-
183
- // Display current run info if available
184
- if (projectStatus) {
185
- const pidAlive = isPidAlive(projectStatus.run.pid);
186
-
187
- if (projectStatus.run.status === "running" && pidAlive) {
188
- console.log(chalk.yellow("⚡ Currently Running:\n"));
189
- console.log(chalk.dim(` Feature: ${projectStatus.run.feature}`));
190
- console.log(chalk.dim(` Run ID: ${projectStatus.run.id}`));
191
- console.log(chalk.dim(` Started: ${projectStatus.run.startedAt}`));
192
- console.log(chalk.dim(` Progress: ${projectStatus.progress.passed}/${projectStatus.progress.total} stories`));
193
- console.log(chalk.dim(` Cost: $${projectStatus.cost.spent.toFixed(4)}`));
194
-
195
- if (projectStatus.current) {
196
- console.log(chalk.dim(` Current: ${projectStatus.current.storyId} - ${projectStatus.current.title}`));
197
- }
198
-
199
- console.log();
200
- } else if ((projectStatus.run.status === "running" && !pidAlive) || projectStatus.run.status === "crashed") {
201
- console.log(chalk.red("💥 Crashed Run Detected:\n"));
202
- console.log(chalk.dim(` Feature: ${projectStatus.run.feature}`));
203
- console.log(chalk.dim(` Run ID: ${projectStatus.run.id}`));
204
- console.log(chalk.dim(` PID: ${projectStatus.run.pid} (dead)`));
205
- console.log(chalk.dim(` Started: ${projectStatus.run.startedAt}`));
206
- if (projectStatus.run.crashedAt) {
207
- console.log(chalk.dim(` Crashed: ${projectStatus.run.crashedAt}`));
208
- }
209
- if (projectStatus.run.crashSignal) {
210
- console.log(chalk.dim(` Signal: ${projectStatus.run.crashSignal}`));
211
- }
212
- console.log();
213
- }
214
- }
215
-
216
- // Load summaries for all features
217
- const summaries = await Promise.all(features.map((name) => getFeatureSummary(name, join(featuresDir, name))));
218
-
219
- console.log(chalk.bold("📊 Features\n"));
220
-
221
- // Print table header
222
- const header = ` ${"Feature".padEnd(25)} ${"Done".padEnd(6)} ${"Failed".padEnd(8)} ${"Pending".padEnd(9)} ${"Last Run".padEnd(22)} ${"Cost".padEnd(10)} Status`;
223
- console.log(chalk.dim(header));
224
- console.log(chalk.dim(` ${"─".repeat(100)}`));
225
-
226
- // Print each feature row
227
- for (const summary of summaries) {
228
- const name = summary.name.padEnd(25);
229
- const done = chalk.green(String(summary.done).padEnd(6));
230
- const failed =
231
- summary.failed > 0 ? chalk.red(String(summary.failed).padEnd(8)) : chalk.dim(String(summary.failed).padEnd(8));
232
- const pending = chalk.dim(String(summary.pending).padEnd(9));
233
- const lastRun = summary.lastRun ? summary.lastRun.padEnd(22) : chalk.dim("No runs yet".padEnd(22));
234
- const cost = summary.cost !== undefined ? `$${summary.cost.toFixed(4)}`.padEnd(10) : chalk.dim("—".padEnd(10));
235
-
236
- let status = "";
237
- if (summary.activeRun) {
238
- status = chalk.yellow("⚡ Running");
239
- } else if (summary.crashedRun) {
240
- status = chalk.red("💥 Crashed");
241
- } else {
242
- status = chalk.dim("—");
243
- }
244
-
245
- console.log(` ${name} ${done} ${failed} ${pending} ${lastRun} ${cost} ${status}`);
246
- }
247
-
248
- console.log();
249
- }
250
-
251
- /** Display single feature details */
252
- async function displayFeatureDetails(featureName: string, featureDir: string): Promise<void> {
253
- const prdPath = join(featureDir, "prd.json");
254
-
255
- // Guard: prd.json may not exist (e.g. plan failed or feature just created)
256
- if (!existsSync(prdPath)) {
257
- console.log(chalk.bold(`\n📊 ${featureName}\n`));
258
- console.log(chalk.dim(`No prd.json found. Run: nax plan -f ${featureName} --from <spec>`));
259
- return;
260
- }
261
-
262
- const prd = await loadPRD(prdPath);
263
- const counts = countStories(prd);
264
-
265
- // Load status.json if available
266
- const status = await loadStatusFile(featureDir);
267
-
268
- console.log(chalk.bold(`\n📊 ${prd.feature}\n`));
269
-
270
- // Check for pending interactions
271
- const pendingIds = await listPendingInteractions(featureDir);
272
- if (pendingIds.length > 0) {
273
- console.log(chalk.cyan(`⏸️ Paused — Waiting for Interaction (${pendingIds.length} pending)\n`));
274
-
275
- for (const id of pendingIds) {
276
- const req = await loadPendingInteraction(id, featureDir);
277
- if (req) {
278
- const safety = req.metadata?.safety ?? "unknown";
279
- const safetyIcon = safety === "red" ? "🔴" : safety === "yellow" ? "🟡" : "🟢";
280
- const timeRemaining = req.timeout ? Math.max(0, req.createdAt + req.timeout - Date.now()) : null;
281
- const timeoutSec = timeRemaining !== null ? Math.floor(timeRemaining / 1000) : null;
282
-
283
- console.log(` ${safetyIcon} ${chalk.bold(req.id)}`);
284
- console.log(chalk.dim(` Type: ${req.type}`));
285
- console.log(chalk.dim(` Summary: ${req.summary}`));
286
- console.log(chalk.dim(` Fallback: ${req.fallback}`));
287
- if (timeoutSec !== null) {
288
- if (timeoutSec > 0) {
289
- console.log(chalk.dim(` Timeout: ${timeoutSec}s remaining`));
290
- } else {
291
- console.log(chalk.red(" Timeout: EXPIRED"));
292
- }
293
- }
294
- console.log();
295
- }
296
- }
297
-
298
- console.log(chalk.dim(" 💡 Respond with: nax interact respond <id> --action approve|reject|skip|abort"));
299
- console.log();
300
- }
301
-
302
- // Display run status if active or crashed
303
- if (status) {
304
- const pidAlive = isPidAlive(status.run.pid);
305
-
306
- if (status.run.status === "running" && pidAlive) {
307
- console.log(chalk.yellow("⚡ Active Run:"));
308
- console.log(chalk.dim(` Run ID: ${status.run.id}`));
309
- console.log(chalk.dim(` PID: ${status.run.pid}`));
310
- console.log(chalk.dim(` Started: ${status.run.startedAt}`));
311
- console.log(chalk.dim(` Progress: ${status.progress.passed}/${status.progress.total} stories`));
312
- console.log(chalk.dim(` Cost: $${status.cost.spent.toFixed(4)}`));
313
-
314
- if (status.current) {
315
- console.log(chalk.dim(` Current: ${status.current.storyId} - ${status.current.title}`));
316
- }
317
-
318
- console.log();
319
- } else if ((status.run.status === "running" && !pidAlive) || status.run.status === "crashed") {
320
- console.log(chalk.red("💥 Crashed Run Detected:\n"));
321
- console.log(chalk.dim(` Run ID: ${status.run.id}`));
322
- console.log(chalk.dim(` PID: ${status.run.pid} (dead)`));
323
- console.log(chalk.dim(` Started: ${status.run.startedAt}`));
324
- if (status.run.crashedAt) {
325
- console.log(chalk.dim(` Crashed: ${status.run.crashedAt}`));
326
- }
327
- if (status.run.crashSignal) {
328
- console.log(chalk.dim(` Signal: ${status.run.crashSignal}`));
329
- }
330
- console.log(chalk.dim(` Progress: ${status.progress.passed}/${status.progress.total} stories (at crash)`));
331
- console.log();
332
- console.log(chalk.yellow("💡 Recovery Hints:"));
333
- console.log(chalk.dim(" • Check the latest run log in runs/ directory"));
334
- console.log(chalk.dim(" • Review status.json for last known state"));
335
- console.log(chalk.dim(` • Re-run with: nax run -f ${featureName}`));
336
- console.log();
337
- }
338
- } else {
339
- console.log(chalk.dim("No active run (status.json not found)\n"));
340
- }
341
-
342
- // Display story counts
343
- console.log(chalk.bold("Progress:"));
344
- console.log(chalk.dim(` Branch: ${prd.branchName}`));
345
- console.log(chalk.dim(` Updated: ${prd.updatedAt}`));
346
- console.log(chalk.dim(` Total: ${counts.total}`));
347
- console.log(chalk.green(` Passed: ${counts.passed}`));
348
- console.log(chalk.red(` Failed: ${counts.failed}`));
349
- console.log(chalk.dim(` Pending: ${counts.pending}`));
350
- if (counts.skipped > 0) {
351
- console.log(chalk.yellow(` Skipped: ${counts.skipped}`));
352
- }
353
- console.log();
354
-
355
- // Display story table
356
- console.log(chalk.bold("Stories:\n"));
357
- for (const story of prd.userStories) {
358
- const icon = story.passes ? "✅" : story.status === "failed" ? "❌" : story.status === "skipped" ? "⏭️" : "⬜";
359
- const routing = story.routing
360
- ? chalk.dim(` [${story.routing.complexity}/${story.routing.modelTier}/${story.routing.testStrategy}]`)
361
- : "";
362
- console.log(` ${icon} ${story.id}: ${story.title}${routing}`);
363
- }
364
-
365
- console.log();
366
-
367
- // Display last run info if completed
368
- if (status && status.run.status !== "running") {
369
- console.log(chalk.dim(`Last run: ${status.run.id}`));
370
- console.log(chalk.dim(`Cost: $${status.cost.spent.toFixed(4)}`));
371
- console.log();
372
- }
373
- }
374
-
375
- /**
376
- * Display feature status (all features table or single feature details)
377
- *
378
- * @param options - Command options
379
- *
380
- * @example
381
- * ```bash
382
- * # Show all features
383
- * nax status
384
- *
385
- * # Show single feature details
386
- * nax status -f structured-logging
387
- * ```
388
- */
389
- export async function displayFeatureStatus(options: FeatureStatusOptions = {}): Promise<void> {
390
- const resolved = resolveProject({
391
- dir: options.dir,
392
- feature: options.feature,
393
- });
394
-
395
- if (options.feature) {
396
- // Single feature view
397
- if (!resolved.featureDir) {
398
- throw new Error("Feature directory not resolved (this should not happen)");
399
- }
400
- await displayFeatureDetails(options.feature, resolved.featureDir);
401
- } else {
402
- // All features table
403
- await displayAllFeatures(resolved.projectDir);
404
- }
405
- }
package/src/cli/status.ts DELETED
@@ -1,13 +0,0 @@
1
- /**
2
- * Status CLI Command
3
- *
4
- * Re-export barrel for backward compatibility.
5
- * Cost metrics: ./status-cost
6
- * Feature display: ./status-features
7
- */
8
-
9
- // Cost metrics
10
- export { displayCostMetrics, displayLastRunMetrics, displayModelEfficiency } from "./status-cost";
11
-
12
- // Feature display
13
- export { displayFeatureStatus, type FeatureStatusOptions } from "./status-features";
@@ -1,171 +0,0 @@
1
- /**
2
- * Common utilities for CLI commands
3
- *
4
- * Provides project resolution logic shared across status, logs, and other commands.
5
- */
6
-
7
- import { existsSync, readdirSync, realpathSync } from "node:fs";
8
- import { join, resolve } from "node:path";
9
- import { MAX_DIRECTORY_DEPTH } from "../config/path-security";
10
- import { NaxError } from "../errors";
11
-
12
- /**
13
- * Options for project resolution
14
- */
15
- export interface ResolveProjectOptions {
16
- /** Explicit project directory (from -d flag) */
17
- dir?: string;
18
- /** Feature name (from -f flag) */
19
- feature?: string;
20
- }
21
-
22
- /**
23
- * Resolved project paths
24
- */
25
- export interface ResolvedProject {
26
- /** Absolute path to project root directory */
27
- projectDir: string;
28
- /** Absolute path to nax config file */
29
- configPath: string;
30
- /** Absolute path to feature directory (if feature specified) */
31
- featureDir?: string;
32
- }
33
-
34
- /**
35
- * Resolves project directory using the following priority:
36
- * 1. Explicit -d flag path
37
- * 2. Current working directory (if it contains nax/ directory)
38
- * 3. Walk up directory tree to find nax/ (up to MAX_DIRECTORY_DEPTH)
39
- *
40
- * Validates:
41
- * - nax/ directory exists
42
- * - nax/config.json exists
43
- * - nax/features/<name>/ exists (if feature specified)
44
- *
45
- * @param options - Resolution options (dir, feature)
46
- * @returns Resolved project paths
47
- * @throws {NaxError} If project cannot be resolved or validation fails
48
- */
49
- export function resolveProject(options: ResolveProjectOptions = {}): ResolvedProject {
50
- const { dir, feature } = options;
51
-
52
- // Step 1: Determine project root and validate structure
53
- let projectRoot: string;
54
- let naxDir: string;
55
- let configPath: string;
56
-
57
- if (dir) {
58
- // Use explicit -d flag path (resolve relative paths and symlinks)
59
- projectRoot = realpathSync(resolve(dir));
60
- naxDir = join(projectRoot, "nax");
61
-
62
- // Validate nax/ directory exists
63
- if (!existsSync(naxDir)) {
64
- throw new NaxError(
65
- `Directory does not contain a nax project: ${projectRoot}\nExpected to find: ${naxDir}`,
66
- "NAX_DIR_NOT_FOUND",
67
- { projectRoot, naxDir },
68
- );
69
- }
70
-
71
- // Validate nax/config.json exists
72
- configPath = join(naxDir, "config.json");
73
- if (!existsSync(configPath)) {
74
- throw new NaxError(
75
- `nax directory found but config.json is missing: ${naxDir}\nExpected to find: ${configPath}`,
76
- "CONFIG_NOT_FOUND",
77
- { naxDir, configPath },
78
- );
79
- }
80
- } else {
81
- // Walk up from CWD to find nax/ directory with config.json
82
- const found = findProjectRoot(process.cwd());
83
- if (!found) {
84
- // Check if CWD has nax/ but missing config.json (for better error message)
85
- const cwdNaxDir = join(process.cwd(), "nax");
86
- if (existsSync(cwdNaxDir)) {
87
- const cwdConfigPath = join(cwdNaxDir, "config.json");
88
- throw new NaxError(
89
- `nax directory found but config.json is missing: ${cwdNaxDir}\nExpected to find: ${cwdConfigPath}`,
90
- "CONFIG_NOT_FOUND",
91
- { naxDir: cwdNaxDir, configPath: cwdConfigPath },
92
- );
93
- }
94
-
95
- throw new NaxError(
96
- "No nax project found. Run this command from within a nax project directory, or use -d flag to specify the project path.",
97
- "PROJECT_NOT_FOUND",
98
- { cwd: process.cwd() },
99
- );
100
- }
101
- projectRoot = found;
102
- naxDir = join(projectRoot, "nax");
103
- configPath = join(naxDir, "config.json");
104
- }
105
-
106
- // Step 4: Validate feature directory (if specified)
107
- let featureDir: string | undefined;
108
- if (feature) {
109
- const featuresDir = join(naxDir, "features");
110
- featureDir = join(featuresDir, feature);
111
-
112
- if (!existsSync(featureDir)) {
113
- // List available features for helpful error message
114
- const availableFeatures = existsSync(featuresDir)
115
- ? readdirSync(featuresDir, { withFileTypes: true })
116
- .filter((entry) => entry.isDirectory())
117
- .map((entry) => entry.name)
118
- : [];
119
-
120
- const availableMsg =
121
- availableFeatures.length > 0
122
- ? `\n\nAvailable features:\n${availableFeatures.map((f) => ` - ${f}`).join("\n")}`
123
- : "\n\nNo features found in this project.";
124
-
125
- throw new NaxError(`Feature not found: ${feature}${availableMsg}`, "FEATURE_NOT_FOUND", {
126
- feature,
127
- featuresDir,
128
- availableFeatures,
129
- });
130
- }
131
- }
132
-
133
- return {
134
- projectDir: projectRoot,
135
- configPath,
136
- featureDir,
137
- };
138
- }
139
-
140
- /**
141
- * Walks up directory tree to find a nax/ directory with config.json.
142
- * Stops at filesystem root or MAX_DIRECTORY_DEPTH.
143
- *
144
- * @param startDir - Starting directory (typically CWD)
145
- * @returns Absolute path to project root (with symlinks resolved), or null if not found
146
- */
147
- function findProjectRoot(startDir: string): string | null {
148
- let current = resolve(startDir);
149
- let depth = 0;
150
-
151
- while (depth < MAX_DIRECTORY_DEPTH) {
152
- const naxDir = join(current, "nax");
153
- const configPath = join(naxDir, "config.json");
154
-
155
- if (existsSync(configPath)) {
156
- // Resolve symlinks for consistent path comparison
157
- return realpathSync(current);
158
- }
159
-
160
- const parent = join(current, "..");
161
- if (parent === current) {
162
- // Reached filesystem root
163
- break;
164
- }
165
-
166
- current = parent;
167
- depth++;
168
- }
169
-
170
- return null;
171
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * Diagnose command wrapper
3
- *
4
- * Thin commander.js wrapper for diagnose CLI command.
5
- */
6
-
7
- import { diagnoseCommand } from "../cli/diagnose";
8
- import type { DiagnoseOptions } from "../cli/diagnose";
9
-
10
- /**
11
- * Execute diagnose command with commander options
12
- *
13
- * @param options - Command options from commander
14
- */
15
- export async function diagnose(options: DiagnoseOptions): Promise<void> {
16
- await diagnoseCommand(options);
17
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Common utilities for CLI commands
3
- */
4
-
5
- export { resolveProject, type ResolveProjectOptions, type ResolvedProject } from "./common";
6
- export { logsCommand, type LogsOptions } from "./logs";
7
- export { precheckCommand, type PrecheckOptions } from "./precheck";
8
- export { runsCommand, type RunsOptions } from "./runs";
9
- export { unlockCommand, type UnlockOptions } from "./unlock";