@nathapp/nax 0.68.5 → 0.68.6

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 (2) hide show
  1. package/dist/nax.js +1070 -1204
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -18380,16 +18380,13 @@ function deepMergeConfig(base, override) {
18380
18380
  for (const hookName of allHookNames) {
18381
18381
  const baseHook = baseHookDefs[hookName];
18382
18382
  const overrideHook = overrideHookDefs[hookName];
18383
- if (baseHook && overrideHook) {
18384
- mergedHookDefs[hookName] = [baseHook, overrideHook];
18385
- } else if (overrideHook) {
18386
- mergedHookDefs[hookName] = overrideHook;
18387
- } else {
18388
- mergedHookDefs[hookName] = baseHook;
18389
- }
18383
+ const baseItems = Array.isArray(baseHook) ? baseHook : baseHook ? [baseHook] : [];
18384
+ const overrideItems = Array.isArray(overrideHook) ? overrideHook : overrideHook ? [overrideHook] : [];
18385
+ const combined = [...baseItems, ...overrideItems];
18386
+ mergedHookDefs[hookName] = combined.length === 1 ? combined[0] : combined;
18390
18387
  }
18391
18388
  merged.hooks = mergedHookDefs;
18392
- } else if (overrideHooks.hooks) {
18389
+ } else if (isPlainObject2(overrideHooks.hooks)) {
18393
18390
  merged.hooks = overrideHooks.hooks;
18394
18391
  }
18395
18392
  for (const hookKey of Object.keys(overrideHooks)) {
@@ -28056,16 +28053,17 @@ function deriveTestPatterns(contextFiles, resolvedGlobs) {
28056
28053
  async function detectTestDir(workdir, resolvedGlobs) {
28057
28054
  const resolvedDirs = resolvedGlobs ? extractTestDirs(resolvedGlobs) : [];
28058
28055
  const candidateDirs = resolvedDirs.length > 0 ? [...new Set([...resolvedDirs, ...DEFAULT_SCAN_TEST_DIRS])] : DEFAULT_SCAN_TEST_DIRS;
28059
- for (const dir of candidateDirs) {
28056
+ const checks3 = await Promise.all(candidateDirs.map(async (dir) => {
28060
28057
  const fullPath = path.join(workdir, dir);
28061
28058
  try {
28062
28059
  const proc = Bun.spawn(["test", "-d", fullPath], { stdout: "pipe", stderr: "pipe" });
28063
28060
  const exitCode = await proc.exited;
28064
- if (exitCode === 0)
28065
- return dir;
28066
- } catch {}
28067
- }
28068
- return null;
28061
+ return exitCode === 0 ? dir : null;
28062
+ } catch {
28063
+ return null;
28064
+ }
28065
+ }));
28066
+ return checks3.find((dir) => dir !== null) ?? null;
28069
28067
  }
28070
28068
  function deriveScanGlob(resolvedTestGlobs, testDir) {
28071
28069
  const prefix = `${testDir}/`;
@@ -29778,9 +29776,10 @@ Your task: make the failing tests pass by writing real source code.
29778
29776
  Workflow:
29779
29777
  1. Read every failing test in scope. The tests are the contract \u2014 understand what each one asserts before editing source.
29780
29778
  2. Run the scoped test files once to establish the baseline (which fail, which pass, and why).
29781
- 3. Implement source code in the package's source location (the project context names it).
29782
- 4. After each meaningful change, re-run only the scoped test files \u2014 never the full suite.
29783
- 5. When all scoped tests pass, stage and commit ALL changed files: \`git commit -m '${commitMsg}'\`.
29779
+ 3. Break the work into small steps before writing: for each step, note the source change and the failing test that verifies it (step -> verify). Resolve ambiguities now, not mid-edit.
29780
+ 4. Implement source code in the package's source location (the project context names it).
29781
+ 5. After each meaningful change, re-run only the scoped test files \u2014 never the full suite.
29782
+ 6. When all scoped tests pass, stage and commit ALL changed files: \`git commit -m '${commitMsg}'\`.
29784
29783
 
29785
29784
  Rules:
29786
29785
  - Do NOT modify test files. Three narrow exceptions: (a) a lint-only fix to a test, (b) a contract drift where the test imports a removed/renamed symbol, (c) a sibling test file rename forced by your source change. Name which exception applies in the commit body before editing any test file.
@@ -29795,10 +29794,11 @@ Context: A test-writer session has already created tests and may have added mini
29795
29794
  Workflow:
29796
29795
  1. Run the existing scoped tests to see which fail and why (assertion failure vs import error).
29797
29796
  2. Read each failing test. Note which ACs they cover and which they DON'T.
29798
- 3. Replace stubs with real implementations. A stub is one of: a type-only declaration, a function returning a placeholder/throwing "not implemented", or a const placeholder.
29799
- 4. If any AC has no test, add one before implementing \u2014 do not implement uncovered behavior.
29800
- 5. Re-run only the scoped test files after each meaningful change.
29801
- 6. When all scoped tests pass, stage and commit ALL changed files: \`git commit -m '${commitMsg}'\`.
29797
+ 3. Break the work into small steps before writing: for each stub, note the real implementation that replaces it and the test that verifies it (step -> verify); flag any AC still missing a test. Resolve ambiguities now, not mid-edit.
29798
+ 4. Replace stubs with real implementations. A stub is one of: a type-only declaration, a function returning a placeholder/throwing "not implemented", or a const placeholder.
29799
+ 5. If any AC has no test, add one before implementing \u2014 do not implement uncovered behavior.
29800
+ 6. Re-run only the scoped test files after each meaningful change.
29801
+ 7. When all scoped tests pass, stage and commit ALL changed files: \`git commit -m '${commitMsg}'\`.
29802
29802
 
29803
29803
  Rules:
29804
29804
  - Three test-modification exceptions apply (lint-only fix, contract drift, sibling rename). Name the exception in the commit body before editing any test the test-writer wrote.
@@ -29815,10 +29815,11 @@ Context: You are session 1 of a multi-session workflow. An implementer will foll
29815
29815
 
29816
29816
  Workflow:
29817
29817
  1. Re-read the acceptance criteria above.
29818
- 2. Create test files in the location the project uses for tests.
29819
- 3. Create stubs in the package's source location so the tests can import and compile. A stub is one of: a type/interface declaration, a function returning a placeholder/throwing "not implemented" (no more than 3 lines of body), or a const placeholder. If a stub body needs real logic, you have crossed into implementer territory \u2014 stop.
29820
- 4. For each AC: at least one success-path test and one boundary/failure-path test.
29821
- 5. Run the new test files. Confirm tests compile (stubs work) AND fail with ASSERTION failures \u2014 NOT import errors or compile errors. A test that errors before reaching its assertion does not prove the behavior is missing.
29818
+ 2. Break the work into small tasks before writing: treat each AC as one task and note the test name(s) you will add (success + boundary) and the minimal stub each test needs to compile. This per-AC list is your checklist.
29819
+ 3. Create test files in the location the project uses for tests.
29820
+ 4. Create stubs in the package's source location so the tests can import and compile. A stub is one of: a type/interface declaration, a function returning a placeholder/throwing "not implemented" (no more than 3 lines of body), or a const placeholder. If a stub body needs real logic, you have crossed into implementer territory \u2014 stop.
29821
+ 5. For each AC: at least one success-path test and one boundary/failure-path test.
29822
+ 6. Run the new test files. Confirm tests compile (stubs work) AND fail with ASSERTION failures \u2014 NOT import errors or compile errors. A test that errors before reaching its assertion does not prove the behavior is missing.
29822
29823
 
29823
29824
  Rules:
29824
29825
  - Stubs are NOT implementations. The implementer in the next session writes real logic.
@@ -29835,9 +29836,10 @@ Context: You are session 1 of a multi-session workflow.
29835
29836
 
29836
29837
  Workflow:
29837
29838
  1. Re-read the acceptance criteria above.
29838
- 2. Create test files in the location the project uses for tests (project context names it).
29839
- 3. For each AC: write at least one test for the success path AND at least one for a boundary/failure path (zero, empty, negative, missing, throws). ACs worded as "throws X" require a test asserting the throw.
29840
- 4. Run the new test files. Confirm every test fails with an ASSERTION failure \u2014 NOT an import error, compile error, or runtime crash before assertion. A test that errors before reaching its assertion does not prove the behavior is missing.
29839
+ 2. Break the work into small tasks before writing: treat each AC as one task and note the test name(s) you will write (success + boundary) and which file they belong in. This per-AC list is your checklist.
29840
+ 3. Create test files in the location the project uses for tests (project context names it).
29841
+ 4. For each AC: write at least one test for the success path AND at least one for a boundary/failure path (zero, empty, negative, missing, throws). ACs worded as "throws X" require a test asserting the throw.
29842
+ 5. Run the new test files. Confirm every test fails with an ASSERTION failure \u2014 NOT an import error, compile error, or runtime crash before assertion. A test that errors before reaching its assertion does not prove the behavior is missing.
29841
29843
 
29842
29844
  Rules:
29843
29845
  - Do NOT create or modify any source files. Read source for types/interfaces only.
@@ -41177,6 +41179,7 @@ ${errors3}
41177
41179
  1. Read the relevant files to verify each finding is a real issue
41178
41180
  2. Only fix findings that are actually valid problems
41179
41181
  3. Do NOT add keys, functions, or imports that already exist \u2014 check first
41182
+ 4. Break the fix into one small step per valid finding before touching code, each verified by re-running the relevant check
41180
41183
 
41181
41184
  ${testEditHeadline(story, `Do NOT change test files or test behavior \u2014 see the ${exceptionCountWord(story)} narrow exceptions appended below.`)}
41182
41185
  Do NOT add new features \u2014 only fix valid issues.
@@ -41200,6 +41203,7 @@ ${errors3}
41200
41203
  1. Read the relevant files to verify each finding is a real issue
41201
41204
  2. Only fix findings that are actually valid problems
41202
41205
  3. Do NOT add keys, functions, or imports that already exist \u2014 check first
41206
+ 4. Break the fix into one small step per valid finding before touching code, each verified by re-running the relevant check
41203
41207
 
41204
41208
  Do NOT add new features \u2014 only fix valid issues.
41205
41209
  Commit your fixes when done.${scopeConstraint}${noTestIsolationBlock(story)}${escapeHatchFor(story)}`;
@@ -41226,6 +41230,7 @@ ${adversarialErrors}
41226
41230
  1. Read the relevant files to verify each finding is a real issue
41227
41231
  2. Only fix findings that are actually valid problems
41228
41232
  3. Do NOT add keys, functions, or imports that already exist \u2014 check first
41233
+ 4. Break the fix into one small step per valid finding before touching code, each verified by re-running the relevant check
41229
41234
 
41230
41235
  Do NOT add new features \u2014 only fix valid issues.
41231
41236
  Commit your fixes when done.${scopeConstraint}${noTestIsolationBlock(story)}${escapeHatchFor(story)}`;
@@ -41491,6 +41496,8 @@ ${findingLines}
41491
41496
 
41492
41497
  **Task:** For each bug above, write a NEW failing test that asserts the spec-correct behavior described in the finding. The test should FAIL with the current (buggy) implementation and PASS once the implementer fixes the source.
41493
41498
 
41499
+ Break the work into one small task per bug before writing: for each, note the failing test's name and which spec-correct behavior it pins down.
41500
+
41494
41501
  Rules:
41495
41502
  1. Write the test against the SPECIFICATION, not the current behavior.
41496
41503
  2. Do NOT fix the source files \u2014 only write test files.
@@ -41518,6 +41525,8 @@ ${fileList}
41518
41525
  ### Implementer handoff
41519
41526
  ${reason}
41520
41527
 
41528
+ Break the work into one small task per listed file before editing: for each, note how its mock setup and dispatch wiring must change to match the AC-mandated dispatch shape.
41529
+
41521
41530
  Rules:
41522
41531
  1. Modify ONLY the files listed above.
41523
41532
  2. Do NOT modify any source file.
@@ -41556,7 +41565,8 @@ Before making any changes:
41556
41565
  2. Do NOT loosen assertions to match current implementation behavior. If a test is failing because the source is wrong, the source is the suspect \u2014 not the test.
41557
41566
  3. Do NOT delete a failing test because the implementation makes it hard to assert on. Refactor the test structure if needed; never silently drop coverage.
41558
41567
  4. If the current behavior disagrees with the acceptance criteria, write the test against the spec and let the implementer fix the source.
41559
- 5. Do NOT modify source implementation files.`;
41568
+ 5. Do NOT modify source implementation files.
41569
+ 6. Break the work into one small change per flagged test before editing, each verified by re-running that test.`;
41560
41570
  return `${opener}
41561
41571
 
41562
41572
  Story: ${story.title} (${story.id})
@@ -41746,7 +41756,7 @@ ${acList}
41746
41756
  ### Findings
41747
41757
  ${llmSection}
41748
41758
 
41749
- **Important:** LLM reviewers may flag false positives. Before making changes for LLM review findings, read the relevant files to verify each finding is a real issue. Do NOT add keys, functions, or imports that already exist.
41759
+ **Important:** LLM reviewers may flag false positives. Before making changes for LLM review findings, read the relevant files to verify each finding is a real issue, then break the fix into one small step per valid finding before touching code, each verified by re-running the relevant check. Do NOT add keys, functions, or imports that already exist.
41750
41760
 
41751
41761
  Do NOT add new features \u2014 only fix the identified issues.
41752
41762
  Commit your fixes when done.${scopeConstraint}${escapeHatchFor(story)}`;
@@ -41904,7 +41914,7 @@ Tests are failing. Fix the source so all tests pass \u2014 not just the ones lis
41904
41914
  ${detail}`);
41905
41915
  }
41906
41916
  lines.push(`
41907
- Fix the implementation to resolve all verifier findings.`);
41917
+ Before editing, break the work into one small fix per finding above (fix -> re-run to verify). Then fix the implementation to resolve all verifier findings.`);
41908
41918
  return lines.join(`
41909
41919
  `);
41910
41920
  }
@@ -48161,8 +48171,9 @@ ${request.summary}
48161
48171
  if (!this.rl) {
48162
48172
  throw new Error("CLI plugin not initialized");
48163
48173
  }
48174
+ let timeoutId;
48164
48175
  const timeoutPromise = new Promise((resolve13) => {
48165
- setTimeout(() => {
48176
+ timeoutId = setTimeout(() => {
48166
48177
  resolve13({
48167
48178
  requestId: request.id,
48168
48179
  action: "skip",
@@ -48172,8 +48183,12 @@ ${request.summary}
48172
48183
  }, timeout);
48173
48184
  });
48174
48185
  const userPromise = this.getUserInput(request);
48175
- const response = await Promise.race([userPromise, timeoutPromise]);
48176
- return response;
48186
+ try {
48187
+ return await Promise.race([userPromise, timeoutPromise]);
48188
+ } finally {
48189
+ if (timeoutId !== undefined)
48190
+ clearTimeout(timeoutId);
48191
+ }
48177
48192
  }
48178
48193
  async getUserInput(request) {
48179
48194
  if (!this.rl) {
@@ -55483,7 +55498,16 @@ var init_routing2 = __esm(() => {
55483
55498
  const TIER_RANK = { fast: 0, balanced: 1, powerful: 2 };
55484
55499
  const derivedTier = decision.modelTier;
55485
55500
  const previousTier = ctx.story.routing?.modelTier;
55486
- const isEscalated = previousTier !== undefined && (TIER_RANK[previousTier] ?? 0) > (TIER_RANK[derivedTier] ?? 0);
55501
+ const previousRank = previousTier !== undefined ? TIER_RANK[previousTier] : undefined;
55502
+ const derivedRank = TIER_RANK[derivedTier];
55503
+ if (previousTier !== undefined && previousRank === undefined) {
55504
+ logger?.warn("routing", "Ignoring unknown previousTier \u2014 not escalating", {
55505
+ storyId: ctx.story.id,
55506
+ previousTier,
55507
+ derivedTier
55508
+ });
55509
+ }
55510
+ const isEscalated = previousTier !== undefined && previousRank !== undefined && derivedRank !== undefined && previousRank > derivedRank;
55487
55511
  const modelTier = isEscalated ? previousTier : derivedTier;
55488
55512
  const routing = { ...decision, modelTier, agent: ctx.story.routing?.agent };
55489
55513
  ctx.story.routing = {
@@ -55590,6 +55614,7 @@ var init_pipeline = __esm(() => {
55590
55614
  init_runner4();
55591
55615
  init_events();
55592
55616
  init_stages();
55617
+ init_event_bus();
55593
55618
  });
55594
55619
 
55595
55620
  // src/cli/prompts-shared.ts
@@ -58150,12 +58175,12 @@ var init_loader4 = __esm(() => {
58150
58175
  });
58151
58176
 
58152
58177
  // src/utils/paths.ts
58153
- import { join as join64 } from "path";
58178
+ import { join as join63 } from "path";
58154
58179
  function getRunsDir() {
58155
- return process.env.NAX_RUNS_DIR ?? join64(globalConfigDir(), "runs");
58180
+ return process.env.NAX_RUNS_DIR ?? join63(globalConfigDir(), "runs");
58156
58181
  }
58157
58182
  function getEventsRootDir() {
58158
- return join64(globalConfigDir(), "events");
58183
+ return join63(globalConfigDir(), "events");
58159
58184
  }
58160
58185
  var init_paths3 = __esm(() => {
58161
58186
  init_paths();
@@ -58215,7 +58240,7 @@ var init_command_argv = __esm(() => {
58215
58240
  });
58216
58241
 
58217
58242
  // src/hooks/runner.ts
58218
- import { join as join71 } from "path";
58243
+ import { join as join70 } from "path";
58219
58244
  function createDrainDeadline2(deadlineMs) {
58220
58245
  let timeoutId;
58221
58246
  const promise2 = new Promise((resolve16) => {
@@ -58234,14 +58259,14 @@ async function loadHooksConfig(projectDir, globalDir) {
58234
58259
  let globalHooks = { hooks: {} };
58235
58260
  let projectHooks = { hooks: {} };
58236
58261
  let skipGlobal = false;
58237
- const projectPath = join71(projectDir, "hooks.json");
58262
+ const projectPath = join70(projectDir, "hooks.json");
58238
58263
  const projectData = await loadJsonFile(projectPath, "hooks");
58239
58264
  if (projectData) {
58240
58265
  projectHooks = projectData;
58241
58266
  skipGlobal = projectData.skipGlobal ?? false;
58242
58267
  }
58243
58268
  if (!skipGlobal && globalDir) {
58244
- const globalPath = join71(globalDir, "hooks.json");
58269
+ const globalPath = join70(globalDir, "hooks.json");
58245
58270
  const globalData = await loadJsonFile(globalPath, "hooks");
58246
58271
  if (globalData) {
58247
58272
  globalHooks = globalData;
@@ -58411,7 +58436,7 @@ var package_default;
58411
58436
  var init_package = __esm(() => {
58412
58437
  package_default = {
58413
58438
  name: "@nathapp/nax",
58414
- version: "0.68.5",
58439
+ version: "0.68.6",
58415
58440
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
58416
58441
  type: "module",
58417
58442
  bin: {
@@ -58506,8 +58531,8 @@ var init_version = __esm(() => {
58506
58531
  NAX_VERSION = package_default.version;
58507
58532
  NAX_COMMIT = (() => {
58508
58533
  try {
58509
- if (/^[0-9a-f]{6,10}$/.test("1056817e"))
58510
- return "1056817e";
58534
+ if (/^[0-9a-f]{6,10}$/.test("acc1d4bd"))
58535
+ return "acc1d4bd";
58511
58536
  } catch {}
58512
58537
  try {
58513
58538
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -58528,9 +58553,9 @@ var init_version = __esm(() => {
58528
58553
  // src/execution/crash-heartbeat.ts
58529
58554
  import { appendFileSync as appendFileSync2 } from "fs";
58530
58555
  async function heartbeatLoop(statusWriter, getTotalCost, getIterations, jsonlFilePath) {
58531
- const logger = getSafeLogger();
58556
+ const logger = _heartbeatDeps.getSafeLogger();
58532
58557
  while (heartbeatActive) {
58533
- await Bun.sleep(60000);
58558
+ await _heartbeatDeps.sleep(60000);
58534
58559
  if (!heartbeatActive)
58535
58560
  break;
58536
58561
  try {
@@ -58559,10 +58584,14 @@ async function heartbeatLoop(statusWriter, getTotalCost, getIterations, jsonlFil
58559
58584
  }
58560
58585
  }
58561
58586
  function startHeartbeat(statusWriter, getTotalCost, getIterations, jsonlFilePath) {
58562
- const logger = getSafeLogger();
58587
+ const logger = _heartbeatDeps.getSafeLogger();
58563
58588
  stopHeartbeat();
58564
58589
  heartbeatActive = true;
58565
- heartbeatLoop(statusWriter, getTotalCost, getIterations, jsonlFilePath).catch(() => {});
58590
+ heartbeatLoop(statusWriter, getTotalCost, getIterations, jsonlFilePath).catch((err) => {
58591
+ _heartbeatDeps.getSafeLogger()?.warn("crash-recovery", "Heartbeat loop crashed; status updates stopped", {
58592
+ error: err instanceof Error ? err.message : String(err)
58593
+ });
58594
+ });
58566
58595
  logger?.debug("crash-recovery", "Heartbeat started (60s interval)");
58567
58596
  }
58568
58597
  function stopHeartbeat() {
@@ -58571,9 +58600,13 @@ function stopHeartbeat() {
58571
58600
  getSafeLogger()?.debug("crash-recovery", "Heartbeat stopped");
58572
58601
  }
58573
58602
  }
58574
- var heartbeatActive = false;
58603
+ var _heartbeatDeps, heartbeatActive = false;
58575
58604
  var init_crash_heartbeat = __esm(() => {
58576
58605
  init_logger2();
58606
+ _heartbeatDeps = {
58607
+ sleep: async (ms) => Bun.sleep(ms),
58608
+ getSafeLogger
58609
+ };
58577
58610
  });
58578
58611
 
58579
58612
  // src/execution/crash-writer.ts
@@ -59376,15 +59409,15 @@ var init_acceptance_loop = __esm(() => {
59376
59409
 
59377
59410
  // src/session/scratch-purge.ts
59378
59411
  import { mkdir as mkdir13, rename, rm } from "fs/promises";
59379
- import { dirname as dirname12, join as join72 } from "path";
59412
+ import { dirname as dirname12, join as join71 } from "path";
59380
59413
  async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
59381
- const sessionsDir = join72(projectDir, ".nax", "features", featureName, "sessions");
59414
+ const sessionsDir = join71(projectDir, ".nax", "features", featureName, "sessions");
59382
59415
  const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
59383
59416
  const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
59384
59417
  let purged = 0;
59385
59418
  for (const sessionId of sessionIds) {
59386
- const sessionDir = join72(sessionsDir, sessionId);
59387
- const descriptorPath = join72(sessionDir, "descriptor.json");
59419
+ const sessionDir = join71(sessionsDir, sessionId);
59420
+ const descriptorPath = join71(sessionDir, "descriptor.json");
59388
59421
  if (!await _scratchPurgeDeps.fileExists(descriptorPath))
59389
59422
  continue;
59390
59423
  let lastActivityAt;
@@ -59400,7 +59433,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
59400
59433
  if (new Date(lastActivityAt).getTime() >= cutoffMs)
59401
59434
  continue;
59402
59435
  if (archiveInsteadOfDelete) {
59403
- const archiveDest = join72(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
59436
+ const archiveDest = join71(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
59404
59437
  await _scratchPurgeDeps.move(sessionDir, archiveDest);
59405
59438
  } else {
59406
59439
  await _scratchPurgeDeps.remove(sessionDir);
@@ -59623,6 +59656,13 @@ async function runDeferredRegression(options) {
59623
59656
  storyOutcomes: {}
59624
59657
  };
59625
59658
  }
59659
+ for (const storyId of affectedStories) {
59660
+ pipelineEventBus.emit({
59661
+ type: "regression:detected",
59662
+ storyId,
59663
+ failedTests: testSummary.failed
59664
+ });
59665
+ }
59626
59666
  let rectificationAttempts = 0;
59627
59667
  let storiesRectified = 0;
59628
59668
  let currentTestOutput = fullSuiteResult.output;
@@ -59736,6 +59776,7 @@ var init_run_regression = __esm(() => {
59736
59776
  init_findings();
59737
59777
  init_logger2();
59738
59778
  init_operations();
59779
+ init_pipeline();
59739
59780
  init_prd();
59740
59781
  init_test_runners();
59741
59782
  init_git();
@@ -60133,12 +60174,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
60133
60174
 
60134
60175
  // src/pipeline/subscribers/events-writer.ts
60135
60176
  import { appendFile as appendFile4, mkdir as mkdir14 } from "fs/promises";
60136
- import { basename as basename14, join as join73 } from "path";
60177
+ import { basename as basename13, join as join72 } from "path";
60137
60178
  function wireEventsWriter(bus, feature, runId, workdir) {
60138
60179
  const logger = getSafeLogger();
60139
- const project = basename14(workdir);
60140
- const eventsDir = join73(getEventsRootDir(), project);
60141
- const eventsFile = join73(eventsDir, "events.jsonl");
60180
+ const project = basename13(workdir);
60181
+ const eventsDir = join72(getEventsRootDir(), project);
60182
+ const eventsFile = join72(eventsDir, "events.jsonl");
60142
60183
  let dirReady = false;
60143
60184
  const write = (line) => {
60144
60185
  return (async () => {
@@ -60319,12 +60360,12 @@ var init_interaction2 = __esm(() => {
60319
60360
 
60320
60361
  // src/pipeline/subscribers/registry.ts
60321
60362
  import { mkdir as mkdir15, writeFile as writeFile2 } from "fs/promises";
60322
- import { basename as basename15, join as join74 } from "path";
60363
+ import { basename as basename14, join as join73 } from "path";
60323
60364
  function wireRegistry(bus, feature, runId, workdir, outputDir) {
60324
60365
  const logger = getSafeLogger();
60325
- const project = basename15(workdir);
60326
- const runDir = join74(getRunsDir(), `${project}-${feature}-${runId}`);
60327
- const metaFile = join74(runDir, "meta.json");
60366
+ const project = basename14(workdir);
60367
+ const runDir = join73(getRunsDir(), `${project}-${feature}-${runId}`);
60368
+ const metaFile = join73(runDir, "meta.json");
60328
60369
  const unsub = bus.on("run:started", (_ev) => {
60329
60370
  return (async () => {
60330
60371
  try {
@@ -60334,8 +60375,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
60334
60375
  project,
60335
60376
  feature,
60336
60377
  workdir,
60337
- statusPath: join74(outputDir, "features", feature, "status.json"),
60338
- eventsDir: join74(outputDir, "features", feature, "runs"),
60378
+ statusPath: join73(outputDir, "features", feature, "status.json"),
60379
+ eventsDir: join73(outputDir, "features", feature, "runs"),
60339
60380
  registeredAt: new Date().toISOString()
60340
60381
  };
60341
60382
  await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
@@ -60580,8 +60621,8 @@ var init_types9 = __esm(() => {
60580
60621
  });
60581
60622
 
60582
60623
  // src/worktree/dependencies.ts
60583
- import { existsSync as existsSync32 } from "fs";
60584
- import { join as join75 } from "path";
60624
+ import { existsSync as existsSync31 } from "fs";
60625
+ import { join as join74 } from "path";
60585
60626
  async function prepareWorktreeDependencies(options) {
60586
60627
  const mode = options.config.execution.worktreeDependencies.mode;
60587
60628
  const resolvedCwd = resolveDependencyCwd(options);
@@ -60595,7 +60636,7 @@ async function prepareWorktreeDependencies(options) {
60595
60636
  }
60596
60637
  }
60597
60638
  function resolveDependencyCwd(options) {
60598
- return options.storyWorkdir ? join75(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
60639
+ return options.storyWorkdir ? join74(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
60599
60640
  }
60600
60641
  function resolveInheritedDependencies(options, resolvedCwd) {
60601
60642
  if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
@@ -60605,7 +60646,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
60605
60646
  }
60606
60647
  function hasDependencyManifests(worktreeRoot, resolvedCwd) {
60607
60648
  const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
60608
- return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join75(directory, filename))));
60649
+ return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join74(directory, filename))));
60609
60650
  }
60610
60651
  async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
60611
60652
  const setupCommand = config2.execution.worktreeDependencies.setupCommand;
@@ -60656,7 +60697,7 @@ var init_dependencies = __esm(() => {
60656
60697
  "build.gradle.kts"
60657
60698
  ];
60658
60699
  _worktreeDependencyDeps = {
60659
- existsSync: existsSync32,
60700
+ existsSync: existsSync31,
60660
60701
  spawn
60661
60702
  };
60662
60703
  });
@@ -60667,19 +60708,19 @@ __export(exports_manager, {
60667
60708
  _managerDeps: () => _managerDeps,
60668
60709
  WorktreeManager: () => WorktreeManager
60669
60710
  });
60670
- import { existsSync as existsSync33, symlinkSync } from "fs";
60711
+ import { existsSync as existsSync32, symlinkSync } from "fs";
60671
60712
  import { mkdir as mkdir16 } from "fs/promises";
60672
- import { join as join76 } from "path";
60713
+ import { join as join75 } from "path";
60673
60714
 
60674
60715
  class WorktreeManager {
60675
60716
  async ensureGitExcludes(projectRoot) {
60676
60717
  const logger = getSafeLogger();
60677
- const infoDir = join76(projectRoot, ".git", "info");
60678
- const excludePath = join76(infoDir, "exclude");
60718
+ const infoDir = join75(projectRoot, ".git", "info");
60719
+ const excludePath = join75(infoDir, "exclude");
60679
60720
  try {
60680
60721
  await mkdir16(infoDir, { recursive: true });
60681
60722
  let existing = "";
60682
- if (existsSync33(excludePath)) {
60723
+ if (existsSync32(excludePath)) {
60683
60724
  existing = await Bun.file(excludePath).text();
60684
60725
  }
60685
60726
  const missing = NAX_GITIGNORE_ENTRIES.filter((entry) => !existing.includes(entry));
@@ -60702,7 +60743,7 @@ ${missing.join(`
60702
60743
  }
60703
60744
  async create(projectRoot, storyId) {
60704
60745
  validateStoryId(storyId);
60705
- const worktreePath = join76(projectRoot, ".nax-wt", storyId);
60746
+ const worktreePath = join75(projectRoot, ".nax-wt", storyId);
60706
60747
  const branchName = `nax/${storyId}`;
60707
60748
  try {
60708
60749
  const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
@@ -60743,9 +60784,9 @@ ${missing.join(`
60743
60784
  }
60744
60785
  throw new Error(`Failed to create worktree: ${String(error48)}`);
60745
60786
  }
60746
- const envSource = join76(projectRoot, ".env");
60747
- if (existsSync33(envSource)) {
60748
- const envTarget = join76(worktreePath, ".env");
60787
+ const envSource = join75(projectRoot, ".env");
60788
+ if (existsSync32(envSource)) {
60789
+ const envTarget = join75(worktreePath, ".env");
60749
60790
  try {
60750
60791
  symlinkSync(envSource, envTarget, "file");
60751
60792
  } catch (error48) {
@@ -60756,7 +60797,7 @@ ${missing.join(`
60756
60797
  }
60757
60798
  async remove(projectRoot, storyId) {
60758
60799
  validateStoryId(storyId);
60759
- const worktreePath = join76(projectRoot, ".nax-wt", storyId);
60800
+ const worktreePath = join75(projectRoot, ".nax-wt", storyId);
60760
60801
  const branchName = `nax/${storyId}`;
60761
60802
  try {
60762
60803
  const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
@@ -61434,6 +61475,12 @@ async function handleTierEscalation(ctx) {
61434
61475
  runtime: ctx.runtime
61435
61476
  });
61436
61477
  }
61478
+ pipelineEventBus.emit({
61479
+ type: "story:escalated",
61480
+ storyId: ctx.story.id,
61481
+ fromTier: ctx.routing.modelTier,
61482
+ toTier: escalatedTier
61483
+ });
61437
61484
  return {
61438
61485
  outcome: "escalated",
61439
61486
  prdDirty: true,
@@ -61444,6 +61491,7 @@ var _tierEscalationDeps;
61444
61491
  var init_tier_escalation = __esm(() => {
61445
61492
  init_hooks();
61446
61493
  init_logger2();
61494
+ init_event_bus();
61447
61495
  init_prd();
61448
61496
  init_routing();
61449
61497
  init_llm();
@@ -61559,10 +61607,10 @@ var init_merge_conflict_rectify = __esm(() => {
61559
61607
  });
61560
61608
 
61561
61609
  // src/execution/pipeline-result-handler.ts
61562
- import { join as join77 } from "path";
61610
+ import { join as join76 } from "path";
61563
61611
  async function removeWorktreeDirectory(projectRoot, storyId) {
61564
61612
  const logger = getSafeLogger();
61565
- const worktreePath = join77(projectRoot, ".nax-wt", storyId);
61613
+ const worktreePath = join76(projectRoot, ".nax-wt", storyId);
61566
61614
  try {
61567
61615
  const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
61568
61616
  cwd: projectRoot,
@@ -61692,6 +61740,11 @@ async function handlePipelineFailure(ctx, pipelineResult) {
61692
61740
  break;
61693
61741
  case "skip":
61694
61742
  logger?.warn("pipeline", "Story skipped", { storyId: ctx.story.id, reason: pipelineResult.reason });
61743
+ pipelineEventBus.emit({
61744
+ type: "story:skipped",
61745
+ storyId: ctx.story.id,
61746
+ reason: pipelineResult.reason || "Story skipped"
61747
+ });
61695
61748
  prdDirty = true;
61696
61749
  break;
61697
61750
  case "fail":
@@ -61772,8 +61825,8 @@ var init_pipeline_result_handler = __esm(() => {
61772
61825
  });
61773
61826
 
61774
61827
  // src/execution/iteration-runner.ts
61775
- import { existsSync as existsSync34 } from "fs";
61776
- import { join as join78 } from "path";
61828
+ import { existsSync as existsSync33 } from "fs";
61829
+ import { join as join77 } from "path";
61777
61830
  async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
61778
61831
  const { story, storiesToExecute, routing, isBatchExecution } = selection;
61779
61832
  if (ctx.dryRun) {
@@ -61798,7 +61851,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
61798
61851
  const storyStartTime = Date.now();
61799
61852
  let effectiveWorkdir = ctx.workdir;
61800
61853
  if (ctx.config.execution.storyIsolation === "worktree") {
61801
- const worktreePath = join78(ctx.workdir, ".nax-wt", story.id);
61854
+ const worktreePath = join77(ctx.workdir, ".nax-wt", story.id);
61802
61855
  const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
61803
61856
  if (!worktreeExists) {
61804
61857
  await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
@@ -61818,7 +61871,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
61818
61871
  }
61819
61872
  const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
61820
61873
  const profileOverride = ctx.config.profile && ctx.config.profile !== "default" ? { profile: ctx.config.profile } : undefined;
61821
- const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join78(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
61874
+ const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join77(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
61822
61875
  let dependencyContext;
61823
61876
  if (ctx.config.execution.storyIsolation === "worktree") {
61824
61877
  try {
@@ -61845,7 +61898,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
61845
61898
  };
61846
61899
  }
61847
61900
  }
61848
- const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ? join78(effectiveWorkdir, story.workdir) : effectiveWorkdir : story.workdir ? join78(ctx.workdir, story.workdir) : ctx.workdir;
61901
+ const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ? join77(effectiveWorkdir, story.workdir) : effectiveWorkdir : story.workdir ? join77(ctx.workdir, story.workdir) : ctx.workdir;
61849
61902
  const pipelineContext = {
61850
61903
  config: effectiveConfig,
61851
61904
  rootConfig: ctx.config,
@@ -61977,7 +62030,7 @@ var init_iteration_runner = __esm(() => {
61977
62030
  loadConfigForWorkdir,
61978
62031
  prepareWorktreeDependencies,
61979
62032
  runPipeline,
61980
- existsSync: existsSync34,
62033
+ existsSync: existsSync33,
61981
62034
  worktreeManager: new WorktreeManager
61982
62035
  };
61983
62036
  });
@@ -61988,7 +62041,7 @@ function selectNextStories(prd, config2, batchPlan, currentBatchIndex, lastStory
61988
62041
  const batch = batchPlan[currentBatchIndex];
61989
62042
  const storiesToExecute = batch.stories.filter((s) => !s.passes && s.status !== "passed" && s.status !== "skipped" && s.status !== "blocked" && s.status !== "failed" && s.status !== "paused" && s.status !== "decomposed");
61990
62043
  if (storiesToExecute.length === 0) {
61991
- return { selection: null, nextBatchIndex: currentBatchIndex + 1 };
62044
+ return null;
61992
62045
  }
61993
62046
  const story2 = storiesToExecute[0];
61994
62047
  return {
@@ -62047,7 +62100,7 @@ __export(exports_parallel_worker, {
62047
62100
  buildWorktreePipelineContext: () => buildWorktreePipelineContext,
62048
62101
  _parallelWorkerDeps: () => _parallelWorkerDeps
62049
62102
  });
62050
- import { join as join79 } from "path";
62103
+ import { join as join78 } from "path";
62051
62104
  function buildWorktreePipelineContext(base, _story) {
62052
62105
  return { ...base, prd: structuredClone(base.prd) };
62053
62106
  }
@@ -62070,7 +62123,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
62070
62123
  story,
62071
62124
  stories: [story],
62072
62125
  projectDir: context.projectDir,
62073
- workdir: dependencyContext.cwd ?? (story.workdir ? join79(worktreePath, story.workdir) : worktreePath),
62126
+ workdir: dependencyContext.cwd ?? (story.workdir ? join78(worktreePath, story.workdir) : worktreePath),
62074
62127
  worktreeDependencyContext: dependencyContext,
62075
62128
  routing,
62076
62129
  storyGitRef: storyGitRef ?? undefined
@@ -62195,10 +62248,27 @@ async function runParallelBatch(options) {
62195
62248
  const rootConfigPath = path21.join(workdir, ".nax", "config.json");
62196
62249
  const profileOverride = config2.profile && config2.profile !== "default" ? { profile: config2.profile } : undefined;
62197
62250
  const storyEffectiveConfigs = new Map;
62198
- await Promise.all(stories.filter((story) => story.workdir).map(async (story) => {
62199
- const effectiveConfig = await loadConfigForWorkdir(rootConfigPath, story.workdir, profileOverride);
62200
- storyEffectiveConfigs.set(story.id, effectiveConfig);
62251
+ const configResults = await Promise.allSettled(stories.filter((story) => story.workdir).map(async (story) => {
62252
+ try {
62253
+ const effectiveConfig = await _parallelBatchDeps.loadConfigForWorkdir(rootConfigPath, story.workdir, profileOverride);
62254
+ return { storyId: story.id, effectiveConfig };
62255
+ } catch (err) {
62256
+ const enriched = new Error(err instanceof Error ? err.message : String(err));
62257
+ enriched.storyId = story.id;
62258
+ throw enriched;
62259
+ }
62201
62260
  }));
62261
+ for (const result of configResults) {
62262
+ if (result.status === "fulfilled") {
62263
+ storyEffectiveConfigs.set(result.value.storyId, result.value.effectiveConfig);
62264
+ } else {
62265
+ const storyId = result.reason?.storyId ?? "(unknown)";
62266
+ logger?.warn("parallel-batch", "Failed to load per-story config; using root config", {
62267
+ storyId,
62268
+ reason: result.reason instanceof Error ? result.reason.message : String(result.reason)
62269
+ });
62270
+ }
62271
+ }
62202
62272
  const dependencyContexts = new Map;
62203
62273
  const readyStories = [];
62204
62274
  const preExecutionFailures = [];
@@ -62357,7 +62427,8 @@ var init_parallel_batch = __esm(() => {
62357
62427
  const { rectifyConflictedStory: rectifyConflictedStory2 } = await Promise.resolve().then(() => (init_merge_conflict_rectify(), exports_merge_conflict_rectify));
62358
62428
  return rectifyConflictedStory2(opts);
62359
62429
  },
62360
- prepareWorktreeDependencies
62430
+ prepareWorktreeDependencies,
62431
+ loadConfigForWorkdir
62361
62432
  };
62362
62433
  });
62363
62434
 
@@ -62725,6 +62796,8 @@ async function executeUnified(ctx, initialPrd) {
62725
62796
  if (!selected)
62726
62797
  return buildResult2("no-stories");
62727
62798
  const { selection } = selected;
62799
+ if (!selection)
62800
+ return buildResult2("no-stories");
62728
62801
  if (!ctx.useBatch)
62729
62802
  lastStoryId = selection.story.id;
62730
62803
  {
@@ -62931,7 +63004,7 @@ async function writeStatusFile(filePath, status) {
62931
63004
  var init_status_file = () => {};
62932
63005
 
62933
63006
  // src/execution/status-writer.ts
62934
- import { join as join80 } from "path";
63007
+ import { join as join79 } from "path";
62935
63008
 
62936
63009
  class StatusWriter {
62937
63010
  statusFile;
@@ -63050,7 +63123,7 @@ class StatusWriter {
63050
63123
  if (!this._prd)
63051
63124
  return;
63052
63125
  const safeLogger = getSafeLogger();
63053
- const featureStatusPath = join80(featureDir, "status.json");
63126
+ const featureStatusPath = join79(featureDir, "status.json");
63054
63127
  const write = async () => {
63055
63128
  try {
63056
63129
  const base = this.getSnapshot(totalCost, iterations);
@@ -63081,11 +63154,11 @@ __export(exports_migrate, {
63081
63154
  migrateCommand: () => migrateCommand,
63082
63155
  detectGeneratedContent: () => detectGeneratedContent
63083
63156
  });
63084
- import { existsSync as existsSync35 } from "fs";
63157
+ import { existsSync as existsSync34 } from "fs";
63085
63158
  import { mkdir as mkdir17, readdir as readdir6, rename as rename3 } from "fs/promises";
63086
63159
  import path22 from "path";
63087
63160
  async function detectGeneratedContent(naxDir) {
63088
- if (!existsSync35(naxDir))
63161
+ if (!existsSync34(naxDir))
63089
63162
  return [];
63090
63163
  const candidates = [];
63091
63164
  let entries = [];
@@ -63100,7 +63173,7 @@ async function detectGeneratedContent(naxDir) {
63100
63173
  }
63101
63174
  }
63102
63175
  const featuresDir = path22.join(naxDir, "features");
63103
- if (existsSync35(featuresDir)) {
63176
+ if (existsSync34(featuresDir)) {
63104
63177
  let featureDirs = [];
63105
63178
  try {
63106
63179
  featureDirs = await readdir6(featuresDir);
@@ -63162,7 +63235,7 @@ async function migrateCommand(options) {
63162
63235
  });
63163
63236
  }
63164
63237
  const src = path22.join(globalConfigDir(), options.reclaim);
63165
- if (!existsSync35(src)) {
63238
+ if (!existsSync34(src)) {
63166
63239
  throw new NaxError(`Nothing to reclaim: ~/.nax/${options.reclaim} does not exist`, "MIGRATE_RECLAIM_NOT_FOUND", {
63167
63240
  stage: "migrate",
63168
63241
  name: options.reclaim
@@ -63208,7 +63281,7 @@ async function migrateCommand(options) {
63208
63281
  }
63209
63282
  const naxDir = path22.join(options.workdir, ".nax");
63210
63283
  const configPath = path22.join(naxDir, "config.json");
63211
- if (!existsSync35(configPath)) {
63284
+ if (!existsSync34(configPath)) {
63212
63285
  throw new NaxError("No .nax/config.json found \u2014 run nax init first", "MIGRATE_NO_CONFIG", {
63213
63286
  stage: "migrate",
63214
63287
  workdir: options.workdir
@@ -63243,7 +63316,7 @@ async function migrateCommand(options) {
63243
63316
  for (const candidate of candidates) {
63244
63317
  const dest = path22.join(destBase, candidate.name);
63245
63318
  await mkdir17(path22.dirname(dest), { recursive: true });
63246
- if (existsSync35(dest)) {
63319
+ if (existsSync34(dest)) {
63247
63320
  throw new NaxError(`Migration conflict: destination already exists.
63248
63321
  Source: ${candidate.srcPath}
63249
63322
  Destination: ${dest}
@@ -63484,7 +63557,7 @@ __export(exports_run_initialization, {
63484
63557
  initializeRun: () => initializeRun,
63485
63558
  _reconcileDeps: () => _reconcileDeps
63486
63559
  });
63487
- import { join as join81 } from "path";
63560
+ import { join as join80 } from "path";
63488
63561
  async function reconcileState(prd, prdPath, workdir, config2) {
63489
63562
  const logger = getSafeLogger();
63490
63563
  let reconciledCount = 0;
@@ -63501,7 +63574,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
63501
63574
  });
63502
63575
  continue;
63503
63576
  }
63504
- const effectiveWorkdir = story.workdir ? join81(workdir, story.workdir) : workdir;
63577
+ const effectiveWorkdir = story.workdir ? join80(workdir, story.workdir) : workdir;
63505
63578
  try {
63506
63579
  const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
63507
63580
  if (!reviewResult.success) {
@@ -93059,6 +93132,229 @@ var require_stack_utils = __commonJS((exports, module) => {
93059
93132
  module.exports = StackUtils;
93060
93133
  });
93061
93134
 
93135
+ // node_modules/react/cjs/react-jsx-dev-runtime.development.js
93136
+ var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
93137
+ var React11 = __toESM(require_react());
93138
+ (function() {
93139
+ function getComponentNameFromType(type) {
93140
+ if (type == null)
93141
+ return null;
93142
+ if (typeof type === "function")
93143
+ return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null;
93144
+ if (typeof type === "string")
93145
+ return type;
93146
+ switch (type) {
93147
+ case REACT_FRAGMENT_TYPE:
93148
+ return "Fragment";
93149
+ case REACT_PROFILER_TYPE:
93150
+ return "Profiler";
93151
+ case REACT_STRICT_MODE_TYPE:
93152
+ return "StrictMode";
93153
+ case REACT_SUSPENSE_TYPE:
93154
+ return "Suspense";
93155
+ case REACT_SUSPENSE_LIST_TYPE:
93156
+ return "SuspenseList";
93157
+ case REACT_ACTIVITY_TYPE:
93158
+ return "Activity";
93159
+ }
93160
+ if (typeof type === "object")
93161
+ switch (typeof type.tag === "number" && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), type.$$typeof) {
93162
+ case REACT_PORTAL_TYPE:
93163
+ return "Portal";
93164
+ case REACT_CONTEXT_TYPE:
93165
+ return type.displayName || "Context";
93166
+ case REACT_CONSUMER_TYPE:
93167
+ return (type._context.displayName || "Context") + ".Consumer";
93168
+ case REACT_FORWARD_REF_TYPE:
93169
+ var innerType = type.render;
93170
+ type = type.displayName;
93171
+ type || (type = innerType.displayName || innerType.name || "", type = type !== "" ? "ForwardRef(" + type + ")" : "ForwardRef");
93172
+ return type;
93173
+ case REACT_MEMO_TYPE:
93174
+ return innerType = type.displayName || null, innerType !== null ? innerType : getComponentNameFromType(type.type) || "Memo";
93175
+ case REACT_LAZY_TYPE:
93176
+ innerType = type._payload;
93177
+ type = type._init;
93178
+ try {
93179
+ return getComponentNameFromType(type(innerType));
93180
+ } catch (x) {}
93181
+ }
93182
+ return null;
93183
+ }
93184
+ function testStringCoercion(value) {
93185
+ return "" + value;
93186
+ }
93187
+ function checkKeyStringCoercion(value) {
93188
+ try {
93189
+ testStringCoercion(value);
93190
+ var JSCompiler_inline_result = false;
93191
+ } catch (e) {
93192
+ JSCompiler_inline_result = true;
93193
+ }
93194
+ if (JSCompiler_inline_result) {
93195
+ JSCompiler_inline_result = console;
93196
+ var JSCompiler_temp_const = JSCompiler_inline_result.error;
93197
+ var JSCompiler_inline_result$jscomp$0 = typeof Symbol === "function" && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
93198
+ JSCompiler_temp_const.call(JSCompiler_inline_result, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", JSCompiler_inline_result$jscomp$0);
93199
+ return testStringCoercion(value);
93200
+ }
93201
+ }
93202
+ function getTaskName(type) {
93203
+ if (type === REACT_FRAGMENT_TYPE)
93204
+ return "<>";
93205
+ if (typeof type === "object" && type !== null && type.$$typeof === REACT_LAZY_TYPE)
93206
+ return "<...>";
93207
+ try {
93208
+ var name = getComponentNameFromType(type);
93209
+ return name ? "<" + name + ">" : "<...>";
93210
+ } catch (x) {
93211
+ return "<...>";
93212
+ }
93213
+ }
93214
+ function getOwner() {
93215
+ var dispatcher = ReactSharedInternals.A;
93216
+ return dispatcher === null ? null : dispatcher.getOwner();
93217
+ }
93218
+ function UnknownOwner() {
93219
+ return Error("react-stack-top-frame");
93220
+ }
93221
+ function hasValidKey(config2) {
93222
+ if (hasOwnProperty.call(config2, "key")) {
93223
+ var getter = Object.getOwnPropertyDescriptor(config2, "key").get;
93224
+ if (getter && getter.isReactWarning)
93225
+ return false;
93226
+ }
93227
+ return config2.key !== undefined;
93228
+ }
93229
+ function defineKeyPropWarningGetter(props, displayName) {
93230
+ function warnAboutAccessingKey() {
93231
+ specialPropKeyWarningShown || (specialPropKeyWarningShown = true, console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", displayName));
93232
+ }
93233
+ warnAboutAccessingKey.isReactWarning = true;
93234
+ Object.defineProperty(props, "key", {
93235
+ get: warnAboutAccessingKey,
93236
+ configurable: true
93237
+ });
93238
+ }
93239
+ function elementRefGetterWithDeprecationWarning() {
93240
+ var componentName = getComponentNameFromType(this.type);
93241
+ didWarnAboutElementRef[componentName] || (didWarnAboutElementRef[componentName] = true, console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."));
93242
+ componentName = this.props.ref;
93243
+ return componentName !== undefined ? componentName : null;
93244
+ }
93245
+ function ReactElement(type, key, props, owner, debugStack, debugTask) {
93246
+ var refProp = props.ref;
93247
+ type = {
93248
+ $$typeof: REACT_ELEMENT_TYPE,
93249
+ type,
93250
+ key,
93251
+ props,
93252
+ _owner: owner
93253
+ };
93254
+ (refProp !== undefined ? refProp : null) !== null ? Object.defineProperty(type, "ref", {
93255
+ enumerable: false,
93256
+ get: elementRefGetterWithDeprecationWarning
93257
+ }) : Object.defineProperty(type, "ref", { enumerable: false, value: null });
93258
+ type._store = {};
93259
+ Object.defineProperty(type._store, "validated", {
93260
+ configurable: false,
93261
+ enumerable: false,
93262
+ writable: true,
93263
+ value: 0
93264
+ });
93265
+ Object.defineProperty(type, "_debugInfo", {
93266
+ configurable: false,
93267
+ enumerable: false,
93268
+ writable: true,
93269
+ value: null
93270
+ });
93271
+ Object.defineProperty(type, "_debugStack", {
93272
+ configurable: false,
93273
+ enumerable: false,
93274
+ writable: true,
93275
+ value: debugStack
93276
+ });
93277
+ Object.defineProperty(type, "_debugTask", {
93278
+ configurable: false,
93279
+ enumerable: false,
93280
+ writable: true,
93281
+ value: debugTask
93282
+ });
93283
+ Object.freeze && (Object.freeze(type.props), Object.freeze(type));
93284
+ return type;
93285
+ }
93286
+ function jsxDEVImpl(type, config2, maybeKey, isStaticChildren, debugStack, debugTask) {
93287
+ var children = config2.children;
93288
+ if (children !== undefined)
93289
+ if (isStaticChildren)
93290
+ if (isArrayImpl(children)) {
93291
+ for (isStaticChildren = 0;isStaticChildren < children.length; isStaticChildren++)
93292
+ validateChildKeys(children[isStaticChildren]);
93293
+ Object.freeze && Object.freeze(children);
93294
+ } else
93295
+ console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");
93296
+ else
93297
+ validateChildKeys(children);
93298
+ if (hasOwnProperty.call(config2, "key")) {
93299
+ children = getComponentNameFromType(type);
93300
+ var keys2 = Object.keys(config2).filter(function(k) {
93301
+ return k !== "key";
93302
+ });
93303
+ isStaticChildren = 0 < keys2.length ? "{key: someKey, " + keys2.join(": ..., ") + ": ...}" : "{key: someKey}";
93304
+ didWarnAboutKeySpread[children + isStaticChildren] || (keys2 = 0 < keys2.length ? "{" + keys2.join(": ..., ") + ": ...}" : "{}", console.error(`A props object containing a "key" prop is being spread into JSX:
93305
+ let props = %s;
93306
+ <%s {...props} />
93307
+ React keys must be passed directly to JSX without using spread:
93308
+ let props = %s;
93309
+ <%s key={someKey} {...props} />`, isStaticChildren, children, keys2, children), didWarnAboutKeySpread[children + isStaticChildren] = true);
93310
+ }
93311
+ children = null;
93312
+ maybeKey !== undefined && (checkKeyStringCoercion(maybeKey), children = "" + maybeKey);
93313
+ hasValidKey(config2) && (checkKeyStringCoercion(config2.key), children = "" + config2.key);
93314
+ if ("key" in config2) {
93315
+ maybeKey = {};
93316
+ for (var propName in config2)
93317
+ propName !== "key" && (maybeKey[propName] = config2[propName]);
93318
+ } else
93319
+ maybeKey = config2;
93320
+ children && defineKeyPropWarningGetter(maybeKey, typeof type === "function" ? type.displayName || type.name || "Unknown" : type);
93321
+ return ReactElement(type, children, maybeKey, getOwner(), debugStack, debugTask);
93322
+ }
93323
+ function validateChildKeys(node) {
93324
+ isValidElement(node) ? node._store && (node._store.validated = 1) : typeof node === "object" && node !== null && node.$$typeof === REACT_LAZY_TYPE && (node._payload.status === "fulfilled" ? isValidElement(node._payload.value) && node._payload.value._store && (node._payload.value._store.validated = 1) : node._store && (node._store.validated = 1));
93325
+ }
93326
+ function isValidElement(object2) {
93327
+ return typeof object2 === "object" && object2 !== null && object2.$$typeof === REACT_ELEMENT_TYPE;
93328
+ }
93329
+ var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React11.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
93330
+ return null;
93331
+ };
93332
+ React11 = {
93333
+ react_stack_bottom_frame: function(callStackForError) {
93334
+ return callStackForError();
93335
+ }
93336
+ };
93337
+ var specialPropKeyWarningShown;
93338
+ var didWarnAboutElementRef = {};
93339
+ var unknownOwnerDebugStack = React11.react_stack_bottom_frame.bind(React11, UnknownOwner)();
93340
+ var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
93341
+ var didWarnAboutKeySpread = {};
93342
+ exports.Fragment = REACT_FRAGMENT_TYPE;
93343
+ exports.jsxDEV = function(type, config2, maybeKey, isStaticChildren) {
93344
+ var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
93345
+ return jsxDEVImpl(type, config2, maybeKey, isStaticChildren, trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack, trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask);
93346
+ };
93347
+ })();
93348
+ });
93349
+
93350
+ // node_modules/react/jsx-dev-runtime.js
93351
+ var require_jsx_dev_runtime = __commonJS((exports, module) => {
93352
+ var react_jsx_dev_runtime_development = __toESM(require_react_jsx_dev_runtime_development());
93353
+ if (false) {} else {
93354
+ module.exports = react_jsx_dev_runtime_development;
93355
+ }
93356
+ });
93357
+
93062
93358
  // node_modules/cli-spinners/spinners.json
93063
93359
  var require_spinners = __commonJS((exports, module) => {
93064
93360
  module.exports = {
@@ -94699,229 +94995,6 @@ var require_cli_spinners = __commonJS((exports, module) => {
94699
94995
  module.exports = spinners;
94700
94996
  });
94701
94997
 
94702
- // node_modules/react/cjs/react-jsx-dev-runtime.development.js
94703
- var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
94704
- var React12 = __toESM(require_react());
94705
- (function() {
94706
- function getComponentNameFromType(type) {
94707
- if (type == null)
94708
- return null;
94709
- if (typeof type === "function")
94710
- return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null;
94711
- if (typeof type === "string")
94712
- return type;
94713
- switch (type) {
94714
- case REACT_FRAGMENT_TYPE:
94715
- return "Fragment";
94716
- case REACT_PROFILER_TYPE:
94717
- return "Profiler";
94718
- case REACT_STRICT_MODE_TYPE:
94719
- return "StrictMode";
94720
- case REACT_SUSPENSE_TYPE:
94721
- return "Suspense";
94722
- case REACT_SUSPENSE_LIST_TYPE:
94723
- return "SuspenseList";
94724
- case REACT_ACTIVITY_TYPE:
94725
- return "Activity";
94726
- }
94727
- if (typeof type === "object")
94728
- switch (typeof type.tag === "number" && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), type.$$typeof) {
94729
- case REACT_PORTAL_TYPE:
94730
- return "Portal";
94731
- case REACT_CONTEXT_TYPE:
94732
- return type.displayName || "Context";
94733
- case REACT_CONSUMER_TYPE:
94734
- return (type._context.displayName || "Context") + ".Consumer";
94735
- case REACT_FORWARD_REF_TYPE:
94736
- var innerType = type.render;
94737
- type = type.displayName;
94738
- type || (type = innerType.displayName || innerType.name || "", type = type !== "" ? "ForwardRef(" + type + ")" : "ForwardRef");
94739
- return type;
94740
- case REACT_MEMO_TYPE:
94741
- return innerType = type.displayName || null, innerType !== null ? innerType : getComponentNameFromType(type.type) || "Memo";
94742
- case REACT_LAZY_TYPE:
94743
- innerType = type._payload;
94744
- type = type._init;
94745
- try {
94746
- return getComponentNameFromType(type(innerType));
94747
- } catch (x) {}
94748
- }
94749
- return null;
94750
- }
94751
- function testStringCoercion(value) {
94752
- return "" + value;
94753
- }
94754
- function checkKeyStringCoercion(value) {
94755
- try {
94756
- testStringCoercion(value);
94757
- var JSCompiler_inline_result = false;
94758
- } catch (e) {
94759
- JSCompiler_inline_result = true;
94760
- }
94761
- if (JSCompiler_inline_result) {
94762
- JSCompiler_inline_result = console;
94763
- var JSCompiler_temp_const = JSCompiler_inline_result.error;
94764
- var JSCompiler_inline_result$jscomp$0 = typeof Symbol === "function" && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
94765
- JSCompiler_temp_const.call(JSCompiler_inline_result, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", JSCompiler_inline_result$jscomp$0);
94766
- return testStringCoercion(value);
94767
- }
94768
- }
94769
- function getTaskName(type) {
94770
- if (type === REACT_FRAGMENT_TYPE)
94771
- return "<>";
94772
- if (typeof type === "object" && type !== null && type.$$typeof === REACT_LAZY_TYPE)
94773
- return "<...>";
94774
- try {
94775
- var name = getComponentNameFromType(type);
94776
- return name ? "<" + name + ">" : "<...>";
94777
- } catch (x) {
94778
- return "<...>";
94779
- }
94780
- }
94781
- function getOwner() {
94782
- var dispatcher = ReactSharedInternals.A;
94783
- return dispatcher === null ? null : dispatcher.getOwner();
94784
- }
94785
- function UnknownOwner() {
94786
- return Error("react-stack-top-frame");
94787
- }
94788
- function hasValidKey(config2) {
94789
- if (hasOwnProperty.call(config2, "key")) {
94790
- var getter = Object.getOwnPropertyDescriptor(config2, "key").get;
94791
- if (getter && getter.isReactWarning)
94792
- return false;
94793
- }
94794
- return config2.key !== undefined;
94795
- }
94796
- function defineKeyPropWarningGetter(props, displayName) {
94797
- function warnAboutAccessingKey() {
94798
- specialPropKeyWarningShown || (specialPropKeyWarningShown = true, console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", displayName));
94799
- }
94800
- warnAboutAccessingKey.isReactWarning = true;
94801
- Object.defineProperty(props, "key", {
94802
- get: warnAboutAccessingKey,
94803
- configurable: true
94804
- });
94805
- }
94806
- function elementRefGetterWithDeprecationWarning() {
94807
- var componentName = getComponentNameFromType(this.type);
94808
- didWarnAboutElementRef[componentName] || (didWarnAboutElementRef[componentName] = true, console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."));
94809
- componentName = this.props.ref;
94810
- return componentName !== undefined ? componentName : null;
94811
- }
94812
- function ReactElement(type, key, props, owner, debugStack, debugTask) {
94813
- var refProp = props.ref;
94814
- type = {
94815
- $$typeof: REACT_ELEMENT_TYPE,
94816
- type,
94817
- key,
94818
- props,
94819
- _owner: owner
94820
- };
94821
- (refProp !== undefined ? refProp : null) !== null ? Object.defineProperty(type, "ref", {
94822
- enumerable: false,
94823
- get: elementRefGetterWithDeprecationWarning
94824
- }) : Object.defineProperty(type, "ref", { enumerable: false, value: null });
94825
- type._store = {};
94826
- Object.defineProperty(type._store, "validated", {
94827
- configurable: false,
94828
- enumerable: false,
94829
- writable: true,
94830
- value: 0
94831
- });
94832
- Object.defineProperty(type, "_debugInfo", {
94833
- configurable: false,
94834
- enumerable: false,
94835
- writable: true,
94836
- value: null
94837
- });
94838
- Object.defineProperty(type, "_debugStack", {
94839
- configurable: false,
94840
- enumerable: false,
94841
- writable: true,
94842
- value: debugStack
94843
- });
94844
- Object.defineProperty(type, "_debugTask", {
94845
- configurable: false,
94846
- enumerable: false,
94847
- writable: true,
94848
- value: debugTask
94849
- });
94850
- Object.freeze && (Object.freeze(type.props), Object.freeze(type));
94851
- return type;
94852
- }
94853
- function jsxDEVImpl(type, config2, maybeKey, isStaticChildren, debugStack, debugTask) {
94854
- var children = config2.children;
94855
- if (children !== undefined)
94856
- if (isStaticChildren)
94857
- if (isArrayImpl(children)) {
94858
- for (isStaticChildren = 0;isStaticChildren < children.length; isStaticChildren++)
94859
- validateChildKeys(children[isStaticChildren]);
94860
- Object.freeze && Object.freeze(children);
94861
- } else
94862
- console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");
94863
- else
94864
- validateChildKeys(children);
94865
- if (hasOwnProperty.call(config2, "key")) {
94866
- children = getComponentNameFromType(type);
94867
- var keys2 = Object.keys(config2).filter(function(k) {
94868
- return k !== "key";
94869
- });
94870
- isStaticChildren = 0 < keys2.length ? "{key: someKey, " + keys2.join(": ..., ") + ": ...}" : "{key: someKey}";
94871
- didWarnAboutKeySpread[children + isStaticChildren] || (keys2 = 0 < keys2.length ? "{" + keys2.join(": ..., ") + ": ...}" : "{}", console.error(`A props object containing a "key" prop is being spread into JSX:
94872
- let props = %s;
94873
- <%s {...props} />
94874
- React keys must be passed directly to JSX without using spread:
94875
- let props = %s;
94876
- <%s key={someKey} {...props} />`, isStaticChildren, children, keys2, children), didWarnAboutKeySpread[children + isStaticChildren] = true);
94877
- }
94878
- children = null;
94879
- maybeKey !== undefined && (checkKeyStringCoercion(maybeKey), children = "" + maybeKey);
94880
- hasValidKey(config2) && (checkKeyStringCoercion(config2.key), children = "" + config2.key);
94881
- if ("key" in config2) {
94882
- maybeKey = {};
94883
- for (var propName in config2)
94884
- propName !== "key" && (maybeKey[propName] = config2[propName]);
94885
- } else
94886
- maybeKey = config2;
94887
- children && defineKeyPropWarningGetter(maybeKey, typeof type === "function" ? type.displayName || type.name || "Unknown" : type);
94888
- return ReactElement(type, children, maybeKey, getOwner(), debugStack, debugTask);
94889
- }
94890
- function validateChildKeys(node) {
94891
- isValidElement(node) ? node._store && (node._store.validated = 1) : typeof node === "object" && node !== null && node.$$typeof === REACT_LAZY_TYPE && (node._payload.status === "fulfilled" ? isValidElement(node._payload.value) && node._payload.value._store && (node._payload.value._store.validated = 1) : node._store && (node._store.validated = 1));
94892
- }
94893
- function isValidElement(object2) {
94894
- return typeof object2 === "object" && object2 !== null && object2.$$typeof === REACT_ELEMENT_TYPE;
94895
- }
94896
- var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React12.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
94897
- return null;
94898
- };
94899
- React12 = {
94900
- react_stack_bottom_frame: function(callStackForError) {
94901
- return callStackForError();
94902
- }
94903
- };
94904
- var specialPropKeyWarningShown;
94905
- var didWarnAboutElementRef = {};
94906
- var unknownOwnerDebugStack = React12.react_stack_bottom_frame.bind(React12, UnknownOwner)();
94907
- var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
94908
- var didWarnAboutKeySpread = {};
94909
- exports.Fragment = REACT_FRAGMENT_TYPE;
94910
- exports.jsxDEV = function(type, config2, maybeKey, isStaticChildren) {
94911
- var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
94912
- return jsxDEVImpl(type, config2, maybeKey, isStaticChildren, trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack, trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask);
94913
- };
94914
- })();
94915
- });
94916
-
94917
- // node_modules/react/jsx-dev-runtime.js
94918
- var require_jsx_dev_runtime = __commonJS((exports, module) => {
94919
- var react_jsx_dev_runtime_development = __toESM(require_react_jsx_dev_runtime_development());
94920
- if (false) {} else {
94921
- module.exports = react_jsx_dev_runtime_development;
94922
- }
94923
- });
94924
-
94925
94998
  // src/commands/curator.ts
94926
94999
  var exports_curator = {};
94927
95000
  __export(exports_curator, {
@@ -94931,15 +95004,15 @@ __export(exports_curator, {
94931
95004
  curatorCommit: () => curatorCommit,
94932
95005
  _curatorCmdDeps: () => _curatorCmdDeps
94933
95006
  });
94934
- import { readdirSync as readdirSync9 } from "fs";
95007
+ import { readdirSync as readdirSync8 } from "fs";
94935
95008
  import { unlink as unlink4 } from "fs/promises";
94936
- import { basename as basename16, join as join83 } from "path";
95009
+ import { basename as basename15, join as join82 } from "path";
94937
95010
  function getProjectKey(config2, projectDir) {
94938
- return config2.name?.trim() || basename16(projectDir);
95011
+ return config2.name?.trim() || basename15(projectDir);
94939
95012
  }
94940
95013
  function listRunIds(runsDir) {
94941
95014
  try {
94942
- return readdirSync9(runsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
95015
+ return readdirSync8(runsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
94943
95016
  } catch {
94944
95017
  return [];
94945
95018
  }
@@ -95016,7 +95089,7 @@ async function curatorStatus(options) {
95016
95089
  const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
95017
95090
  const projectKey = getProjectKey(config2, resolved.projectDir);
95018
95091
  const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
95019
- const runsDir = join83(outputDir, "runs");
95092
+ const runsDir = join82(outputDir, "runs");
95020
95093
  const runIds = listRunIds(runsDir);
95021
95094
  let runId;
95022
95095
  if (options.run) {
@@ -95033,8 +95106,8 @@ async function curatorStatus(options) {
95033
95106
  runId = runIds[runIds.length - 1];
95034
95107
  }
95035
95108
  console.log(`Run: ${runId}`);
95036
- const runDir = join83(runsDir, runId);
95037
- const observationsPath = join83(runDir, "observations.jsonl");
95109
+ const runDir = join82(runsDir, runId);
95110
+ const observationsPath = join82(runDir, "observations.jsonl");
95038
95111
  const observations = await parseObservations(observationsPath);
95039
95112
  const counts = new Map;
95040
95113
  for (const obs of observations) {
@@ -95044,7 +95117,7 @@ async function curatorStatus(options) {
95044
95117
  for (const [kind, count] of counts.entries()) {
95045
95118
  console.log(` ${kind}: ${count}`);
95046
95119
  }
95047
- const proposalsPath = join83(runDir, "curator-proposals.md");
95120
+ const proposalsPath = join82(runDir, "curator-proposals.md");
95048
95121
  const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
95049
95122
  if (proposalText !== null) {
95050
95123
  console.log("");
@@ -95058,8 +95131,8 @@ async function curatorCommit(options) {
95058
95131
  const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
95059
95132
  const projectKey = getProjectKey(config2, resolved.projectDir);
95060
95133
  const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
95061
- const runDir = join83(outputDir, "runs", options.runId);
95062
- const proposalsPath = join83(runDir, "curator-proposals.md");
95134
+ const runDir = join82(outputDir, "runs", options.runId);
95135
+ const proposalsPath = join82(runDir, "curator-proposals.md");
95063
95136
  const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
95064
95137
  if (proposalText === null) {
95065
95138
  console.log(`curator-proposals.md not found for run ${options.runId}.`);
@@ -95075,7 +95148,7 @@ async function curatorCommit(options) {
95075
95148
  const dropFileState = new Map;
95076
95149
  const skippedDrops = new Set;
95077
95150
  for (const drop2 of drops) {
95078
- const targetPath = join83(resolved.projectDir, drop2.canonicalFile);
95151
+ const targetPath = join82(resolved.projectDir, drop2.canonicalFile);
95079
95152
  if (!dropFileState.has(targetPath)) {
95080
95153
  const fileExists2 = await Bun.file(targetPath).exists();
95081
95154
  const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
@@ -95109,7 +95182,7 @@ async function curatorCommit(options) {
95109
95182
  if (skippedDrops.has(drop2)) {
95110
95183
  continue;
95111
95184
  }
95112
- const targetPath = join83(resolved.projectDir, drop2.canonicalFile);
95185
+ const targetPath = join82(resolved.projectDir, drop2.canonicalFile);
95113
95186
  const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
95114
95187
  const filtered = filterDropContent(existing, drop2.description);
95115
95188
  await _curatorCmdDeps.writeFile(targetPath, filtered);
@@ -95118,7 +95191,7 @@ async function curatorCommit(options) {
95118
95191
  }
95119
95192
  const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
95120
95193
  for (const add2 of adds) {
95121
- const targetPath = join83(resolved.projectDir, add2.canonicalFile);
95194
+ const targetPath = join82(resolved.projectDir, add2.canonicalFile);
95122
95195
  const content = buildAddContent(add2);
95123
95196
  await _curatorCmdDeps.appendFile(targetPath, content);
95124
95197
  modifiedFiles.add(targetPath);
@@ -95155,7 +95228,7 @@ async function curatorDryrun(options) {
95155
95228
  const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
95156
95229
  const projectKey = getProjectKey(config2, resolved.projectDir);
95157
95230
  const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
95158
- const runsDir = join83(outputDir, "runs");
95231
+ const runsDir = join82(outputDir, "runs");
95159
95232
  const runIds = listRunIds(runsDir);
95160
95233
  if (runIds.length === 0) {
95161
95234
  console.log("No runs found.");
@@ -95166,7 +95239,7 @@ async function curatorDryrun(options) {
95166
95239
  console.log(`Run ${options.run} not found in ${runsDir}.`);
95167
95240
  return;
95168
95241
  }
95169
- const observationsPath = join83(runsDir, runId, "observations.jsonl");
95242
+ const observationsPath = join82(runsDir, runId, "observations.jsonl");
95170
95243
  const observations = await parseObservations(observationsPath);
95171
95244
  const thresholds = getThresholds(config2);
95172
95245
  const proposals = runHeuristics(observations, thresholds);
@@ -95207,12 +95280,12 @@ async function curatorGc(options) {
95207
95280
  await _curatorCmdDeps.writeFile(rollupPath, newContent);
95208
95281
  const projectKey = getProjectKey(config2, resolved.projectDir);
95209
95282
  const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
95210
- const perRunsDir = join83(outputDir, "runs");
95283
+ const perRunsDir = join82(outputDir, "runs");
95211
95284
  for (const runId of uniqueRunIds) {
95212
95285
  if (!keepSet.has(runId)) {
95213
- const runDir = join83(perRunsDir, runId);
95214
- await _curatorCmdDeps.removeFile(join83(runDir, "observations.jsonl"));
95215
- await _curatorCmdDeps.removeFile(join83(runDir, "curator-proposals.md"));
95286
+ const runDir = join82(perRunsDir, runId);
95287
+ await _curatorCmdDeps.removeFile(join82(runDir, "observations.jsonl"));
95288
+ await _curatorCmdDeps.removeFile(join82(runDir, "curator-proposals.md"));
95216
95289
  }
95217
95290
  }
95218
95291
  console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
@@ -95255,9 +95328,9 @@ var init_curator2 = __esm(() => {
95255
95328
 
95256
95329
  // bin/nax.ts
95257
95330
  init_source();
95258
- import { existsSync as existsSync37, mkdirSync as mkdirSync7 } from "fs";
95331
+ import { existsSync as existsSync36, mkdirSync as mkdirSync7 } from "fs";
95259
95332
  import { homedir as homedir3 } from "os";
95260
- import { basename as basename17, join as join84 } from "path";
95333
+ import { basename as basename16, join as join83 } from "path";
95261
95334
 
95262
95335
  // node_modules/commander/esm.mjs
95263
95336
  var import__ = __toESM(require_commander(), 1);
@@ -96413,324 +96486,6 @@ function formatSource(type, sourcePath) {
96413
96486
  function pad(str, width) {
96414
96487
  return str.padEnd(width);
96415
96488
  }
96416
- // src/cli/diagnose.ts
96417
- init_config();
96418
- init_logger2();
96419
- init_prd();
96420
- init_runtime();
96421
- import { existsSync as existsSync25, readdirSync as readdirSync5 } from "fs";
96422
- import { basename as basename12, join as join57 } from "path";
96423
-
96424
- // src/cli/diagnose-analysis.ts
96425
- function detectFailurePattern(story, _prd, status) {
96426
- if (story.status === "passed" && story.priorErrors?.some((err) => err.toLowerCase().includes("greenfield-no-tests"))) {
96427
- return "AUTO_RECOVERED";
96428
- }
96429
- if (story.status !== "failed" && story.status !== "blocked" && story.status !== "paused") {
96430
- return "UNKNOWN";
96431
- }
96432
- if (story.failureCategory === "greenfield-no-tests" || story.priorErrors?.some((err) => err.toLowerCase().includes("greenfield-no-tests"))) {
96433
- return "GREENFIELD_TDD";
96434
- }
96435
- const testFailingCount = story.priorErrors?.filter((err) => err.toLowerCase().includes("tests-failing")).length || 0;
96436
- if (testFailingCount >= 2)
96437
- return "TEST_MISMATCH";
96438
- if (story.priorErrors?.some((err) => err.toLowerCase().includes("precheck-failed")) || (status?.progress.blocked ?? 0) > 0) {
96439
- return "ENVIRONMENTAL";
96440
- }
96441
- if (story.priorErrors?.some((err) => err.toLowerCase().includes("ratelimited")))
96442
- return "RATE_LIMITED";
96443
- if (story.failureCategory === "isolation-violation")
96444
- return "ISOLATION_VIOLATION";
96445
- if (status?.run.status === "stalled")
96446
- return "STALLED";
96447
- if (story.priorErrors?.some((err) => err.toLowerCase().includes("session-failure")))
96448
- return "SESSION_CRASH";
96449
- if (story.attempts > 3)
96450
- return "MAX_TIERS_EXHAUSTED";
96451
- return "UNKNOWN";
96452
- }
96453
- function getPatternSymptom(pattern) {
96454
- const symptoms = {
96455
- GREENFIELD_TDD: "Story attempted in greenfield project with no existing tests",
96456
- TEST_MISMATCH: "Multiple test failures across attempts",
96457
- ENVIRONMENTAL: "Environment prechecks failed or blockers detected",
96458
- RATE_LIMITED: "API rate limit exceeded",
96459
- ISOLATION_VIOLATION: "Story modified files outside its scope",
96460
- MAX_TIERS_EXHAUSTED: "Story attempted at all configured model tiers without success",
96461
- SESSION_CRASH: "Agent session crashed without producing commits",
96462
- STALLED: "All stories blocked or paused -- no forward progress possible",
96463
- LOCK_STALE: "Lock file present but process is dead",
96464
- AUTO_RECOVERED: "Greenfield issue detected but S5 auto-recovery succeeded",
96465
- UNKNOWN: "Unknown failure pattern"
96466
- };
96467
- return symptoms[pattern] ?? "Unknown failure pattern";
96468
- }
96469
- function getPatternFixSuggestion(pattern, _story) {
96470
- const fixes = {
96471
- GREENFIELD_TDD: "Add --greenfield flag or bootstrap with scaffolding tests first",
96472
- TEST_MISMATCH: "Review acceptance criteria; tests may be too strict or story underspecified",
96473
- ENVIRONMENTAL: "Fix precheck issues (deps, env, build) before re-running",
96474
- RATE_LIMITED: "Wait for rate limit to reset or increase tier limits",
96475
- ISOLATION_VIOLATION: "Narrow story scope or adjust expectedFiles to allow cross-file changes",
96476
- MAX_TIERS_EXHAUSTED: "Simplify story or split into smaller sub-stories",
96477
- SESSION_CRASH: "Check agent logs for crash details; may need manual intervention",
96478
- STALLED: "Resolve blocked stories or skip them to unblock dependencies",
96479
- LOCK_STALE: "Run: rm nax.lock",
96480
- AUTO_RECOVERED: "No action needed -- S5 successfully handled greenfield scenario",
96481
- UNKNOWN: "Review logs and prior errors for clues"
96482
- };
96483
- return fixes[pattern] ?? "Review logs and prior errors for clues";
96484
- }
96485
- function generateRecommendations(report) {
96486
- const recommendations = [];
96487
- if (report.lockCheck.lockPresent && report.lockCheck.pidAlive === false) {
96488
- recommendations.push(`Remove stale lock: ${report.lockCheck.fixCommand}`);
96489
- }
96490
- const criticalPatterns = report.failureAnalysis.filter((f) => ["ENVIRONMENTAL", "STALLED", "SESSION_CRASH"].includes(f.pattern));
96491
- if (criticalPatterns.length > 0) {
96492
- recommendations.push(`Fix ${criticalPatterns.length} critical blocker(s): ${criticalPatterns.map((f) => f.storyId).join(", ")}`);
96493
- }
96494
- if (report.failureAnalysis.some((f) => f.pattern === "RATE_LIMITED")) {
96495
- recommendations.push("Wait for rate limits to reset before re-running");
96496
- }
96497
- if (report.failureAnalysis.some((f) => f.pattern === "GREENFIELD_TDD")) {
96498
- recommendations.push("Consider adding --greenfield flag or bootstrap tests for greenfield stories");
96499
- }
96500
- if (report.runSummary.storiesFailed > 0 && recommendations.length === 0) {
96501
- recommendations.push(`Re-run with: nax run -f ${report.runSummary.feature}`);
96502
- }
96503
- if (report.runSummary.storiesFailed === 0 && report.runSummary.storiesPending === 0) {
96504
- recommendations.push("All stories passed -- feature is complete!");
96505
- }
96506
- return recommendations;
96507
- }
96508
- function diagnoseStories(prd, status) {
96509
- const storyBreakdown = [];
96510
- const failureAnalysis = [];
96511
- for (const story of prd.userStories) {
96512
- const pattern = detectFailurePattern(story, prd, status);
96513
- const diagnosis = {
96514
- storyId: story.id,
96515
- title: story.title,
96516
- status: story.status,
96517
- attempts: story.attempts,
96518
- tier: story.routing?.modelTier,
96519
- strategy: story.routing?.testStrategy,
96520
- pattern
96521
- };
96522
- storyBreakdown.push(diagnosis);
96523
- if (story.status === "failed" || story.status === "blocked" || story.status === "paused" || pattern === "AUTO_RECOVERED") {
96524
- diagnosis.symptom = getPatternSymptom(pattern);
96525
- diagnosis.fixSuggestion = getPatternFixSuggestion(pattern, story);
96526
- failureAnalysis.push(diagnosis);
96527
- }
96528
- }
96529
- return { storyBreakdown, failureAnalysis };
96530
- }
96531
-
96532
- // src/cli/diagnose-formatter.ts
96533
- init_source();
96534
- function formatReport(report, verbose) {
96535
- const lines = [];
96536
- lines.push(source_default.bold(`
96537
- Diagnosis Report: ${report.runSummary.feature}
96538
- `));
96539
- if (!report.dataSources.eventsFound) {
96540
- lines.push(source_default.yellow(`[WARN] events.jsonl not found -- diagnosis limited to PRD + git log
96541
- `));
96542
- }
96543
- lines.push(source_default.bold(`Run Summary
96544
- `));
96545
- if (report.runSummary.lastRunTime) {
96546
- lines.push(source_default.dim(` Last Run: ${report.runSummary.lastRunTime}`));
96547
- }
96548
- lines.push(source_default.dim(` Status: ${report.runSummary.status}`));
96549
- lines.push(source_default.green(` Passed: ${report.runSummary.storiesPassed}`));
96550
- lines.push(source_default.red(` Failed: ${report.runSummary.storiesFailed}`));
96551
- lines.push(source_default.dim(` Pending: ${report.runSummary.storiesPending}`));
96552
- if (report.runSummary.cost !== undefined) {
96553
- lines.push(source_default.dim(` Cost: $${report.runSummary.cost.toFixed(4)}`));
96554
- }
96555
- lines.push(source_default.dim(` Commits: ${report.runSummary.commitsProduced}`));
96556
- lines.push("");
96557
- if (verbose && report.storyBreakdown.length > 0) {
96558
- lines.push(source_default.bold(`Story Breakdown
96559
- `));
96560
- for (const story of report.storyBreakdown) {
96561
- const icon = story.status === "passed" ? "[OK]" : story.status === "failed" ? "[FAIL]" : "[ ]";
96562
- const pattern = story.pattern !== "UNKNOWN" ? source_default.yellow(` [${story.pattern}]`) : "";
96563
- lines.push(` ${icon} ${story.storyId}: ${story.title}${pattern}`);
96564
- if (verbose && story.tier) {
96565
- lines.push(source_default.dim(` Tier: ${story.tier}, Strategy: ${story.strategy}, Attempts: ${story.attempts}`));
96566
- }
96567
- }
96568
- lines.push("");
96569
- }
96570
- if (report.failureAnalysis.length > 0) {
96571
- lines.push(source_default.bold(`Failure Analysis
96572
- `));
96573
- for (const failure of report.failureAnalysis) {
96574
- const level = failure.pattern === "AUTO_RECOVERED" ? source_default.green("INFO") : source_default.red("ERROR");
96575
- lines.push(` ${level} ${failure.storyId}: ${failure.title}`);
96576
- lines.push(source_default.dim(` Pattern: ${failure.pattern}`));
96577
- if (failure.symptom) {
96578
- lines.push(source_default.dim(` Symptom: ${failure.symptom}`));
96579
- }
96580
- if (failure.fixSuggestion) {
96581
- lines.push(source_default.yellow(` Fix: ${failure.fixSuggestion}`));
96582
- }
96583
- lines.push("");
96584
- }
96585
- }
96586
- lines.push(source_default.bold(`Lock Check
96587
- `));
96588
- if (!report.lockCheck.lockPresent) {
96589
- lines.push(source_default.dim(` No lock file present
96590
- `));
96591
- } else if (report.lockCheck.pidAlive === false) {
96592
- lines.push(source_default.red(` [FAIL] Stale lock detected (PID ${report.lockCheck.pid} is dead)`));
96593
- lines.push(source_default.yellow(` Fix: ${report.lockCheck.fixCommand}
96594
- `));
96595
- } else {
96596
- lines.push(source_default.green(` [OK] Active lock (PID ${report.lockCheck.pid})
96597
- `));
96598
- }
96599
- if (report.recommendations.length > 0) {
96600
- lines.push(source_default.bold(`Recommendations
96601
- `));
96602
- for (let i = 0;i < report.recommendations.length; i++) {
96603
- lines.push(` ${i + 1}. ${report.recommendations[i]}`);
96604
- }
96605
- lines.push("");
96606
- }
96607
- return lines.join(`
96608
- `);
96609
- }
96610
-
96611
- // src/cli/diagnose.ts
96612
- var _diagnoseDeps = {
96613
- projectOutputDir,
96614
- loadConfig
96615
- };
96616
- function isProcessAlive2(pid) {
96617
- try {
96618
- const result = Bun.spawnSync(["ps", "-p", String(pid)], { stdout: "ignore", stderr: "ignore" });
96619
- return result.exitCode === 0;
96620
- } catch {
96621
- return false;
96622
- }
96623
- }
96624
- async function loadStatusFile2(outputDir) {
96625
- const statusPath = join57(outputDir, "status.json");
96626
- if (!existsSync25(statusPath))
96627
- return null;
96628
- try {
96629
- return await Bun.file(statusPath).json();
96630
- } catch {
96631
- return null;
96632
- }
96633
- }
96634
- async function countCommitsSince(workdir, since) {
96635
- if (!since)
96636
- return 0;
96637
- try {
96638
- const result = Bun.spawnSync(["git", "log", "--oneline", `--since=${since}`, "--all"], {
96639
- cwd: workdir,
96640
- stdout: "pipe",
96641
- stderr: "ignore"
96642
- });
96643
- if (result.exitCode !== 0)
96644
- return 0;
96645
- const output = new TextDecoder().decode(result.stdout);
96646
- return output.trim().split(`
96647
- `).filter((line) => line.length > 0).length;
96648
- } catch {
96649
- return 0;
96650
- }
96651
- }
96652
- async function checkLock(workdir) {
96653
- const lockFile = Bun.file(join57(workdir, "nax.lock"));
96654
- if (!await lockFile.exists())
96655
- return { lockPresent: false };
96656
- try {
96657
- const lockData = JSON.parse(await lockFile.text());
96658
- const pid = lockData.pid;
96659
- const pidAlive = isProcessAlive2(pid);
96660
- if (!pidAlive)
96661
- return { lockPresent: true, pidAlive: false, pid, fixCommand: "rm nax.lock" };
96662
- return { lockPresent: true, pidAlive: true, pid };
96663
- } catch {
96664
- return { lockPresent: true };
96665
- }
96666
- }
96667
- async function diagnoseCommand(options = {}) {
96668
- const logger = getLogger();
96669
- const workdir = options.workdir ?? process.cwd();
96670
- const naxSubdir = findProjectDir(workdir);
96671
- let projectDir = naxSubdir ? join57(naxSubdir, "..") : null;
96672
- if (!projectDir && existsSync25(join57(workdir, ".nax"))) {
96673
- projectDir = workdir;
96674
- }
96675
- if (!projectDir)
96676
- throw new Error("Not in a nax project directory");
96677
- const config2 = await _diagnoseDeps.loadConfig(projectDir).catch(() => null);
96678
- const projectKey = config2?.name?.trim() || basename12(projectDir);
96679
- const outputDir = _diagnoseDeps.projectOutputDir(projectKey, config2?.outputDir);
96680
- let feature = options.feature;
96681
- if (!feature) {
96682
- const status2 = await loadStatusFile2(outputDir);
96683
- if (status2) {
96684
- feature = status2.run.feature;
96685
- } else {
96686
- const featuresDir = join57(outputDir, "features");
96687
- if (!existsSync25(featuresDir))
96688
- throw new Error("No features found in project");
96689
- const features = readdirSync5(featuresDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
96690
- if (features.length === 0)
96691
- throw new Error("No features found");
96692
- feature = features[0];
96693
- logger.info("diagnose", "No feature specified, using first found", { feature });
96694
- }
96695
- }
96696
- const featureDir = join57(outputDir, "features", feature);
96697
- const prdPath = join57(featureDir, "prd.json");
96698
- if (!existsSync25(prdPath))
96699
- throw new Error(`Feature not found: ${feature}`);
96700
- const prd = await loadPRD(prdPath);
96701
- const status = await loadStatusFile2(outputDir);
96702
- const lockCheck = await checkLock(projectDir);
96703
- const commitCount = await countCommitsSince(projectDir, status?.run.startedAt);
96704
- const { storyBreakdown, failureAnalysis } = diagnoseStories(prd, status);
96705
- const report = {
96706
- runSummary: {
96707
- feature,
96708
- lastRunTime: status?.run.startedAt,
96709
- status: status?.run.status ?? "unknown",
96710
- storiesPassed: prd.userStories.filter((s) => s.status === "passed").length,
96711
- storiesFailed: prd.userStories.filter((s) => s.status === "failed").length,
96712
- storiesPending: prd.userStories.filter((s) => s.status !== "passed" && s.status !== "failed" && s.status !== "skipped").length,
96713
- cost: status?.cost.spent,
96714
- commitsProduced: commitCount
96715
- },
96716
- storyBreakdown,
96717
- failureAnalysis,
96718
- lockCheck,
96719
- recommendations: [],
96720
- dataSources: {
96721
- prdFound: true,
96722
- statusFound: status !== null,
96723
- eventsFound: false,
96724
- gitLogFound: commitCount > 0
96725
- }
96726
- };
96727
- report.recommendations = generateRecommendations(report);
96728
- if (options.json) {
96729
- console.log(JSON.stringify(report, null, 2));
96730
- } else {
96731
- console.log(formatReport(report, options.verbose ?? false));
96732
- }
96733
- }
96734
96489
  // src/cli/interact.ts
96735
96490
  init_common();
96736
96491
  init_interaction();
@@ -96738,8 +96493,8 @@ init_interaction();
96738
96493
  init_source();
96739
96494
  init_loader();
96740
96495
  init_generator2();
96741
- import { existsSync as existsSync26 } from "fs";
96742
- import { join as join58 } from "path";
96496
+ import { existsSync as existsSync25 } from "fs";
96497
+ import { join as join57 } from "path";
96743
96498
  var VALID_AGENTS = ["claude", "codex", "opencode", "cursor", "windsurf", "aider", "gemini"];
96744
96499
  async function generateCommand(options) {
96745
96500
  const workdir = options.dir ?? process.cwd();
@@ -96782,7 +96537,7 @@ async function generateCommand(options) {
96782
96537
  return;
96783
96538
  }
96784
96539
  if (options.package) {
96785
- const packageDir = join58(workdir, options.package);
96540
+ const packageDir = join57(workdir, options.package);
96786
96541
  if (dryRun) {
96787
96542
  console.log(source_default.yellow("\u26A0 Dry run \u2014 no files will be written"));
96788
96543
  }
@@ -96802,10 +96557,10 @@ async function generateCommand(options) {
96802
96557
  process.exit(1);
96803
96558
  return;
96804
96559
  }
96805
- const contextPath = options.context ? join58(workdir, options.context) : join58(workdir, ".nax/context.md");
96806
- const outputDir = options.output ? join58(workdir, options.output) : workdir;
96560
+ const contextPath = options.context ? join57(workdir, options.context) : join57(workdir, ".nax/context.md");
96561
+ const outputDir = options.output ? join57(workdir, options.output) : workdir;
96807
96562
  const autoInject = !options.noAutoInject;
96808
- if (!existsSync26(contextPath)) {
96563
+ if (!existsSync25(contextPath)) {
96809
96564
  console.error(source_default.red(`\u2717 Context file not found: ${contextPath}`));
96810
96565
  console.error(source_default.yellow(" Create .nax/context.md first, or run `nax init` to scaffold it."));
96811
96566
  process.exit(1);
@@ -96908,8 +96663,8 @@ async function generateCommand(options) {
96908
96663
  }
96909
96664
  // src/cli/config-display.ts
96910
96665
  init_loader();
96911
- import { existsSync as existsSync28 } from "fs";
96912
- import { join as join60 } from "path";
96666
+ import { existsSync as existsSync27 } from "fs";
96667
+ import { join as join59 } from "path";
96913
96668
 
96914
96669
  // src/cli/config-descriptions.ts
96915
96670
  var FIELD_DESCRIPTIONS = {
@@ -97160,10 +96915,10 @@ function deepEqual(a, b) {
97160
96915
  // src/cli/config-get.ts
97161
96916
  init_defaults();
97162
96917
  init_loader();
97163
- import { existsSync as existsSync27 } from "fs";
97164
- import { join as join59 } from "path";
96918
+ import { existsSync as existsSync26 } from "fs";
96919
+ import { join as join58 } from "path";
97165
96920
  async function loadConfigFile(path18) {
97166
- if (!existsSync27(path18))
96921
+ if (!existsSync26(path18))
97167
96922
  return null;
97168
96923
  try {
97169
96924
  return await Bun.file(path18).json();
@@ -97183,7 +96938,7 @@ async function loadProjectConfig() {
97183
96938
  const projectDir = findProjectDir();
97184
96939
  if (!projectDir)
97185
96940
  return null;
97186
- const projectPath = join59(projectDir, "config.json");
96941
+ const projectPath = join58(projectDir, "config.json");
97187
96942
  return await loadConfigFile(projectPath);
97188
96943
  }
97189
96944
 
@@ -97243,14 +96998,14 @@ async function configCommand(config2, options = {}) {
97243
96998
  function determineConfigSources() {
97244
96999
  const globalPath = globalConfigPath();
97245
97000
  const projectDir = findProjectDir();
97246
- const projectPath = projectDir ? join60(projectDir, "config.json") : null;
97001
+ const projectPath = projectDir ? join59(projectDir, "config.json") : null;
97247
97002
  return {
97248
97003
  global: fileExists(globalPath) ? globalPath : null,
97249
97004
  project: projectPath && fileExists(projectPath) ? projectPath : null
97250
97005
  };
97251
97006
  }
97252
97007
  function fileExists(path18) {
97253
- return existsSync28(path18);
97008
+ return existsSync27(path18);
97254
97009
  }
97255
97010
  function displayConfigWithDescriptions(obj, path18, sources, indent = 0) {
97256
97011
  const indentStr = " ".repeat(indent);
@@ -97391,16 +97146,16 @@ function formatValueForTable(value) {
97391
97146
  init_paths();
97392
97147
  init_profile();
97393
97148
  import { mkdirSync as mkdirSync5 } from "fs";
97394
- import { readdirSync as readdirSync6 } from "fs";
97395
- import { join as join61 } from "path";
97149
+ import { readdirSync as readdirSync5 } from "fs";
97150
+ import { join as join60 } from "path";
97396
97151
  var _profileCLIDeps = {
97397
97152
  env: process.env
97398
97153
  };
97399
97154
  var SENSITIVE_KEY_PATTERN = /key|token|secret|password|credential/i;
97400
97155
  var VAR_PATTERN = /\$[A-Za-z_][A-Za-z0-9_]*/;
97401
97156
  async function profileListCommand(startDir) {
97402
- const globalProfilesDir = join61(globalConfigDir(), "profiles");
97403
- const projectProfilesDir = join61(projectConfigDir(startDir), "profiles");
97157
+ const globalProfilesDir = join60(globalConfigDir(), "profiles");
97158
+ const projectProfilesDir = join60(projectConfigDir(startDir), "profiles");
97404
97159
  const globalProfiles = scanProfileDir(globalProfilesDir);
97405
97160
  const projectProfiles = scanProfileDir(projectProfilesDir);
97406
97161
  const activeProfile = await resolveProfileName({}, _profileCLIDeps.env, startDir);
@@ -97426,7 +97181,7 @@ async function profileListCommand(startDir) {
97426
97181
  }
97427
97182
  function scanProfileDir(dir) {
97428
97183
  try {
97429
- return readdirSync6(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
97184
+ return readdirSync5(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
97430
97185
  } catch {
97431
97186
  return [];
97432
97187
  }
@@ -97459,7 +97214,7 @@ function maskProfileValues(obj) {
97459
97214
  return result;
97460
97215
  }
97461
97216
  async function profileUseCommand(profileName, startDir) {
97462
- const configPath = join61(projectConfigDir(startDir), "config.json");
97217
+ const configPath = join60(projectConfigDir(startDir), "config.json");
97463
97218
  const configFile = Bun.file(configPath);
97464
97219
  let existing = {};
97465
97220
  if (await configFile.exists()) {
@@ -97478,8 +97233,8 @@ async function profileCurrentCommand(startDir) {
97478
97233
  return resolveProfileName({}, _profileCLIDeps.env, startDir);
97479
97234
  }
97480
97235
  async function profileCreateCommand(profileName, startDir) {
97481
- const profilesDir = join61(projectConfigDir(startDir), "profiles");
97482
- const profilePath = join61(profilesDir, `${profileName}.json`);
97236
+ const profilesDir = join60(projectConfigDir(startDir), "profiles");
97237
+ const profilePath = join60(profilesDir, `${profileName}.json`);
97483
97238
  const profileFile = Bun.file(profilePath);
97484
97239
  if (await profileFile.exists()) {
97485
97240
  throw new Error(`Profile "${profileName}" already exists at ${profilePath}`);
@@ -97601,7 +97356,7 @@ async function contextInspectCommand(options) {
97601
97356
  init_canonical_loader();
97602
97357
  init_errors();
97603
97358
  import { mkdir as mkdir12 } from "fs/promises";
97604
- import { basename as basename13, join as join62 } from "path";
97359
+ import { basename as basename12, join as join61 } from "path";
97605
97360
  var _rulesCLIDeps = {
97606
97361
  readFile: async (path18) => Bun.file(path18).text(),
97607
97362
  writeFile: async (path18, content) => {
@@ -97610,7 +97365,7 @@ var _rulesCLIDeps = {
97610
97365
  fileExists: async (path18) => Bun.file(path18).exists(),
97611
97366
  globInDir: (dir) => {
97612
97367
  try {
97613
- return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join62(dir, f));
97368
+ return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join61(dir, f));
97614
97369
  } catch {
97615
97370
  return [];
97616
97371
  }
@@ -97659,7 +97414,7 @@ ${r.content}`).join(`
97659
97414
  `);
97660
97415
  const shimContent = `${header + body}
97661
97416
  `;
97662
- const shimPath = join62(workdir, shimFileName);
97417
+ const shimPath = join61(workdir, shimFileName);
97663
97418
  if (options.dryRun) {
97664
97419
  console.log(`[dry-run] Would write ${shimPath} (${shimContent.length} bytes)`);
97665
97420
  return;
@@ -97688,20 +97443,20 @@ function neutralizeContent(content) {
97688
97443
  }
97689
97444
  async function collectMigrationSources(workdir) {
97690
97445
  const sources = [];
97691
- const claudeMdPath = join62(workdir, "CLAUDE.md");
97446
+ const claudeMdPath = join61(workdir, "CLAUDE.md");
97692
97447
  if (await _rulesCLIDeps.fileExists(claudeMdPath)) {
97693
97448
  const content = await _rulesCLIDeps.readFile(claudeMdPath);
97694
97449
  if (content.trim()) {
97695
97450
  sources.push({ sourcePath: claudeMdPath, targetFileName: "project-conventions.md", content });
97696
97451
  }
97697
97452
  }
97698
- const rulesDir = join62(workdir, ".claude", "rules");
97453
+ const rulesDir = join61(workdir, ".claude", "rules");
97699
97454
  const ruleFiles = _rulesCLIDeps.globInDir(rulesDir);
97700
97455
  for (const filePath of ruleFiles) {
97701
97456
  try {
97702
97457
  const content = await _rulesCLIDeps.readFile(filePath);
97703
97458
  if (content.trim()) {
97704
- sources.push({ sourcePath: filePath, targetFileName: basename13(filePath), content });
97459
+ sources.push({ sourcePath: filePath, targetFileName: basename12(filePath), content });
97705
97460
  }
97706
97461
  } catch {}
97707
97462
  }
@@ -97715,7 +97470,7 @@ async function rulesMigrateCommand(options) {
97715
97470
  console.log("[WARN] No source files found (checked CLAUDE.md and .claude/rules/*.md). Nothing to migrate.");
97716
97471
  return;
97717
97472
  }
97718
- const targetDir = join62(workdir, CANONICAL_RULES_DIR);
97473
+ const targetDir = join61(workdir, CANONICAL_RULES_DIR);
97719
97474
  if (!options.dryRun) {
97720
97475
  try {
97721
97476
  await _rulesCLIDeps.mkdir(targetDir);
@@ -97726,7 +97481,7 @@ async function rulesMigrateCommand(options) {
97726
97481
  let written = 0;
97727
97482
  let skipped = 0;
97728
97483
  for (const { sourcePath, targetFileName, content } of sources) {
97729
- const targetPath = join62(targetDir, targetFileName);
97484
+ const targetPath = join61(targetDir, targetFileName);
97730
97485
  if (!force && !options.dryRun && await _rulesCLIDeps.fileExists(targetPath)) {
97731
97486
  console.log(`[skip] ${targetFileName} already exists (use --force to overwrite)`);
97732
97487
  skipped++;
@@ -97765,7 +97520,7 @@ function collectCanonicalRuleRoots(workdir) {
97765
97520
  const packageRel = normalized.slice(0, idx);
97766
97521
  if (!packageRel)
97767
97522
  continue;
97768
- roots.add(join62(workdir, packageRel));
97523
+ roots.add(join61(workdir, packageRel));
97769
97524
  }
97770
97525
  return [...roots].sort();
97771
97526
  }
@@ -97787,7 +97542,7 @@ init_logger2();
97787
97542
  init_detect2();
97788
97543
  init_workspace();
97789
97544
  init_common();
97790
- import { join as join63 } from "path";
97545
+ import { join as join62 } from "path";
97791
97546
  function resolveEffective(detected, configPatterns) {
97792
97547
  if (configPatterns !== undefined)
97793
97548
  return "config";
@@ -97872,7 +97627,7 @@ async function detectCommand(options) {
97872
97627
  const rootDetected = detectionMap[""] ?? { patterns: [], confidence: "empty", sources: [] };
97873
97628
  const pkgEntries = await Promise.all(packageDirs.map(async (dir) => {
97874
97629
  const det = detectionMap[dir] ?? { patterns: [], confidence: "empty", sources: [] };
97875
- const pkgConfigPath = join63(workdir, ".nax", "mono", dir, "config.json");
97630
+ const pkgConfigPath = join62(workdir, ".nax", "mono", dir, "config.json");
97876
97631
  const pkgRaw = await loadRawConfig(pkgConfigPath);
97877
97632
  const pkgPatterns = deepGet(pkgRaw, TEST_PATTERNS_KEY);
97878
97633
  const effective = Array.isArray(pkgPatterns) ? pkgPatterns : undefined;
@@ -97926,13 +97681,13 @@ async function detectCommand(options) {
97926
97681
  if (rootDetected.confidence === "empty") {
97927
97682
  console.log(source_default.yellow(" root: skipped (empty detection)"));
97928
97683
  } else {
97929
- const rootConfigPath = join63(workdir, ".nax", "config.json");
97684
+ const rootConfigPath = join62(workdir, ".nax", "config.json");
97930
97685
  try {
97931
97686
  const status = await applyToConfig(rootConfigPath, rootDetected.patterns, options.force ?? false);
97932
97687
  if (status === "skipped") {
97933
97688
  console.log(source_default.dim(" root: skipped (testFilePatterns already set; use --force to overwrite)"));
97934
97689
  } else {
97935
- console.log(source_default.green(` root: ${status} \u2192 ${join63(".nax", "config.json")}`));
97690
+ console.log(source_default.green(` root: ${status} \u2192 ${join62(".nax", "config.json")}`));
97936
97691
  }
97937
97692
  } catch (err) {
97938
97693
  console.error(source_default.red(` root: write failed \u2014 ${err.message}`));
@@ -97945,13 +97700,13 @@ async function detectCommand(options) {
97945
97700
  console.log(source_default.dim(` ${dir}: skipped (empty detection)`));
97946
97701
  continue;
97947
97702
  }
97948
- const pkgConfigPath = join63(workdir, ".nax", "mono", dir, "config.json");
97703
+ const pkgConfigPath = join62(workdir, ".nax", "mono", dir, "config.json");
97949
97704
  try {
97950
97705
  const status = await applyToConfig(pkgConfigPath, det.patterns, options.force ?? false);
97951
97706
  if (status === "skipped") {
97952
97707
  console.log(source_default.dim(` ${dir}: skipped (already set)`));
97953
97708
  } else {
97954
- console.log(source_default.green(` ${dir}: ${status} \u2192 ${join63(".nax", "mono", dir, "config.json")}`));
97709
+ console.log(source_default.green(` ${dir}: ${status} \u2192 ${join62(".nax", "mono", dir, "config.json")}`));
97955
97710
  }
97956
97711
  } catch (err) {
97957
97712
  console.error(source_default.red(` ${dir}: write failed \u2014 ${err.message}`));
@@ -97966,27 +97721,22 @@ async function detectCommand(options) {
97966
97721
  process.exitCode = allEmpty ? 1 : 0;
97967
97722
  }
97968
97723
 
97969
- // src/commands/diagnose.ts
97970
- async function diagnose(options) {
97971
- await diagnoseCommand(options);
97972
- }
97973
-
97974
97724
  // src/commands/logs.ts
97975
97725
  init_common();
97976
- import { existsSync as existsSync30 } from "fs";
97977
- import { join as join67 } from "path";
97726
+ import { existsSync as existsSync29 } from "fs";
97727
+ import { join as join66 } from "path";
97978
97728
 
97979
97729
  // src/commands/logs-formatter.ts
97980
97730
  init_source();
97981
97731
  init_formatter();
97982
- import { readdirSync as readdirSync8 } from "fs";
97983
- import { join as join66 } from "path";
97732
+ import { readdirSync as readdirSync7 } from "fs";
97733
+ import { join as join65 } from "path";
97984
97734
 
97985
97735
  // src/commands/logs-reader.ts
97986
97736
  init_paths3();
97987
- import { existsSync as existsSync29, readdirSync as readdirSync7 } from "fs";
97737
+ import { existsSync as existsSync28, readdirSync as readdirSync6 } from "fs";
97988
97738
  import { readdir as readdir4 } from "fs/promises";
97989
- import { join as join65 } from "path";
97739
+ import { join as join64 } from "path";
97990
97740
  var _logsReaderDeps = {
97991
97741
  getRunsDir
97992
97742
  };
@@ -98000,7 +97750,7 @@ async function resolveRunFileFromRegistry(runId) {
98000
97750
  }
98001
97751
  let matched = null;
98002
97752
  for (const entry of entries) {
98003
- const metaPath = join65(runsDir, entry, "meta.json");
97753
+ const metaPath = join64(runsDir, entry, "meta.json");
98004
97754
  try {
98005
97755
  const meta3 = await Bun.file(metaPath).json();
98006
97756
  if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
@@ -98012,24 +97762,24 @@ async function resolveRunFileFromRegistry(runId) {
98012
97762
  if (!matched) {
98013
97763
  throw new Error(`Run not found in registry: ${runId}`);
98014
97764
  }
98015
- if (!existsSync29(matched.eventsDir)) {
97765
+ if (!existsSync28(matched.eventsDir)) {
98016
97766
  console.log(`Log directory unavailable for run: ${runId}`);
98017
97767
  return null;
98018
97768
  }
98019
- const files = readdirSync7(matched.eventsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
97769
+ const files = readdirSync6(matched.eventsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
98020
97770
  if (files.length === 0) {
98021
97771
  console.log(`No log files found for run: ${runId}`);
98022
97772
  return null;
98023
97773
  }
98024
97774
  const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
98025
- return join65(matched.eventsDir, specificFile ?? files[0]);
97775
+ return join64(matched.eventsDir, specificFile ?? files[0]);
98026
97776
  }
98027
97777
  async function selectRunFile(runsDir) {
98028
- const files = readdirSync7(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
97778
+ const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
98029
97779
  if (files.length === 0) {
98030
97780
  return null;
98031
97781
  }
98032
- return join65(runsDir, files[0]);
97782
+ return join64(runsDir, files[0]);
98033
97783
  }
98034
97784
  async function extractRunSummary(filePath) {
98035
97785
  const file3 = Bun.file(filePath);
@@ -98104,7 +97854,7 @@ var LOG_LEVEL_PRIORITY2 = {
98104
97854
  error: 3
98105
97855
  };
98106
97856
  async function displayRunsList(runsDir) {
98107
- const files = readdirSync8(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
97857
+ const files = readdirSync7(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
98108
97858
  if (files.length === 0) {
98109
97859
  console.log(source_default.dim("No runs found"));
98110
97860
  return;
@@ -98115,7 +97865,7 @@ Runs:
98115
97865
  console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
98116
97866
  console.log(source_default.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
98117
97867
  for (const file3 of files) {
98118
- const filePath = join66(runsDir, file3);
97868
+ const filePath = join65(runsDir, file3);
98119
97869
  const summary = await extractRunSummary(filePath);
98120
97870
  const timestamp = file3.replace(".jsonl", "");
98121
97871
  const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
@@ -98229,7 +97979,7 @@ async function logsCommand(options) {
98229
97979
  return;
98230
97980
  }
98231
97981
  const resolved = resolveProject({ dir: options.dir });
98232
- const naxDir = join67(resolved.projectDir, ".nax");
97982
+ const naxDir = join66(resolved.projectDir, ".nax");
98233
97983
  const configPath = resolved.configPath;
98234
97984
  const configFile = Bun.file(configPath);
98235
97985
  const config2 = await configFile.json();
@@ -98237,9 +97987,9 @@ async function logsCommand(options) {
98237
97987
  if (!featureName) {
98238
97988
  throw new Error("No feature specified in config.json");
98239
97989
  }
98240
- const featureDir = join67(naxDir, "features", featureName);
98241
- const runsDir = join67(featureDir, "runs");
98242
- if (!existsSync30(runsDir)) {
97990
+ const featureDir = join66(naxDir, "features", featureName);
97991
+ const runsDir = join66(featureDir, "runs");
97992
+ if (!existsSync29(runsDir)) {
98243
97993
  throw new Error(`No runs directory found for feature: ${featureName}`);
98244
97994
  }
98245
97995
  if (options.list) {
@@ -98263,8 +98013,8 @@ init_config();
98263
98013
  init_prd();
98264
98014
  init_precheck();
98265
98015
  init_common();
98266
- import { existsSync as existsSync31 } from "fs";
98267
- import { join as join68 } from "path";
98016
+ import { existsSync as existsSync30 } from "fs";
98017
+ import { join as join67 } from "path";
98268
98018
  async function precheckCommand(options) {
98269
98019
  const resolved = resolveProject({
98270
98020
  dir: options.dir,
@@ -98286,14 +98036,14 @@ async function precheckCommand(options) {
98286
98036
  process.exit(1);
98287
98037
  }
98288
98038
  }
98289
- const naxDir = join68(resolved.projectDir, ".nax");
98290
- const featureDir = join68(naxDir, "features", featureName);
98291
- const prdPath = join68(featureDir, "prd.json");
98292
- if (!existsSync31(featureDir)) {
98039
+ const naxDir = join67(resolved.projectDir, ".nax");
98040
+ const featureDir = join67(naxDir, "features", featureName);
98041
+ const prdPath = join67(featureDir, "prd.json");
98042
+ if (!existsSync30(featureDir)) {
98293
98043
  console.error(source_default.red(`Feature not found: ${featureName}`));
98294
98044
  process.exit(1);
98295
98045
  }
98296
- if (!existsSync31(prdPath)) {
98046
+ if (!existsSync30(prdPath)) {
98297
98047
  console.error(source_default.red(`Missing prd.json for feature: ${featureName}`));
98298
98048
  console.error(source_default.dim(`Run: nax plan -f ${featureName} --from spec.md --auto`));
98299
98049
  process.exit(EXIT_CODES.INVALID_PRD);
@@ -98311,7 +98061,7 @@ async function precheckCommand(options) {
98311
98061
  init_source();
98312
98062
  init_paths3();
98313
98063
  import { readdir as readdir5 } from "fs/promises";
98314
- import { join as join69 } from "path";
98064
+ import { join as join68 } from "path";
98315
98065
  var DEFAULT_LIMIT = 20;
98316
98066
  var _runsCmdDeps = {
98317
98067
  getRunsDir
@@ -98366,7 +98116,7 @@ async function runsCommand(options = {}) {
98366
98116
  }
98367
98117
  const rows = [];
98368
98118
  for (const entry of entries) {
98369
- const metaPath = join69(runsDir, entry, "meta.json");
98119
+ const metaPath = join68(runsDir, entry, "meta.json");
98370
98120
  let meta3;
98371
98121
  try {
98372
98122
  meta3 = await Bun.file(metaPath).json();
@@ -98443,8 +98193,8 @@ async function runsCommand(options = {}) {
98443
98193
 
98444
98194
  // src/commands/unlock.ts
98445
98195
  init_source();
98446
- import { join as join70 } from "path";
98447
- function isProcessAlive3(pid) {
98196
+ import { join as join69 } from "path";
98197
+ function isProcessAlive2(pid) {
98448
98198
  try {
98449
98199
  process.kill(pid, 0);
98450
98200
  return true;
@@ -98458,7 +98208,7 @@ function formatLockAge(ageMs) {
98458
98208
  }
98459
98209
  async function unlockCommand(options) {
98460
98210
  const workdir = options.dir ?? process.cwd();
98461
- const lockPath = join70(workdir, "nax.lock");
98211
+ const lockPath = join69(workdir, "nax.lock");
98462
98212
  const lockFile = Bun.file(lockPath);
98463
98213
  const exists = await lockFile.exists();
98464
98214
  if (!exists) {
@@ -98476,7 +98226,7 @@ async function unlockCommand(options) {
98476
98226
  const { pid, timestamp } = lockData;
98477
98227
  const ageMs = Date.now() - timestamp;
98478
98228
  if (!options.force) {
98479
- if (isProcessAlive3(pid)) {
98229
+ if (isProcessAlive2(pid)) {
98480
98230
  console.error(source_default.red(`nax is still running (PID ${pid}). Use --force to override.`));
98481
98231
  process.exit(1);
98482
98232
  }
@@ -105156,7 +104906,7 @@ var import_react27 = __toESM(require_react(), 1);
105156
104906
  // node_modules/ink/build/hooks/use-cursor.js
105157
104907
  var import_react28 = __toESM(require_react(), 1);
105158
104908
  // src/tui/App.tsx
105159
- var import_react35 = __toESM(require_react(), 1);
104909
+ var import_react36 = __toESM(require_react(), 1);
105160
104910
 
105161
104911
  // src/utils/queue-writer.ts
105162
104912
  async function writeQueueCommand(queueFilePath, command) {
@@ -105185,151 +104935,8 @@ ${commandLine2}
105185
104935
  await Bun.write(queueFilePath, newContent);
105186
104936
  }
105187
104937
 
105188
- // node_modules/ink-spinner/build/index.js
105189
- var import_react29 = __toESM(require_react(), 1);
105190
- var import_cli_spinners = __toESM(require_cli_spinners(), 1);
105191
- function Spinner({ type = "dots" }) {
105192
- const [frame, setFrame] = import_react29.useState(0);
105193
- const spinner = import_cli_spinners.default[type];
105194
- import_react29.useEffect(() => {
105195
- const timer = setInterval(() => {
105196
- setFrame((previousFrame) => {
105197
- const isLastFrame = previousFrame === spinner.frames.length - 1;
105198
- return isLastFrame ? 0 : previousFrame + 1;
105199
- });
105200
- }, spinner.interval);
105201
- return () => {
105202
- clearInterval(timer);
105203
- };
105204
- }, [spinner]);
105205
- return import_react29.default.createElement(Text, null, spinner.frames[frame]);
105206
- }
105207
- var build_default = Spinner;
105208
-
105209
- // src/tui/components/AgentPanel.tsx
105210
- var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
105211
- var MAX_OUTPUT_LINES = 500;
105212
- function AgentPanel({ focused = false, outputLines = [], activeCalls }) {
105213
- const borderColor = focused ? "cyan" : "gray";
105214
- const bufferedLines = outputLines.length > MAX_OUTPUT_LINES ? outputLines.slice(-MAX_OUTPUT_LINES) : outputLines;
105215
- const activeCallList = activeCalls ? Array.from(activeCalls.values()) : [];
105216
- const hasActiveCalls = activeCallList.length > 0;
105217
- const hasOutput = bufferedLines.length > 0;
105218
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105219
- flexDirection: "column",
105220
- flexGrow: 1,
105221
- borderStyle: "single",
105222
- borderColor,
105223
- children: [
105224
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105225
- paddingX: 1,
105226
- borderStyle: "single",
105227
- borderBottom: true,
105228
- borderColor,
105229
- children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105230
- bold: true,
105231
- color: focused ? "cyan" : undefined,
105232
- children: [
105233
- "Agent ",
105234
- focused && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105235
- dimColor: true,
105236
- children: "(focused)"
105237
- }, undefined, false, undefined, this)
105238
- ]
105239
- }, undefined, true, undefined, this)
105240
- }, undefined, false, undefined, this),
105241
- hasActiveCalls && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105242
- flexDirection: "column",
105243
- paddingX: 1,
105244
- paddingY: 1,
105245
- children: activeCallList.map((call) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(AgentCallRow, {
105246
- call
105247
- }, call.callId, false, undefined, this))
105248
- }, undefined, false, undefined, this),
105249
- !hasActiveCalls && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105250
- flexDirection: "column",
105251
- paddingX: 1,
105252
- paddingY: 1,
105253
- children: hasOutput ? bufferedLines.map((line, i) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105254
- children: line
105255
- }, `line-${i}-${line.slice(0, 20)}`, false, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105256
- dimColor: true,
105257
- children: [
105258
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(build_default, {
105259
- type: "dots"
105260
- }, undefined, false, undefined, this),
105261
- " Waiting for agent..."
105262
- ]
105263
- }, undefined, true, undefined, this)
105264
- }, undefined, false, undefined, this)
105265
- ]
105266
- }, undefined, true, undefined, this);
105267
- }
105268
- function formatMs(ms) {
105269
- if (ms < 1000)
105270
- return `${ms}ms`;
105271
- return `${Math.floor(ms / 1000)}s`;
105272
- }
105273
- function AgentCallRow({ call }) {
105274
- const now3 = Date.now();
105275
- const elapsedMs = now3 - call.startedAt;
105276
- const idleMs = now3 - call.lastActivityAt;
105277
- return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105278
- flexDirection: "row",
105279
- gap: 1,
105280
- children: [
105281
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105282
- color: "cyan",
105283
- children: call.agentName
105284
- }, undefined, false, undefined, this),
105285
- call.storyId && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105286
- dimColor: true,
105287
- children: call.storyId
105288
- }, undefined, false, undefined, this),
105289
- call.stage && /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105290
- dimColor: true,
105291
- children: [
105292
- "[",
105293
- call.stage,
105294
- "]"
105295
- ]
105296
- }, undefined, true, undefined, this),
105297
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105298
- children: [
105299
- " elapsed:",
105300
- formatMs(elapsedMs)
105301
- ]
105302
- }, undefined, true, undefined, this),
105303
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105304
- children: [
105305
- " idle:",
105306
- formatMs(idleMs)
105307
- ]
105308
- }, undefined, true, undefined, this),
105309
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105310
- children: [
105311
- " msg:",
105312
- call.messageUpdates
105313
- ]
105314
- }, undefined, true, undefined, this),
105315
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105316
- children: [
105317
- " think:",
105318
- call.thinkingUpdates
105319
- ]
105320
- }, undefined, true, undefined, this),
105321
- /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105322
- children: [
105323
- " usage:",
105324
- call.usageUpdates
105325
- ]
105326
- }, undefined, true, undefined, this)
105327
- ]
105328
- }, undefined, true, undefined, this);
105329
- }
105330
-
105331
104938
  // src/tui/components/CostOverlay.tsx
105332
- var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
104939
+ var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
105333
104940
  function formatCost2(cost) {
105334
104941
  return `$${cost.toFixed(4)}`;
105335
104942
  }
@@ -105338,7 +104945,7 @@ function CostOverlay({ visible = false, stories = [], totalCost = 0 }) {
105338
104945
  return null;
105339
104946
  }
105340
104947
  const executedStories = stories.filter((s) => s.cost && s.cost > 0 || s.status !== "pending");
105341
- return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104948
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105342
104949
  flexDirection: "column",
105343
104950
  borderStyle: "double",
105344
104951
  borderColor: "cyan",
@@ -105346,87 +104953,87 @@ function CostOverlay({ visible = false, stories = [], totalCost = 0 }) {
105346
104953
  paddingY: 1,
105347
104954
  minWidth: 60,
105348
104955
  children: [
105349
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104956
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105350
104957
  paddingBottom: 1,
105351
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
104958
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105352
104959
  bold: true,
105353
104960
  color: "cyan",
105354
104961
  children: "Cost Breakdown"
105355
104962
  }, undefined, false, undefined, this)
105356
104963
  }, undefined, false, undefined, this),
105357
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104964
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105358
104965
  paddingBottom: 1,
105359
104966
  borderBottom: true,
105360
104967
  borderColor: "gray",
105361
104968
  children: [
105362
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104969
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105363
104970
  width: 12,
105364
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
104971
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105365
104972
  bold: true,
105366
104973
  children: "Story ID"
105367
104974
  }, undefined, false, undefined, this)
105368
104975
  }, undefined, false, undefined, this),
105369
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104976
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105370
104977
  width: 12,
105371
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
104978
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105372
104979
  bold: true,
105373
104980
  children: "Status"
105374
104981
  }, undefined, false, undefined, this)
105375
104982
  }, undefined, false, undefined, this),
105376
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104983
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105377
104984
  width: 12,
105378
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
104985
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105379
104986
  bold: true,
105380
104987
  children: "Cost"
105381
104988
  }, undefined, false, undefined, this)
105382
104989
  }, undefined, false, undefined, this)
105383
104990
  ]
105384
104991
  }, undefined, true, undefined, this),
105385
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104992
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105386
104993
  flexDirection: "column",
105387
104994
  paddingY: 1,
105388
- children: executedStories.length > 0 ? executedStories.map((story) => /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104995
+ children: executedStories.length > 0 ? executedStories.map((story) => /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105389
104996
  children: [
105390
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104997
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105391
104998
  width: 12,
105392
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
104999
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105393
105000
  children: story.story.id
105394
105001
  }, undefined, false, undefined, this)
105395
105002
  }, undefined, false, undefined, this),
105396
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105003
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105397
105004
  width: 12,
105398
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105005
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105399
105006
  color: story.status === "passed" ? "green" : story.status === "failed" ? "red" : undefined,
105400
105007
  children: story.status
105401
105008
  }, undefined, false, undefined, this)
105402
105009
  }, undefined, false, undefined, this),
105403
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105010
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105404
105011
  width: 12,
105405
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105012
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105406
105013
  children: formatCost2(story.cost || 0)
105407
105014
  }, undefined, false, undefined, this)
105408
105015
  }, undefined, false, undefined, this)
105409
105016
  ]
105410
- }, story.story.id, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105017
+ }, story.story.id, true, undefined, this)) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105411
105018
  dimColor: true,
105412
105019
  children: "No stories executed yet"
105413
105020
  }, undefined, false, undefined, this)
105414
105021
  }, undefined, false, undefined, this),
105415
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105022
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105416
105023
  paddingTop: 1,
105417
105024
  borderTop: true,
105418
105025
  borderColor: "gray",
105419
105026
  children: [
105420
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105027
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105421
105028
  width: 24,
105422
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105029
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105423
105030
  bold: true,
105424
105031
  children: "Total Cost:"
105425
105032
  }, undefined, false, undefined, this)
105426
105033
  }, undefined, false, undefined, this),
105427
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105034
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105428
105035
  width: 12,
105429
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105036
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105430
105037
  bold: true,
105431
105038
  color: "cyan",
105432
105039
  children: formatCost2(totalCost)
@@ -105434,16 +105041,16 @@ function CostOverlay({ visible = false, stories = [], totalCost = 0 }) {
105434
105041
  }, undefined, false, undefined, this)
105435
105042
  ]
105436
105043
  }, undefined, true, undefined, this),
105437
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105044
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
105438
105045
  justifyContent: "center",
105439
105046
  paddingTop: 1,
105440
105047
  borderTop: true,
105441
105048
  borderColor: "gray",
105442
- children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105049
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105443
105050
  dimColor: true,
105444
105051
  children: [
105445
105052
  "Press ",
105446
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105053
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
105447
105054
  color: "yellow",
105448
105055
  children: "Esc"
105449
105056
  }, undefined, false, undefined, this),
@@ -105456,118 +105063,118 @@ function CostOverlay({ visible = false, stories = [], totalCost = 0 }) {
105456
105063
  }
105457
105064
 
105458
105065
  // src/tui/components/HelpOverlay.tsx
105459
- var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
105066
+ var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
105460
105067
  function HelpOverlay({ visible = false }) {
105461
105068
  if (!visible) {
105462
105069
  return null;
105463
105070
  }
105464
- return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105071
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105465
105072
  flexDirection: "column",
105466
105073
  borderStyle: "double",
105467
105074
  borderColor: "cyan",
105468
105075
  paddingX: 2,
105469
105076
  paddingY: 1,
105470
105077
  children: [
105471
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105078
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105472
105079
  paddingBottom: 1,
105473
- children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105080
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105474
105081
  bold: true,
105475
105082
  color: "cyan",
105476
105083
  children: "Keyboard Shortcuts"
105477
105084
  }, undefined, false, undefined, this)
105478
105085
  }, undefined, false, undefined, this),
105479
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105086
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105480
105087
  flexDirection: "column",
105481
105088
  paddingBottom: 1,
105482
105089
  children: [
105483
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105090
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105484
105091
  dimColor: true,
105485
105092
  children: "Stories Panel (default):"
105486
105093
  }, undefined, false, undefined, this),
105487
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105094
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105488
105095
  children: [
105489
105096
  " ",
105490
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105097
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105491
105098
  color: "yellow",
105492
105099
  children: "p"
105493
105100
  }, undefined, false, undefined, this),
105494
105101
  " \u2014 Pause after current story"
105495
105102
  ]
105496
105103
  }, undefined, true, undefined, this),
105497
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105104
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105498
105105
  children: [
105499
105106
  " ",
105500
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105107
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105501
105108
  color: "yellow",
105502
105109
  children: "a"
105503
105110
  }, undefined, false, undefined, this),
105504
105111
  " \u2014 Abort run"
105505
105112
  ]
105506
105113
  }, undefined, true, undefined, this),
105507
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105114
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105508
105115
  children: [
105509
105116
  " ",
105510
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105117
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105511
105118
  color: "yellow",
105512
105119
  children: "s"
105513
105120
  }, undefined, false, undefined, this),
105514
105121
  " \u2014 Skip current story"
105515
105122
  ]
105516
105123
  }, undefined, true, undefined, this),
105517
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105124
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105518
105125
  children: [
105519
105126
  " ",
105520
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105127
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105521
105128
  color: "yellow",
105522
105129
  children: "Tab"
105523
105130
  }, undefined, false, undefined, this),
105524
105131
  " \u2014 Toggle focus to Agent panel"
105525
105132
  ]
105526
105133
  }, undefined, true, undefined, this),
105527
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105134
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105528
105135
  children: [
105529
105136
  " ",
105530
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105137
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105531
105138
  color: "yellow",
105532
105139
  children: "q"
105533
105140
  }, undefined, false, undefined, this),
105534
105141
  " \u2014 Quit TUI"
105535
105142
  ]
105536
105143
  }, undefined, true, undefined, this),
105537
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105144
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105538
105145
  children: [
105539
105146
  " ",
105540
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105147
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105541
105148
  color: "yellow",
105542
105149
  children: "?"
105543
105150
  }, undefined, false, undefined, this),
105544
105151
  " \u2014 Show this help"
105545
105152
  ]
105546
105153
  }, undefined, true, undefined, this),
105547
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105154
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105548
105155
  children: [
105549
105156
  " ",
105550
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105157
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105551
105158
  color: "yellow",
105552
105159
  children: "c"
105553
105160
  }, undefined, false, undefined, this),
105554
105161
  " \u2014 Show cost breakdown"
105555
105162
  ]
105556
105163
  }, undefined, true, undefined, this),
105557
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105164
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105558
105165
  children: [
105559
105166
  " ",
105560
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105167
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105561
105168
  color: "yellow",
105562
105169
  children: "r"
105563
105170
  }, undefined, false, undefined, this),
105564
105171
  " \u2014 Retry last failed story"
105565
105172
  ]
105566
105173
  }, undefined, true, undefined, this),
105567
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105174
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105568
105175
  children: [
105569
105176
  " ",
105570
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105177
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105571
105178
  color: "yellow",
105572
105179
  children: "Esc"
105573
105180
  }, undefined, false, undefined, this),
@@ -105576,28 +105183,28 @@ function HelpOverlay({ visible = false }) {
105576
105183
  }, undefined, true, undefined, this)
105577
105184
  ]
105578
105185
  }, undefined, true, undefined, this),
105579
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105186
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105580
105187
  flexDirection: "column",
105581
105188
  paddingBottom: 1,
105582
105189
  children: [
105583
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105190
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105584
105191
  dimColor: true,
105585
105192
  children: "Agent Panel (when focused):"
105586
105193
  }, undefined, false, undefined, this),
105587
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105194
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105588
105195
  children: [
105589
105196
  " ",
105590
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105197
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105591
105198
  color: "yellow",
105592
105199
  children: "Ctrl+]"
105593
105200
  }, undefined, false, undefined, this),
105594
105201
  " \u2014 Escape back to Stories panel"
105595
105202
  ]
105596
105203
  }, undefined, true, undefined, this),
105597
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105204
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105598
105205
  children: [
105599
105206
  " ",
105600
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105207
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105601
105208
  dimColor: true,
105602
105209
  children: "All other keys"
105603
105210
  }, undefined, false, undefined, this),
@@ -105606,16 +105213,16 @@ function HelpOverlay({ visible = false }) {
105606
105213
  }, undefined, true, undefined, this)
105607
105214
  ]
105608
105215
  }, undefined, true, undefined, this),
105609
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105216
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
105610
105217
  justifyContent: "center",
105611
105218
  paddingTop: 1,
105612
105219
  borderTop: true,
105613
105220
  borderColor: "gray",
105614
- children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105221
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105615
105222
  dimColor: true,
105616
105223
  children: [
105617
105224
  "Press ",
105618
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105225
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
105619
105226
  color: "yellow",
105620
105227
  children: "Esc"
105621
105228
  }, undefined, false, undefined, this),
@@ -105627,46 +105234,289 @@ function HelpOverlay({ visible = false }) {
105627
105234
  }, undefined, true, undefined, this);
105628
105235
  }
105629
105236
 
105630
- // src/tui/components/StatusBar.tsx
105631
- var jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
105632
- function StatusBar({ currentStory, currentStage, modelTier, testStrategy }) {
105633
- if (!currentStory) {
105634
- return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
105635
- paddingX: 1,
105636
- borderStyle: "single",
105637
- borderColor: "gray",
105638
- children: /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
105639
- dimColor: true,
105640
- children: "Idle"
105641
- }, undefined, false, undefined, this)
105642
- }, undefined, false, undefined, this);
105643
- }
105644
- const storyInfo = `Story ${currentStory.id}`;
105645
- const stageInfo = currentStage ? ` \xB7 ${currentStage}` : "";
105646
- const tierInfo = modelTier ? ` \xB7 ${modelTier}` : "";
105647
- const strategyInfo = testStrategy ? ` \xB7 ${testStrategy}` : "";
105648
- return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
105649
- paddingX: 1,
105237
+ // node_modules/ink-spinner/build/index.js
105238
+ var import_react29 = __toESM(require_react(), 1);
105239
+ var import_cli_spinners = __toESM(require_cli_spinners(), 1);
105240
+ function Spinner({ type = "dots" }) {
105241
+ const [frame, setFrame] = import_react29.useState(0);
105242
+ const spinner = import_cli_spinners.default[type];
105243
+ import_react29.useEffect(() => {
105244
+ const timer = setInterval(() => {
105245
+ setFrame((previousFrame) => {
105246
+ const isLastFrame = previousFrame === spinner.frames.length - 1;
105247
+ return isLastFrame ? 0 : previousFrame + 1;
105248
+ });
105249
+ }, spinner.interval);
105250
+ return () => {
105251
+ clearInterval(timer);
105252
+ };
105253
+ }, [spinner]);
105254
+ return import_react29.default.createElement(Text, null, spinner.frames[frame]);
105255
+ }
105256
+ var build_default = Spinner;
105257
+
105258
+ // src/tui/components/LiveActivityPanel.tsx
105259
+ var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
105260
+ var MAX_ESCALATION_DISPLAY = 5;
105261
+ function LiveActivityPanel({
105262
+ focused = false,
105263
+ activeCalls,
105264
+ runSummary,
105265
+ runErrored,
105266
+ escalationLog = []
105267
+ }) {
105268
+ const borderColor = focused ? "cyan" : "gray";
105269
+ const activeCallList = activeCalls ? Array.from(activeCalls.values()) : [];
105270
+ const hasActiveCalls = activeCallList.length > 0;
105271
+ const hasSummary = runSummary !== undefined;
105272
+ const hasError = runErrored !== undefined;
105273
+ const recentEscalations = escalationLog.slice(-MAX_ESCALATION_DISPLAY);
105274
+ const hasEscalations = recentEscalations.length > 0;
105275
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105276
+ flexDirection: "column",
105277
+ flexGrow: 1,
105650
105278
  borderStyle: "single",
105651
- borderColor: "gray",
105652
- children: /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
105279
+ borderColor,
105280
+ children: [
105281
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105282
+ paddingX: 1,
105283
+ borderStyle: "single",
105284
+ borderBottom: true,
105285
+ borderColor,
105286
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105287
+ bold: true,
105288
+ color: focused ? "cyan" : undefined,
105289
+ children: [
105290
+ "Live Activity ",
105291
+ focused && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105292
+ dimColor: true,
105293
+ children: "(focused)"
105294
+ }, undefined, false, undefined, this)
105295
+ ]
105296
+ }, undefined, true, undefined, this)
105297
+ }, undefined, false, undefined, this),
105298
+ hasError && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105299
+ paddingX: 1,
105300
+ paddingY: 1,
105301
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105302
+ color: "red",
105303
+ children: [
105304
+ "[FAIL] ",
105305
+ runErrored
105306
+ ]
105307
+ }, undefined, true, undefined, this)
105308
+ }, undefined, false, undefined, this),
105309
+ hasSummary && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105310
+ flexDirection: "column",
105311
+ paddingX: 1,
105312
+ paddingY: 1,
105313
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(RunSummaryRow, {
105314
+ summary: runSummary
105315
+ }, undefined, false, undefined, this)
105316
+ }, undefined, false, undefined, this),
105317
+ hasActiveCalls && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105318
+ flexDirection: "column",
105319
+ paddingX: 1,
105320
+ paddingY: 1,
105321
+ children: activeCallList.map((call) => /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(ActiveCallRow, {
105322
+ call
105323
+ }, call.callId, false, undefined, this))
105324
+ }, undefined, false, undefined, this),
105325
+ hasEscalations && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105326
+ flexDirection: "column",
105327
+ paddingX: 1,
105328
+ children: [
105329
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105330
+ dimColor: true,
105331
+ children: "Escalations:"
105332
+ }, undefined, false, undefined, this),
105333
+ recentEscalations.map((entry) => /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(EscalationRow, {
105334
+ entry
105335
+ }, `${entry.storyId}-${entry.at}`, false, undefined, this))
105336
+ ]
105337
+ }, undefined, true, undefined, this),
105338
+ !hasActiveCalls && !hasSummary && !hasError && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105339
+ paddingX: 1,
105340
+ paddingY: 1,
105341
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105342
+ dimColor: true,
105343
+ children: [
105344
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(build_default, {
105345
+ type: "dots"
105346
+ }, undefined, false, undefined, this),
105347
+ " Waiting for agent..."
105348
+ ]
105349
+ }, undefined, true, undefined, this)
105350
+ }, undefined, false, undefined, this)
105351
+ ]
105352
+ }, undefined, true, undefined, this);
105353
+ }
105354
+ function ActiveCallRow({ call }) {
105355
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105356
+ flexDirection: "column",
105357
+ marginBottom: 1,
105358
+ children: [
105359
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105360
+ flexDirection: "row",
105361
+ gap: 1,
105362
+ children: [
105363
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105364
+ color: "cyan",
105365
+ children: call.agentName
105366
+ }, undefined, false, undefined, this),
105367
+ call.storyId && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105368
+ children: call.storyId
105369
+ }, undefined, false, undefined, this),
105370
+ call.stage && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105371
+ dimColor: true,
105372
+ children: [
105373
+ "[",
105374
+ call.stage,
105375
+ "]"
105376
+ ]
105377
+ }, undefined, true, undefined, this)
105378
+ ]
105379
+ }, undefined, true, undefined, this),
105380
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105381
+ flexDirection: "row",
105382
+ gap: 1,
105383
+ children: [
105384
+ call.model && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105385
+ dimColor: true,
105386
+ children: [
105387
+ "model:",
105388
+ call.model
105389
+ ]
105390
+ }, undefined, true, undefined, this),
105391
+ call.lastToolName && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105392
+ dimColor: true,
105393
+ children: [
105394
+ "tool:",
105395
+ call.lastToolName
105396
+ ]
105397
+ }, undefined, true, undefined, this),
105398
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105399
+ dimColor: true,
105400
+ children: [
105401
+ "tools:",
105402
+ call.toolCallUpdates,
105403
+ " msg:",
105404
+ call.messageUpdates
105405
+ ]
105406
+ }, undefined, true, undefined, this)
105407
+ ]
105408
+ }, undefined, true, undefined, this)
105409
+ ]
105410
+ }, undefined, true, undefined, this);
105411
+ }
105412
+ function RunSummaryRow({ summary }) {
105413
+ const cost = summary.totalCost !== undefined ? `$${summary.totalCost.toFixed(4)}` : null;
105414
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105415
+ flexDirection: "column",
105416
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105417
+ flexDirection: "row",
105418
+ gap: 1,
105653
105419
  children: [
105654
- /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
105420
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105655
105421
  bold: true,
105656
- children: storyInfo
105422
+ children: "Run complete"
105657
105423
  }, undefined, false, undefined, this),
105658
- /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
105424
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105425
+ color: "green",
105426
+ children: [
105427
+ summary.passedStories,
105428
+ " passed"
105429
+ ]
105430
+ }, undefined, true, undefined, this),
105431
+ summary.failedStories > 0 && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105432
+ color: "red",
105433
+ children: [
105434
+ summary.failedStories,
105435
+ " failed"
105436
+ ]
105437
+ }, undefined, true, undefined, this),
105438
+ summary.skippedStories > 0 && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105659
105439
  dimColor: true,
105660
105440
  children: [
105661
- stageInfo,
105662
- tierInfo,
105663
- strategyInfo
105441
+ summary.skippedStories,
105442
+ " skipped"
105664
105443
  ]
105665
- }, undefined, true, undefined, this)
105444
+ }, undefined, true, undefined, this),
105445
+ cost && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105446
+ dimColor: true,
105447
+ children: cost
105448
+ }, undefined, false, undefined, this)
105666
105449
  ]
105667
105450
  }, undefined, true, undefined, this)
105668
105451
  }, undefined, false, undefined, this);
105669
105452
  }
105453
+ function EscalationRow({ entry }) {
105454
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
105455
+ flexDirection: "row",
105456
+ gap: 1,
105457
+ children: [
105458
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105459
+ dimColor: true,
105460
+ children: entry.storyId
105461
+ }, undefined, false, undefined, this),
105462
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105463
+ color: "yellow",
105464
+ children: entry.fromTier
105465
+ }, undefined, false, undefined, this),
105466
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105467
+ dimColor: true,
105468
+ children: "->"
105469
+ }, undefined, false, undefined, this),
105470
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
105471
+ color: "cyan",
105472
+ children: entry.toTier
105473
+ }, undefined, false, undefined, this)
105474
+ ]
105475
+ }, undefined, true, undefined, this);
105476
+ }
105477
+
105478
+ // src/tui/components/StatusBar.tsx
105479
+ var jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
105480
+ function StatusBar({
105481
+ currentStage,
105482
+ currentStoryId,
105483
+ modelTier,
105484
+ runPaused,
105485
+ runComplete,
105486
+ isParallel,
105487
+ activeCount = 0
105488
+ }) {
105489
+ const hints = runComplete ? "q quit c cost ? help" : "p pause a abort s skip c cost ? help";
105490
+ let context;
105491
+ if (runComplete) {
105492
+ context = "done";
105493
+ } else if (runPaused) {
105494
+ context = "run paused";
105495
+ } else if (isParallel && activeCount > 0) {
105496
+ context = `parallel \xB7 ${activeCount} active`;
105497
+ } else if (currentStoryId) {
105498
+ const parts = [currentStoryId, currentStage, modelTier].filter(Boolean);
105499
+ context = parts.join(" \xB7 ");
105500
+ } else {
105501
+ context = "idle";
105502
+ }
105503
+ return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
105504
+ paddingX: 1,
105505
+ borderStyle: "single",
105506
+ borderColor: "gray",
105507
+ justifyContent: "space-between",
105508
+ children: [
105509
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
105510
+ dimColor: true,
105511
+ children: hints
105512
+ }, undefined, false, undefined, this),
105513
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
105514
+ dimColor: true,
105515
+ children: context
105516
+ }, undefined, false, undefined, this)
105517
+ ]
105518
+ }, undefined, true, undefined, this);
105519
+ }
105670
105520
 
105671
105521
  // src/tui/components/StoriesPanel.tsx
105672
105522
  var import_react31 = __toESM(require_react(), 1);
@@ -105731,13 +105581,7 @@ function getStatusIcon(status) {
105731
105581
  return "\u23F8\uFE0F";
105732
105582
  }
105733
105583
  }
105734
- function formatElapsedTime(ms) {
105735
- const totalSeconds = Math.floor(ms / 1000);
105736
- const minutes = Math.floor(totalSeconds / 60);
105737
- const seconds = totalSeconds % 60;
105738
- return `${minutes}m ${seconds}s`;
105739
- }
105740
- function StoriesPanel({ stories, totalCost, elapsedMs, width, compact: compact2 = false, maxHeight }) {
105584
+ function StoriesPanel({ stories, width, compact: compact2 = false, maxHeight }) {
105741
105585
  const maxVisible = compact2 ? COMPACT_MAX_VISIBLE_STORIES : MAX_VISIBLE_STORIES;
105742
105586
  const needsScrolling = stories.length > maxVisible;
105743
105587
  const [scrollOffset, setScrollOffset] = import_react31.useState(0);
@@ -105810,20 +105654,37 @@ function StoriesPanel({ stories, totalCost, elapsedMs, width, compact: compact2
105810
105654
  }, undefined, true, undefined, this)
105811
105655
  }, s.story.id, false, undefined, this);
105812
105656
  }
105813
- const routing = s.routing ? ` ${s.routing.complexity.slice(0, 3)} ${s.routing.modelTier}` : "";
105657
+ const routing = s.routing ? ` ${s.routing.complexity.slice(0, 3)}` : "";
105658
+ const shortTier = s.modelTier?.slice(0, 3);
105659
+ const tierSuffix = s.status === "retrying" && shortTier ? `\u2192${shortTier}` : s.status === "running" && shortTier ? shortTier : "";
105660
+ const showFailureLine = (s.status === "failed" || s.status === "paused") && s.failureReason;
105814
105661
  return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
105815
- children: /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105816
- children: [
105817
- icon,
105818
- " ",
105819
- s.story.id,
105820
- /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105821
- dimColor: true,
105822
- children: routing
105823
- }, undefined, false, undefined, this)
105824
- ]
105825
- }, undefined, true, undefined, this)
105826
- }, s.story.id, false, undefined, this);
105662
+ flexDirection: "column",
105663
+ children: [
105664
+ /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105665
+ children: [
105666
+ icon,
105667
+ " ",
105668
+ s.story.id,
105669
+ /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105670
+ dimColor: true,
105671
+ children: routing
105672
+ }, undefined, false, undefined, this),
105673
+ tierSuffix ? /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105674
+ dimColor: true,
105675
+ children: [
105676
+ " ",
105677
+ tierSuffix
105678
+ ]
105679
+ }, undefined, true, undefined, this) : null
105680
+ ]
105681
+ }, undefined, true, undefined, this),
105682
+ showFailureLine && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105683
+ dimColor: true,
105684
+ children: ` \u2514 ${s.failureReason.slice(0, 25)}`
105685
+ }, undefined, false, undefined, this)
105686
+ ]
105687
+ }, s.story.id, true, undefined, this);
105827
105688
  })
105828
105689
  }, undefined, false, undefined, this),
105829
105690
  needsScrolling && canScrollDown && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
@@ -105836,50 +105697,7 @@ function StoriesPanel({ stories, totalCost, elapsedMs, width, compact: compact2
105836
105697
  " more below"
105837
105698
  ]
105838
105699
  }, undefined, true, undefined, this)
105839
- }, undefined, false, undefined, this),
105840
- /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
105841
- flexDirection: "column",
105842
- paddingX: 1,
105843
- paddingY: 1,
105844
- borderStyle: "single",
105845
- borderTop: true,
105846
- borderColor: "gray",
105847
- children: [
105848
- !compact2 && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(jsx_dev_runtime5.Fragment, {
105849
- children: [
105850
- /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105851
- children: [
105852
- "Cost: ",
105853
- /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105854
- color: "green",
105855
- children: [
105856
- "$",
105857
- totalCost.toFixed(4)
105858
- ]
105859
- }, undefined, true, undefined, this)
105860
- ]
105861
- }, undefined, true, undefined, this),
105862
- /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105863
- children: [
105864
- "Time: ",
105865
- /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105866
- color: "cyan",
105867
- children: formatElapsedTime(elapsedMs)
105868
- }, undefined, false, undefined, this)
105869
- ]
105870
- }, undefined, true, undefined, this)
105871
- ]
105872
- }, undefined, true, undefined, this),
105873
- compact2 && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Text, {
105874
- children: [
105875
- "$",
105876
- totalCost.toFixed(2),
105877
- " \xB7 ",
105878
- formatElapsedTime(elapsedMs)
105879
- ]
105880
- }, undefined, true, undefined, this)
105881
- ]
105882
- }, undefined, true, undefined, this)
105700
+ }, undefined, false, undefined, this)
105883
105701
  ]
105884
105702
  }, undefined, true, undefined, this);
105885
105703
  }
@@ -105908,7 +105726,8 @@ function useAgentStreamEvents(bus) {
105908
105726
  thinkingUpdates: 0,
105909
105727
  usageUpdates: 0,
105910
105728
  toolCallUpdates: 0,
105911
- status: "active"
105729
+ status: "active",
105730
+ model: event.model
105912
105731
  });
105913
105732
  break;
105914
105733
  }
@@ -105951,7 +105770,8 @@ function useAgentStreamEvents(bus) {
105951
105770
  next.set(event.callId, {
105952
105771
  ...state,
105953
105772
  toolCallUpdates: state.toolCallUpdates + 1,
105954
- lastActivityAt: event.timestamp
105773
+ lastActivityAt: event.timestamp,
105774
+ lastToolName: event.toolName
105955
105775
  });
105956
105776
  }
105957
105777
  break;
@@ -106025,128 +105845,159 @@ function useKeyboard({ focus, currentStory, onAction, disabled = false }) {
106025
105845
  });
106026
105846
  }
106027
105847
 
106028
- // src/tui/hooks/usePipelineEvents.ts
105848
+ // src/tui/hooks/usePipelineBusEvents.ts
105849
+ init_pipeline();
106029
105850
  var import_react33 = __toESM(require_react(), 1);
106030
- function usePipelineEvents(events, initialStories) {
105851
+ function usePipelineBusEvents(initialStories) {
106031
105852
  const [state, setState] = import_react33.useState(() => ({
106032
- stories: initialStories.map((story) => ({
106033
- story,
106034
- status: story.passes ? "passed" : "pending",
106035
- routing: story.routing,
106036
- cost: 0
106037
- })),
105853
+ stories: initialStories,
106038
105854
  totalCost: 0,
106039
- elapsedMs: 0
105855
+ elapsedMs: 0,
105856
+ runPaused: false,
105857
+ runErrored: false,
105858
+ escalationLog: []
106040
105859
  }));
106041
105860
  const startTimeRef = import_react33.useRef(Date.now());
106042
105861
  import_react33.useEffect(() => {
106043
105862
  const startTime = startTimeRef.current;
106044
- let timer = null;
106045
- const startTimer = () => {
106046
- if (!timer) {
106047
- timer = setInterval(() => {
106048
- setState((prev) => ({
106049
- ...prev,
106050
- elapsedMs: Date.now() - startTime
106051
- }));
106052
- }, 1000);
106053
- }
106054
- };
106055
- const stopTimer = () => {
106056
- if (timer) {
106057
- clearInterval(timer);
106058
- timer = null;
106059
- }
106060
- };
106061
- const onStoryStart = (story) => {
106062
- startTimer();
105863
+ const timer = setInterval(() => {
106063
105864
  setState((prev) => ({
106064
105865
  ...prev,
106065
- currentStory: story,
106066
- stories: prev.stories.map((s) => s.story.id === story.id ? { ...s, status: "running" } : s)
105866
+ elapsedMs: Date.now() - startTime
106067
105867
  }));
106068
- };
106069
- const onStoryComplete = (story, result2) => {
106070
- stopTimer();
105868
+ }, 1000);
105869
+ const unsubStarted = pipelineEventBus.on("story:started", (event) => {
105870
+ setState((prev) => ({
105871
+ ...prev,
105872
+ stories: prev.stories.map((s) => s.story.id === event.storyId ? {
105873
+ ...s,
105874
+ status: "running",
105875
+ modelTier: event.modelTier,
105876
+ iteration: event.iteration
105877
+ } : s)
105878
+ }));
105879
+ });
105880
+ const unsubCompleted = pipelineEventBus.on("story:completed", (event) => {
106071
105881
  setState((prev) => {
106072
105882
  const newStories = prev.stories.map((s) => {
106073
- if (s.story.id === story.id) {
106074
- let status = "pending";
106075
- if (result2.action === "continue") {
106076
- status = "passed";
106077
- } else if (result2.action === "fail") {
106078
- status = "failed";
106079
- } else if (result2.action === "skip") {
106080
- status = "skipped";
106081
- } else if (result2.action === "pause") {
106082
- status = "paused";
106083
- }
106084
- const storyCost = (s.cost || 0) + (result2.cost || 0);
105883
+ if (s.story.id === event.storyId) {
105884
+ const status = event.passed ? "passed" : "failed";
105885
+ const storyCost = event.cost ?? s.cost;
106085
105886
  return { ...s, status, cost: storyCost };
106086
105887
  }
106087
105888
  return s;
106088
105889
  });
106089
- const totalCost = newStories.reduce((sum2, s) => sum2 + (s.cost || 0), 0);
106090
- return {
106091
- ...prev,
106092
- stories: newStories,
106093
- currentStory: undefined,
106094
- totalCost
106095
- };
105890
+ const totalCost = newStories.reduce((sum2, s) => sum2 + (s.cost ?? 0), 0);
105891
+ return { ...prev, stories: newStories, totalCost };
106096
105892
  });
106097
- };
106098
- const onStoryEscalate = (story) => {
105893
+ });
105894
+ const unsubFailed = pipelineEventBus.on("story:failed", (event) => {
106099
105895
  setState((prev) => ({
106100
105896
  ...prev,
106101
- stories: prev.stories.map((s) => s.story.id === story.id ? { ...s, status: "retrying" } : s)
105897
+ stories: prev.stories.map((s) => s.story.id === event.storyId ? {
105898
+ ...s,
105899
+ status: "failed",
105900
+ failureReason: event.reason
105901
+ } : s)
106102
105902
  }));
106103
- };
106104
- const onStageEnter = (stage) => {
105903
+ });
105904
+ const unsubSkipped = pipelineEventBus.on("story:skipped", (event) => {
106105
105905
  setState((prev) => ({
106106
105906
  ...prev,
106107
- currentStage: stage
105907
+ stories: prev.stories.map((s) => s.story.id === event.storyId ? { ...s, status: "skipped" } : s)
106108
105908
  }));
106109
- };
106110
- const onRunComplete = (summary) => {
105909
+ });
105910
+ const unsubEscalated = pipelineEventBus.on("story:escalated", (event) => {
105911
+ const entry = {
105912
+ storyId: event.storyId,
105913
+ fromTier: event.fromTier,
105914
+ toTier: event.toTier,
105915
+ at: Date.now()
105916
+ };
106111
105917
  setState((prev) => ({
106112
105918
  ...prev,
106113
- totalCost: summary.totalCost,
106114
- summary
105919
+ stories: prev.stories.map((s) => s.story.id === event.storyId ? { ...s, status: "retrying" } : s),
105920
+ escalationLog: [...prev.escalationLog, entry]
106115
105921
  }));
106116
- };
106117
- events.on("story:start", onStoryStart);
106118
- events.on("story:complete", onStoryComplete);
106119
- events.on("story:escalate", onStoryEscalate);
106120
- events.on("stage:enter", onStageEnter);
106121
- events.on("run:complete", onRunComplete);
105922
+ });
105923
+ const unsubStoryPaused = pipelineEventBus.on("story:paused", (event) => {
105924
+ setState((prev) => ({
105925
+ ...prev,
105926
+ stories: prev.stories.map((s) => s.story.id === event.storyId ? { ...s, status: "paused", failureReason: event.reason } : s)
105927
+ }));
105928
+ });
105929
+ const unsubPaused = pipelineEventBus.on("run:paused", (_event) => {
105930
+ setState((prev) => ({ ...prev, runPaused: true }));
105931
+ });
105932
+ const unsubResumed = pipelineEventBus.on("run:resumed", (_event) => {
105933
+ setState((prev) => ({ ...prev, runPaused: false }));
105934
+ });
105935
+ const unsubCompleted2 = pipelineEventBus.on("run:completed", (event) => {
105936
+ clearInterval(timer);
105937
+ const summary = {
105938
+ totalStories: event.totalStories,
105939
+ passedStories: event.passedStories,
105940
+ failedStories: event.failedStories,
105941
+ skippedStories: event.skippedStories,
105942
+ pausedStories: event.pausedStories,
105943
+ durationMs: event.durationMs,
105944
+ totalCost: event.totalCost
105945
+ };
105946
+ setState((prev) => ({
105947
+ ...prev,
105948
+ elapsedMs: event.durationMs,
105949
+ runSummary: summary,
105950
+ totalCost: event.totalCost ?? prev.totalCost
105951
+ }));
105952
+ });
105953
+ const unsubErrored = pipelineEventBus.on("run:errored", (_event) => {
105954
+ setState((prev) => ({ ...prev, runErrored: true }));
105955
+ });
106122
105956
  return () => {
106123
- stopTimer();
106124
- events.off("story:start", onStoryStart);
106125
- events.off("story:complete", onStoryComplete);
106126
- events.off("story:escalate", onStoryEscalate);
106127
- events.off("stage:enter", onStageEnter);
106128
- events.off("run:complete", onRunComplete);
105957
+ clearInterval(timer);
105958
+ unsubStarted();
105959
+ unsubCompleted();
105960
+ unsubFailed();
105961
+ unsubSkipped();
105962
+ unsubEscalated();
105963
+ unsubStoryPaused();
105964
+ unsubPaused();
105965
+ unsubResumed();
105966
+ unsubCompleted2();
105967
+ unsubErrored();
106129
105968
  };
106130
- }, [events]);
105969
+ }, []);
106131
105970
  return state;
106132
105971
  }
106133
105972
 
106134
- // src/tui/hooks/usePty.ts
105973
+ // src/tui/hooks/usePipelineEvents.ts
106135
105974
  var import_react34 = __toESM(require_react(), 1);
105975
+ function usePipelineEvents(events) {
105976
+ const [currentStage, setCurrentStage] = import_react34.useState(undefined);
105977
+ import_react34.useEffect(() => {
105978
+ const onStageEnter = (stage) => setCurrentStage(stage);
105979
+ events.on("stage:enter", onStageEnter);
105980
+ return () => events.off("stage:enter", onStageEnter);
105981
+ }, [events]);
105982
+ return { currentStage };
105983
+ }
105984
+
105985
+ // src/tui/hooks/usePty.ts
105986
+ var import_react35 = __toESM(require_react(), 1);
106136
105987
  var MAX_PTY_BUFFER_LINES = 500;
106137
105988
  var MAX_LINE_LENGTH = 1e4;
106138
105989
  var PTY_FLUSH_INTERVAL_MS = 100;
106139
105990
  function usePty(options) {
106140
- const [state, setState] = import_react34.useState(() => ({
105991
+ const [state, setState] = import_react35.useState(() => ({
106141
105992
  outputLines: [],
106142
105993
  isRunning: false
106143
105994
  }));
106144
- const [handle, setHandle] = import_react34.useState(null);
105995
+ const [handle, setHandle] = import_react35.useState(null);
106145
105996
  const command = options?.command;
106146
105997
  const argsJson = JSON.stringify(options?.args);
106147
105998
  const cwd2 = options?.cwd;
106148
105999
  const envJson = JSON.stringify(options?.env);
106149
- import_react34.useEffect(() => {
106000
+ import_react35.useEffect(() => {
106150
106001
  if (!command) {
106151
106002
  return;
106152
106003
  }
@@ -106215,8 +106066,8 @@ function usePty(options) {
106215
106066
  proc.kill();
106216
106067
  };
106217
106068
  }, [command, argsJson, cwd2, envJson]);
106218
- const handleResize = import_react34.useCallback((_cols, _rows) => {}, []);
106219
- import_react34.useEffect(() => {
106069
+ const handleResize = import_react35.useCallback((_cols, _rows) => {}, []);
106070
+ import_react35.useEffect(() => {
106220
106071
  const onResize = () => {
106221
106072
  const cols = process.stdout.columns ?? 80;
106222
106073
  const rows = process.stdout.rows ?? 24;
@@ -106232,6 +106083,14 @@ function usePty(options) {
106232
106083
 
106233
106084
  // src/tui/App.tsx
106234
106085
  var jsx_dev_runtime6 = __toESM(require_jsx_dev_runtime(), 1);
106086
+ function formatElapsed(ms) {
106087
+ const mins = Math.floor(ms / 60000);
106088
+ const secs = Math.floor(ms % 60000 / 1000);
106089
+ return `${mins}m ${secs}s`;
106090
+ }
106091
+ function formatCost3(cost) {
106092
+ return `$${cost.toFixed(4)}`;
106093
+ }
106235
106094
  function App2({
106236
106095
  feature,
106237
106096
  stories: initialStories,
@@ -106241,15 +106100,21 @@ function App2({
106241
106100
  agentStreamEvents
106242
106101
  }) {
106243
106102
  const layout = useLayout();
106244
- const state = usePipelineEvents(events, initialStories.map((s) => s.story));
106103
+ const busState = usePipelineBusEvents(initialStories);
106104
+ const { currentStage } = usePipelineEvents(events);
106245
106105
  const { exit } = use_app_default();
106246
- const [focus, setFocus] = import_react35.useState("stories" /* Stories */);
106247
- const [showHelp, setShowHelp] = import_react35.useState(false);
106248
- const [showCost, setShowCost] = import_react35.useState(false);
106249
- const [showQuitConfirm, setShowQuitConfirm] = import_react35.useState(false);
106250
- const [showAbortConfirm, setShowAbortConfirm] = import_react35.useState(false);
106251
- const { outputLines: agentOutputLines, handle: ptyHandle } = usePty(ptyOptions ?? null);
106106
+ const [focus, setFocus] = import_react36.useState("stories" /* Stories */);
106107
+ const [showHelp, setShowHelp] = import_react36.useState(false);
106108
+ const [showCost, setShowCost] = import_react36.useState(false);
106109
+ const [showQuitConfirm, setShowQuitConfirm] = import_react36.useState(false);
106110
+ const [showAbortConfirm, setShowAbortConfirm] = import_react36.useState(false);
106111
+ const { handle: ptyHandle } = usePty(ptyOptions ?? null);
106252
106112
  const { activeCalls } = useAgentStreamEvents(agentStreamEvents);
106113
+ const isRunComplete = !!busState.runSummary;
106114
+ const runningStories = busState.stories.filter((s) => s.status === "running");
106115
+ const isParallel = runningStories.length > 1;
106116
+ const currentRunningStory = runningStories[0];
106117
+ const runErroredForPanel = busState.runErrored ? "Run encountered an error" : undefined;
106253
106118
  const handleKeyboardAction = async (action) => {
106254
106119
  switch (action.type) {
106255
106120
  case "TOGGLE_FOCUS":
@@ -106271,7 +106136,7 @@ function App2({
106271
106136
  setShowAbortConfirm(false);
106272
106137
  break;
106273
106138
  case "QUIT":
106274
- if (state.currentStory) {
106139
+ if (currentRunningStory) {
106275
106140
  setShowQuitConfirm(true);
106276
106141
  } else {
106277
106142
  exit();
@@ -106283,7 +106148,7 @@ function App2({
106283
106148
  }
106284
106149
  break;
106285
106150
  case "ABORT":
106286
- if (state.currentStory) {
106151
+ if (currentRunningStory) {
106287
106152
  setShowAbortConfirm(true);
106288
106153
  } else if (queueFilePath) {
106289
106154
  await writeQueueCommand(queueFilePath, { type: "ABORT" });
@@ -106325,12 +106190,18 @@ function App2({
106325
106190
  });
106326
106191
  useKeyboard({
106327
106192
  focus,
106328
- currentStory: state.currentStory,
106193
+ currentStory: currentRunningStory?.story,
106329
106194
  onAction: handleKeyboardAction,
106330
106195
  disabled: showQuitConfirm || showAbortConfirm
106331
106196
  });
106332
- const currentRouting = state.currentStory?.routing;
106333
106197
  const isTooSmall = layout.width < MIN_TERMINAL_WIDTH;
106198
+ const activeCount = runningStories.length;
106199
+ const headerRight = [
106200
+ activeCount > 0 ? `${activeCount} running` : null,
106201
+ formatCost3(busState.totalCost),
106202
+ formatElapsed(busState.elapsedMs)
106203
+ ].filter(Boolean).join(" \xB7 ");
106204
+ const maxHeight = layout.mode === "single" ? COMPACT_MAX_VISIBLE_STORIES : MAX_VISIBLE_STORIES;
106334
106205
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
106335
106206
  flexDirection: "column",
106336
106207
  height: "100%",
@@ -106340,22 +106211,29 @@ function App2({
106340
106211
  borderStyle: "single",
106341
106212
  borderBottom: true,
106342
106213
  borderColor: "cyan",
106343
- children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
106344
- bold: true,
106345
- color: "cyan",
106346
- children: [
106347
- "nax run \u2014 ",
106348
- feature
106349
- ]
106350
- }, undefined, true, undefined, this)
106351
- }, undefined, false, undefined, this),
106214
+ justifyContent: "space-between",
106215
+ children: [
106216
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
106217
+ bold: true,
106218
+ color: "cyan",
106219
+ children: [
106220
+ "nax run \u2014 ",
106221
+ feature
106222
+ ]
106223
+ }, undefined, true, undefined, this),
106224
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
106225
+ dimColor: true,
106226
+ children: headerRight
106227
+ }, undefined, false, undefined, this)
106228
+ ]
106229
+ }, undefined, true, undefined, this),
106352
106230
  isTooSmall && /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
106353
106231
  paddingX: 1,
106354
106232
  backgroundColor: "yellow",
106355
106233
  children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
106356
106234
  color: "black",
106357
106235
  children: [
106358
- "\u26A0\uFE0F Terminal too narrow (",
106236
+ "Terminal too narrow (",
106359
106237
  layout.width,
106360
106238
  " cols). Minimum ",
106361
106239
  MIN_TERMINAL_WIDTH,
@@ -106368,33 +106246,36 @@ function App2({
106368
106246
  flexGrow: 1,
106369
106247
  children: [
106370
106248
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(StoriesPanel, {
106371
- stories: state.stories,
106372
- totalCost: state.totalCost,
106373
- elapsedMs: state.elapsedMs,
106249
+ stories: busState.stories,
106374
106250
  width: layout.mode === "single" ? layout.width : layout.storiesPanelWidth,
106375
106251
  compact: layout.mode === "single",
106376
- maxHeight: layout.mode === "single" ? 10 : undefined
106252
+ maxHeight
106377
106253
  }, undefined, false, undefined, this),
106378
- /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(AgentPanel, {
106254
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(LiveActivityPanel, {
106379
106255
  focused: focus === "agent" /* Agent */,
106380
- outputLines: agentOutputLines,
106381
- activeCalls
106256
+ activeCalls,
106257
+ runSummary: busState.runSummary,
106258
+ runErrored: runErroredForPanel,
106259
+ escalationLog: busState.escalationLog
106382
106260
  }, undefined, false, undefined, this)
106383
106261
  ]
106384
106262
  }, undefined, true, undefined, this),
106385
106263
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(StatusBar, {
106386
- currentStory: state.currentStory,
106387
- currentStage: state.currentStage,
106388
- modelTier: currentRouting?.modelTier,
106389
- testStrategy: currentRouting?.testStrategy
106264
+ currentStage,
106265
+ currentStoryId: currentRunningStory?.story.id,
106266
+ modelTier: currentRunningStory?.modelTier,
106267
+ runPaused: busState.runPaused,
106268
+ runComplete: isRunComplete,
106269
+ isParallel,
106270
+ activeCount
106390
106271
  }, undefined, false, undefined, this),
106391
106272
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(HelpOverlay, {
106392
106273
  visible: showHelp
106393
106274
  }, undefined, false, undefined, this),
106394
106275
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(CostOverlay, {
106395
106276
  visible: showCost,
106396
- stories: state.stories,
106397
- totalCost: state.totalCost
106277
+ stories: busState.stories,
106278
+ totalCost: busState.totalCost
106398
106279
  }, undefined, false, undefined, this),
106399
106280
  showQuitConfirm && /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
106400
106281
  position: "absolute",
@@ -106412,7 +106293,7 @@ function App2({
106412
106293
  children: [
106413
106294
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
106414
106295
  color: "yellow",
106415
- children: "\u26A0\uFE0F Story is running. Quit anyway?"
106296
+ children: "Story is running. Quit anyway?"
106416
106297
  }, undefined, false, undefined, this),
106417
106298
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
106418
106299
  paddingTop: 1,
@@ -106452,7 +106333,7 @@ function App2({
106452
106333
  children: [
106453
106334
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
106454
106335
  color: "red",
106455
- children: "\u26A0\uFE0F Story is running. Abort anyway?"
106336
+ children: "Story is running. Abort anyway?"
106456
106337
  }, undefined, false, undefined, this),
106457
106338
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
106458
106339
  paddingTop: 1,
@@ -106541,8 +106422,8 @@ Next: nax generate --package ${options.package}`));
106541
106422
  }
106542
106423
  return;
106543
106424
  }
106544
- const naxDir = join84(workdir, ".nax");
106545
- if (existsSync37(naxDir) && !options.force) {
106425
+ const naxDir = join83(workdir, ".nax");
106426
+ if (existsSync36(naxDir) && !options.force) {
106546
106427
  console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
106547
106428
  return;
106548
106429
  }
@@ -106570,11 +106451,11 @@ Next: nax generate --package ${options.package}`));
106570
106451
  }
106571
106452
  }
106572
106453
  }
106573
- mkdirSync7(join84(naxDir, "features"), { recursive: true });
106574
- mkdirSync7(join84(naxDir, "hooks"), { recursive: true });
106454
+ mkdirSync7(join83(naxDir, "features"), { recursive: true });
106455
+ mkdirSync7(join83(naxDir, "hooks"), { recursive: true });
106575
106456
  const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
106576
- await Bun.write(join84(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
106577
- await Bun.write(join84(naxDir, "hooks.json"), JSON.stringify({
106457
+ await Bun.write(join83(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
106458
+ await Bun.write(join83(naxDir, "hooks.json"), JSON.stringify({
106578
106459
  hooks: {
106579
106460
  "on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
106580
106461
  "on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
@@ -106582,12 +106463,12 @@ Next: nax generate --package ${options.package}`));
106582
106463
  "on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
106583
106464
  }
106584
106465
  }, null, 2));
106585
- await Bun.write(join84(naxDir, ".gitignore"), `# nax temp files
106466
+ await Bun.write(join83(naxDir, ".gitignore"), `# nax temp files
106586
106467
  *.tmp
106587
106468
  .paused.json
106588
106469
  .nax-verifier-verdict.json
106589
106470
  `);
106590
- await Bun.write(join84(naxDir, "context.md"), `# Project Context
106471
+ await Bun.write(join83(naxDir, "context.md"), `# Project Context
106591
106472
 
106592
106473
  This document defines coding standards, architectural decisions, and forbidden patterns for this project.
106593
106474
  Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
@@ -106684,7 +106565,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
106684
106565
  console.error(source_default.red("Error: --plan requires --from <spec-path>"));
106685
106566
  process.exit(1);
106686
106567
  }
106687
- if (options.from && !existsSync37(options.from)) {
106568
+ if (options.from && !existsSync36(options.from)) {
106688
106569
  console.error(source_default.red(`Error: File not found: ${options.from} (required with --plan)`));
106689
106570
  process.exit(1);
106690
106571
  }
@@ -106717,10 +106598,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
106717
106598
  console.error(source_default.red("nax not initialized. Run: nax init"));
106718
106599
  process.exit(1);
106719
106600
  }
106720
- const featureDir = join84(naxDir, "features", options.feature);
106721
- const prdPath = join84(featureDir, "prd.json");
106601
+ const featureDir = join83(naxDir, "features", options.feature);
106602
+ const prdPath = join83(featureDir, "prd.json");
106722
106603
  if (options.plan && options.from) {
106723
- if (existsSync37(prdPath) && !options.force) {
106604
+ if (existsSync36(prdPath) && !options.force) {
106724
106605
  console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
106725
106606
  console.error(source_default.dim(" Use --force to overwrite, or run without --plan to use the existing PRD."));
106726
106607
  process.exit(1);
@@ -106740,10 +106621,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
106740
106621
  }
106741
106622
  }
106742
106623
  try {
106743
- const planLogDir = join84(featureDir, "plan");
106624
+ const planLogDir = join83(featureDir, "plan");
106744
106625
  mkdirSync7(planLogDir, { recursive: true });
106745
106626
  const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
106746
- const planLogPath = join84(planLogDir, `${planLogId}.jsonl`);
106627
+ const planLogPath = join83(planLogDir, `${planLogId}.jsonl`);
106747
106628
  initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
106748
106629
  console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
106749
106630
  console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
@@ -106782,17 +106663,17 @@ program2.command("run").description("Run the orchestration loop for a feature").
106782
106663
  process.exit(1);
106783
106664
  }
106784
106665
  }
106785
- if (!existsSync37(prdPath)) {
106666
+ if (!existsSync36(prdPath)) {
106786
106667
  console.error(source_default.red(`Feature "${options.feature}" not found or missing prd.json`));
106787
106668
  process.exit(1);
106788
106669
  }
106789
106670
  resetLogger();
106790
- const projectKey = config2.name?.trim() || basename17(workdir);
106671
+ const projectKey = config2.name?.trim() || basename16(workdir);
106791
106672
  const outputDir = projectOutputDir(projectKey, config2.outputDir);
106792
- const runsDir = join84(outputDir, "features", options.feature, "runs");
106673
+ const runsDir = join83(outputDir, "features", options.feature, "runs");
106793
106674
  mkdirSync7(runsDir, { recursive: true });
106794
106675
  const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
106795
- const logFilePath = join84(runsDir, `${runId}.jsonl`);
106676
+ const logFilePath = join83(runsDir, `${runId}.jsonl`);
106796
106677
  const isTTY = process.stdout.isTTY ?? false;
106797
106678
  const headlessFlag = options.headless ?? false;
106798
106679
  const headlessEnv = process.env.NAX_HEADLESS === "1";
@@ -106809,7 +106690,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
106809
106690
  config2.agent.default = options.agent;
106810
106691
  }
106811
106692
  config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
106812
- const globalNaxDir = join84(homedir3(), ".nax");
106693
+ const globalNaxDir = join83(homedir3(), ".nax");
106813
106694
  const hooks = await loadHooksConfig(naxDir, globalNaxDir);
106814
106695
  const eventEmitter = new PipelineEventEmitter;
106815
106696
  let tuiInstance;
@@ -106824,15 +106705,13 @@ program2.command("run").description("Run the orchestration loop for a feature").
106824
106705
  tuiInstance = renderTui({
106825
106706
  feature: options.feature,
106826
106707
  stories: initialStories,
106827
- totalCost: 0,
106828
- elapsedMs: 0,
106829
106708
  events: eventEmitter,
106830
106709
  ptyOptions: null
106831
106710
  });
106832
106711
  } else {
106833
106712
  console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
106834
106713
  }
106835
- const statusFilePath = join84(outputDir, "status.json");
106714
+ const statusFilePath = join83(outputDir, "status.json");
106836
106715
  let parallel;
106837
106716
  if (options.parallel !== undefined) {
106838
106717
  parallel = Number.parseInt(options.parallel, 10);
@@ -106858,9 +106737,9 @@ program2.command("run").description("Run the orchestration loop for a feature").
106858
106737
  headless: useHeadless,
106859
106738
  skipPrecheck: options.skipPrecheck ?? false
106860
106739
  });
106861
- const latestSymlink = join84(runsDir, "latest.jsonl");
106740
+ const latestSymlink = join83(runsDir, "latest.jsonl");
106862
106741
  try {
106863
- if (existsSync37(latestSymlink)) {
106742
+ if (existsSync36(latestSymlink)) {
106864
106743
  Bun.spawnSync(["rm", latestSymlink]);
106865
106744
  }
106866
106745
  Bun.spawnSync(["ln", "-s", `${runId}.jsonl`, latestSymlink], {
@@ -106919,9 +106798,9 @@ features.command("create <name>").description("Create a new feature").option("-d
106919
106798
  console.error(source_default.red("nax not initialized. Run: nax init"));
106920
106799
  process.exit(1);
106921
106800
  }
106922
- const featureDir = join84(naxDir, "features", name);
106801
+ const featureDir = join83(naxDir, "features", name);
106923
106802
  mkdirSync7(featureDir, { recursive: true });
106924
- await Bun.write(join84(featureDir, "spec.md"), `# Feature: ${name}
106803
+ await Bun.write(join83(featureDir, "spec.md"), `# Feature: ${name}
106925
106804
 
106926
106805
  ## Overview
106927
106806
 
@@ -106954,7 +106833,7 @@ features.command("create <name>").description("Create a new feature").option("-d
106954
106833
 
106955
106834
  <!-- What this feature explicitly does NOT cover. -->
106956
106835
  `);
106957
- await Bun.write(join84(featureDir, "progress.txt"), `# Progress: ${name}
106836
+ await Bun.write(join83(featureDir, "progress.txt"), `# Progress: ${name}
106958
106837
 
106959
106838
  Created: ${new Date().toISOString()}
106960
106839
 
@@ -106980,13 +106859,13 @@ features.command("list").description("List all features").option("-d, --dir <pat
106980
106859
  console.error(source_default.red("nax not initialized."));
106981
106860
  process.exit(1);
106982
106861
  }
106983
- const featuresDir = join84(naxDir, "features");
106984
- if (!existsSync37(featuresDir)) {
106862
+ const featuresDir = join83(naxDir, "features");
106863
+ if (!existsSync36(featuresDir)) {
106985
106864
  console.log(source_default.dim("No features yet."));
106986
106865
  return;
106987
106866
  }
106988
- const { readdirSync: readdirSync10 } = await import("fs");
106989
- const entries = readdirSync10(featuresDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
106867
+ const { readdirSync: readdirSync9 } = await import("fs");
106868
+ const entries = readdirSync9(featuresDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
106990
106869
  if (entries.length === 0) {
106991
106870
  console.log(source_default.dim("No features yet."));
106992
106871
  return;
@@ -106995,8 +106874,8 @@ features.command("list").description("List all features").option("-d, --dir <pat
106995
106874
  Features:
106996
106875
  `));
106997
106876
  for (const name of entries) {
106998
- const prdPath = join84(featuresDir, name, "prd.json");
106999
- if (existsSync37(prdPath)) {
106877
+ const prdPath = join83(featuresDir, name, "prd.json");
106878
+ if (existsSync36(prdPath)) {
107000
106879
  const prd = await loadPRD(prdPath);
107001
106880
  const c = countStories(prd);
107002
106881
  console.log(` ${name} \u2014 ${c.passed}/${c.total} stories done`);
@@ -107030,10 +106909,10 @@ Use: nax plan -f <feature> --from <spec>`));
107030
106909
  cliOverrides.profile = options.profile;
107031
106910
  }
107032
106911
  const config2 = await loadConfig(workdir, cliOverrides);
107033
- const featureLogDir = join84(naxDir, "features", options.feature, "plan");
106912
+ const featureLogDir = join83(naxDir, "features", options.feature, "plan");
107034
106913
  mkdirSync7(featureLogDir, { recursive: true });
107035
106914
  const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
107036
- const planLogPath = join84(featureLogDir, `${planLogId}.jsonl`);
106915
+ const planLogPath = join83(featureLogDir, `${planLogId}.jsonl`);
107037
106916
  initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
107038
106917
  console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
107039
106918
  try {
@@ -107198,19 +107077,6 @@ program2.command("logs").description("Display run logs with filtering and follow
107198
107077
  process.exit(1);
107199
107078
  }
107200
107079
  });
107201
- program2.command("diagnose").description("Diagnose run failures and generate recommendations").option("-f, --feature <name>", "Feature name (defaults to current feature)").option("-d, --dir <path>", "Working directory", process.cwd()).option("--json", "Output machine-readable JSON", false).option("--verbose", "Verbose output with story breakdown", false).action(async (options) => {
107202
- try {
107203
- await diagnose({
107204
- feature: options.feature,
107205
- workdir: options.dir,
107206
- json: options.json,
107207
- verbose: options.verbose
107208
- });
107209
- } catch (err) {
107210
- console.error(source_default.red(`Error: ${err.message}`));
107211
- process.exit(1);
107212
- }
107213
- });
107214
107080
  program2.command("precheck").description("Validate feature readiness before execution").option("-f, --feature <name>", "Feature name").option("-d, --dir <path>", "Project directory", process.cwd()).option("--json", "Output machine-readable JSON", false).option("--light", "Environment-only check \u2014 skips PRD validation (use before nax plan)", false).action(async (options) => {
107215
107081
  try {
107216
107082
  await precheckCommand({