nairon-bench 0.5.3 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +328 -93
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8516,9 +8516,9 @@ async function collectGit(projectDir, since) {
8516
8516
  }
8517
8517
 
8518
8518
  // src/collectors/agents.ts
8519
- import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
8519
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
8520
8520
  import { homedir as homedir2 } from "node:os";
8521
- import { join as join2, basename, resolve } from "node:path";
8521
+ import { join as join2, basename, resolve, sep as sep2 } from "node:path";
8522
8522
  // ../shared/src/constants.ts
8523
8523
  var PHASE_WEIGHTS = {
8524
8524
  requirements: 0.2,
@@ -8935,18 +8935,34 @@ async function collectAgentSessions(since, useCache = true, projectDir) {
8935
8935
  const openCodeSessions = collectOpenCodeSessions(openCodeDir, since, targetProjectDir);
8936
8936
  sessions.push(...openCodeSessions);
8937
8937
  }
8938
- const cursorDirs = [
8939
- join2(homedir2(), ".cursor", "sessions"),
8940
- join2(homedir2(), "Library", "Application Support", "Cursor", "sessions"),
8941
- join2(homedir2(), ".config", "cursor", "sessions")
8938
+ const cursorProjectsDirs = [
8939
+ join2(homedir2(), ".cursor", "projects"),
8940
+ join2(homedir2(), "Library", "Application Support", "Cursor", "projects"),
8941
+ join2(homedir2(), ".config", "cursor", "projects")
8942
8942
  ];
8943
- for (const cursorDir of cursorDirs) {
8944
- if (existsSync2(cursorDir)) {
8945
- const cursorSessions = collectCursorSessions(cursorDir, since);
8946
- sessions.push(...cursorSessions);
8947
- break;
8943
+ let cursorSessions = [];
8944
+ for (const cursorProjectsDir of cursorProjectsDirs) {
8945
+ if (existsSync2(cursorProjectsDir)) {
8946
+ cursorSessions = collectCursorProjectSessions(cursorProjectsDir, since, targetProjectDir);
8947
+ if (cursorSessions.length > 0)
8948
+ break;
8949
+ }
8950
+ }
8951
+ if (cursorSessions.length === 0) {
8952
+ const cursorDirs = [
8953
+ join2(homedir2(), ".cursor", "sessions"),
8954
+ join2(homedir2(), "Library", "Application Support", "Cursor", "sessions"),
8955
+ join2(homedir2(), ".config", "cursor", "sessions")
8956
+ ];
8957
+ for (const cursorDir of cursorDirs) {
8958
+ if (existsSync2(cursorDir)) {
8959
+ cursorSessions = collectCursorSessions(cursorDir, since, targetProjectDir);
8960
+ if (cursorSessions.length > 0)
8961
+ break;
8962
+ }
8948
8963
  }
8949
8964
  }
8965
+ sessions.push(...cursorSessions);
8950
8966
  const windsurfDirs = [
8951
8967
  join2(homedir2(), ".codeium", "chat_history"),
8952
8968
  join2(homedir2(), ".windsurf", "sessions"),
@@ -9549,7 +9565,7 @@ function detectOpenCodePatterns(messages, partStorageDir) {
9549
9565
  }
9550
9566
  return patterns;
9551
9567
  }
9552
- function collectCursorSessions(sessionsDir, since) {
9568
+ function collectCursorSessions(sessionsDir, since, targetProjectDir) {
9553
9569
  const sessions = [];
9554
9570
  try {
9555
9571
  const files = readdirSync(sessionsDir).filter((f3) => f3.endsWith(".json") || f3.endsWith(".jsonl"));
@@ -9572,6 +9588,10 @@ function collectCursorSessions(sessionsDir, since) {
9572
9588
  }
9573
9589
  if (data.length === 0)
9574
9590
  continue;
9591
+ const sessionProjectDir = getCursorSessionProjectDir(data);
9592
+ if (!sessionProjectDir || !isPathMatch(sessionProjectDir, targetProjectDir)) {
9593
+ continue;
9594
+ }
9575
9595
  const firstEntry = data[0];
9576
9596
  const lastEntry = data[data.length - 1];
9577
9597
  const startTime = firstEntry?.timestamp ? new Date(firstEntry.timestamp) : new Date;
@@ -9613,6 +9633,152 @@ function collectCursorSessions(sessionsDir, since) {
9613
9633
  } catch {}
9614
9634
  return sessions;
9615
9635
  }
9636
+ function collectCursorProjectSessions(projectsDir, since, targetProjectDir) {
9637
+ const sessions = [];
9638
+ try {
9639
+ const entries = readdirSync(projectsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
9640
+ const targetKey = normalizeCursorProjectKey(encodeCursorProjectKey(targetProjectDir));
9641
+ const matchingProjects = entries.filter((name) => {
9642
+ const normalized = normalizeCursorProjectKey(name);
9643
+ return normalized === targetKey || normalized.startsWith(targetKey + "-") || targetKey.startsWith(normalized + "-");
9644
+ });
9645
+ for (const projectName of matchingProjects) {
9646
+ const transcriptsDir = join2(projectsDir, projectName, "agent-transcripts");
9647
+ if (!existsSync2(transcriptsDir))
9648
+ continue;
9649
+ const files = readdirSync(transcriptsDir).filter((f3) => f3.endsWith(".json")).map((f3) => join2(transcriptsDir, f3));
9650
+ for (const filePath of files) {
9651
+ const session = parseCursorTranscript(filePath, since);
9652
+ if (session)
9653
+ sessions.push(session);
9654
+ }
9655
+ }
9656
+ } catch {}
9657
+ return sessions;
9658
+ }
9659
+ function parseCursorTranscript(filePath, since) {
9660
+ try {
9661
+ const cached = sessionCache?.get(filePath);
9662
+ if (cached) {
9663
+ const cachedEndedAt = cached.endedAt ? new Date(cached.endedAt) : null;
9664
+ if (cachedEndedAt && cachedEndedAt >= since) {
9665
+ return cached;
9666
+ }
9667
+ return null;
9668
+ }
9669
+ const stats = statSync2(filePath);
9670
+ const endedAt = new Date(stats.mtimeMs);
9671
+ if (endedAt < since)
9672
+ return null;
9673
+ const startedAt = stats.birthtimeMs && stats.birthtimeMs > 0 ? new Date(stats.birthtimeMs) : endedAt;
9674
+ const content = readFileSync2(filePath, "utf-8");
9675
+ const data = JSON.parse(content);
9676
+ if (!Array.isArray(data) || data.length === 0)
9677
+ return null;
9678
+ let messageCount = 0;
9679
+ let toolCalls = 0;
9680
+ const toolNames = new Set;
9681
+ for (const entry of data) {
9682
+ if (entry?.role)
9683
+ messageCount += 1;
9684
+ if (Array.isArray(entry?.toolCalls)) {
9685
+ toolCalls += entry.toolCalls.length;
9686
+ for (const tool of entry.toolCalls) {
9687
+ if (tool?.toolName)
9688
+ toolNames.add(tool.toolName);
9689
+ }
9690
+ }
9691
+ if (entry?.toolResult?.toolName) {
9692
+ toolNames.add(entry.toolResult.toolName);
9693
+ }
9694
+ }
9695
+ const durationMinutes = Math.max(1, Math.round((endedAt.getTime() - startedAt.getTime()) / 60000));
9696
+ const session = {
9697
+ agent: "cursor",
9698
+ sessionId: basename(filePath, ".json").slice(0, 8),
9699
+ startedAt: startedAt.toISOString(),
9700
+ endedAt: endedAt.toISOString(),
9701
+ durationMinutes,
9702
+ inputTokens: 0,
9703
+ outputTokens: 0,
9704
+ cachedTokens: 0,
9705
+ totalTokens: 0,
9706
+ costUsd: 0,
9707
+ model: "cursor",
9708
+ toolCalls,
9709
+ messageCount,
9710
+ toolNames: Array.from(toolNames),
9711
+ patterns: [{ type: "smooth_flow", count: 1, estimatedWastedTokens: 0, messageIndices: [] }]
9712
+ };
9713
+ sessionCache?.set(filePath, session);
9714
+ return session;
9715
+ } catch {
9716
+ return null;
9717
+ }
9718
+ }
9719
+ function encodeCursorProjectKey(projectDir) {
9720
+ const normalized = resolve(projectDir);
9721
+ const trimmed2 = normalized.replace(/^[\\/]+/, "");
9722
+ return trimmed2.replace(/[:\\/]/g, "-");
9723
+ }
9724
+ function normalizeCursorProjectKey(projectKey) {
9725
+ return process.platform === "win32" ? projectKey.toLowerCase() : projectKey;
9726
+ }
9727
+ function isPathMatch(pathA, pathB) {
9728
+ const resolvedA = resolve(pathA);
9729
+ const resolvedB = resolve(pathB);
9730
+ return resolvedA === resolvedB || resolvedA.startsWith(resolvedB + sep2) || resolvedB.startsWith(resolvedA + sep2);
9731
+ }
9732
+ function getCursorSessionProjectDir(entries) {
9733
+ for (const entry of entries) {
9734
+ const pathCandidate = extractCursorProjectPath(entry);
9735
+ if (pathCandidate)
9736
+ return pathCandidate;
9737
+ }
9738
+ return null;
9739
+ }
9740
+ function extractCursorProjectPath(entry) {
9741
+ const candidates = [
9742
+ entry.cwd,
9743
+ entry.projectPath,
9744
+ entry.workspacePath,
9745
+ entry.workspaceRoot,
9746
+ entry.rootPath,
9747
+ entry.repositoryPath,
9748
+ entry.folder,
9749
+ entry.workspace
9750
+ ];
9751
+ for (const candidate of candidates) {
9752
+ if (typeof candidate === "string") {
9753
+ const normalized = normalizeFileUri(candidate);
9754
+ if (normalized)
9755
+ return normalized;
9756
+ }
9757
+ if (candidate && typeof candidate === "object") {
9758
+ const record = candidate;
9759
+ const nestedCandidates = [record.path, record.uri, record.folder, record.workspace, record.root];
9760
+ for (const nested of nestedCandidates) {
9761
+ if (typeof nested === "string") {
9762
+ const normalized = normalizeFileUri(nested);
9763
+ if (normalized)
9764
+ return normalized;
9765
+ }
9766
+ }
9767
+ }
9768
+ }
9769
+ return null;
9770
+ }
9771
+ function normalizeFileUri(value) {
9772
+ if (!value)
9773
+ return null;
9774
+ if (!value.startsWith("file://"))
9775
+ return value;
9776
+ let decoded = decodeURIComponent(value.replace(/^file:\/\//, ""));
9777
+ if (/^\/[A-Za-z]:\//.test(decoded)) {
9778
+ decoded = decoded.slice(1);
9779
+ }
9780
+ return decoded;
9781
+ }
9616
9782
  function collectWindsurfSessions(sessionsDir, since) {
9617
9783
  const sessions = [];
9618
9784
  try {
@@ -11414,7 +11580,7 @@ function generateOverallSummary(requirements, planning, implementation, review,
11414
11580
  }
11415
11581
  return parts.join(" ") || "Balanced across all phases.";
11416
11582
  }
11417
- function formatSDLCForTerminal(analysis) {
11583
+ function formatSDLCPhaseForTerminal(phase, overall) {
11418
11584
  const lines = [];
11419
11585
  const width = 50;
11420
11586
  const CYAN = "\x1B[36m";
@@ -11441,48 +11607,55 @@ function formatSDLCForTerminal(analysis) {
11441
11607
  }
11442
11608
  };
11443
11609
  lines.push("");
11444
- lines.push(`${BOLD}${CYAN} SDLC PHASE BREAKDOWN${RESET}`);
11610
+ lines.push(`${BOLD}${CYAN} SDLC OPTIMIZATION${RESET}`);
11445
11611
  lines.push(`${DIM} ${"─".repeat(width)}${RESET}`);
11446
11612
  lines.push("");
11447
- const overall = analysis.overall;
11448
11613
  lines.push(` ${BOLD}Overall:${RESET} ${gradeColor(overall.grade)}${overall.grade}${RESET} (${overall.score}/100)`);
11449
11614
  lines.push(` ${DIM}${overall.summary}${RESET}`);
11450
11615
  lines.push("");
11451
- const phases = [
11452
- { emoji: "1", ...analysis.requirements },
11453
- { emoji: "2", ...analysis.planning },
11454
- { emoji: "3", ...analysis.implementation },
11455
- { emoji: "4", ...analysis.review }
11456
- ];
11457
- for (const phase of phases) {
11458
- const color = gradeColor(phase.grade);
11459
- const bar = renderBar(phase.score, 15);
11460
- lines.push(` ${BOLD}${phase.emoji}. ${phase.name}${RESET}`);
11461
- lines.push(` ${bar} ${color}${phase.grade}${RESET} ${DIM}(${phase.score}/100)${RESET}`);
11462
- if (phase.metrics.length > 0) {
11463
- const topMetrics = phase.metrics.slice(0, 2);
11464
- for (const m2 of topMetrics) {
11465
- const statusIcon = m2.status === "good" ? GREEN + "+" : m2.status === "warning" ? YELLOW + "~" : RED + "-";
11466
- lines.push(` ${statusIcon}${RESET} ${m2.name}: ${m2.value}${m2.target ? ` ${DIM}(target: ${m2.target})${RESET}` : ""}`);
11467
- }
11468
- }
11469
- if (phase.recommendations.length > 0) {
11470
- const rec = phase.recommendations[0];
11616
+ const phaseColor = gradeColor(phase.grade);
11617
+ lines.push(` ${BOLD}Focus:${RESET} ${phase.name}`);
11618
+ lines.push(` ${phaseColor}${phase.grade}${RESET} ${DIM}(${phase.score}/100)${RESET}`);
11619
+ lines.push("");
11620
+ if (phase.metrics.length > 0) {
11621
+ lines.push(` ${BOLD}Signals:${RESET}`);
11622
+ const topMetrics = phase.metrics.slice(0, 4);
11623
+ for (const m2 of topMetrics) {
11624
+ const statusIcon = m2.status === "good" ? GREEN + "+" : m2.status === "warning" ? YELLOW + "~" : RED + "-";
11625
+ lines.push(` ${statusIcon}${RESET} ${m2.name}: ${m2.value}${m2.target ? ` ${DIM}(target: ${m2.target})${RESET}` : ""}`);
11626
+ }
11627
+ lines.push("");
11628
+ }
11629
+ if (phase.strengths.length > 0) {
11630
+ lines.push(` ${BOLD}Strengths:${RESET}`);
11631
+ for (const item of phase.strengths.slice(0, 3)) {
11632
+ lines.push(` ${GREEN}+${RESET} ${item}`);
11633
+ }
11634
+ lines.push("");
11635
+ }
11636
+ if (phase.weaknesses.length > 0) {
11637
+ lines.push(` ${BOLD}Weak Spots:${RESET}`);
11638
+ for (const item of phase.weaknesses.slice(0, 3)) {
11639
+ lines.push(` ${RED}!${RESET} ${item}`);
11640
+ }
11641
+ lines.push("");
11642
+ }
11643
+ lines.push(` ${BOLD}Optimizations:${RESET}`);
11644
+ if (phase.recommendations.length === 0) {
11645
+ lines.push(` ${DIM}No optimizations available for this phase.${RESET}`);
11646
+ } else {
11647
+ for (const rec of phase.recommendations) {
11471
11648
  const impactColor = rec.impact === "high" ? RED : rec.impact === "medium" ? YELLOW : DIM;
11472
- lines.push(` ${impactColor}!${RESET} ${rec.title}`);
11649
+ lines.push(` ${impactColor}!${RESET} ${rec.title}`);
11650
+ lines.push(` ${DIM}${rec.description}${RESET}`);
11473
11651
  if (rec.installCommand) {
11474
- lines.push(` ${DIM}${rec.installCommand}${RESET}`);
11652
+ lines.push(` ${DIM}${rec.installCommand}${RESET}`);
11475
11653
  }
11476
11654
  }
11477
- lines.push("");
11478
11655
  }
11656
+ lines.push("");
11479
11657
  return lines;
11480
11658
  }
11481
- function renderBar(value, width) {
11482
- const filled = Math.round(value / 100 * width);
11483
- const empty = width - filled;
11484
- return "█".repeat(filled) + "░".repeat(empty);
11485
- }
11486
11659
 
11487
11660
  // src/lib/frustration-detector.ts
11488
11661
  import { existsSync as existsSync7, readFileSync as readFileSync7, readdirSync as fsReaddirSync } from "node:fs";
@@ -16634,46 +16807,88 @@ var scanCommand = defineCommand2({
16634
16807
  } else if (sdlc.overall.summary.includes("optimizations available")) {
16635
16808
  sdlc.overall.summary = sdlc.overall.summary.replace(/\d+ optimizations available\./, "All recommended tools installed.");
16636
16809
  }
16637
- const sdlcLines = formatSDLCForTerminal(sdlc);
16638
- for (const line of sdlcLines) {
16639
- console.log(line);
16640
- }
16641
- let allRecs = [];
16642
- for (const phase of [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review]) {
16643
- for (const rec of phase.recommendations) {
16810
+ const phaseOptions = [
16811
+ { value: "requirements", label: "Requirements & Context" },
16812
+ { value: "planning", label: "Planning & Design" },
16813
+ { value: "implementation", label: "Implementation" },
16814
+ { value: "review", label: "Review & Testing" },
16815
+ { value: "exit", label: "Exit" }
16816
+ ];
16817
+ while (true) {
16818
+ const phaseChoice = await consola.prompt("Which SDLC phase do you want to optimize?", {
16819
+ type: "select",
16820
+ options: phaseOptions
16821
+ });
16822
+ if (typeof phaseChoice === "symbol" || phaseChoice === "exit") {
16823
+ break;
16824
+ }
16825
+ const selectedPhase = phaseChoice === "planning" ? sdlc.planning : phaseChoice === "implementation" ? sdlc.implementation : phaseChoice === "review" ? sdlc.review : sdlc.requirements;
16826
+ const sdlcLines = formatSDLCPhaseForTerminal(selectedPhase, sdlc.overall);
16827
+ for (const line of sdlcLines) {
16828
+ console.log(line);
16829
+ }
16830
+ let phaseRecs = [];
16831
+ for (const rec of selectedPhase.recommendations) {
16644
16832
  if (rec.installCommand) {
16645
- allRecs.push(phaseRecToInstallable(rec));
16833
+ phaseRecs.push(phaseRecToInstallable(rec));
16646
16834
  }
16647
16835
  }
16648
- }
16649
- allRecs = filterAlreadyInstalled(allRecs, installedStatus);
16650
- if (allRecs.length > 0) {
16651
- console.log();
16652
- const optionLabels = allRecs.map((rec) => `${rec.name} - ${rec.description}`);
16653
- const selected = await consola.prompt(`${allRecs.length} optimizations available. Select to install (space to select, enter to confirm):`, {
16654
- type: "multiselect",
16655
- options: optionLabels,
16656
- required: false
16836
+ phaseRecs = filterAlreadyInstalled(phaseRecs, installedStatus);
16837
+ const nextAction = await consola.prompt("What would you like to do next?", {
16838
+ type: "select",
16839
+ options: phaseRecs.length > 0 ? [
16840
+ { value: "install", label: "Install optimizations" },
16841
+ { value: "change", label: "Choose another phase" },
16842
+ { value: "exit", label: "Exit" }
16843
+ ] : [
16844
+ { value: "change", label: "Choose another phase" },
16845
+ { value: "exit", label: "Exit" }
16846
+ ]
16657
16847
  });
16658
- if (selected && typeof selected !== "symbol" && Array.isArray(selected) && selected.length > 0) {
16659
- const toInstall = allRecs.filter((rec) => selected.some((s2) => s2.startsWith(rec.name))).map((r3) => ({ ...r3, selected: true }));
16660
- if (toInstall.length > 0) {
16661
- console.log();
16662
- console.log(` ${colors2.bold("Installing...")}${colors2.dim("")}`);
16663
- console.log();
16664
- const results = await installOptimizations(toInstall, projectDir, {});
16665
- for (const result of results) {
16666
- if (result.success) {
16667
- console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
16668
- } else {
16669
- console.log(` ${colors2.error("✗")} ${result.name}: ${result.error || result.message}`);
16848
+ if (typeof nextAction === "symbol" || nextAction === "exit") {
16849
+ break;
16850
+ }
16851
+ if (nextAction === "change") {
16852
+ continue;
16853
+ }
16854
+ if (phaseRecs.length > 0) {
16855
+ console.log();
16856
+ const optionLabels = phaseRecs.map((rec) => `${rec.name} - ${rec.description}`);
16857
+ const selected = await consola.prompt(`${phaseRecs.length} optimizations available for ${selectedPhase.name}. Select to install (space to select, enter to confirm):`, {
16858
+ type: "multiselect",
16859
+ options: optionLabels,
16860
+ required: false
16861
+ });
16862
+ if (selected && typeof selected !== "symbol" && Array.isArray(selected) && selected.length > 0) {
16863
+ const toInstall = phaseRecs.filter((rec) => selected.some((s2) => s2.startsWith(rec.name))).map((r3) => ({ ...r3, selected: true }));
16864
+ if (toInstall.length > 0) {
16865
+ console.log();
16866
+ console.log(` ${colors2.bold("Installing...")}${colors2.dim("")}`);
16867
+ console.log();
16868
+ const results = await installOptimizations(toInstall, projectDir, {});
16869
+ for (const result of results) {
16870
+ if (result.success) {
16871
+ console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
16872
+ } else {
16873
+ console.log(` ${colors2.error("✗")} ${result.name}: ${result.error || result.message}`);
16874
+ }
16670
16875
  }
16876
+ console.log();
16671
16877
  }
16878
+ } else {
16879
+ console.log(` ${colors2.dim("Skipped.")}`);
16672
16880
  console.log();
16673
16881
  }
16674
- } else {
16675
- console.log(` ${colors2.dim("Skipped.")}`);
16676
- console.log();
16882
+ }
16883
+ const continueChoice = await consola.prompt("Continue with another phase?", {
16884
+ type: "select",
16885
+ options: [
16886
+ { value: "change", label: "Choose another phase" },
16887
+ { value: "exit", label: "Exit" }
16888
+ ]
16889
+ });
16890
+ if (typeof continueChoice === "symbol" || continueChoice === "exit") {
16891
+ break;
16677
16892
  }
16678
16893
  }
16679
16894
  }
@@ -17070,7 +17285,7 @@ init_dist();
17070
17285
  init_client();
17071
17286
 
17072
17287
  // src/collectors/report-data.ts
17073
- import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync2 } from "node:fs";
17288
+ import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync3 } from "node:fs";
17074
17289
  import { homedir as homedir9 } from "node:os";
17075
17290
  import { join as join11, basename as basename3 } from "node:path";
17076
17291
  async function collectReportData(projectDir, since, until = new Date, harness) {
@@ -17177,7 +17392,7 @@ function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
17177
17392
  const transcriptFiles = readdirSync5(transcriptsDir).filter((f3) => f3.endsWith(".jsonl"));
17178
17393
  for (const file of transcriptFiles) {
17179
17394
  const filePath = join11(transcriptsDir, file);
17180
- const stat = statSync2(filePath);
17395
+ const stat = statSync3(filePath);
17181
17396
  if (stat.mtime < since || stat.mtime > until)
17182
17397
  continue;
17183
17398
  try {
@@ -17193,7 +17408,7 @@ function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
17193
17408
  const projectFiles = readdirSync5(projectSessionDir).filter((f3) => f3.endsWith(".jsonl"));
17194
17409
  for (const file of projectFiles) {
17195
17410
  const filePath = join11(projectSessionDir, file);
17196
- const stat = statSync2(filePath);
17411
+ const stat = statSync3(filePath);
17197
17412
  if (stat.mtime < since || stat.mtime > until)
17198
17413
  continue;
17199
17414
  try {
@@ -20558,10 +20773,10 @@ function renderCoverageSummary(report) {
20558
20773
  lines.push(` Format: ${report.format}`);
20559
20774
  lines.push(` Overall: ${report.summary.overall}%`);
20560
20775
  lines.push("");
20561
- lines.push(` Lines: ${renderBar2(report.summary.lines.percentage)} ${report.summary.lines.percentage}%`);
20562
- lines.push(` Statements: ${renderBar2(report.summary.statements.percentage)} ${report.summary.statements.percentage}%`);
20563
- lines.push(` Functions: ${renderBar2(report.summary.functions.percentage)} ${report.summary.functions.percentage}%`);
20564
- lines.push(` Branches: ${renderBar2(report.summary.branches.percentage)} ${report.summary.branches.percentage}%`);
20776
+ lines.push(` Lines: ${renderBar(report.summary.lines.percentage)} ${report.summary.lines.percentage}%`);
20777
+ lines.push(` Statements: ${renderBar(report.summary.statements.percentage)} ${report.summary.statements.percentage}%`);
20778
+ lines.push(` Functions: ${renderBar(report.summary.functions.percentage)} ${report.summary.functions.percentage}%`);
20779
+ lines.push(` Branches: ${renderBar(report.summary.branches.percentage)} ${report.summary.branches.percentage}%`);
20565
20780
  if (report.uncoveredFiles.length > 0) {
20566
20781
  lines.push("");
20567
20782
  lines.push(` Uncovered files: ${report.uncoveredFiles.length}`);
@@ -20607,7 +20822,7 @@ function renderCoverageMarkdown(report) {
20607
20822
  }
20608
20823
  return lines;
20609
20824
  }
20610
- function renderBar2(percentage, width = 15) {
20825
+ function renderBar(percentage, width = 15) {
20611
20826
  const filled = Math.round(percentage / 100 * width);
20612
20827
  const empty = width - filled;
20613
20828
  return "█".repeat(filled) + "░".repeat(empty);
@@ -21790,10 +22005,10 @@ function formatReportAsTerminal(report) {
21790
22005
  lines.push(` ${report.gradeDescription}`);
21791
22006
  lines.push("");
21792
22007
  lines.push(" Score Breakdown:");
21793
- lines.push(` SDLC Coverage: ${renderBar3(report.scores.sdlcCoverage)} ${report.scores.sdlcCoverage}`);
21794
- lines.push(` Prompt Quality: ${renderBar3(report.scores.promptQuality)} ${report.scores.promptQuality}`);
21795
- lines.push(` Tool Utilization: ${renderBar3(report.scores.toolUtilization)} ${report.scores.toolUtilization}`);
21796
- lines.push(` Efficiency: ${renderBar3(report.scores.efficiency)} ${report.scores.efficiency}`);
22008
+ lines.push(` SDLC Coverage: ${renderBar2(report.scores.sdlcCoverage)} ${report.scores.sdlcCoverage}`);
22009
+ lines.push(` Prompt Quality: ${renderBar2(report.scores.promptQuality)} ${report.scores.promptQuality}`);
22010
+ lines.push(` Tool Utilization: ${renderBar2(report.scores.toolUtilization)} ${report.scores.toolUtilization}`);
22011
+ lines.push(` Efficiency: ${renderBar2(report.scores.efficiency)} ${report.scores.efficiency}`);
21797
22012
  lines.push("");
21798
22013
  lines.push(" Quick Stats:");
21799
22014
  lines.push(` Sessions: ${report.summary.totalSessions} | Prompts: ${report.summary.totalPrompts} | Commits: ${report.summary.totalCommits}`);
@@ -21880,7 +22095,7 @@ function formatReportAsTerminal(report) {
21880
22095
  return lines.join(`
21881
22096
  `);
21882
22097
  }
21883
- function renderBar3(value, width = 20) {
22098
+ function renderBar2(value, width = 20) {
21884
22099
  const filled = Math.round(value / 100 * width);
21885
22100
  const empty = width - filled;
21886
22101
  return "█".repeat(filled) + "░".repeat(empty);
@@ -22434,7 +22649,7 @@ async function showHistory(client, clerkId, limit, format2) {
22434
22649
  const recent = trend.slice(-limit);
22435
22650
  for (const entry of recent) {
22436
22651
  const date = new Date(entry.date).toLocaleDateString();
22437
- const bar = renderBar4(entry.overall, 30);
22652
+ const bar = renderBar3(entry.overall, 30);
22438
22653
  const eff = `${entry.tokenEfficiency}x`;
22439
22654
  consola.log(` ${date.padEnd(12)} ${String(entry.overall).padStart(3)}/100 ${bar} eff: ${eff}`);
22440
22655
  }
@@ -22489,7 +22704,7 @@ function renderScanReport(scan, phaseFilter) {
22489
22704
  const phases = phaseFilter ? scan.phases.filter((p) => p.phase === phaseFilter) : scan.phases;
22490
22705
  lines.push("Phase Scores:");
22491
22706
  for (const phase of phases) {
22492
- const bar = renderBar4(phase.score, 20);
22707
+ const bar = renderBar3(phase.score, 20);
22493
22708
  const delta = phase.delta !== undefined && phase.delta !== null ? ` (${phase.delta > 0 ? "+" : ""}${phase.delta})` : "";
22494
22709
  lines.push(` ${phase.phase.padEnd(16)} ${String(phase.score).padStart(3)}/100 ${bar}${delta}`);
22495
22710
  }
@@ -22507,7 +22722,7 @@ function renderScanReport(scan, phaseFilter) {
22507
22722
  return lines.join(`
22508
22723
  `);
22509
22724
  }
22510
- function renderBar4(value, width) {
22725
+ function renderBar3(value, width) {
22511
22726
  const filled = Math.round(value / 100 * width);
22512
22727
  const empty = width - filled;
22513
22728
  return "█".repeat(filled) + "░".repeat(empty);
@@ -23804,6 +24019,26 @@ var BOLD = "\x1B[1m";
23804
24019
  var RESET = "\x1B[0m";
23805
24020
  var MAGENTA = "\x1B[35m";
23806
24021
  var CHANGELOG = [
24022
+ {
24023
+ version: "0.6.1",
24024
+ date: "2026-02-16",
24025
+ title: "Phase Navigation",
24026
+ highlights: [
24027
+ "nb scan now lets you switch phases or exit anytime",
24028
+ "Clear next-step prompts for installs or switching",
24029
+ "Cleaner interactive flow for phase optimizations"
24030
+ ]
24031
+ },
24032
+ {
24033
+ version: "0.6.0",
24034
+ date: "2026-02-15",
24035
+ title: "Phase-Focused Optimizations",
24036
+ highlights: [
24037
+ "nb scan now asks which SDLC phase to optimize",
24038
+ "Phase-specific optimization breakdown and installs",
24039
+ "New SDLC optimization formatter and coverage test"
24040
+ ]
24041
+ },
23807
24042
  {
23808
24043
  version: "0.5.3",
23809
24044
  date: "2026-02-14",
@@ -24286,7 +24521,7 @@ function showFullChangelog() {
24286
24521
  // package.json
24287
24522
  var package_default = {
24288
24523
  name: "nairon-bench",
24289
- version: "0.5.3",
24524
+ version: "0.6.1",
24290
24525
  description: "AI workflow benchmarking CLI",
24291
24526
  type: "module",
24292
24527
  bin: {
@@ -26813,7 +27048,7 @@ function formatBytes(bytes) {
26813
27048
  // package.json
26814
27049
  var package_default2 = {
26815
27050
  name: "nairon-bench",
26816
- version: "0.5.3",
27051
+ version: "0.6.1",
26817
27052
  description: "AI workflow benchmarking CLI",
26818
27053
  type: "module",
26819
27054
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nairon-bench",
3
- "version": "0.5.3",
3
+ "version": "0.6.1",
4
4
  "description": "AI workflow benchmarking CLI",
5
5
  "type": "module",
6
6
  "bin": {