kairn-cli 2.2.3 → 2.2.4

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.
package/dist/cli.js CHANGED
@@ -221,7 +221,7 @@ var ui = {
221
221
  // Key-value pairs
222
222
  kv: (key, value) => ` ${chalk.cyan(key.padEnd(14))} ${value}`,
223
223
  // File list
224
- file: (path24) => chalk.dim(` ${path24}`),
224
+ file: (path25) => chalk.dim(` ${path25}`),
225
225
  // Tool display
226
226
  tool: (name, reason) => ` ${warmStone("\u25CF")} ${chalk.bold(name)}
227
227
  ${chalk.dim(reason)}`,
@@ -3702,8 +3702,8 @@ var keysCommand = new Command10("keys").description("Add or update API keys for
3702
3702
  import { Command as Command11 } from "commander";
3703
3703
  import chalk14 from "chalk";
3704
3704
  import ora2 from "ora";
3705
- import fs23 from "fs/promises";
3706
- import path23 from "path";
3705
+ import fs24 from "fs/promises";
3706
+ import path24 from "path";
3707
3707
  import { parse as yamlParse2 } from "yaml";
3708
3708
  import { confirm as confirm3, select as select4 } from "@inquirer/prompts";
3709
3709
 
@@ -4569,31 +4569,77 @@ function parseToolCalls(stdout) {
4569
4569
  return [];
4570
4570
  }
4571
4571
  }
4572
- async function evaluateAll(tasks, harnessPath, workspacePath, iteration, config, onProgress) {
4572
+ function computeStddev(values, mean) {
4573
+ if (values.length <= 1) return 0;
4574
+ const sumSqDiffs = values.reduce((sum, v) => sum + (v - mean) ** 2, 0);
4575
+ return Math.sqrt(sumSqDiffs / values.length);
4576
+ }
4577
+ async function evaluateAll(tasks, harnessPath, workspacePath, iteration, config, onProgress, runsPerTask = 1) {
4573
4578
  const results = {};
4574
4579
  const projectRoot = path18.resolve(workspacePath, "..");
4580
+ const effectiveRuns = Math.max(1, runsPerTask);
4575
4581
  for (const task of tasks) {
4576
- const traceDir = path18.join(
4577
- workspacePath,
4578
- "traces",
4579
- iteration.toString(),
4580
- task.id
4581
- );
4582
4582
  onProgress?.({ type: "task-start", iteration, taskId: task.id });
4583
- const taskResult = await runTask(task, harnessPath, traceDir, iteration, projectRoot);
4584
- let score = taskResult.score;
4585
- if (config) {
4586
- const stdout = await fs18.readFile(path18.join(traceDir, "stdout.log"), "utf-8").catch(() => "");
4587
- const stderr = await fs18.readFile(path18.join(traceDir, "stderr.log"), "utf-8").catch(() => "");
4588
- score = await scoreTask(task, traceDir, stdout, stderr, config);
4589
- await writeScore(traceDir, score);
4590
- }
4591
- results[task.id] = score;
4583
+ if (effectiveRuns > 1 && config) {
4584
+ const runScores = [];
4585
+ let passCount = 0;
4586
+ for (let run = 0; run < effectiveRuns; run++) {
4587
+ const traceDir = path18.join(
4588
+ workspacePath,
4589
+ "traces",
4590
+ iteration.toString(),
4591
+ `${task.id}_run${run}`
4592
+ );
4593
+ onProgress?.({
4594
+ type: "task-run",
4595
+ iteration,
4596
+ taskId: task.id,
4597
+ message: `Run ${run + 1}/${effectiveRuns} of ${task.id}`
4598
+ });
4599
+ await runTask(task, harnessPath, traceDir, iteration, projectRoot);
4600
+ const stdout = await fs18.readFile(path18.join(traceDir, "stdout.log"), "utf-8").catch(() => "");
4601
+ const stderr = await fs18.readFile(path18.join(traceDir, "stderr.log"), "utf-8").catch(() => "");
4602
+ const score = await scoreTask(task, traceDir, stdout, stderr, config);
4603
+ await writeScore(traceDir, score);
4604
+ runScores.push(score.score ?? (score.pass ? 100 : 0));
4605
+ if (score.pass) passCount++;
4606
+ }
4607
+ const mean = runScores.reduce((a, b) => a + b, 0) / runScores.length;
4608
+ const stddev = computeStddev(runScores, mean);
4609
+ results[task.id] = {
4610
+ pass: passCount > effectiveRuns / 2,
4611
+ score: mean,
4612
+ details: `Mean of ${effectiveRuns} runs`,
4613
+ variance: {
4614
+ runs: effectiveRuns,
4615
+ scores: runScores,
4616
+ mean,
4617
+ stddev
4618
+ }
4619
+ };
4620
+ } else {
4621
+ const traceDir = path18.join(
4622
+ workspacePath,
4623
+ "traces",
4624
+ iteration.toString(),
4625
+ task.id
4626
+ );
4627
+ const taskResult = await runTask(task, harnessPath, traceDir, iteration, projectRoot);
4628
+ let score = taskResult.score;
4629
+ if (config) {
4630
+ const stdout = await fs18.readFile(path18.join(traceDir, "stdout.log"), "utf-8").catch(() => "");
4631
+ const stderr = await fs18.readFile(path18.join(traceDir, "stderr.log"), "utf-8").catch(() => "");
4632
+ score = await scoreTask(task, traceDir, stdout, stderr, config);
4633
+ await writeScore(traceDir, score);
4634
+ }
4635
+ results[task.id] = score;
4636
+ }
4637
+ const finalScore = results[task.id];
4592
4638
  onProgress?.({
4593
4639
  type: "task-scored",
4594
4640
  iteration,
4595
4641
  taskId: task.id,
4596
- score: score.score ?? (score.pass ? 100 : 0)
4642
+ score: finalScore.score ?? (finalScore.pass ? 100 : 0)
4597
4643
  });
4598
4644
  }
4599
4645
  const scores = Object.values(results);
@@ -5052,7 +5098,8 @@ async function evolve(workspacePath, tasks, kairnConfig, evolveConfig, onProgres
5052
5098
  workspacePath,
5053
5099
  iter,
5054
5100
  kairnConfig,
5055
- onProgress
5101
+ onProgress,
5102
+ evolveConfig.runsPerTask
5056
5103
  );
5057
5104
  onProgress?.({ type: "iteration-scored", iteration: iter, score: aggregate });
5058
5105
  if (iter === 0) baselineScore = aggregate;
@@ -5409,24 +5456,128 @@ async function generateJsonReport(workspacePath) {
5409
5456
  };
5410
5457
  }
5411
5458
 
5459
+ // src/evolve/apply.ts
5460
+ import fs23 from "fs/promises";
5461
+ import path23 from "path";
5462
+ async function listIterations(workspacePath) {
5463
+ const iterationsDir = path23.join(workspacePath, "iterations");
5464
+ let entries;
5465
+ try {
5466
+ entries = await fs23.readdir(iterationsDir);
5467
+ } catch {
5468
+ return [];
5469
+ }
5470
+ const nums = [];
5471
+ for (const entry of entries) {
5472
+ const n = parseInt(entry, 10);
5473
+ if (!isNaN(n)) {
5474
+ try {
5475
+ await fs23.access(path23.join(iterationsDir, entry, "harness"));
5476
+ nums.push(n);
5477
+ } catch {
5478
+ }
5479
+ }
5480
+ }
5481
+ return nums.sort((a, b) => a - b);
5482
+ }
5483
+ async function findBestIteration(workspacePath, iterations) {
5484
+ let bestIter = iterations[0];
5485
+ let bestScore = -Infinity;
5486
+ for (const iter of iterations) {
5487
+ const log = await loadIterationLog(workspacePath, iter);
5488
+ const score = log?.score ?? 0;
5489
+ if (score > bestScore) {
5490
+ bestScore = score;
5491
+ bestIter = iter;
5492
+ }
5493
+ }
5494
+ return bestIter;
5495
+ }
5496
+ async function listFilesRecursive(dir) {
5497
+ const results = [];
5498
+ async function walk(current) {
5499
+ let entries;
5500
+ try {
5501
+ entries = await fs23.readdir(current, { withFileTypes: true });
5502
+ } catch {
5503
+ return;
5504
+ }
5505
+ for (const entry of entries) {
5506
+ const fullPath = path23.join(current, entry.name);
5507
+ if (entry.isDirectory()) {
5508
+ await walk(fullPath);
5509
+ } else {
5510
+ results.push(path23.relative(dir, fullPath));
5511
+ }
5512
+ }
5513
+ }
5514
+ await walk(dir);
5515
+ return results;
5516
+ }
5517
+ async function applyEvolution(workspacePath, projectRoot, targetIteration) {
5518
+ const iterations = await listIterations(workspacePath);
5519
+ if (iterations.length === 0) {
5520
+ throw new Error("No iterations found in workspace. Run `kairn evolve run` first.");
5521
+ }
5522
+ let iter;
5523
+ if (targetIteration !== void 0) {
5524
+ if (!iterations.includes(targetIteration)) {
5525
+ throw new Error(
5526
+ `Iteration ${targetIteration} not found. Available: ${iterations.join(", ")}`
5527
+ );
5528
+ }
5529
+ iter = targetIteration;
5530
+ } else {
5531
+ iter = await findBestIteration(workspacePath, iterations);
5532
+ }
5533
+ const harnessPath = path23.join(
5534
+ workspacePath,
5535
+ "iterations",
5536
+ iter.toString(),
5537
+ "harness"
5538
+ );
5539
+ const claudeDir = path23.join(projectRoot, ".claude");
5540
+ const diffPreview = await generateDiff2(claudeDir, harnessPath);
5541
+ const currentFiles = await listFilesRecursive(claudeDir);
5542
+ const targetFiles = await listFilesRecursive(harnessPath);
5543
+ const allPaths = /* @__PURE__ */ new Set([...currentFiles, ...targetFiles]);
5544
+ const filesChanged = [];
5545
+ for (const filePath of allPaths) {
5546
+ const currentContent = await fs23.readFile(path23.join(claudeDir, filePath), "utf-8").catch(() => null);
5547
+ const targetContent = await fs23.readFile(path23.join(harnessPath, filePath), "utf-8").catch(() => null);
5548
+ if (currentContent !== targetContent) {
5549
+ filesChanged.push(filePath);
5550
+ }
5551
+ }
5552
+ await fs23.rm(claudeDir, { recursive: true, force: true });
5553
+ await copyDir(harnessPath, claudeDir);
5554
+ return {
5555
+ iteration: iter,
5556
+ filesChanged,
5557
+ diffPreview
5558
+ };
5559
+ }
5560
+
5412
5561
  // src/commands/evolve.ts
5413
5562
  var DEFAULT_CONFIG = {
5414
5563
  model: "claude-sonnet-4-6",
5415
5564
  proposerModel: "claude-opus-4-6",
5416
5565
  scorer: "pass-fail",
5417
5566
  maxIterations: 5,
5418
- parallelTasks: 1
5567
+ parallelTasks: 1,
5568
+ runsPerTask: 1
5419
5569
  };
5420
5570
  async function loadEvolveConfigFromWorkspace(workspacePath) {
5421
5571
  try {
5422
- const configStr = await fs23.readFile(path23.join(workspacePath, "config.yaml"), "utf-8");
5572
+ const configStr = await fs24.readFile(path24.join(workspacePath, "config.yaml"), "utf-8");
5423
5573
  const parsed = yamlParse2(configStr);
5424
5574
  return {
5425
5575
  model: parsed.model ?? DEFAULT_CONFIG.model,
5426
5576
  proposerModel: parsed.proposer_model ?? DEFAULT_CONFIG.proposerModel,
5427
5577
  scorer: parsed.scorer ?? DEFAULT_CONFIG.scorer,
5428
5578
  maxIterations: parsed.max_iterations ?? DEFAULT_CONFIG.maxIterations,
5429
- parallelTasks: parsed.parallel_tasks ?? DEFAULT_CONFIG.parallelTasks
5579
+ parallelTasks: parsed.parallel_tasks ?? DEFAULT_CONFIG.parallelTasks,
5580
+ runsPerTask: parsed.runs_per_task ?? DEFAULT_CONFIG.runsPerTask
5430
5581
  };
5431
5582
  } catch {
5432
5583
  return { ...DEFAULT_CONFIG };
@@ -5437,9 +5588,9 @@ evolveCommand.command("init").description("Initialize an evolution workspace wit
5437
5588
  try {
5438
5589
  const projectRoot = process.cwd();
5439
5590
  console.log(ui.section("Evolve Init"));
5440
- const claudeDir = path23.join(projectRoot, ".claude");
5591
+ const claudeDir = path24.join(projectRoot, ".claude");
5441
5592
  try {
5442
- await fs23.access(claudeDir);
5593
+ await fs24.access(claudeDir);
5443
5594
  } catch {
5444
5595
  console.log(ui.error("No .claude/ directory found. Run kairn describe first."));
5445
5596
  process.exit(1);
@@ -5489,7 +5640,7 @@ evolveCommand.command("init").description("Initialize an evolution workspace wit
5489
5640
  if (config) {
5490
5641
  let claudeMd = "";
5491
5642
  try {
5492
- claudeMd = await fs23.readFile(path23.join(claudeDir, "CLAUDE.md"), "utf-8");
5643
+ claudeMd = await fs24.readFile(path24.join(claudeDir, "CLAUDE.md"), "utf-8");
5493
5644
  } catch {
5494
5645
  }
5495
5646
  const profile = await buildProjectProfile(projectRoot);
@@ -5520,16 +5671,16 @@ evolveCommand.command("init").description("Initialize an evolution workspace wit
5520
5671
  evolveCommand.command("baseline").description("Snapshot current .claude/ directory as baseline").action(async () => {
5521
5672
  try {
5522
5673
  const projectRoot = process.cwd();
5523
- const workspace = path23.join(projectRoot, ".kairn-evolve");
5674
+ const workspace = path24.join(projectRoot, ".kairn-evolve");
5524
5675
  console.log(ui.section("Evolve Baseline"));
5525
5676
  try {
5526
- await fs23.access(workspace);
5677
+ await fs24.access(workspace);
5527
5678
  } catch {
5528
5679
  console.log(ui.error("No .kairn-evolve/ directory found. Run kairn evolve init first."));
5529
5680
  process.exit(1);
5530
5681
  }
5531
5682
  await snapshotBaseline(projectRoot, workspace);
5532
- const baselineDir = path23.join(workspace, "baseline");
5683
+ const baselineDir = path24.join(workspace, "baseline");
5533
5684
  const fileCount = await countFiles(baselineDir);
5534
5685
  console.log(ui.success(`Baseline snapshot created (${fileCount} files)`));
5535
5686
  } catch (err) {
@@ -5538,21 +5689,21 @@ evolveCommand.command("baseline").description("Snapshot current .claude/ directo
5538
5689
  process.exit(1);
5539
5690
  }
5540
5691
  });
5541
- evolveCommand.command("run").description("Run tasks against the current harness").option("--task <id>", "Run a specific task by ID").option("--iterations <n>", "Number of evolution iterations", "5").action(async (options) => {
5692
+ evolveCommand.command("run").description("Run tasks against the current harness").option("--task <id>", "Run a specific task by ID").option("--iterations <n>", "Number of evolution iterations", "5").option("--runs <n>", "Run each task N times for variance measurement", "1").action(async (options) => {
5542
5693
  try {
5543
5694
  const projectRoot = process.cwd();
5544
- const workspace = path23.join(projectRoot, ".kairn-evolve");
5695
+ const workspace = path24.join(projectRoot, ".kairn-evolve");
5545
5696
  console.log(ui.section("Evolve Run"));
5546
5697
  try {
5547
- await fs23.access(workspace);
5698
+ await fs24.access(workspace);
5548
5699
  } catch {
5549
5700
  console.log(ui.error("No .kairn-evolve/ directory found. Run kairn evolve init first."));
5550
5701
  process.exit(1);
5551
5702
  }
5552
- const tasksPath = path23.join(workspace, "tasks.yaml");
5703
+ const tasksPath = path24.join(workspace, "tasks.yaml");
5553
5704
  let tasksContent;
5554
5705
  try {
5555
- tasksContent = await fs23.readFile(tasksPath, "utf-8");
5706
+ tasksContent = await fs24.readFile(tasksPath, "utf-8");
5556
5707
  } catch {
5557
5708
  console.log(ui.error("No tasks.yaml found. Run kairn evolve init first."));
5558
5709
  process.exit(1);
@@ -5571,15 +5722,15 @@ evolveCommand.command("run").description("Run tasks against the current harness"
5571
5722
  console.log(ui.info(`Running ${tasksToRun.length} task(s)...`));
5572
5723
  console.log("");
5573
5724
  const config = await loadConfig();
5574
- const harnessPath = path23.join(projectRoot, ".claude");
5725
+ const harnessPath = path24.join(projectRoot, ".claude");
5575
5726
  const results = [];
5576
5727
  for (const task of tasksToRun) {
5577
- const traceDir = path23.join(workspace, "traces", "0", task.id);
5728
+ const traceDir = path24.join(workspace, "traces", "0", task.id);
5578
5729
  const spinner = ora2(`Running: ${task.id}`).start();
5579
5730
  const result = await runTask(task, harnessPath, traceDir, 0);
5580
5731
  if (config) {
5581
- const stdout = await fs23.readFile(path23.join(traceDir, "stdout.log"), "utf-8").catch(() => "");
5582
- const stderr = await fs23.readFile(path23.join(traceDir, "stderr.log"), "utf-8").catch(() => "");
5732
+ const stdout = await fs24.readFile(path24.join(traceDir, "stdout.log"), "utf-8").catch(() => "");
5733
+ const stderr = await fs24.readFile(path24.join(traceDir, "stderr.log"), "utf-8").catch(() => "");
5583
5734
  const score = await scoreTask(task, traceDir, stdout, stderr, config);
5584
5735
  result.score = score;
5585
5736
  await writeScore(traceDir, score);
@@ -5607,8 +5758,14 @@ evolveCommand.command("run").description("Run tasks against the current harness"
5607
5758
  process.exit(1);
5608
5759
  }
5609
5760
  evolveConfig.maxIterations = iterations;
5761
+ const runs = parseInt(options.runs ?? "1", 10);
5762
+ if (isNaN(runs) || runs < 1) {
5763
+ console.log(ui.error("--runs must be a positive integer"));
5764
+ process.exit(1);
5765
+ }
5766
+ evolveConfig.runsPerTask = runs;
5610
5767
  try {
5611
- await fs23.access(path23.join(workspace, "iterations", "0", "harness"));
5768
+ await fs24.access(path24.join(workspace, "iterations", "0", "harness"));
5612
5769
  } catch {
5613
5770
  console.log(ui.error("No baseline harness found. Run kairn evolve baseline first."));
5614
5771
  process.exit(1);
@@ -5641,6 +5798,9 @@ evolveCommand.command("run").description("Run tasks against the current harness"
5641
5798
  case "task-start":
5642
5799
  console.log(chalk14.dim(` Running: ${event.taskId ?? "unknown"}...`));
5643
5800
  break;
5801
+ case "task-run":
5802
+ console.log(chalk14.dim(` ${event.message ?? ""}`));
5803
+ break;
5644
5804
  case "task-scored": {
5645
5805
  const taskScore = event.score ?? 0;
5646
5806
  const taskStatus = taskScore >= 100 ? chalk14.green("PASS") : taskScore >= 60 ? chalk14.yellow("PARTIAL") : chalk14.red("FAIL");
@@ -5662,9 +5822,18 @@ evolveCommand.command("run").description("Run tasks against the current harness"
5662
5822
  console.log(` Improvement: ${improvement.toFixed(1)} points`);
5663
5823
  }
5664
5824
  console.log("");
5665
- console.log(" Iter Score Mutations Status");
5825
+ const showVariance = runs > 1;
5826
+ console.log(showVariance ? " Iter Score Mutations Status" : " Iter Score Mutations Status");
5666
5827
  for (const iter of result.iterations) {
5667
- const scoreStr = iter.score.toFixed(1).padStart(6) + "%";
5828
+ let scoreDisplay;
5829
+ if (showVariance) {
5830
+ const taskScores = Object.values(iter.taskResults);
5831
+ const stddevs = taskScores.map((s) => s.variance?.stddev).filter((v) => v !== void 0);
5832
+ const avgStddev = stddevs.length > 0 ? stddevs.reduce((a, b) => a + b, 0) / stddevs.length : 0;
5833
+ scoreDisplay = `${iter.score.toFixed(1).padStart(6)}% \xB1${avgStddev.toFixed(1)}`;
5834
+ } else {
5835
+ scoreDisplay = iter.score.toFixed(1).padStart(6) + "%";
5836
+ }
5668
5837
  const mutations = iter.proposal?.mutations.length ?? 0;
5669
5838
  const mutStr = mutations > 0 ? mutations.toString() : "-";
5670
5839
  let status = "evaluated";
@@ -5672,7 +5841,7 @@ evolveCommand.command("run").description("Run tasks against the current harness"
5672
5841
  else if (!iter.proposal && !iter.diffPatch) status = "rollback";
5673
5842
  else if (iter.score >= 100) status = "perfect";
5674
5843
  else if (iter.iteration === result.bestIteration) status = "best";
5675
- console.log(` ${iter.iteration.toString().padStart(4)} ${scoreStr} ${mutStr.padStart(9)} ${status}`);
5844
+ console.log(` ${iter.iteration.toString().padStart(4)} ${scoreDisplay} ${mutStr.padStart(9)} ${status}`);
5676
5845
  }
5677
5846
  }
5678
5847
  } catch (err) {
@@ -5681,12 +5850,56 @@ evolveCommand.command("run").description("Run tasks against the current harness"
5681
5850
  process.exit(1);
5682
5851
  }
5683
5852
  });
5853
+ evolveCommand.command("apply").description("Apply the best evolved harness to your project").option("--iter <n>", "Apply a specific iteration instead of the best").option("--force", "Apply even if git working tree is dirty").option("--no-commit", "Skip automatic git commit after applying").action(async (options) => {
5854
+ try {
5855
+ const projectRoot = process.cwd();
5856
+ const workspace = path24.join(projectRoot, ".kairn-evolve");
5857
+ console.log(ui.section("Evolve Apply"));
5858
+ try {
5859
+ await fs24.access(workspace);
5860
+ } catch {
5861
+ console.log(ui.error("No .kairn-evolve/ directory found. Run kairn evolve init first."));
5862
+ process.exit(1);
5863
+ }
5864
+ let targetIteration;
5865
+ if (options.iter) {
5866
+ targetIteration = parseInt(options.iter, 10);
5867
+ if (isNaN(targetIteration)) {
5868
+ console.log(ui.error("--iter must be a number"));
5869
+ process.exit(1);
5870
+ }
5871
+ }
5872
+ const result = await applyEvolution(workspace, projectRoot, targetIteration);
5873
+ if (result.diffPreview) {
5874
+ console.log(ui.section("Changes"));
5875
+ for (const line of result.diffPreview.split("\n")) {
5876
+ if (line.startsWith("---") || line.startsWith("+++")) {
5877
+ console.log(chalk14.bold(line));
5878
+ } else if (line.startsWith("+")) {
5879
+ console.log(chalk14.green(line));
5880
+ } else if (line.startsWith("-")) {
5881
+ console.log(chalk14.red(line));
5882
+ } else {
5883
+ console.log(line);
5884
+ }
5885
+ }
5886
+ }
5887
+ console.log("");
5888
+ console.log(ui.success(
5889
+ `Applied iteration ${result.iteration} harness (${result.filesChanged.length} files)`
5890
+ ));
5891
+ } catch (err) {
5892
+ const msg = err instanceof Error ? err.message : String(err);
5893
+ console.log(ui.error(msg));
5894
+ process.exit(1);
5895
+ }
5896
+ });
5684
5897
  evolveCommand.command("report").description("Generate a summary report of the evolution run").option("--json", "Output machine-readable JSON instead of Markdown").action(async (options) => {
5685
5898
  try {
5686
5899
  const projectRoot = process.cwd();
5687
- const workspace = path23.join(projectRoot, ".kairn-evolve");
5900
+ const workspace = path24.join(projectRoot, ".kairn-evolve");
5688
5901
  try {
5689
- await fs23.access(workspace);
5902
+ await fs24.access(workspace);
5690
5903
  } catch {
5691
5904
  console.log(ui.error("No .kairn-evolve/ directory found. Run kairn evolve init first."));
5692
5905
  process.exit(1);
@@ -5707,23 +5920,23 @@ evolveCommand.command("report").description("Generate a summary report of the ev
5707
5920
  evolveCommand.command("diff <iter1> <iter2>").description("Show harness changes between two iterations").action(async (iter1Str, iter2Str) => {
5708
5921
  try {
5709
5922
  const projectRoot = process.cwd();
5710
- const workspace = path23.join(projectRoot, ".kairn-evolve");
5923
+ const workspace = path24.join(projectRoot, ".kairn-evolve");
5711
5924
  const iter1 = parseInt(iter1Str, 10);
5712
5925
  const iter2 = parseInt(iter2Str, 10);
5713
5926
  if (isNaN(iter1) || isNaN(iter2)) {
5714
5927
  console.log(ui.error("Both arguments must be integers (iteration numbers)"));
5715
5928
  process.exit(1);
5716
5929
  }
5717
- const harness1 = path23.join(workspace, "iterations", iter1.toString(), "harness");
5718
- const harness2 = path23.join(workspace, "iterations", iter2.toString(), "harness");
5930
+ const harness1 = path24.join(workspace, "iterations", iter1.toString(), "harness");
5931
+ const harness2 = path24.join(workspace, "iterations", iter2.toString(), "harness");
5719
5932
  try {
5720
- await fs23.access(harness1);
5933
+ await fs24.access(harness1);
5721
5934
  } catch {
5722
5935
  console.log(ui.error(`Iteration ${iter1} harness not found at ${harness1}`));
5723
5936
  process.exit(1);
5724
5937
  }
5725
5938
  try {
5726
- await fs23.access(harness2);
5939
+ await fs24.access(harness2);
5727
5940
  } catch {
5728
5941
  console.log(ui.error(`Iteration ${iter2} harness not found at ${harness2}`));
5729
5942
  process.exit(1);
@@ -5778,10 +5991,10 @@ evolveCommand.command("diff <iter1> <iter2>").description("Show harness changes
5778
5991
  async function countFiles(dir) {
5779
5992
  let count = 0;
5780
5993
  try {
5781
- const entries = await fs23.readdir(dir, { withFileTypes: true });
5994
+ const entries = await fs24.readdir(dir, { withFileTypes: true });
5782
5995
  for (const entry of entries) {
5783
5996
  if (entry.isDirectory()) {
5784
- count += await countFiles(path23.join(dir, entry.name));
5997
+ count += await countFiles(path24.join(dir, entry.name));
5785
5998
  } else {
5786
5999
  count++;
5787
6000
  }