nairon-bench 0.3.15 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +647 -398
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15364,6 +15364,362 @@ function wrapText(text, width) {
15364
15364
  return lines;
15365
15365
  }
15366
15366
 
15367
+ // src/lib/effort-analyzer.ts
15368
+ function analyzeEffort(sessions, git) {
15369
+ const sessionEfforts = [];
15370
+ let totalGeneration = 0;
15371
+ let totalReview = 0;
15372
+ let totalCorrection = 0;
15373
+ let totalIntegration = 0;
15374
+ let totalCorrectionLoops = 0;
15375
+ let totalContextChurn = 0;
15376
+ let totalRegenerations = 0;
15377
+ for (const session of sessions) {
15378
+ const effort = analyzeSessionEffort(session);
15379
+ sessionEfforts.push(effort);
15380
+ totalGeneration += effort.generationMinutes;
15381
+ totalReview += effort.reviewMinutes;
15382
+ totalCorrection += effort.correctionMinutes;
15383
+ totalIntegration += effort.integrationMinutes;
15384
+ for (const pattern of session.patterns) {
15385
+ if (pattern.type === "undo_loop") {
15386
+ totalCorrectionLoops += pattern.count;
15387
+ }
15388
+ if (pattern.type === "context_compaction" || pattern.type === "memory_loss") {
15389
+ totalContextChurn += pattern.count;
15390
+ }
15391
+ if (pattern.type === "repeated_rephrasing") {
15392
+ totalRegenerations += pattern.count;
15393
+ }
15394
+ }
15395
+ }
15396
+ const totalMinutes = totalGeneration + totalReview + totalCorrection + totalIntegration;
15397
+ const safeTotal = totalMinutes || 1;
15398
+ const generationPercent = Math.round(totalGeneration / safeTotal * 100);
15399
+ const reviewPercent = Math.round(totalReview / safeTotal * 100);
15400
+ const correctionPercent = Math.round(totalCorrection / safeTotal * 100);
15401
+ const integrationPercent = Math.round(totalIntegration / safeTotal * 100);
15402
+ const safeGeneration = totalGeneration || 1;
15403
+ const correctionRatio = totalCorrection / safeGeneration;
15404
+ const reviewOverhead = totalReview / safeGeneration;
15405
+ const trueEffortMultiplier = totalMinutes / safeGeneration;
15406
+ return {
15407
+ generationMinutes: totalGeneration,
15408
+ reviewMinutes: totalReview,
15409
+ correctionMinutes: totalCorrection,
15410
+ integrationMinutes: totalIntegration,
15411
+ totalMinutes,
15412
+ generationPercent,
15413
+ reviewPercent,
15414
+ correctionPercent,
15415
+ integrationPercent,
15416
+ totalSessions: sessions.length,
15417
+ correctionLoops: totalCorrectionLoops,
15418
+ contextChurnEvents: totalContextChurn,
15419
+ regenerationCycles: totalRegenerations,
15420
+ correctionRatio: Math.round(correctionRatio * 100) / 100,
15421
+ reviewOverhead: Math.round(reviewOverhead * 100) / 100,
15422
+ trueEffortMultiplier: Math.round(trueEffortMultiplier * 100) / 100,
15423
+ sessions: sessionEfforts
15424
+ };
15425
+ }
15426
+ function analyzeSessionEffort(session) {
15427
+ const totalMinutes = session.durationMinutes;
15428
+ let generationRatio = 0.4;
15429
+ let reviewRatio = 0.3;
15430
+ let correctionRatio = 0.2;
15431
+ let integrationRatio = 0.1;
15432
+ const patterns = [];
15433
+ let contextChurn = "low";
15434
+ let correctionIntensity = "low";
15435
+ for (const pattern of session.patterns) {
15436
+ patterns.push(pattern.type);
15437
+ if (pattern.type === "undo_loop") {
15438
+ const undoImpact = Math.min(pattern.count * 0.05, 0.25);
15439
+ correctionRatio += undoImpact;
15440
+ generationRatio -= undoImpact / 2;
15441
+ reviewRatio -= undoImpact / 2;
15442
+ correctionIntensity = pattern.count >= 5 ? "high" : pattern.count >= 2 ? "medium" : "low";
15443
+ }
15444
+ if (pattern.type === "memory_loss" || pattern.type === "context_compaction") {
15445
+ const contextImpact = Math.min(pattern.count * 0.08, 0.2);
15446
+ correctionRatio += contextImpact / 2;
15447
+ reviewRatio += contextImpact / 2;
15448
+ generationRatio -= contextImpact;
15449
+ contextChurn = pattern.count >= 3 ? "high" : pattern.count >= 1 ? "medium" : "low";
15450
+ }
15451
+ if (pattern.type === "repeated_rephrasing") {
15452
+ const rephrasingImpact = Math.min(pattern.count * 0.03, 0.15);
15453
+ generationRatio += rephrasingImpact;
15454
+ reviewRatio -= rephrasingImpact / 2;
15455
+ integrationRatio -= rephrasingImpact / 2;
15456
+ }
15457
+ if (pattern.type === "frustration_caps") {
15458
+ correctionRatio += 0.05;
15459
+ reviewRatio -= 0.05;
15460
+ }
15461
+ if (pattern.type === "smooth_flow") {
15462
+ generationRatio += 0.1;
15463
+ correctionRatio -= 0.1;
15464
+ }
15465
+ }
15466
+ const totalRatio = generationRatio + reviewRatio + correctionRatio + integrationRatio;
15467
+ generationRatio /= totalRatio;
15468
+ reviewRatio /= totalRatio;
15469
+ correctionRatio /= totalRatio;
15470
+ integrationRatio /= totalRatio;
15471
+ const generationMinutes = Math.round(totalMinutes * generationRatio);
15472
+ const reviewMinutes = Math.round(totalMinutes * reviewRatio);
15473
+ const correctionMinutes = Math.round(totalMinutes * correctionRatio);
15474
+ const integrationMinutes = totalMinutes - generationMinutes - reviewMinutes - correctionMinutes;
15475
+ return {
15476
+ sessionId: session.sessionId,
15477
+ agent: session.agent,
15478
+ startedAt: session.startedAt,
15479
+ generationMinutes,
15480
+ reviewMinutes,
15481
+ correctionMinutes,
15482
+ integrationMinutes,
15483
+ totalMinutes,
15484
+ patterns,
15485
+ contextChurn,
15486
+ correctionIntensity
15487
+ };
15488
+ }
15489
+ function generateLeadershipReport(effort, periodLabel = "Last 7 days") {
15490
+ const totalHours = effort.totalMinutes / 60;
15491
+ const generationHours = effort.generationMinutes / 60;
15492
+ const reviewHours = effort.reviewMinutes / 60;
15493
+ const correctionHours = effort.correctionMinutes / 60;
15494
+ const integrationHours = effort.integrationMinutes / 60;
15495
+ const perceivedEffort = generationHours;
15496
+ const hiddenWork = totalHours - perceivedEffort;
15497
+ const hiddenWorkPercent = hiddenWork / totalHours * 100;
15498
+ const contextChurnRate = effort.contextChurnEvents / Math.max(effort.totalSessions, 1);
15499
+ const repeatedCorrectionRate = effort.correctionLoops / Math.max(effort.totalSessions, 1);
15500
+ let burnoutRisk = "low";
15501
+ if (effort.correctionRatio > 0.8 || hiddenWorkPercent > 60) {
15502
+ burnoutRisk = "high";
15503
+ } else if (effort.correctionRatio > 0.5 || hiddenWorkPercent > 40) {
15504
+ burnoutRisk = "medium";
15505
+ }
15506
+ const insights = [];
15507
+ if (hiddenWorkPercent > 50) {
15508
+ insights.push(`${Math.round(hiddenWorkPercent)}% of effort is invisible (review, correction, integration) - leadership may underestimate true workload`);
15509
+ }
15510
+ if (effort.correctionRatio > 0.5) {
15511
+ insights.push(`High correction ratio (${Math.round(effort.correctionRatio * 100)}%) - AI output requires significant human oversight`);
15512
+ }
15513
+ if (contextChurnRate > 0.5) {
15514
+ insights.push(`Frequent context loss (${Math.round(contextChurnRate * 100)}% of sessions) - engineers repeatedly re-explaining requirements`);
15515
+ }
15516
+ if (effort.trueEffortMultiplier > 2) {
15517
+ insights.push(`True effort is ${effort.trueEffortMultiplier.toFixed(1)}x perceived effort - AI accelerates generation but not total delivery`);
15518
+ }
15519
+ if (burnoutRisk === "high") {
15520
+ insights.push("High burnout risk: excessive correction cycles indicate AI output quality issues");
15521
+ }
15522
+ if (insights.length === 0) {
15523
+ insights.push("AI workflow appears efficient - correction overhead is within healthy limits");
15524
+ }
15525
+ return {
15526
+ period: periodLabel,
15527
+ aiAssistedTasksCount: effort.totalSessions,
15528
+ totalAIGenerationHours: Math.round(generationHours * 10) / 10,
15529
+ totalReviewHours: Math.round(reviewHours * 10) / 10,
15530
+ totalCorrectionHours: Math.round(correctionHours * 10) / 10,
15531
+ totalIntegrationHours: Math.round(integrationHours * 10) / 10,
15532
+ totalEffortHours: Math.round(totalHours * 10) / 10,
15533
+ averageCorrectionRatio: Math.round(effort.correctionRatio * 100) / 100,
15534
+ integrationOverheadPercent: effort.integrationPercent,
15535
+ contextChurnRate: Math.round(contextChurnRate * 100) / 100,
15536
+ perceivedEffortHours: Math.round(perceivedEffort * 10) / 10,
15537
+ trueEffortHours: Math.round(totalHours * 10) / 10,
15538
+ hiddenWorkHours: Math.round(hiddenWork * 10) / 10,
15539
+ hiddenWorkPercent: Math.round(hiddenWorkPercent),
15540
+ burnoutRisk,
15541
+ contextLossFrequency: effort.contextChurnEvents,
15542
+ repeatedCorrectionRate: Math.round(repeatedCorrectionRate * 100) / 100,
15543
+ insights
15544
+ };
15545
+ }
15546
+ function formatEffortBreakdown(effort) {
15547
+ const lines = [];
15548
+ lines.push("");
15549
+ lines.push(colors2.dim(" " + "═".repeat(50)));
15550
+ lines.push(` ${icons.chart} ${colors2.bold("Effort Breakdown")} ${colors2.dim("(AI Work Visibility)")}`);
15551
+ lines.push(colors2.dim(" " + "═".repeat(50)));
15552
+ lines.push("");
15553
+ const total = effort.totalMinutes || 1;
15554
+ const genBar = "█".repeat(Math.round(effort.generationPercent / 5));
15555
+ const revBar = "█".repeat(Math.round(effort.reviewPercent / 5));
15556
+ const corBar = "█".repeat(Math.round(effort.correctionPercent / 5));
15557
+ const intBar = "█".repeat(Math.round(effort.integrationPercent / 5));
15558
+ lines.push(` ${colors2.bold("Time Breakdown:")}`);
15559
+ lines.push(` ${colors2.success("Generation")} ${formatTime(effort.generationMinutes).padEnd(10)} ${colors2.success(genBar)} ${effort.generationPercent}%`);
15560
+ lines.push(` ${colors2.primary("Review")} ${formatTime(effort.reviewMinutes).padEnd(10)} ${colors2.primary(revBar)} ${effort.reviewPercent}%`);
15561
+ lines.push(` ${colors2.warning("Correction")} ${formatTime(effort.correctionMinutes).padEnd(10)} ${colors2.warning(corBar)} ${effort.correctionPercent}%`);
15562
+ lines.push(` ${colors2.dim("Integration")} ${formatTime(effort.integrationMinutes).padEnd(10)} ${colors2.dim(intBar)} ${effort.integrationPercent}%`);
15563
+ lines.push("");
15564
+ lines.push(` ${colors2.bold("Total Active Effort:")} ${formatTime(effort.totalMinutes)}`);
15565
+ lines.push("");
15566
+ const hiddenWork = effort.reviewMinutes + effort.correctionMinutes + effort.integrationMinutes;
15567
+ const hiddenPercent = Math.round(hiddenWork / total * 100);
15568
+ if (hiddenPercent > 30) {
15569
+ lines.push(` ${colors2.warning("!")} ${colors2.bold("Hidden Work Alert:")}`);
15570
+ lines.push(` ${hiddenPercent}% of effort is invisible (review + correction + integration)`);
15571
+ lines.push(` ${colors2.dim("This is work leadership may not see")}`);
15572
+ lines.push("");
15573
+ }
15574
+ lines.push(` ${colors2.bold("Key Metrics:")}`);
15575
+ lines.push(` Correction ratio: ${formatRatio(effort.correctionRatio)} ${getRatioIndicator(effort.correctionRatio)}`);
15576
+ lines.push(` Review overhead: ${formatRatio(effort.reviewOverhead)}`);
15577
+ lines.push(` True effort factor: ${effort.trueEffortMultiplier}x ${colors2.dim("(total / generation)")}`);
15578
+ lines.push("");
15579
+ if (effort.correctionLoops > 0 || effort.contextChurnEvents > 0) {
15580
+ lines.push(` ${colors2.bold("Detected Issues:")}`);
15581
+ if (effort.correctionLoops > 0) {
15582
+ lines.push(` ${colors2.warning("•")} ${effort.correctionLoops} correction loop${effort.correctionLoops > 1 ? "s" : ""}`);
15583
+ }
15584
+ if (effort.contextChurnEvents > 0) {
15585
+ lines.push(` ${colors2.warning("•")} ${effort.contextChurnEvents} context churn event${effort.contextChurnEvents > 1 ? "s" : ""}`);
15586
+ }
15587
+ if (effort.regenerationCycles > 0) {
15588
+ lines.push(` ${colors2.dim("•")} ${effort.regenerationCycles} regeneration cycle${effort.regenerationCycles > 1 ? "s" : ""}`);
15589
+ }
15590
+ lines.push("");
15591
+ }
15592
+ lines.push(colors2.dim(" " + "═".repeat(50)));
15593
+ return lines;
15594
+ }
15595
+ function formatLeadershipReport(report) {
15596
+ const lines = [];
15597
+ lines.push("");
15598
+ lines.push(colors2.dim(" " + "═".repeat(60)));
15599
+ lines.push(` ${icons.chart} ${colors2.bold("Leadership Report")} ${colors2.dim(`(${report.period})`)}`);
15600
+ lines.push(colors2.dim(" " + "═".repeat(60)));
15601
+ lines.push("");
15602
+ lines.push(` ${colors2.bold("Executive Summary")}`);
15603
+ lines.push(` ─────────────────────────────────────────────────────`);
15604
+ lines.push(` AI-Assisted Sessions: ${report.aiAssistedTasksCount}`);
15605
+ lines.push(` Total Effort: ${report.totalEffortHours} hours`);
15606
+ lines.push("");
15607
+ lines.push(` ${colors2.bold("Effort Visibility")}`);
15608
+ lines.push(` ─────────────────────────────────────────────────────`);
15609
+ lines.push(` ${colors2.success("AI Generation:")} ${report.totalAIGenerationHours}h ${colors2.dim("← What leadership sees")}`);
15610
+ lines.push(` ${colors2.primary("Review:")} ${report.totalReviewHours}h`);
15611
+ lines.push(` ${colors2.warning("Correction:")} ${report.totalCorrectionHours}h`);
15612
+ lines.push(` ${colors2.dim("Integration:")} ${report.totalIntegrationHours}h`);
15613
+ lines.push(` ─────────────────────────────────────────────────`);
15614
+ lines.push(` ${colors2.bold("True Total:")} ${report.trueEffortHours}h ${colors2.dim("← Actual effort")}`);
15615
+ lines.push("");
15616
+ if (report.hiddenWorkPercent > 20) {
15617
+ lines.push(` ${colors2.warning(icons.warning)} ${colors2.bold("Hidden Work:")}`);
15618
+ lines.push(` ${report.hiddenWorkHours}h (${report.hiddenWorkPercent}%) is invisible to leadership`);
15619
+ lines.push("");
15620
+ }
15621
+ lines.push(` ${colors2.bold("Risk Indicators")}`);
15622
+ lines.push(` ─────────────────────────────────────────────────────`);
15623
+ const burnoutColor = report.burnoutRisk === "high" ? colors2.error : report.burnoutRisk === "medium" ? colors2.warning : colors2.success;
15624
+ lines.push(` Burnout Risk: ${burnoutColor(report.burnoutRisk.toUpperCase())}`);
15625
+ lines.push(` Correction Ratio: ${report.averageCorrectionRatio} ${getRatioIndicator(report.averageCorrectionRatio)}`);
15626
+ lines.push(` Context Churn Rate: ${report.contextChurnRate}`);
15627
+ lines.push("");
15628
+ if (report.insights.length > 0) {
15629
+ lines.push(` ${colors2.bold("Key Insights")}`);
15630
+ lines.push(` ─────────────────────────────────────────────────────`);
15631
+ for (const insight of report.insights) {
15632
+ lines.push(` ${colors2.primary("→")} ${insight}`);
15633
+ }
15634
+ lines.push("");
15635
+ }
15636
+ lines.push(colors2.dim(" " + "═".repeat(60)));
15637
+ return lines;
15638
+ }
15639
+ function formatLeadershipReportMarkdown(report) {
15640
+ let md = `# AI Work Visibility Report
15641
+
15642
+ `;
15643
+ md += `**Period:** ${report.period}
15644
+
15645
+ `;
15646
+ md += `## Executive Summary
15647
+
15648
+ `;
15649
+ md += `| Metric | Value |
15650
+ `;
15651
+ md += `|--------|-------|
15652
+ `;
15653
+ md += `| AI-Assisted Sessions | ${report.aiAssistedTasksCount} |
15654
+ `;
15655
+ md += `| Total Effort | ${report.totalEffortHours} hours |
15656
+ `;
15657
+ md += `| Perceived Effort (AI Generation) | ${report.perceivedEffortHours} hours |
15658
+ `;
15659
+ md += `| Hidden Work | ${report.hiddenWorkHours} hours (${report.hiddenWorkPercent}%) |
15660
+
15661
+ `;
15662
+ md += `## Effort Breakdown
15663
+
15664
+ `;
15665
+ md += `| Phase | Hours | % of Total |
15666
+ `;
15667
+ md += `|-------|-------|------------|
15668
+ `;
15669
+ md += `| AI Generation | ${report.totalAIGenerationHours}h | ${Math.round(report.totalAIGenerationHours / report.totalEffortHours * 100)}% |
15670
+ `;
15671
+ md += `| Review | ${report.totalReviewHours}h | ${Math.round(report.totalReviewHours / report.totalEffortHours * 100)}% |
15672
+ `;
15673
+ md += `| Correction | ${report.totalCorrectionHours}h | ${Math.round(report.totalCorrectionHours / report.totalEffortHours * 100)}% |
15674
+ `;
15675
+ md += `| Integration | ${report.totalIntegrationHours}h | ${Math.round(report.totalIntegrationHours / report.totalEffortHours * 100)}% |
15676
+
15677
+ `;
15678
+ md += `## Risk Assessment
15679
+
15680
+ `;
15681
+ md += `- **Burnout Risk:** ${report.burnoutRisk.toUpperCase()}
15682
+ `;
15683
+ md += `- **Correction Ratio:** ${report.averageCorrectionRatio}
15684
+ `;
15685
+ md += `- **Context Churn Rate:** ${report.contextChurnRate}
15686
+
15687
+ `;
15688
+ md += `## Key Insights
15689
+
15690
+ `;
15691
+ for (const insight of report.insights) {
15692
+ md += `- ${insight}
15693
+ `;
15694
+ }
15695
+ md += `
15696
+ `;
15697
+ md += `---
15698
+
15699
+ `;
15700
+ md += `*Generated by nairon-bench - AI Workflow Benchmarking*
15701
+ `;
15702
+ return md;
15703
+ }
15704
+ function formatTime(minutes) {
15705
+ if (minutes < 60) {
15706
+ return `${minutes}m`;
15707
+ }
15708
+ const hours = Math.floor(minutes / 60);
15709
+ const mins = minutes % 60;
15710
+ return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
15711
+ }
15712
+ function formatRatio(ratio) {
15713
+ return `${Math.round(ratio * 100)}%`;
15714
+ }
15715
+ function getRatioIndicator(ratio) {
15716
+ if (ratio > 0.8)
15717
+ return colors2.error("(high - needs attention)");
15718
+ if (ratio > 0.5)
15719
+ return colors2.warning("(moderate)");
15720
+ return colors2.success("(healthy)");
15721
+ }
15722
+
15367
15723
  // src/lib/optimization-installer.ts
15368
15724
  import { execSync as execSync2, spawnSync } from "node:child_process";
15369
15725
  import { existsSync as existsSync8, writeFileSync as writeFileSync3, readFileSync as readFileSync8, mkdirSync as mkdirSync3, readdirSync as readdirSync4 } from "node:fs";
@@ -15711,159 +16067,52 @@ function filterAlreadyInstalled(optimizations, status) {
15711
16067
  return true;
15712
16068
  });
15713
16069
  }
15714
- var QUICK_INSTALL_PRESETS = {
15715
- essential: [
15716
- {
15717
- id: "context7",
15718
- name: "Context7 MCP",
15719
- type: "mcp",
15720
- description: "Up-to-date library documentation",
15721
- installCommand: "claude mcp add context7 https://mcp.context7.com/mcp --transport http",
15722
- selected: true
15723
- },
15724
- {
15725
- id: "supermemory",
15726
- name: "Supermemory MCP",
15727
- type: "mcp",
15728
- description: "Persistent memory across sessions",
15729
- installCommand: "claude mcp add supermemory -- npx -y @supermemory/mcp@latest",
15730
- selected: true
15731
- },
15732
- {
15733
- id: "beads",
15734
- name: "Beads Task Manager",
15735
- type: "mcp",
15736
- description: "Persistent task tracking",
15737
- installCommand: "bun add -g beads && bd init",
15738
- selected: true
15739
- }
15740
- ],
15741
- productivity: [
15742
- {
15743
- id: "claude-md",
15744
- name: "CLAUDE.md",
15745
- type: "config",
15746
- description: "Project context file",
15747
- configPath: "CLAUDE.md",
15748
- configContent: `# Project Instructions
15749
-
15750
- ## Build & Test Commands
15751
- \`\`\`bash
15752
- bun test # Run tests
15753
- bun run build # Build project
15754
- bun run lint # Run linter
15755
- \`\`\`
15756
-
15757
- ## Architecture
15758
- Describe your project structure here.
15759
-
15760
- ## Conventions
15761
- - Use TypeScript
15762
- - Write tests for new features
15763
- - Use conventional commits
15764
- `,
15765
- selected: true
15766
- },
15767
- {
15768
- id: "vitest",
15769
- name: "Vitest",
15770
- type: "library",
15771
- description: "Fast unit testing framework",
15772
- installCommand: "bun add -D vitest",
15773
- selected: true
15774
- }
15775
- ]
15776
- };
15777
16070
 
15778
16071
  // src/commands/scan.ts
15779
16072
  var scanCommand = defineCommand2({
15780
16073
  meta: {
15781
16074
  name: "scan",
15782
- description: "Analyze local data sources (git, AI sessions, tests) and compute your NaironAI score"
16075
+ description: "Scan your AI workflow and get optimization recommendations (interactive)"
15783
16076
  },
15784
16077
  args: {
15785
- since: {
15786
- type: "string",
15787
- description: 'Time range: 6h, 24h, 7d, 30d, or "7 days"',
15788
- default: "7d"
15789
- },
15790
- project: {
15791
- type: "string",
15792
- description: "Project directory to scan (defaults to cwd)"
15793
- },
15794
- install: {
15795
- type: "boolean",
15796
- alias: "i",
15797
- description: "Install recommended optimizations (interactive)",
15798
- default: false
15799
- },
15800
- "install-all": {
15801
- type: "boolean",
15802
- description: "Install all recommended optimizations (non-interactive)",
15803
- default: false
15804
- },
15805
- "install-essentials": {
15806
- type: "boolean",
15807
- description: "Install essential tools: Context7, Supermemory, Beads",
15808
- default: false
15809
- },
15810
- offline: {
15811
- type: "boolean",
15812
- description: "Skip uploading results to Convex",
15813
- default: false
15814
- },
15815
- "no-report": {
15816
- type: "boolean",
15817
- description: "Skip generating markdown report",
15818
- default: false
15819
- },
15820
- "report-dir": {
15821
- type: "string",
15822
- description: "Directory for reports (defaults to .nairon/reports)",
15823
- default: ".nairon/reports"
15824
- },
15825
- brief: {
15826
- type: "boolean",
15827
- description: "Show brief output (skip detailed analysis)",
15828
- default: false
15829
- },
15830
16078
  json: {
15831
16079
  type: "boolean",
15832
- description: "Output results as JSON (for CI/scripts)",
16080
+ description: "Output as JSON (for CI/scripts)",
15833
16081
  default: false
15834
16082
  },
15835
16083
  quiet: {
15836
16084
  type: "boolean",
15837
16085
  alias: "q",
15838
- description: "Quiet mode - only output the score number",
15839
- default: false
15840
- },
15841
- "no-cache": {
15842
- type: "boolean",
15843
- description: "Disable session caching (slower but ensures fresh data)",
16086
+ description: "Only output score number",
15844
16087
  default: false
15845
- },
15846
- watch: {
15847
- type: "boolean",
15848
- alias: "w",
15849
- description: "Watch mode - re-scan on file changes",
15850
- default: false
15851
- },
15852
- "watch-interval": {
15853
- type: "string",
15854
- description: "Watch interval in seconds (default: 30)",
15855
- default: "30"
15856
16088
  }
15857
16089
  },
15858
16090
  async run({ args }) {
15859
- const projectDir = args.project ?? process.cwd();
15860
- const since = parseSince(args.since);
16091
+ const projectDir = process.cwd();
15861
16092
  const jsonOutput = args.json;
15862
16093
  const quietMode = args.quiet;
15863
- const useCache = !args["no-cache"];
15864
- const watchMode = args.watch;
15865
- const watchInterval = parseInt(args["watch-interval"] || "30", 10) * 1000;
15866
16094
  const silent = jsonOutput || quietMode;
16095
+ let since;
16096
+ if (silent) {
16097
+ since = parseSince("7d");
16098
+ } else {
16099
+ console.log();
16100
+ console.log(" \uD83D\uDD0D " + "\x1B[1mNaironAI Workflow Scanner\x1B[0m");
16101
+ console.log(" " + "\x1B[2m" + "─".repeat(35) + "\x1B[0m");
16102
+ console.log();
16103
+ const period = await consola.prompt("Time period to analyze?", {
16104
+ type: "select",
16105
+ options: [
16106
+ { value: "7d", label: "Last 7 days (recommended)" },
16107
+ { value: "24h", label: "Last 24 hours" },
16108
+ { value: "30d", label: "Last 30 days" }
16109
+ ]
16110
+ });
16111
+ since = parseSince(period);
16112
+ }
16113
+ const useCache = true;
16114
+ const watchMode = false;
16115
+ const watchInterval = 30000;
15867
16116
  if (watchMode) {
15868
16117
  console.log();
15869
16118
  console.log(colors2.bold(colors2.primary(" NaironAI Watch Mode")));
@@ -15996,12 +16245,17 @@ var scanCommand = defineCommand2({
15996
16245
  console.log(` Projected monthly: ${colors2.primary(`$${scanCost.projectedMonthlyCostUsd.toFixed(2)}`)}`);
15997
16246
  console.log(colors2.dim(" " + "═".repeat(45)));
15998
16247
  console.log();
15999
- if (!args["no-report"]) {
16000
- const reportDir = join9(projectDir, args["report-dir"]);
16001
- const reportPath = generateReport(reportDir, score, git, agents, tests, args.since, sdlcAnalysis, scanCost, analysis);
16002
- console.log(` ${icons.success} Report saved: ${colors2.dim(reportPath)}`);
16248
+ const reportDir = join9(projectDir, ".nairon/reports");
16249
+ const reportPath = generateReport(reportDir, score, git, agents, tests, "7d", sdlcAnalysis, scanCost, analysis);
16250
+ console.log(` ${icons.success} Report saved: ${colors2.dim(reportPath)}`);
16251
+ if (agents && agents.sessions.length > 0) {
16252
+ const effortBreakdown = analyzeEffort(agents.sessions, git);
16253
+ const effortLines = formatEffortBreakdown(effortBreakdown);
16254
+ for (const line of effortLines) {
16255
+ console.log(line);
16256
+ }
16003
16257
  }
16004
- if (agents && agents.sessions.length > 0 && !args.brief) {
16258
+ if (agents && agents.sessions.length > 0) {
16005
16259
  const frustrationSummary = detectFrustrations(agents.sessions);
16006
16260
  if (frustrationSummary.totalFrustrations > 0) {
16007
16261
  const frustrationLines = formatFrustrationSummary(frustrationSummary);
@@ -16010,68 +16264,71 @@ var scanCommand = defineCommand2({
16010
16264
  }
16011
16265
  }
16012
16266
  }
16013
- if (!args.brief) {
16014
- const installedStatus = checkInstalledStatus(projectDir);
16015
- const projectContext = loadProjectContext(projectDir);
16016
- if (projectContext) {
16017
- console.log(` ${colors2.dim("Using project context from onboarding for personalized recommendations")}`);
16018
- }
16019
- const sdlc = analyzeSDLC(agents, git, tests, projectDir, analysis, projectContext);
16020
- for (const phase of [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review]) {
16021
- phase.recommendations = phase.recommendations.filter((rec) => {
16022
- const id = rec.title.toLowerCase().replace(/\s+/g, "-");
16023
- if (id.includes("context7") && installedStatus.context7)
16024
- return false;
16025
- if (id.includes("supermemory") && installedStatus.supermemory)
16026
- return false;
16027
- if (id.includes("nia") && installedStatus.nia)
16028
- return false;
16029
- if (id.includes("beads") && installedStatus.beads)
16030
- return false;
16031
- return true;
16032
- });
16033
- for (const tool of phase.tools) {
16034
- if (tool.name.toLowerCase().includes("context7") && installedStatus.context7) {
16035
- tool.installed = true;
16036
- }
16037
- if (tool.name.toLowerCase().includes("supermemory") && installedStatus.supermemory) {
16038
- tool.installed = true;
16039
- }
16040
- if (tool.name.toLowerCase().includes("nia") && installedStatus.nia) {
16041
- tool.installed = true;
16042
- }
16267
+ const installedStatus = checkInstalledStatus(projectDir);
16268
+ const projectContext = loadProjectContext(projectDir);
16269
+ if (projectContext) {
16270
+ console.log(` ${colors2.dim("Using project context from onboarding for personalized recommendations")}`);
16271
+ }
16272
+ const sdlc = analyzeSDLC(agents, git, tests, projectDir, analysis, projectContext);
16273
+ for (const phase of [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review]) {
16274
+ phase.recommendations = phase.recommendations.filter((rec) => {
16275
+ const id = rec.title.toLowerCase().replace(/\s+/g, "-");
16276
+ if (id.includes("context7") && installedStatus.context7)
16277
+ return false;
16278
+ if (id.includes("supermemory") && installedStatus.supermemory)
16279
+ return false;
16280
+ if (id.includes("nia") && installedStatus.nia)
16281
+ return false;
16282
+ if (id.includes("beads") && installedStatus.beads)
16283
+ return false;
16284
+ return true;
16285
+ });
16286
+ for (const tool of phase.tools) {
16287
+ if (tool.name.toLowerCase().includes("context7") && installedStatus.context7) {
16288
+ tool.installed = true;
16289
+ }
16290
+ if (tool.name.toLowerCase().includes("supermemory") && installedStatus.supermemory) {
16291
+ tool.installed = true;
16292
+ }
16293
+ if (tool.name.toLowerCase().includes("nia") && installedStatus.nia) {
16294
+ tool.installed = true;
16043
16295
  }
16044
16296
  }
16045
- const totalRecs = [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review].reduce((a2, p) => a2 + p.recommendations.length, 0);
16046
- if (totalRecs > 0) {
16047
- sdlc.overall.summary = sdlc.overall.summary.replace(/\d+ optimizations available\./, `${totalRecs} optimizations available.`);
16048
- } else if (sdlc.overall.summary.includes("optimizations available")) {
16049
- sdlc.overall.summary = sdlc.overall.summary.replace(/\d+ optimizations available\./, "All recommended tools installed.");
16050
- }
16051
- const sdlcLines = formatSDLCForTerminal(sdlc);
16052
- for (const line of sdlcLines) {
16053
- console.log(line);
16054
- }
16055
- let allRecs = [];
16056
- for (const phase of [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review]) {
16057
- for (const rec of phase.recommendations) {
16058
- if (rec.installCommand) {
16059
- allRecs.push(phaseRecToInstallable(rec));
16060
- }
16297
+ }
16298
+ const totalRecs = [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review].reduce((a2, p) => a2 + p.recommendations.length, 0);
16299
+ if (totalRecs > 0) {
16300
+ sdlc.overall.summary = sdlc.overall.summary.replace(/\d+ optimizations available\./, `${totalRecs} optimizations available.`);
16301
+ } else if (sdlc.overall.summary.includes("optimizations available")) {
16302
+ sdlc.overall.summary = sdlc.overall.summary.replace(/\d+ optimizations available\./, "All recommended tools installed.");
16303
+ }
16304
+ const sdlcLines = formatSDLCForTerminal(sdlc);
16305
+ for (const line of sdlcLines) {
16306
+ console.log(line);
16307
+ }
16308
+ let allRecs = [];
16309
+ for (const phase of [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review]) {
16310
+ for (const rec of phase.recommendations) {
16311
+ if (rec.installCommand) {
16312
+ allRecs.push(phaseRecToInstallable(rec));
16061
16313
  }
16062
16314
  }
16063
- allRecs = filterAlreadyInstalled(allRecs, installedStatus);
16064
- if (args["install-essentials"]) {
16065
- console.log();
16066
- console.log(` ${colors2.bold(colors2.primary("Installing Essential Tools"))}`);
16067
- console.log(colors2.dim(" " + "─".repeat(40)));
16068
- console.log();
16069
- const essentials = filterAlreadyInstalled(QUICK_INSTALL_PRESETS.essential, installedStatus);
16070
- if (essentials.length === 0) {
16071
- console.log(` ${colors2.success("✓")} All essential tools already installed!`);
16315
+ }
16316
+ allRecs = filterAlreadyInstalled(allRecs, installedStatus);
16317
+ if (allRecs.length > 0) {
16318
+ console.log();
16319
+ const optionLabels = allRecs.map((rec) => `${rec.name} - ${rec.description}`);
16320
+ const selected = await consola.prompt(`${allRecs.length} optimizations available. Select to install (space to select, enter to confirm):`, {
16321
+ type: "multiselect",
16322
+ options: optionLabels,
16323
+ required: false
16324
+ });
16325
+ if (selected && typeof selected !== "symbol" && Array.isArray(selected) && selected.length > 0) {
16326
+ const toInstall = allRecs.filter((rec) => selected.some((s2) => s2.startsWith(rec.name))).map((r3) => ({ ...r3, selected: true }));
16327
+ if (toInstall.length > 0) {
16072
16328
  console.log();
16073
- } else {
16074
- const results = await installOptimizations(essentials.map((e2) => ({ ...e2, selected: true })), projectDir, {});
16329
+ console.log(` ${colors2.bold("Installing...")}${colors2.dim("")}`);
16330
+ console.log();
16331
+ const results = await installOptimizations(toInstall, projectDir, {});
16075
16332
  for (const result of results) {
16076
16333
  if (result.success) {
16077
16334
  console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
@@ -16081,82 +16338,15 @@ var scanCommand = defineCommand2({
16081
16338
  }
16082
16339
  console.log();
16083
16340
  }
16084
- } else if (args["install-all"] && allRecs.length > 0) {
16085
- console.log();
16086
- console.log(` ${colors2.bold(colors2.primary("Installing All Optimizations"))}`);
16087
- console.log(colors2.dim(" " + "─".repeat(40)));
16088
- console.log();
16089
- const results = await installOptimizations(allRecs.map((r3) => ({ ...r3, selected: true })), projectDir, {});
16090
- for (const result of results) {
16091
- if (result.success) {
16092
- console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
16093
- } else {
16094
- console.log(` ${colors2.error("✗")} ${result.name}: ${result.error || result.message}`);
16095
- }
16096
- }
16097
- console.log();
16098
- } else if (allRecs.length > 0 && !args["install-essentials"] && !args["install-all"]) {
16341
+ } else {
16342
+ console.log(` ${colors2.dim("Skipped.")}`);
16099
16343
  console.log();
16100
- const optionLabels = allRecs.map((rec) => `${rec.name} - ${rec.description}`);
16101
- const selected = await consola.prompt(`${allRecs.length} optimizations available. Select to install (space to select, enter to confirm):`, {
16102
- type: "multiselect",
16103
- options: optionLabels,
16104
- required: false
16105
- });
16106
- if (selected && typeof selected !== "symbol" && Array.isArray(selected) && selected.length > 0) {
16107
- const toInstall = allRecs.filter((rec) => selected.some((s2) => s2.startsWith(rec.name))).map((r3) => ({ ...r3, selected: true }));
16108
- if (toInstall.length > 0) {
16109
- console.log();
16110
- console.log(` ${colors2.bold("Installing...")}${colors2.dim("")}`);
16111
- console.log();
16112
- const results = await installOptimizations(toInstall, projectDir, {});
16113
- for (const result of results) {
16114
- if (result.success) {
16115
- console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
16116
- } else {
16117
- console.log(` ${colors2.error("✗")} ${result.name}: ${result.error || result.message}`);
16118
- }
16119
- }
16120
- console.log();
16121
- }
16122
- } else {
16123
- console.log(` ${colors2.dim("Skipped. Run")} ${colors2.primary("nb scan --install-essentials")} ${colors2.dim("anytime to quick-install.")}`);
16124
- console.log();
16125
- }
16126
16344
  }
16127
16345
  }
16128
16346
  }
16129
- if (args.offline) {
16130
- if (!silent) {
16131
- console.log(` ${icons.info} Offline mode - skipping cloud sync`);
16132
- console.log();
16133
- }
16134
- if (jsonOutput) {
16135
- const output = {
16136
- score: score.overall,
16137
- tier: score.tier,
16138
- baseScore: score.baseScore,
16139
- tokenEfficiency: score.tokenEfficiency,
16140
- phases: score.phases,
16141
- cost: scanCost,
16142
- git: git ? { commitCount: git.commitCount, authors: git.authors.length } : null,
16143
- agents: agents ? { sessions: agents.totalSessions, tokens: agents.totalTokens } : null,
16144
- tests: tests ? { total: tests.totalTests, passRate: tests.passRate } : null,
16145
- scannedAt: score.scannedAt
16146
- };
16147
- console.log(JSON.stringify(output, null, 2));
16148
- } else if (quietMode) {
16149
- console.log(score.overall);
16150
- }
16151
- return;
16152
- }
16153
16347
  const client = getClient();
16154
16348
  const clerkId = getClerkId();
16155
16349
  if (!client || !clerkId) {
16156
- if (!silent) {
16157
- console.log(` ${icons.info} Run ${colors2.primary("nb init")} to enable cloud sync`);
16158
- console.log();
16159
- }
16160
16350
  if (jsonOutput) {
16161
16351
  const output = {
16162
16352
  score: score.overall,
@@ -19023,7 +19213,7 @@ function renderTimelineASCII(timeline) {
19023
19213
  if (timeline.milestones.length > 0) {
19024
19214
  lines.push(" Key Milestones:");
19025
19215
  for (const milestone of timeline.milestones.slice(-5)) {
19026
- const time = formatTime(milestone.timestamp);
19216
+ const time = formatTime2(milestone.timestamp);
19027
19217
  const icon = getMilestoneIcon(milestone.type);
19028
19218
  lines.push(` ${time} ${icon} ${truncate(milestone.title, 40)}`);
19029
19219
  }
@@ -19032,7 +19222,7 @@ function renderTimelineASCII(timeline) {
19032
19222
  if (timeline.strugglePoints.length > 0) {
19033
19223
  lines.push(" Struggle Points:");
19034
19224
  for (const struggle of timeline.strugglePoints.slice(-3)) {
19035
- const time = formatTime(struggle.timestamp);
19225
+ const time = formatTime2(struggle.timestamp);
19036
19226
  const icon = getSeverityIcon(struggle.severity);
19037
19227
  lines.push(` ${time} ${icon} ${truncate(struggle.description, 40)}`);
19038
19228
  }
@@ -19100,7 +19290,7 @@ function truncate(str, len2) {
19100
19290
  function cleanCommitMessage(message) {
19101
19291
  return message.replace(/^(feat|fix|refactor|docs|test|chore|style|perf|ci|build|revert)(\(.+?\))?:\s*/i, "").replace(/^(add|fix|update|remove|implement|refactor)\s+/i, "").trim();
19102
19292
  }
19103
- function formatTime(date) {
19293
+ function formatTime2(date) {
19104
19294
  return date.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" });
19105
19295
  }
19106
19296
  function formatDate(date) {
@@ -21381,136 +21571,146 @@ import { resolve } from "node:path";
21381
21571
  var reportCommand = defineCommand2({
21382
21572
  meta: {
21383
21573
  name: "report",
21384
- description: "Generate AI-nativeness reports for hackathon submissions or regular benchmarks"
21574
+ description: "Generate AI-nativeness reports (interactive)"
21385
21575
  },
21386
21576
  args: {
21387
- hackathon: {
21388
- type: "boolean",
21389
- description: "Generate hackathon submission report (last 48 hours)",
21390
- default: false
21391
- },
21392
- harness: {
21393
- type: "string",
21394
- description: "AI harness to analyze: claude-code, opencode, cursor, or all"
21395
- },
21396
- since: {
21397
- type: "string",
21398
- description: "Time range: 48h, 7d, 30d, or ISO date"
21399
- },
21400
- output: {
21401
- type: "string",
21402
- description: "Save report to file (e.g., report.md)"
21403
- },
21404
- publish: {
21405
- type: "boolean",
21406
- description: "Publish report and get a shareable public link",
21407
- default: false
21408
- },
21409
- phase: {
21410
- type: "string",
21411
- description: "Drill into a specific phase (requirements, planning, implementation, testing, review)"
21412
- },
21413
- weekly: {
21414
- type: "boolean",
21415
- description: "Show latest scheduled weekly improvement report",
21416
- default: false
21417
- },
21418
- history: {
21577
+ json: {
21419
21578
  type: "boolean",
21420
- description: "Show score trend over time",
21579
+ description: "Output as JSON (for CI/scripts)",
21421
21580
  default: false
21422
- },
21423
- limit: {
21424
- type: "string",
21425
- description: "Number of historical scans to show",
21426
- default: "10"
21427
- },
21428
- format: {
21429
- type: "string",
21430
- description: "Output format: terminal, md, json, or text (legacy)",
21431
- default: "terminal"
21432
21581
  }
21433
21582
  },
21434
21583
  async run({ args }) {
21435
- if (args.hackathon || args.since) {
21436
- await runHackathonReport(args);
21584
+ if (args.json) {
21585
+ const projectDir = process.cwd();
21586
+ const since = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
21587
+ const report = await generateHackathonReport(projectDir, since, new Date, "all");
21588
+ console.log(formatReportAsJSON(report));
21437
21589
  return;
21438
21590
  }
21439
- if (!args.weekly && !args.history && !args.phase) {
21440
- const choice = await consola.prompt("What would you like to report on?", {
21441
- type: "select",
21442
- options: [
21443
- { value: "hackathon", label: "Hackathon (last 48 hours)" },
21444
- { value: "week", label: "Last week" },
21445
- { value: "month", label: "Last month" },
21446
- { value: "cloud", label: "Cloud benchmark (requires nb init)" }
21447
- ]
21448
- });
21449
- if (choice === "hackathon" || choice === "week" || choice === "month") {
21450
- const sinceMap = {
21451
- hackathon: "48h",
21452
- week: "7d",
21453
- month: "30d"
21454
- };
21455
- args.since = sinceMap[choice];
21456
- const harness = await consola.prompt("Which AI harness did you use?", {
21457
- type: "select",
21458
- options: [
21459
- { value: "claude-code", label: "Claude Code" },
21460
- { value: "opencode", label: "OpenCode" },
21461
- { value: "cursor", label: "Cursor" },
21462
- { value: "all", label: "All (combine sessions from all harnesses)" }
21463
- ]
21464
- });
21465
- args.harness = harness;
21466
- const format2 = await consola.prompt("Output format?", {
21467
- type: "select",
21468
- options: [
21469
- { value: "terminal", label: "Terminal (view now)" },
21470
- { value: "md", label: "Markdown (for submission)" },
21471
- { value: "publish", label: "Public link (shareable URL)" },
21472
- { value: "json", label: "JSON (programmatic)" }
21473
- ]
21474
- });
21475
- if (format2 === "publish") {
21476
- args.publish = true;
21477
- args.format = "terminal";
21478
- } else {
21479
- args.format = format2;
21480
- }
21481
- if (format2 === "md") {
21482
- const filename = await consola.prompt("Save to file?", {
21483
- type: "text",
21484
- default: "ai-nativeness-report.md",
21485
- placeholder: "report.md"
21486
- });
21487
- if (filename && typeof filename === "string") {
21488
- args.output = filename;
21489
- }
21490
- }
21491
- await runHackathonReport(args);
21492
- return;
21493
- }
21494
- args.format = "text";
21495
- }
21496
- const client = getClient();
21497
- const clerkId = getClerkId();
21498
- if (!client || !clerkId) {
21499
- consola.error("Not connected to Convex. Run `nb init` to set up your profile.");
21500
- consola.info("Use `nb report --hackathon` for local AI-nativeness report.");
21591
+ console.log();
21592
+ console.log(" \uD83D\uDCCA " + "\x1B[1mNaironAI Report Generator\x1B[0m");
21593
+ console.log(" " + "\x1B[2m" + "─".repeat(35) + "\x1B[0m");
21594
+ console.log();
21595
+ const reportType = await consola.prompt("What kind of report?", {
21596
+ type: "select",
21597
+ options: [
21598
+ { value: "ai-nativeness", label: "AI-Nativeness Report (recommended)" },
21599
+ { value: "leadership", label: "Leadership Report (effort visibility)" },
21600
+ { value: "cloud", label: "Cloud Benchmark (requires nb init)" }
21601
+ ]
21602
+ });
21603
+ if (reportType === "leadership") {
21604
+ await runLeadershipReportInteractive();
21501
21605
  return;
21502
21606
  }
21503
- if (args.weekly) {
21504
- await showWeeklyReport(client, clerkId, args.format);
21607
+ if (reportType === "cloud") {
21608
+ await runCloudReport();
21505
21609
  return;
21506
21610
  }
21507
- if (args.history) {
21508
- await showHistory(client, clerkId, parseInt(args.limit, 10), args.format);
21509
- return;
21611
+ const period = await consola.prompt("Time period?", {
21612
+ type: "select",
21613
+ options: [
21614
+ { value: "48h", label: "Last 48 hours (hackathon)" },
21615
+ { value: "7d", label: "Last 7 days" },
21616
+ { value: "30d", label: "Last 30 days" }
21617
+ ]
21618
+ });
21619
+ const harness = await consola.prompt("Which AI tool?", {
21620
+ type: "select",
21621
+ options: [
21622
+ { value: "all", label: "All tools (recommended)" },
21623
+ { value: "claude-code", label: "Claude Code" },
21624
+ { value: "opencode", label: "OpenCode" },
21625
+ { value: "cursor", label: "Cursor" }
21626
+ ]
21627
+ });
21628
+ const format2 = await consola.prompt("Output format?", {
21629
+ type: "select",
21630
+ options: [
21631
+ { value: "publish", label: "Public link (shareable URL)" },
21632
+ { value: "terminal", label: "Terminal (view now)" },
21633
+ { value: "md", label: "Markdown file" },
21634
+ { value: "json", label: "JSON" }
21635
+ ]
21636
+ });
21637
+ const reportArgs = {
21638
+ since: period,
21639
+ harness,
21640
+ format: format2 === "publish" ? "terminal" : format2,
21641
+ publish: format2 === "publish"
21642
+ };
21643
+ if (format2 === "md") {
21644
+ const filename = await consola.prompt("Save to file?", {
21645
+ type: "text",
21646
+ default: "ai-nativeness-report.md",
21647
+ placeholder: "report.md"
21648
+ });
21649
+ if (filename && typeof filename === "string") {
21650
+ reportArgs.output = filename;
21651
+ }
21510
21652
  }
21511
- await showLatestScan(client, clerkId, args.phase, args.format);
21653
+ await runHackathonReport(reportArgs);
21512
21654
  }
21513
21655
  });
21656
+ async function runLeadershipReportInteractive() {
21657
+ const period = await consola.prompt("Time period?", {
21658
+ type: "select",
21659
+ options: [
21660
+ { value: "7d", label: "Last 7 days" },
21661
+ { value: "30d", label: "Last 30 days" },
21662
+ { value: "48h", label: "Last 48 hours" }
21663
+ ]
21664
+ });
21665
+ const format2 = await consola.prompt("Output format?", {
21666
+ type: "select",
21667
+ options: [
21668
+ { value: "terminal", label: "Terminal (view now)" },
21669
+ { value: "md", label: "Markdown file" }
21670
+ ]
21671
+ });
21672
+ let output;
21673
+ if (format2 === "md") {
21674
+ const filename = await consola.prompt("Save to file?", {
21675
+ type: "text",
21676
+ default: "leadership-report.md"
21677
+ });
21678
+ if (filename && typeof filename === "string") {
21679
+ output = filename;
21680
+ }
21681
+ }
21682
+ await runLeadershipReport({
21683
+ since: period,
21684
+ format: format2,
21685
+ output
21686
+ });
21687
+ }
21688
+ async function runCloudReport() {
21689
+ const client = getClient();
21690
+ const clerkId = getClerkId();
21691
+ if (!client || !clerkId) {
21692
+ consola.error("Not connected to Convex. Run `nb init` to set up your profile.");
21693
+ consola.info("Try the AI-Nativeness Report instead - it works locally.");
21694
+ return;
21695
+ }
21696
+ const cloudOption = await consola.prompt("What would you like to see?", {
21697
+ type: "select",
21698
+ options: [
21699
+ { value: "latest", label: "Latest scan results" },
21700
+ { value: "history", label: "Score history (trend)" },
21701
+ { value: "weekly", label: "Weekly improvement report" }
21702
+ ]
21703
+ });
21704
+ if (cloudOption === "weekly") {
21705
+ await showWeeklyReport(client, clerkId, "text");
21706
+ return;
21707
+ }
21708
+ if (cloudOption === "history") {
21709
+ await showHistory(client, clerkId, 10, "text");
21710
+ return;
21711
+ }
21712
+ await showLatestScan(client, clerkId, undefined, "text");
21713
+ }
21514
21714
  async function runHackathonReport(args) {
21515
21715
  const projectDir = process.cwd();
21516
21716
  let harness = args.harness;
@@ -21724,6 +21924,41 @@ async function publishReport(report) {
21724
21924
  consola.info("Try `nb report --hackathon --format md` for local markdown instead.");
21725
21925
  }
21726
21926
  }
21927
+ async function runLeadershipReport(args) {
21928
+ const projectDir = process.cwd();
21929
+ const since = parseSince2(args.since || "7d");
21930
+ const periodLabel = args.since === "30d" ? "Last 30 days" : args.since === "48h" ? "Last 48 hours" : "Last 7 days";
21931
+ consola.start(`Generating leadership report (${periodLabel})...`);
21932
+ const agents = await collectAgentSessions(since);
21933
+ if (!agents || agents.sessions.length === 0) {
21934
+ consola.warn("No AI sessions found in the specified time range.");
21935
+ consola.info("Try running with --since 30d for a longer time range.");
21936
+ return;
21937
+ }
21938
+ const effort = analyzeEffort(agents.sessions);
21939
+ const report = generateLeadershipReport(effort, periodLabel);
21940
+ const format2 = args.format || "terminal";
21941
+ let output;
21942
+ if (format2 === "md" || format2 === "markdown") {
21943
+ output = formatLeadershipReportMarkdown(report);
21944
+ } else {
21945
+ output = formatLeadershipReport(report).join(`
21946
+ `);
21947
+ }
21948
+ if (args.output) {
21949
+ const filepath = resolve(projectDir, args.output);
21950
+ writeFileSync5(filepath, output);
21951
+ consola.success(`Report saved to ${filepath}`);
21952
+ }
21953
+ console.log(output);
21954
+ consola.log("");
21955
+ consola.info(`Sessions analyzed: ${report.aiAssistedTasksCount}`);
21956
+ consola.info(`True effort: ${report.trueEffortHours}h (${report.hiddenWorkPercent}% invisible)`);
21957
+ consola.info(`Burnout risk: ${report.burnoutRisk.toUpperCase()}`);
21958
+ if (format2 === "terminal" || !format2) {
21959
+ consola.info("Run `nb report --leadership --format md` for exportable markdown");
21960
+ }
21961
+ }
21727
21962
  function parseSince2(since) {
21728
21963
  const match = since.match(/^(\d+)(h|d|w|m)$/);
21729
21964
  if (match) {
@@ -22473,25 +22708,17 @@ function printVerificationResults(summary, verbose = false) {
22473
22708
  var doctorCommand = defineCommand2({
22474
22709
  meta: {
22475
22710
  name: "doctor",
22476
- description: "Check tool detection, data sources, and connectivity health"
22711
+ description: "Check system health and diagnose issues"
22477
22712
  },
22478
22713
  args: {
22479
22714
  "verify-recommendations": {
22480
22715
  type: "boolean",
22481
- description: "Verify all recommendations in the database are valid",
22482
- alias: "verify",
22716
+ description: "",
22483
22717
  default: false
22484
22718
  },
22485
22719
  thorough: {
22486
22720
  type: "boolean",
22487
- description: "Run thorough verification with network checks",
22488
- alias: "t",
22489
- default: false
22490
- },
22491
- verbose: {
22492
- type: "boolean",
22493
- description: "Show all results including valid recommendations",
22494
- alias: "v",
22721
+ description: "",
22495
22722
  default: false
22496
22723
  }
22497
22724
  },
@@ -22517,16 +22744,16 @@ var doctorCommand = defineCommand2({
22517
22744
  } else {
22518
22745
  spinner2.succeed("All recommendations verified");
22519
22746
  }
22520
- printVerificationResults(summary, args.verbose);
22747
+ printVerificationResults(summary, true);
22521
22748
  if (summary.invalid > 0) {
22522
22749
  process.exit(1);
22523
22750
  }
22524
22751
  return;
22525
22752
  }
22526
22753
  console.log();
22527
- console.log(colors2.bold(colors2.primary(" NaironAI Doctor")));
22528
- console.log(colors2.dim(` Checking system health...
22529
- `));
22754
+ console.log(" \uD83E\uDE7A " + "\x1B[1mNaironAI Doctor\x1B[0m");
22755
+ console.log(" " + "\x1B[2m" + "─".repeat(35) + "\x1B[0m");
22756
+ console.log();
22530
22757
  const spinner = createSpinner("Running diagnostics...");
22531
22758
  spinner.start();
22532
22759
  const results = [];
@@ -23160,6 +23387,28 @@ var BOLD = "\x1B[1m";
23160
23387
  var RESET = "\x1B[0m";
23161
23388
  var MAGENTA = "\x1B[35m";
23162
23389
  var CHANGELOG = [
23390
+ {
23391
+ version: "0.5.0",
23392
+ date: "2026-02-14",
23393
+ title: "Interactive-First CLI",
23394
+ highlights: [
23395
+ "No more flags to remember - commands guide you through options",
23396
+ "Just run nb scan or nb report and follow the prompts",
23397
+ "Public link is now the first option for report sharing",
23398
+ "CI/scripts still supported via --json flag"
23399
+ ]
23400
+ },
23401
+ {
23402
+ version: "0.4.0",
23403
+ date: "2026-02-13",
23404
+ title: "AI Work Visibility",
23405
+ highlights: [
23406
+ "New: Effort breakdown shows generation/review/correction/integration time",
23407
+ "New: nb report --leadership for executive-ready reports",
23408
+ "See hidden work (61% invisible!) that leadership may miss",
23409
+ "Burnout risk detection and true effort multiplier"
23410
+ ]
23411
+ },
23163
23412
  {
23164
23413
  version: "0.3.15",
23165
23414
  date: "2026-02-14",
@@ -23186,7 +23435,7 @@ var CHANGELOG = [
23186
23435
  title: "Reliable Recommendations",
23187
23436
  highlights: [
23188
23437
  "Fixed skills.sh format - skills now install correctly",
23189
- "New: nb doctor --verify-recommendations to validate install commands"
23438
+ "Improved recommendation validation before release"
23190
23439
  ]
23191
23440
  },
23192
23441
  {
@@ -23588,7 +23837,7 @@ function showFullChangelog() {
23588
23837
  // package.json
23589
23838
  var package_default = {
23590
23839
  name: "nairon-bench",
23591
- version: "0.3.15",
23840
+ version: "0.5.0",
23592
23841
  description: "AI workflow benchmarking CLI",
23593
23842
  type: "module",
23594
23843
  bin: {
@@ -26113,7 +26362,7 @@ function formatBytes(bytes) {
26113
26362
  // package.json
26114
26363
  var package_default2 = {
26115
26364
  name: "nairon-bench",
26116
- version: "0.3.15",
26365
+ version: "0.5.0",
26117
26366
  description: "AI workflow benchmarking CLI",
26118
26367
  type: "module",
26119
26368
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nairon-bench",
3
- "version": "0.3.15",
3
+ "version": "0.5.0",
4
4
  "description": "AI workflow benchmarking CLI",
5
5
  "type": "module",
6
6
  "bin": {