nairon-bench 0.0.21 → 0.0.23

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 +192 -78
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8545,7 +8545,7 @@ var PERCENTILE_THRESHOLDS = [
8545
8545
  label: "Intermediate",
8546
8546
  badge: "Bronze"
8547
8547
  },
8548
- { tier: "developing", minPercentile: 0, label: "Developing", badge: "--" }
8548
+ { tier: "developing", minPercentile: 0, label: "Developing", badge: "" }
8549
8549
  ];
8550
8550
  var AGENT_LOG_PATHS = {
8551
8551
  claude: "~/.claude/projects",
@@ -13982,6 +13982,15 @@ function createSpinner(text) {
13982
13982
  color: "cyan"
13983
13983
  });
13984
13984
  }
13985
+ function formatScore(score) {
13986
+ if (score >= 80)
13987
+ return colors2.excellent(score.toString());
13988
+ if (score >= 60)
13989
+ return colors2.good(score.toString());
13990
+ if (score >= 40)
13991
+ return colors2.moderate(score.toString());
13992
+ return colors2.poor(score.toString());
13993
+ }
13985
13994
  function formatTier(tier) {
13986
13995
  const tierColors = {
13987
13996
  elite: (s2) => import_picocolors.default.bold(import_picocolors.default.magenta(s2)),
@@ -15243,7 +15252,6 @@ function detectEasyWins(detectedAgents) {
15243
15252
  }
15244
15253
 
15245
15254
  // src/commands/insights.ts
15246
- init_dist();
15247
15255
  init_client();
15248
15256
  var insightsCommand = defineCommand2({
15249
15257
  meta: {
@@ -15260,15 +15268,19 @@ var insightsCommand = defineCommand2({
15260
15268
  description: "Time range to analyze",
15261
15269
  default: "7 days"
15262
15270
  },
15263
- format: {
15264
- type: "string",
15265
- description: "Output format: text (default) or json",
15266
- default: "text"
15271
+ json: {
15272
+ type: "boolean",
15273
+ description: "Output as JSON",
15274
+ default: false
15267
15275
  }
15268
15276
  },
15269
15277
  async run({ args }) {
15270
- consola.start(`Analyzing your workflow for insights...
15271
- `);
15278
+ console.log();
15279
+ console.log(colors2.bold(colors2.primary(" Workflow Insights")));
15280
+ console.log(colors2.dim(" " + "─".repeat(40)));
15281
+ console.log();
15282
+ const spinner = createSpinner("Analyzing your workflow...");
15283
+ spinner.start();
15272
15284
  const client = getClient();
15273
15285
  const clerkId = getClerkId();
15274
15286
  let score = null;
@@ -15277,11 +15289,12 @@ var insightsCommand = defineCommand2({
15277
15289
  clerkId
15278
15290
  });
15279
15291
  if (summary) {
15280
- if (args.format === "json") {
15281
- consola.log(JSON.stringify(summary, null, 2));
15292
+ spinner.succeed("Analysis complete");
15293
+ if (args.json) {
15294
+ console.log(JSON.stringify(summary, null, 2));
15282
15295
  return;
15283
15296
  }
15284
- renderCloudInsights(summary);
15297
+ await renderCloudInsights(summary);
15285
15298
  }
15286
15299
  const scan = await client.query(api.scans.getLatestScan, { clerkId });
15287
15300
  if (scan) {
@@ -15289,38 +15302,32 @@ var insightsCommand = defineCommand2({
15289
15302
  }
15290
15303
  }
15291
15304
  if (!score) {
15292
- consola.info("Computing local insights (run `nb init` for cloud-powered insights)...\n");
15305
+ spinner.text = "Computing local insights...";
15293
15306
  const since = parseSince2(args.since);
15294
15307
  const git = await collectGit(process.cwd(), since);
15295
15308
  const agents = await collectAgentSessions(since);
15296
15309
  const tests = await collectTestResults(process.cwd());
15297
15310
  score = computeNaironScore(git ?? undefined, agents ?? undefined, tests ?? undefined);
15311
+ spinner.succeed("Analysis complete");
15312
+ } else {
15313
+ spinner.succeed("Analysis complete");
15298
15314
  }
15299
- if (args.format === "json") {
15300
- consola.log(JSON.stringify(generateInsights(score, args.phase), null, 2));
15315
+ if (args.json) {
15316
+ console.log(JSON.stringify(generateInsights(score, args.phase), null, 2));
15301
15317
  return;
15302
15318
  }
15303
- renderLocalInsights(score, args.phase);
15319
+ await renderLocalInsights(score, args.phase);
15304
15320
  if (client && clerkId) {
15305
15321
  try {
15306
15322
  const recommended = await client.query(api.tools.getRecommendedForUser, {
15307
15323
  clerkId
15308
15324
  });
15309
15325
  if (recommended && recommended.length > 0) {
15310
- consola.log("");
15311
- consola.log("Recommended Tools:");
15312
- consola.log("─".repeat(50));
15313
- for (const tool of recommended.slice(0, 5)) {
15314
- const phases = tool.sdlcPhases.join(", ");
15315
- consola.log(` ${tool.name} - ${tool.description}`);
15316
- consola.log(` Phases: ${phases} | ${tool.pricing.free ? "Free" : tool.pricing.paid ?? "Paid"}`);
15317
- if (tool.installCommands) {
15318
- consola.log(` Install: ${JSON.stringify(tool.installCommands)}`);
15319
- }
15320
- }
15326
+ await renderToolRecommendations(recommended);
15321
15327
  }
15322
15328
  } catch {}
15323
15329
  }
15330
+ console.log();
15324
15331
  }
15325
15332
  });
15326
15333
  function generateInsights(score, phaseFilter) {
@@ -15379,72 +15386,129 @@ function generateInsights(score, phaseFilter) {
15379
15386
  insights.sort((a2, b2) => b2.estimatedImpact - a2.estimatedImpact);
15380
15387
  return insights;
15381
15388
  }
15382
- function renderLocalInsights(score, phaseFilter) {
15389
+ async function renderLocalInsights(score, phaseFilter) {
15383
15390
  const insights = generateInsights(score, phaseFilter);
15391
+ console.log();
15392
+ console.log(` ${icons.chart} ${colors2.bold("Current Score:")} ${formatScore(score.overall)}/100 ${colors2.dim("(")}${formatTier(getTierLabel(score.tier))}${colors2.dim(")")}`);
15393
+ console.log();
15384
15394
  if (insights.length === 0) {
15385
- consola.success("No critical insights. Your workflow looks strong!");
15395
+ console.log(` ${icons.success} ${colors2.success("No critical insights. Your workflow looks strong!")}`);
15386
15396
  return;
15387
15397
  }
15388
- consola.log("");
15389
- consola.box({
15390
- title: `Insights (${score.overall}/100 - ${getTierLabel(score.tier)})`,
15391
- message: insights.map((i3) => {
15392
- const icon = i3.severity === "critical" ? "[!!]" : i3.severity === "warning" ? "[!]" : "[i]";
15393
- return [
15394
- `${icon} ${i3.title} (+${i3.estimatedImpact} pts potential)`,
15395
- ` ${i3.description}`,
15396
- ` Action: ${i3.action}`
15397
- ].join(`
15398
- `);
15399
- }).join(`
15400
-
15401
- `)
15402
- });
15398
+ const critical = insights.filter((i3) => i3.severity === "critical");
15399
+ const warning2 = insights.filter((i3) => i3.severity === "warning");
15400
+ const info2 = insights.filter((i3) => i3.severity === "info");
15401
+ if (critical.length > 0) {
15402
+ console.log(` ${colors2.error(colors2.bold("Critical Issues"))}`);
15403
+ console.log(colors2.dim(" " + "─".repeat(40)));
15404
+ for (const insight of critical) {
15405
+ await sleep(150);
15406
+ await renderInsightCard(insight);
15407
+ }
15408
+ console.log();
15409
+ }
15410
+ if (warning2.length > 0) {
15411
+ console.log(` ${colors2.warning(colors2.bold("Needs Attention"))}`);
15412
+ console.log(colors2.dim(" " + "─".repeat(40)));
15413
+ for (const insight of warning2) {
15414
+ await sleep(150);
15415
+ await renderInsightCard(insight);
15416
+ }
15417
+ console.log();
15418
+ }
15419
+ if (info2.length > 0) {
15420
+ console.log(` ${colors2.info(colors2.bold("Opportunities"))}`);
15421
+ console.log(colors2.dim(" " + "─".repeat(40)));
15422
+ for (const insight of info2) {
15423
+ await sleep(150);
15424
+ await renderInsightCard(insight);
15425
+ }
15426
+ }
15427
+ }
15428
+ async function renderInsightCard(insight) {
15429
+ const severityConfig = {
15430
+ critical: { icon: icons.error, color: colors2.error, badge: "CRITICAL" },
15431
+ warning: { icon: icons.warning, color: colors2.warning, badge: "WARNING" },
15432
+ info: { icon: icons.info, color: colors2.info, badge: "TIP" }
15433
+ };
15434
+ const config = severityConfig[insight.severity];
15435
+ console.log();
15436
+ console.log(` ${config.icon} ${config.color(colors2.bold(insight.title))}`);
15437
+ console.log(` ${colors2.dim(insight.description)}`);
15438
+ console.log();
15439
+ console.log(` ${colors2.primary(icons.arrow)} ${colors2.dim("Action:")} ${insight.action}`);
15440
+ console.log(` ${colors2.success(icons.star)} ${colors2.dim("Potential impact:")} ${colors2.success(`+${insight.estimatedImpact}`)} pts`);
15403
15441
  }
15404
- function renderCloudInsights(summary) {
15442
+ async function renderCloudInsights(summary) {
15405
15443
  const direction = summary.scoreChange > 0 ? "+" : "";
15406
- consola.log("");
15407
- consola.box({
15408
- title: "Cloud Insights (powered by your scan history)",
15409
- message: [
15410
- `Score trend: ${direction}${summary.scoreChange} pts over ${summary.reportsAnalyzed} reports`,
15411
- `Period: ${new Date(summary.periodStart).toLocaleDateString()} - ${new Date(summary.periodEnd).toLocaleDateString()}`,
15412
- "",
15413
- "Top Frustrations:",
15414
- ...summary.topFrustrations.map((f3) => ` - ${f3.topic}: ${f3.count} occurrences, ~${f3.minutesWasted}min / ~${f3.tokensWasted.toLocaleString()} tokens wasted`)
15415
- ].join(`
15416
- `)
15417
- });
15444
+ const trendColor = summary.scoreChange > 0 ? colors2.success : summary.scoreChange < 0 ? colors2.error : colors2.dim;
15445
+ console.log();
15446
+ console.log(` ${icons.chart} ${colors2.bold("Score Trend")}`);
15447
+ console.log(colors2.dim(" " + "─".repeat(40)));
15448
+ console.log();
15449
+ const scoreText = trendColor(colors2.bold(direction + summary.scoreChange + " pts"));
15450
+ const reportsText = colors2.primary(summary.reportsAnalyzed.toString());
15451
+ console.log(" " + scoreText + " over " + reportsText + " reports");
15452
+ const periodStart = new Date(summary.periodStart).toLocaleDateString();
15453
+ const periodEnd = new Date(summary.periodEnd).toLocaleDateString();
15454
+ console.log(" " + colors2.dim("Period:") + " " + periodStart + " → " + periodEnd);
15455
+ console.log();
15456
+ if (summary.topFrustrations.length > 0) {
15457
+ console.log(" " + icons.warning + " " + colors2.bold("Top Frustrations"));
15458
+ console.log(colors2.dim(" " + "─".repeat(40)));
15459
+ console.log();
15460
+ for (const f3 of summary.topFrustrations) {
15461
+ await sleep(100);
15462
+ console.log(" " + icons.bullet + " " + colors2.warning(f3.topic));
15463
+ const details = f3.count + " occurrences · ~" + f3.minutesWasted + "min · ~" + f3.tokensWasted.toLocaleString() + " tokens wasted";
15464
+ console.log(" " + colors2.dim(details));
15465
+ }
15466
+ }
15467
+ }
15468
+ async function renderToolRecommendations(tools) {
15469
+ console.log();
15470
+ console.log(` ${icons.rocket} ${colors2.bold("Recommended Tools")}`);
15471
+ console.log(colors2.dim(" " + "─".repeat(40)));
15472
+ console.log();
15473
+ for (const tool of tools.slice(0, 3)) {
15474
+ await sleep(100);
15475
+ const phases = tool.sdlcPhases.join(", ");
15476
+ const priceTag = tool.pricing.free ? colors2.success("Free") : colors2.warning(tool.pricing.paid ?? "Paid");
15477
+ console.log(` ${colors2.primary(colors2.bold(tool.name))}`);
15478
+ console.log(` ${colors2.dim(tool.description)}`);
15479
+ console.log(` ${colors2.dim("Phases:")} ${phases} ${colors2.dim("|")} ${priceTag}`);
15480
+ console.log();
15481
+ }
15418
15482
  }
15419
15483
  function getPhaseAction(phase, severity) {
15420
15484
  const actions = {
15421
15485
  requirements: {
15422
- critical: "Start each task with a spec. Write acceptance criteria before opening your editor. Use `nb tools discover --phase=requirements` for spec tools.",
15423
- warning: "Break large tasks into smaller, well-defined stories. Use AI to draft acceptance criteria from vague requirements.",
15424
- info: "Consider adding user stories and edge cases to your specs. Track requirement changes over time."
15486
+ critical: "Start each task with a spec. Write acceptance criteria before opening your editor.",
15487
+ warning: "Break large tasks into smaller, well-defined stories. Use AI to draft acceptance criteria.",
15488
+ info: "Add user stories and edge cases to your specs. Track requirement changes."
15425
15489
  },
15426
15490
  planning: {
15427
- critical: "Write a PRD or design doc before coding. Use architecture decision records (ADRs). Try tools like Eraser.io or tldraw for diagrams.",
15428
- warning: "Add a planning phase to your workflow. Sketch the approach in comments or markdown before implementation.",
15429
- info: "Experiment with different planning tools. Compare wireframing in AI vs manual approaches."
15491
+ critical: "Write a PRD or design doc before coding. Use ADRs for architecture decisions.",
15492
+ warning: "Add a planning phase. Sketch the approach in comments or markdown first.",
15493
+ info: "Experiment with different planning tools. Compare wireframing approaches."
15430
15494
  },
15431
15495
  implementation: {
15432
- critical: "Focus on smaller, reviewable diffs. Avoid long coding sessions without commits. Use AI agents with clear, specific prompts.",
15433
- warning: "Improve commit cadence. Aim for focused commits under 200 lines. Use structured prompts instead of iterating.",
15434
- info: "Optimize your AI prompting style. Try providing more context upfront to reduce back-and-forth."
15496
+ critical: "Focus on smaller, reviewable diffs. Avoid long sessions without commits.",
15497
+ warning: "Improve commit cadence. Aim for focused commits under 200 lines.",
15498
+ info: "Optimize your prompting style. Provide more context upfront."
15435
15499
  },
15436
15500
  testing: {
15437
- critical: "Add test coverage immediately. Start with integration tests for critical paths. Use `nb tools discover --phase=testing` for testing tools.",
15438
- warning: "Increase pass rate and coverage. Write tests before fixing bugs (TDD for bugs). Add CI to catch regressions.",
15439
- info: "Push for 80%+ coverage. Add property-based or snapshot tests for edge cases."
15501
+ critical: "Add test coverage immediately. Start with integration tests for critical paths.",
15502
+ warning: "Increase pass rate and coverage. Write tests before fixing bugs (TDD for bugs).",
15503
+ info: "Push for 80%+ coverage. Add property-based tests for edge cases."
15440
15504
  },
15441
15505
  review: {
15442
- critical: "Write meaningful commit messages (explain WHY, not WHAT). Keep diffs small. Use PR templates to ensure consistent review quality.",
15443
- warning: "Improve commit message quality. Use conventional commits. Request reviews before merging.",
15444
- info: "Add automated review tools (linters, type checking in CI). Track review turnaround time."
15506
+ critical: "Write meaningful commit messages (explain WHY). Keep diffs small.",
15507
+ warning: "Use conventional commits. Request reviews before merging.",
15508
+ info: "Add automated review tools. Track review turnaround time."
15445
15509
  }
15446
15510
  };
15447
- return actions[phase]?.[severity] ?? "Improve this phase by focusing on consistency and tooling.";
15511
+ return actions[phase]?.[severity] ?? "Focus on consistency and tooling.";
15448
15512
  }
15449
15513
  function capitalize2(s2) {
15450
15514
  return s2.charAt(0).toUpperCase() + s2.slice(1);
@@ -15946,7 +16010,8 @@ var dashboardCommand = defineCommand2({
15946
16010
  return sparkChars[idx] ?? " ";
15947
16011
  }).join("");
15948
16012
  consola.log(` ${spark}`);
15949
- consola.log(` ${String(minScore).padStart(3)} ${"─".repeat(spark.length - 8)} ${String(maxScore).padStart(3)}`);
16013
+ const dashWidth = Math.max(0, spark.length - 8);
16014
+ consola.log(` ${String(minScore).padStart(3)} ${"─".repeat(dashWidth)} ${String(maxScore).padStart(3)}`);
15950
16015
  const first2 = scores[0];
15951
16016
  const last2 = scores[scores.length - 1];
15952
16017
  const delta = last2 - first2;
@@ -16417,10 +16482,13 @@ function renderMiniChart(scores) {
16417
16482
  for (const row of chart) {
16418
16483
  console.log(" " + row.join(""));
16419
16484
  }
16420
- const startLabel = "oldest";
16421
- const endLabel = "newest";
16422
- const padding = sampled.length - startLabel.length - endLabel.length;
16423
- console.log(` ${colors2.dim(startLabel)}${" ".repeat(Math.max(0, padding))}${colors2.dim(endLabel)}`);
16485
+ if (sampled.length >= 6) {
16486
+ const startLabel = "← older";
16487
+ const endLabel = "newer →";
16488
+ const chartWidth = sampled.length;
16489
+ const padding = Math.max(0, chartWidth - startLabel.length - endLabel.length);
16490
+ console.log(` ${colors2.dim(startLabel)}${" ".repeat(padding)}${colors2.dim(endLabel)}`);
16491
+ }
16424
16492
  }
16425
16493
 
16426
16494
  // src/commands/cost.ts
@@ -17631,9 +17699,55 @@ function formatBytes(bytes) {
17631
17699
  const i3 = Math.floor(Math.log(bytes) / Math.log(k2));
17632
17700
  return `${parseFloat((bytes / Math.pow(k2, i3)).toFixed(1))} ${sizes[i3]}`;
17633
17701
  }
17702
+ // package.json
17703
+ var package_default = {
17704
+ name: "nairon-bench",
17705
+ version: "0.0.23",
17706
+ description: "AI workflow benchmarking CLI",
17707
+ type: "module",
17708
+ bin: {
17709
+ "nairon-bench": "./dist/index.js",
17710
+ nb: "./dist/index.js"
17711
+ },
17712
+ files: [
17713
+ "dist"
17714
+ ],
17715
+ repository: {
17716
+ type: "git",
17717
+ url: "https://github.com/ObaidUr-Rahmaan/nairon-bench"
17718
+ },
17719
+ keywords: [
17720
+ "ai",
17721
+ "benchmark",
17722
+ "cli",
17723
+ "workflow"
17724
+ ],
17725
+ license: "MIT",
17726
+ scripts: {
17727
+ dev: "bun run src/index.ts",
17728
+ build: "bun build --outdir=dist --target=node src/index.ts && sed -i.bak '1s|#!/usr/bin/env bun|#!/usr/bin/env node|' dist/index.js && rm -f dist/index.js.bak",
17729
+ "build:binary": "bun build --compile --outfile=dist/nb src/index.ts",
17730
+ "build:all": "bun run build:macos-arm64 && bun run build:macos-x64 && bun run build:linux-x64 && bun run build:linux-arm64 && bun run build:windows-x64",
17731
+ "build:macos-arm64": "bun build --compile --target=bun-darwin-arm64 --outfile=dist/nb-darwin-arm64 src/index.ts",
17732
+ "build:macos-x64": "bun build --compile --target=bun-darwin-x64 --outfile=dist/nb-darwin-x64 src/index.ts",
17733
+ "build:linux-x64": "bun build --compile --target=bun-linux-x64 --outfile=dist/nb-linux-x64 src/index.ts",
17734
+ "build:linux-arm64": "bun build --compile --target=bun-linux-arm64 --outfile=dist/nb-linux-arm64 src/index.ts",
17735
+ "build:windows-x64": "bun build --compile --target=bun-windows-x64 --outfile=dist/nb-windows-x64.exe src/index.ts",
17736
+ typecheck: "tsc --noEmit",
17737
+ test: "bun test",
17738
+ "test:e2e": "bun test --test-name-pattern e2e",
17739
+ clean: "rm -rf dist",
17740
+ prepublishOnly: "bun run build"
17741
+ },
17742
+ dependencies: {
17743
+ "cli-boxes": "^4.0.1",
17744
+ ora: "^9.3.0",
17745
+ picocolors: "^1.1.1"
17746
+ }
17747
+ };
17634
17748
 
17635
17749
  // src/index.ts
17636
- var VERSION = "0.0.13";
17750
+ var VERSION = package_default.version;
17637
17751
  var CYAN = "\x1B[36m";
17638
17752
  var YELLOW = "\x1B[33m";
17639
17753
  var DIM = "\x1B[2m";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nairon-bench",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "AI workflow benchmarking CLI",
5
5
  "type": "module",
6
6
  "bin": {