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.
- package/dist/index.js +647 -398
- 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: "
|
|
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
|
|
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: "
|
|
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 =
|
|
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
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
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
|
|
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
|
-
|
|
16014
|
-
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
|
|
16035
|
-
|
|
16036
|
-
|
|
16037
|
-
|
|
16038
|
-
|
|
16039
|
-
|
|
16040
|
-
|
|
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
|
-
|
|
16046
|
-
|
|
16047
|
-
|
|
16048
|
-
|
|
16049
|
-
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
|
|
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
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
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
|
-
|
|
16074
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
21574
|
+
description: "Generate AI-nativeness reports (interactive)"
|
|
21385
21575
|
},
|
|
21386
21576
|
args: {
|
|
21387
|
-
|
|
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: "
|
|
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.
|
|
21436
|
-
|
|
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
|
-
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
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 (
|
|
21504
|
-
await
|
|
21607
|
+
if (reportType === "cloud") {
|
|
21608
|
+
await runCloudReport();
|
|
21505
21609
|
return;
|
|
21506
21610
|
}
|
|
21507
|
-
|
|
21508
|
-
|
|
21509
|
-
|
|
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
|
|
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
|
|
22711
|
+
description: "Check system health and diagnose issues"
|
|
22477
22712
|
},
|
|
22478
22713
|
args: {
|
|
22479
22714
|
"verify-recommendations": {
|
|
22480
22715
|
type: "boolean",
|
|
22481
|
-
description: "
|
|
22482
|
-
alias: "verify",
|
|
22716
|
+
description: "",
|
|
22483
22717
|
default: false
|
|
22484
22718
|
},
|
|
22485
22719
|
thorough: {
|
|
22486
22720
|
type: "boolean",
|
|
22487
|
-
description: "
|
|
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,
|
|
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(
|
|
22528
|
-
console.log(
|
|
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
|
-
"
|
|
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.
|
|
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.
|
|
26365
|
+
version: "0.5.0",
|
|
26117
26366
|
description: "AI workflow benchmarking CLI",
|
|
26118
26367
|
type: "module",
|
|
26119
26368
|
bin: {
|