@aiready/cli 0.14.22 → 0.14.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  __require,
4
4
  analyzeUnified,
5
5
  scoreUnified
6
- } from "./chunk-JRRBBFYB.mjs";
6
+ } from "./chunk-HUSUJEQJ.mjs";
7
7
 
8
8
  // src/cli.ts
9
9
  import { Command } from "commander";
@@ -12,17 +12,14 @@ import { join as join2, dirname } from "path";
12
12
  import { fileURLToPath } from "url";
13
13
 
14
14
  // src/commands/scan.ts
15
- import chalk5 from "chalk";
16
- import { writeFileSync, readFileSync as readFileSync2 } from "fs";
17
- import { resolve as resolvePath3 } from "path";
15
+ import chalk6 from "chalk";
16
+ import { writeFileSync } from "fs";
17
+ import { resolve as resolvePath4 } from "path";
18
18
  import {
19
- loadMergedConfig,
20
- handleJSONOutput,
19
+ handleJSONOutput as handleJSONOutput2,
21
20
  handleCLIError as handleCLIError2,
22
21
  resolveOutputPath,
23
22
  getRepoMetadata,
24
- calculateTokenBudget,
25
- ToolName as ToolName2,
26
23
  emitIssuesAsAnnotations
27
24
  } from "@aiready/core";
28
25
 
@@ -31,12 +28,11 @@ import { resolve as resolvePath } from "path";
31
28
  import { existsSync, readFileSync } from "fs";
32
29
  import chalk from "chalk";
33
30
  import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";
34
- import { findLatestReport } from "@aiready/core";
35
- function getReportTimestamp() {
36
- const now = /* @__PURE__ */ new Date();
37
- const pad = (n) => String(n).padStart(2, "0");
38
- return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
39
- }
31
+ import {
32
+ findLatestReport,
33
+ getReportTimestamp,
34
+ handleJSONOutput
35
+ } from "@aiready/core";
40
36
  async function warnIfGraphCapExceeded(report, dirPath) {
41
37
  try {
42
38
  const { loadConfig: loadConfig4 } = await import("@aiready/core");
@@ -247,19 +243,22 @@ function printScoring(scoringResult, scoringProfile) {
247
243
  ` ${progressBar} ${tool.score}/100 (${rating}) ${emoji} ${tool.toolName}`
248
244
  );
249
245
  });
250
- const allRecs = scoringResult.breakdown.flatMap(
251
- (t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
252
- ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 5);
253
- if (allRecs.length > 0) {
254
- console.log(chalk2.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
255
- allRecs.forEach((rec, i) => {
256
- const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
257
- console.log(` ${i + 1}. ${priorityIcon} ${chalk2.bold(rec.action)}`);
258
- console.log(
259
- ` Impact: ${chalk2.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
260
- );
261
- });
262
- }
246
+ printTopRecommendations(scoringResult.breakdown);
247
+ }
248
+ }
249
+ function printTopRecommendations(breakdown) {
250
+ const allRecs = breakdown.flatMap(
251
+ (t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
252
+ ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 5);
253
+ if (allRecs.length > 0) {
254
+ console.log(chalk2.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
255
+ allRecs.forEach((rec, i) => {
256
+ const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
257
+ console.log(` ${i + 1}. ${priorityIcon} ${chalk2.bold(rec.action)}`);
258
+ console.log(
259
+ ` Impact: ${chalk2.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
260
+ );
261
+ });
263
262
  }
264
263
  }
265
264
  function mapToUnifiedReport(res, scoring) {
@@ -399,6 +398,9 @@ ENVIRONMENT VARIABLES:
399
398
  AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
400
399
  `;
401
400
 
401
+ // src/commands/scan-config.ts
402
+ import { loadMergedConfig, ToolName as ToolName2 } from "@aiready/core";
403
+
402
404
  // src/commands/scan-helpers.ts
403
405
  import chalk4 from "chalk";
404
406
  import { ToolName } from "@aiready/core";
@@ -470,180 +472,211 @@ function createProgressCallback() {
470
472
  };
471
473
  }
472
474
 
473
- // src/commands/scan.ts
474
- async function scanAction(directory, options) {
475
- console.log(chalk5.blue("\u{1F680} Starting AIReady unified analysis...\n"));
476
- const startTime = Date.now();
477
- const resolvedDir = resolvePath3(process.cwd(), directory ?? ".");
478
- const repoMetadata = getRepoMetadata(resolvedDir);
479
- try {
480
- const defaults = {
481
- tools: [
482
- "pattern-detect",
483
- "context-analyzer",
484
- "naming-consistency",
485
- "ai-signal-clarity",
486
- "agent-grounding",
487
- "testability-index",
488
- "doc-drift",
489
- "dependency-health",
490
- "change-amplification"
491
- ],
492
- include: void 0,
493
- exclude: void 0,
494
- output: {
495
- format: "console",
496
- file: void 0
497
- }
498
- };
499
- let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
500
- if (options.profile) {
501
- profileTools = getProfileTools(options.profile);
502
- }
503
- const cliOverrides = {
504
- include: options.include?.split(","),
505
- exclude: options.exclude?.split(",")
506
- };
507
- if (profileTools) cliOverrides.tools = profileTools;
508
- const baseOptions = await loadMergedConfig(
475
+ // src/commands/scan-config.ts
476
+ var SCAN_DEFAULTS = {
477
+ tools: [
478
+ "pattern-detect",
479
+ "context-analyzer",
480
+ "naming-consistency",
481
+ "ai-signal-clarity",
482
+ "agent-grounding",
483
+ "testability-index",
484
+ "doc-drift",
485
+ "dependency-health",
486
+ "change-amplification"
487
+ ],
488
+ include: void 0,
489
+ exclude: void 0,
490
+ output: {
491
+ format: "console",
492
+ file: void 0
493
+ }
494
+ };
495
+ async function resolveScanConfig(resolvedDir, options) {
496
+ let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
497
+ if (options.profile) {
498
+ profileTools = getProfileTools(options.profile);
499
+ }
500
+ const cliOverrides = {
501
+ include: options.include?.split(","),
502
+ exclude: options.exclude?.split(",")
503
+ };
504
+ if (profileTools) cliOverrides.tools = profileTools;
505
+ const baseOptions = await loadMergedConfig(
506
+ resolvedDir,
507
+ SCAN_DEFAULTS,
508
+ cliOverrides
509
+ );
510
+ const finalOptions = { ...baseOptions };
511
+ if (baseOptions.tools.includes(ToolName2.PatternDetect) || baseOptions.tools.includes("patterns")) {
512
+ const { getSmartDefaults } = await import("@aiready/pattern-detect");
513
+ const patternSmartDefaults = await getSmartDefaults(
509
514
  resolvedDir,
510
- defaults,
511
- cliOverrides
515
+ finalOptions.toolConfigs?.[ToolName2.PatternDetect] ?? {}
512
516
  );
513
- const finalOptions = { ...baseOptions };
514
- if (baseOptions.tools.includes(ToolName2.PatternDetect) || baseOptions.tools.includes("patterns")) {
515
- const { getSmartDefaults } = await import("@aiready/pattern-detect");
516
- const patternSmartDefaults = await getSmartDefaults(
517
- resolvedDir,
518
- finalOptions.toolConfigs?.[ToolName2.PatternDetect] ?? {}
519
- );
520
- if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
521
- finalOptions.toolConfigs[ToolName2.PatternDetect] = {
522
- ...patternSmartDefaults,
523
- ...finalOptions.toolConfigs[ToolName2.PatternDetect]
524
- };
525
- }
526
- console.log(chalk5.cyan("\n=== AIReady Run Preview ==="));
527
- console.log(
528
- chalk5.white("Tools to run:"),
529
- (finalOptions.tools ?? []).join(", ")
530
- );
531
- const progressCallback = createProgressCallback();
532
- const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
533
- const results = await analyzeUnified({
517
+ if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
518
+ finalOptions.toolConfigs[ToolName2.PatternDetect] = {
519
+ ...patternSmartDefaults,
520
+ ...finalOptions.toolConfigs[ToolName2.PatternDetect]
521
+ };
522
+ }
523
+ return finalOptions;
524
+ }
525
+
526
+ // src/commands/scan-orchestrator.ts
527
+ import chalk5 from "chalk";
528
+ import { readFileSync as readFileSync2 } from "fs";
529
+ import { resolve as resolvePath3 } from "path";
530
+ import { calculateTokenBudget } from "@aiready/core";
531
+ async function runUnifiedScan(resolvedDir, finalOptions, options, startTime) {
532
+ console.log(chalk5.cyan("\n=== AIReady Run Preview ==="));
533
+ console.log(
534
+ chalk5.white("Tools to run:"),
535
+ (finalOptions.tools ?? []).join(", ")
536
+ );
537
+ const progressCallback = createProgressCallback();
538
+ const scoringProfile = options.profile ?? finalOptions.scoring?.profile ?? "default";
539
+ const results = await analyzeUnified({
540
+ ...finalOptions,
541
+ progressCallback,
542
+ onProgress: () => {
543
+ },
544
+ suppressToolConfig: true
545
+ });
546
+ printScanSummary(results, startTime);
547
+ let scoringResult;
548
+ if (options.score || finalOptions.scoring?.showBreakdown) {
549
+ scoringResult = await scoreUnified(results, {
534
550
  ...finalOptions,
535
- progressCallback,
536
- onProgress: () => {
537
- },
538
- suppressToolConfig: true
551
+ scoring: {
552
+ ...finalOptions.scoring,
553
+ profile: scoringProfile
554
+ }
539
555
  });
540
- printScanSummary(results, startTime);
541
- let scoringResult;
542
- if (options.score || finalOptions.scoring?.showBreakdown) {
543
- scoringResult = await scoreUnified(results, {
544
- ...finalOptions,
545
- scoring: {
546
- ...finalOptions.scoring,
547
- profile: scoringProfile
548
- }
549
- });
550
- printScoring(scoringResult, scoringProfile);
551
- if (options.compareTo) {
552
- try {
553
- const prevReport = JSON.parse(
554
- readFileSync2(resolvePath3(process.cwd(), options.compareTo), "utf8")
555
- );
556
- const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
557
- if (typeof prevScore === "number") {
558
- const diff = scoringResult.overall - prevScore;
559
- const diffStr = diff > 0 ? `+${diff}` : String(diff);
560
- if (diff > 0)
561
- console.log(
562
- chalk5.green(
563
- ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
564
- )
565
- );
566
- else if (diff < 0)
567
- console.log(
568
- chalk5.red(
569
- ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
570
- )
571
- );
572
- else
573
- console.log(
574
- chalk5.blue(
575
- ` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
576
- )
577
- );
578
- }
579
- } catch (e) {
580
- void e;
581
- }
556
+ printScoring(scoringResult, scoringProfile);
557
+ if (options.compareTo) {
558
+ handleTrendComparison(options.compareTo, scoringResult);
559
+ }
560
+ await handleBusinessImpactMetrics(
561
+ results,
562
+ scoringResult,
563
+ options.model ?? "gpt-5.4-mini"
564
+ );
565
+ }
566
+ return { results, scoringResult };
567
+ }
568
+ function handleTrendComparison(baselinePath, currentScoring) {
569
+ try {
570
+ const prevReport = JSON.parse(
571
+ readFileSync2(resolvePath3(process.cwd(), baselinePath), "utf8")
572
+ );
573
+ const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
574
+ if (typeof prevScore === "number") {
575
+ const diff = currentScoring.overall - prevScore;
576
+ const diffStr = diff > 0 ? `+${diff}` : String(diff);
577
+ if (diff > 0)
578
+ console.log(
579
+ chalk5.green(
580
+ ` \u{1F4C8} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
581
+ )
582
+ );
583
+ else if (diff < 0)
584
+ console.log(
585
+ chalk5.red(
586
+ ` \u{1F4C9} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
587
+ )
588
+ );
589
+ else
590
+ console.log(
591
+ chalk5.blue(
592
+ ` \u2796 Trend: No change (${prevScore} \u2192 ${currentScoring.overall})`
593
+ )
594
+ );
595
+ }
596
+ } catch (e) {
597
+ void e;
598
+ }
599
+ }
600
+ async function handleBusinessImpactMetrics(results, scoringResult, modelId) {
601
+ const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
602
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
603
+ 0
604
+ );
605
+ const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
606
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
607
+ 0
608
+ );
609
+ const totalContext = Math.max(
610
+ ...(scoringResult.breakdown ?? []).map(
611
+ (s) => s.tokenBudget?.totalContextTokens ?? 0
612
+ ),
613
+ 0
614
+ );
615
+ if (totalContext > 0) {
616
+ const unifiedBudget = calculateTokenBudget({
617
+ totalContextTokens: totalContext,
618
+ wastedTokens: {
619
+ duplication: totalWastedDuplication,
620
+ fragmentation: totalWastedFragmentation,
621
+ chattiness: totalContext * 0.1
622
+ // Default chattiness
582
623
  }
583
- const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
584
- (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
585
- 0
586
- );
587
- const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
588
- (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
589
- 0
590
- );
591
- const totalContext = Math.max(
592
- ...(scoringResult.breakdown ?? []).map(
593
- (s) => s.tokenBudget?.totalContextTokens ?? 0
594
- ),
595
- 0
596
- );
597
- if (totalContext > 0) {
598
- const unifiedBudget = calculateTokenBudget({
599
- totalContextTokens: totalContext,
600
- wastedTokens: {
601
- duplication: totalWastedDuplication,
602
- fragmentation: totalWastedFragmentation,
603
- chattiness: totalContext * 0.1
604
- // Default chattiness
605
- }
606
- });
607
- const allIssues = [];
608
- for (const toolId of results.summary.toolsRun) {
609
- if (results[toolId]?.results) {
610
- results[toolId].results.forEach((fileRes) => {
611
- if (fileRes.issues) {
612
- allIssues.push(...fileRes.issues);
613
- }
614
- });
624
+ });
625
+ const allIssues = [];
626
+ for (const toolId of results.summary.toolsRun) {
627
+ if (results[toolId]?.results) {
628
+ results[toolId].results.forEach((fileRes) => {
629
+ if (fileRes.issues) {
630
+ allIssues.push(...fileRes.issues);
615
631
  }
616
- }
617
- const modelId = options.model ?? "gpt-5.4-mini";
618
- const roi = (await import("@aiready/core")).calculateBusinessROI({
619
- tokenWaste: unifiedBudget.wastedTokens.total,
620
- issues: allIssues,
621
- modelId
622
632
  });
623
- printBusinessImpact(roi, unifiedBudget);
624
- results.summary.businessImpact = {
625
- estimatedMonthlyWaste: roi.monthlySavings,
626
- potentialSavings: roi.monthlySavings,
627
- productivityHours: roi.productivityGainHours
628
- };
629
- scoringResult.tokenBudget = unifiedBudget;
630
- scoringResult.businessROI = roi;
631
633
  }
632
634
  }
635
+ const { calculateBusinessROI } = await import("@aiready/core");
636
+ const roi = calculateBusinessROI({
637
+ tokenWaste: unifiedBudget.wastedTokens.total,
638
+ issues: allIssues,
639
+ modelId
640
+ });
641
+ printBusinessImpact(roi, unifiedBudget);
642
+ results.summary.businessImpact = {
643
+ estimatedMonthlyWaste: roi.monthlySavings,
644
+ potentialSavings: roi.monthlySavings,
645
+ productivityHours: roi.productivityGainHours
646
+ };
647
+ scoringResult.tokenBudget = unifiedBudget;
648
+ scoringResult.businessROI = roi;
649
+ }
650
+ }
651
+
652
+ // src/commands/scan.ts
653
+ async function scanAction(directory, options) {
654
+ console.log(chalk6.blue("\u{1F680} Starting AIReady unified analysis...\n"));
655
+ const startTime = Date.now();
656
+ const resolvedDir = resolvePath4(process.cwd(), directory ?? ".");
657
+ const repoMetadata = getRepoMetadata(resolvedDir);
658
+ try {
659
+ const finalOptions = await resolveScanConfig(resolvedDir, options);
660
+ const { results, scoringResult } = await runUnifiedScan(
661
+ resolvedDir,
662
+ finalOptions,
663
+ options,
664
+ startTime
665
+ );
633
666
  console.log(
634
- chalk5.dim(
667
+ chalk6.dim(
635
668
  "\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
636
669
  )
637
670
  );
638
- console.log(chalk5.dim("\u{1F4AC} Found a bug or have a metric idea?"));
639
- console.log(chalk5.dim("\u{1F449} Copy/paste this to your AI agent:"));
671
+ console.log(chalk6.dim("\u{1F4AC} Found a bug or have a metric idea?"));
672
+ console.log(chalk6.dim("\u{1F449} Copy/paste this to your AI agent:"));
640
673
  console.log(
641
- chalk5.cyan(
674
+ chalk6.cyan(
642
675
  ` "Any feedback for the tools? Please use 'aiready bug' to report \u2764\uFE0F"`
643
676
  )
644
677
  );
645
678
  console.log(
646
- chalk5.dim(
679
+ chalk6.dim(
647
680
  "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
648
681
  )
649
682
  );
@@ -658,7 +691,7 @@ async function scanAction(directory, options) {
658
691
  resolvedDir
659
692
  );
660
693
  if (outputFormat === "json") {
661
- handleJSONOutput(
694
+ handleJSONOutput2(
662
695
  outputData,
663
696
  outputPath,
664
697
  `\u2705 Report saved to ${outputPath}`
@@ -666,7 +699,7 @@ async function scanAction(directory, options) {
666
699
  } else {
667
700
  try {
668
701
  writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
669
- console.log(chalk5.dim(`\u2705 Report auto-persisted to ${outputPath}`));
702
+ console.log(chalk6.dim(`\u2705 Report auto-persisted to ${outputPath}`));
670
703
  } catch (err) {
671
704
  void err;
672
705
  }
@@ -678,53 +711,75 @@ async function scanAction(directory, options) {
678
711
  });
679
712
  }
680
713
  await warnIfGraphCapExceeded(outputData, resolvedDir);
681
- if (scoringResult) {
682
- const threshold = options.threshold ? parseInt(options.threshold) : void 0;
683
- const failOnLevel = options.failOn ?? "critical";
684
- const isCI = options.ci ?? process.env.CI === "true";
685
- let shouldFail = false;
686
- let failReason = "";
687
- const report = mapToUnifiedReport(results, scoringResult);
688
- if (isCI && report.results && report.results.length > 0) {
689
- console.log(
690
- chalk5.cyan(
691
- `
692
- \u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
693
- )
694
- );
695
- emitIssuesAsAnnotations(report.results);
696
- }
697
- if (threshold && scoringResult.overall < threshold) {
698
- shouldFail = true;
699
- failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
700
- }
701
- if (failOnLevel !== "none") {
702
- if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
703
- shouldFail = true;
704
- failReason = `Found ${report.summary.criticalIssues} critical issues`;
705
- } else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
706
- shouldFail = true;
707
- failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
708
- }
709
- }
710
- if (shouldFail) {
711
- console.log(chalk5.red(`
712
- \u{1F6AB} SCAN FAILED: ${failReason}`));
713
- process.exit(1);
714
- } else {
715
- console.log(chalk5.green("\n\u2705 SCAN PASSED"));
716
- }
717
- }
714
+ await handleGatekeeper(outputData, scoringResult, options, results);
718
715
  } catch (error) {
719
716
  handleCLIError2(error, "Analysis");
720
717
  }
721
718
  }
722
- var SCAN_HELP_TEXT = `...`;
719
+ async function handleGatekeeper(outputData, scoringResult, options, results) {
720
+ if (!scoringResult) return;
721
+ const threshold = options.threshold ? parseInt(options.threshold) : void 0;
722
+ const failOnLevel = options.failOn ?? "critical";
723
+ const isCI = options.ci ?? process.env.CI === "true";
724
+ let shouldFail = false;
725
+ let failReason = "";
726
+ const report = mapToUnifiedReport(results, scoringResult);
727
+ if (isCI && report.results && report.results.length > 0) {
728
+ console.log(
729
+ chalk6.cyan(
730
+ `
731
+ \u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
732
+ )
733
+ );
734
+ emitIssuesAsAnnotations(report.results);
735
+ }
736
+ if (threshold && scoringResult.overall < threshold) {
737
+ shouldFail = true;
738
+ failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
739
+ }
740
+ if (failOnLevel !== "none") {
741
+ if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
742
+ shouldFail = true;
743
+ failReason = `Found ${report.summary.criticalIssues} critical issues`;
744
+ } else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
745
+ shouldFail = true;
746
+ failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
747
+ }
748
+ }
749
+ if (shouldFail) {
750
+ console.log(chalk6.red(`
751
+ \u{1F6AB} SCAN FAILED: ${failReason}`));
752
+ process.exit(1);
753
+ } else {
754
+ console.log(chalk6.green("\n\u2705 SCAN PASSED"));
755
+ }
756
+ }
757
+ var SCAN_HELP_TEXT = `
758
+ Run a comprehensive AI-readiness scan of your codebase.
759
+
760
+ ${chalk6.bold("Examples:")}
761
+ $ aiready scan .
762
+ $ aiready scan src --profile agentic
763
+ $ aiready scan . --threshold 80 --fail-on critical
764
+ $ aiready scan . --output json --output-file report.json
765
+
766
+ ${chalk6.bold("Profiles:")}
767
+ agentic - Focus on AI signal clarity and agent grounding
768
+ cost - Focus on token budget and pattern reuse
769
+ logic - Focus on testability and naming consistency
770
+ ui - Focus on component naming and documentation
771
+ security - Focus on naming and testability
772
+ onboarding - Focus on context and grounding
773
+
774
+ ${chalk6.bold("CI/CD Integration:")}
775
+ Use --threshold and --fail-on to use AIReady as a quality gate in your CI pipelines.
776
+ When running in GitHub Actions, it will automatically emit annotations for found issues.
777
+ `;
723
778
 
724
779
  // src/commands/init.ts
725
780
  import { writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
726
781
  import { join } from "path";
727
- import chalk6 from "chalk";
782
+ import chalk7 from "chalk";
728
783
  import { ToolName as ToolName3 } from "@aiready/core";
729
784
  async function initAction(options) {
730
785
  const fileExt = options.format === "js" ? "js" : "json";
@@ -732,7 +787,7 @@ async function initAction(options) {
732
787
  const filePath = join(process.cwd(), fileName);
733
788
  if (existsSync2(filePath) && !options.force) {
734
789
  console.error(
735
- chalk6.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
790
+ chalk7.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
736
791
  );
737
792
  process.exit(1);
738
793
  }
@@ -954,35 +1009,36 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
954
1009
  try {
955
1010
  writeFileSync2(filePath, content, "utf8");
956
1011
  console.log(
957
- chalk6.green(`
958
- \u2705 Created default configuration: ${chalk6.bold(fileName)}`)
1012
+ chalk7.green(`
1013
+ \u2705 Created default configuration: ${chalk7.bold(fileName)}`)
959
1014
  );
960
1015
  console.log(
961
- chalk6.cyan("You can now fine-tune your settings and run AIReady with:")
1016
+ chalk7.cyan("You can now fine-tune your settings and run AIReady with:")
962
1017
  );
963
- console.log(chalk6.white(` $ aiready scan
1018
+ console.log(chalk7.white(` $ aiready scan
964
1019
  `));
965
1020
  } catch (error) {
966
- console.error(chalk6.red(`Failed to write configuration file: ${error}`));
1021
+ console.error(chalk7.red(`Failed to write configuration file: ${error}`));
967
1022
  process.exit(1);
968
1023
  }
969
1024
  }
970
1025
 
971
1026
  // src/commands/patterns.ts
972
- import chalk7 from "chalk";
973
- import { resolve as resolvePath4 } from "path";
1027
+ import chalk8 from "chalk";
974
1028
  import {
975
- loadMergedConfig as loadMergedConfig2,
976
- handleJSONOutput as handleJSONOutput2,
977
1029
  handleCLIError as handleCLIError3,
978
1030
  getElapsedTime,
979
- resolveOutputPath as resolveOutputPath2,
980
- formatToolScore
1031
+ formatToolScore,
1032
+ printTerminalHeader,
1033
+ getTerminalDivider,
1034
+ prepareActionConfig,
1035
+ resolveOutputFormat,
1036
+ formatStandardReport,
1037
+ handleStandardJSONOutput
981
1038
  } from "@aiready/core";
982
1039
  async function patternsAction(directory, options) {
983
- console.log(chalk7.blue("\u{1F50D} Analyzing patterns...\n"));
1040
+ console.log(chalk8.blue("\u{1F50D} Analyzing patterns...\n"));
984
1041
  const startTime = Date.now();
985
- const resolvedDir = resolvePath4(process.cwd(), directory ?? ".");
986
1042
  try {
987
1043
  const useSmartDefaults = !options.fullScan;
988
1044
  const defaults = {
@@ -1011,8 +1067,8 @@ async function patternsAction(directory, options) {
1011
1067
  if (options.minSharedTokens) {
1012
1068
  cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
1013
1069
  }
1014
- const finalOptions = await loadMergedConfig2(
1015
- resolvedDir,
1070
+ const { resolvedDir, finalOptions } = await prepareActionConfig(
1071
+ directory,
1016
1072
  defaults,
1017
1073
  cliOptions
1018
1074
  );
@@ -1026,60 +1082,53 @@ async function patternsAction(directory, options) {
1026
1082
  if (options.score) {
1027
1083
  patternScore = calculatePatternScore(duplicates, results.length);
1028
1084
  }
1029
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1030
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1085
+ const { format: outputFormat, file: userOutputFile } = resolveOutputFormat(
1086
+ options,
1087
+ finalOptions
1088
+ );
1031
1089
  if (outputFormat === "json") {
1032
- const outputData = {
1090
+ const outputData = formatStandardReport({
1033
1091
  results,
1034
- summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1035
- ...patternScore && { scoring: patternScore }
1036
- };
1037
- const outputPath = resolveOutputPath2(
1038
- userOutputFile,
1039
- `aiready-report-${getReportTimestamp()}.json`,
1040
- resolvedDir
1041
- );
1042
- handleJSONOutput2(
1092
+ summary,
1093
+ elapsedTime,
1094
+ score: patternScore
1095
+ });
1096
+ handleStandardJSONOutput({
1043
1097
  outputData,
1044
- outputPath,
1045
- `\u2705 Results saved to ${outputPath}`
1046
- );
1098
+ outputFile: userOutputFile,
1099
+ resolvedDir
1100
+ });
1047
1101
  } else {
1048
- const terminalWidth = process.stdout.columns || 80;
1049
- const dividerWidth = Math.min(60, terminalWidth - 2);
1050
- const divider = "\u2501".repeat(dividerWidth);
1051
- console.log(chalk7.cyan(divider));
1052
- console.log(chalk7.bold.white(" PATTERN ANALYSIS SUMMARY"));
1053
- console.log(chalk7.cyan(divider) + "\n");
1102
+ printTerminalHeader("PATTERN ANALYSIS SUMMARY");
1054
1103
  console.log(
1055
- chalk7.white(`\u{1F4C1} Files analyzed: ${chalk7.bold(results.length)}`)
1104
+ chalk8.white(`\u{1F4C1} Files analyzed: ${chalk8.bold(results.length)}`)
1056
1105
  );
1057
1106
  console.log(
1058
- chalk7.yellow(
1059
- `\u26A0 Duplicate patterns found: ${chalk7.bold(summary.totalPatterns)}`
1107
+ chalk8.yellow(
1108
+ `\u26A0 Duplicate patterns found: ${chalk8.bold(summary.totalPatterns)}`
1060
1109
  )
1061
1110
  );
1062
1111
  console.log(
1063
- chalk7.red(
1064
- `\u{1F4B0} Token cost (wasted): ${chalk7.bold(summary.totalTokenCost.toLocaleString())}`
1112
+ chalk8.red(
1113
+ `\u{1F4B0} Token cost (wasted): ${chalk8.bold(summary.totalTokenCost.toLocaleString())}`
1065
1114
  )
1066
1115
  );
1067
1116
  console.log(
1068
- chalk7.gray(`\u23F1 Analysis time: ${chalk7.bold(elapsedTime + "s")}`)
1117
+ chalk8.gray(`\u23F1 Analysis time: ${chalk8.bold(elapsedTime + "s")}`)
1069
1118
  );
1070
1119
  const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
1071
1120
  if (sortedTypes.length > 0) {
1072
- console.log(chalk7.cyan("\n" + divider));
1073
- console.log(chalk7.bold.white(" PATTERNS BY TYPE"));
1074
- console.log(chalk7.cyan(divider) + "\n");
1121
+ console.log("\n" + getTerminalDivider());
1122
+ console.log(chalk8.bold.white(" PATTERNS BY TYPE"));
1123
+ console.log(getTerminalDivider() + "\n");
1075
1124
  sortedTypes.forEach(([type, count]) => {
1076
- console.log(` ${chalk7.white(type.padEnd(15))} ${chalk7.bold(count)}`);
1125
+ console.log(` ${chalk8.white(type.padEnd(15))} ${chalk8.bold(count)}`);
1077
1126
  });
1078
1127
  }
1079
1128
  if (summary.totalPatterns > 0 && duplicates.length > 0) {
1080
- console.log(chalk7.cyan("\n" + divider));
1081
- console.log(chalk7.bold.white(" TOP DUPLICATE PATTERNS"));
1082
- console.log(chalk7.cyan(divider) + "\n");
1129
+ console.log("\n" + getTerminalDivider());
1130
+ console.log(chalk8.bold.white(" TOP DUPLICATE PATTERNS"));
1131
+ console.log(getTerminalDivider() + "\n");
1083
1132
  const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
1084
1133
  topDuplicates.forEach((dup) => {
1085
1134
  const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
@@ -1087,25 +1136,25 @@ async function patternsAction(directory, options) {
1087
1136
  const file1Name = dup.file1.split("/").pop() || dup.file1;
1088
1137
  const file2Name = dup.file2.split("/").pop() || dup.file2;
1089
1138
  console.log(
1090
- `${severityIcon} ${severity}: ${chalk7.bold(file1Name)} \u2194 ${chalk7.bold(file2Name)}`
1139
+ `${severityIcon} ${severity}: ${chalk8.bold(file1Name)} \u2194 ${chalk8.bold(file2Name)}`
1091
1140
  );
1092
1141
  console.log(
1093
- ` Similarity: ${chalk7.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk7.bold(dup.tokenCost.toLocaleString())} tokens each`
1142
+ ` Similarity: ${chalk8.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk8.bold(dup.tokenCost.toLocaleString())} tokens each`
1094
1143
  );
1095
1144
  console.log(
1096
- ` Lines: ${chalk7.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk7.cyan(dup.line2 + "-" + dup.endLine2)}
1145
+ ` Lines: ${chalk8.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk8.cyan(dup.line2 + "-" + dup.endLine2)}
1097
1146
  `
1098
1147
  );
1099
1148
  });
1100
1149
  } else {
1101
1150
  console.log(
1102
- chalk7.green("\n\u2728 Great! No duplicate patterns detected.\n")
1151
+ chalk8.green("\n\u2728 Great! No duplicate patterns detected.\n")
1103
1152
  );
1104
1153
  }
1105
1154
  if (patternScore) {
1106
- console.log(chalk7.cyan(divider));
1107
- console.log(chalk7.bold.white(" AI READINESS SCORE (Patterns)"));
1108
- console.log(chalk7.cyan(divider) + "\n");
1155
+ console.log(getTerminalDivider());
1156
+ console.log(chalk8.bold.white(" AI READINESS SCORE (Patterns)"));
1157
+ console.log(getTerminalDivider() + "\n");
1109
1158
  console.log(formatToolScore(patternScore));
1110
1159
  console.log();
1111
1160
  }
@@ -1122,20 +1171,19 @@ EXAMPLES:
1122
1171
  `;
1123
1172
 
1124
1173
  // src/commands/context.ts
1125
- import chalk8 from "chalk";
1126
- import { resolve as resolvePath5 } from "path";
1174
+ import chalk9 from "chalk";
1127
1175
  import {
1128
- loadMergedConfig as loadMergedConfig3,
1129
- handleJSONOutput as handleJSONOutput3,
1130
1176
  handleCLIError as handleCLIError4,
1131
1177
  getElapsedTime as getElapsedTime2,
1132
- resolveOutputPath as resolveOutputPath3,
1133
- formatToolScore as formatToolScore2
1178
+ formatToolScore as formatToolScore2,
1179
+ prepareActionConfig as prepareActionConfig2,
1180
+ resolveOutputFormat as resolveOutputFormat2,
1181
+ formatStandardReport as formatStandardReport2,
1182
+ handleStandardJSONOutput as handleStandardJSONOutput2
1134
1183
  } from "@aiready/core";
1135
1184
  async function contextAction(directory, options) {
1136
- console.log(chalk8.blue("\u{1F9E0} Analyzing context costs...\n"));
1185
+ console.log(chalk9.blue("\u{1F9E0} Analyzing context costs...\n"));
1137
1186
  const startTime = Date.now();
1138
- const resolvedDir = resolvePath5(process.cwd(), directory ?? ".");
1139
1187
  try {
1140
1188
  const defaults = {
1141
1189
  maxDepth: 5,
@@ -1147,7 +1195,7 @@ async function contextAction(directory, options) {
1147
1195
  file: void 0
1148
1196
  }
1149
1197
  };
1150
- const baseOptions = await loadMergedConfig3(resolvedDir, defaults, {
1198
+ const { resolvedDir, finalOptions: baseOptions } = await prepareActionConfig2(directory, defaults, {
1151
1199
  maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
1152
1200
  maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
1153
1201
  include: options.include?.split(","),
@@ -1179,107 +1227,105 @@ async function contextAction(directory, options) {
1179
1227
  if (options.score) {
1180
1228
  contextScore = calculateContextScore(summary);
1181
1229
  }
1182
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1183
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1230
+ const { format: outputFormat, file: userOutputFile } = resolveOutputFormat2(
1231
+ options,
1232
+ finalOptions
1233
+ );
1184
1234
  if (outputFormat === "json") {
1185
- const outputData = {
1235
+ const outputData = formatStandardReport2({
1186
1236
  results,
1187
- summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1188
- ...contextScore && { scoring: contextScore }
1189
- };
1190
- const outputPath = resolveOutputPath3(
1191
- userOutputFile,
1192
- `aiready-report-${getReportTimestamp()}.json`,
1193
- resolvedDir
1194
- );
1195
- handleJSONOutput3(
1237
+ summary,
1238
+ elapsedTime,
1239
+ score: contextScore
1240
+ });
1241
+ handleStandardJSONOutput2({
1196
1242
  outputData,
1197
- outputPath,
1198
- `\u2705 Results saved to ${outputPath}`
1199
- );
1243
+ outputFile: userOutputFile,
1244
+ resolvedDir
1245
+ });
1200
1246
  } else {
1201
1247
  const terminalWidth = process.stdout.columns ?? 80;
1202
1248
  const dividerWidth = Math.min(60, terminalWidth - 2);
1203
1249
  const divider = "\u2501".repeat(dividerWidth);
1204
- console.log(chalk8.cyan(divider));
1205
- console.log(chalk8.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1206
- console.log(chalk8.cyan(divider) + "\n");
1250
+ console.log(chalk9.cyan(divider));
1251
+ console.log(chalk9.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1252
+ console.log(chalk9.cyan(divider) + "\n");
1207
1253
  console.log(
1208
- chalk8.white(`\u{1F4C1} Files analyzed: ${chalk8.bold(summary.totalFiles)}`)
1254
+ chalk9.white(`\u{1F4C1} Files analyzed: ${chalk9.bold(summary.totalFiles)}`)
1209
1255
  );
1210
1256
  console.log(
1211
- chalk8.white(
1212
- `\u{1F4CA} Total tokens: ${chalk8.bold(summary.totalTokens.toLocaleString())}`
1257
+ chalk9.white(
1258
+ `\u{1F4CA} Total tokens: ${chalk9.bold(summary.totalTokens.toLocaleString())}`
1213
1259
  )
1214
1260
  );
1215
1261
  console.log(
1216
- chalk8.yellow(
1217
- `\u{1F4B0} Avg context budget: ${chalk8.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1262
+ chalk9.yellow(
1263
+ `\u{1F4B0} Avg context budget: ${chalk9.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1218
1264
  )
1219
1265
  );
1220
1266
  console.log(
1221
- chalk8.white(`\u23F1 Analysis time: ${chalk8.bold(elapsedTime + "s")}
1267
+ chalk9.white(`\u23F1 Analysis time: ${chalk9.bold(elapsedTime + "s")}
1222
1268
  `)
1223
1269
  );
1224
1270
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
1225
1271
  if (totalIssues > 0) {
1226
- console.log(chalk8.bold("\u26A0\uFE0F Issues Found:\n"));
1272
+ console.log(chalk9.bold("\u26A0\uFE0F Issues Found:\n"));
1227
1273
  if (summary.criticalIssues > 0) {
1228
1274
  console.log(
1229
- chalk8.red(` \u{1F534} Critical: ${chalk8.bold(summary.criticalIssues)}`)
1275
+ chalk9.red(` \u{1F534} Critical: ${chalk9.bold(summary.criticalIssues)}`)
1230
1276
  );
1231
1277
  }
1232
1278
  if (summary.majorIssues > 0) {
1233
1279
  console.log(
1234
- chalk8.yellow(` \u{1F7E1} Major: ${chalk8.bold(summary.majorIssues)}`)
1280
+ chalk9.yellow(` \u{1F7E1} Major: ${chalk9.bold(summary.majorIssues)}`)
1235
1281
  );
1236
1282
  }
1237
1283
  if (summary.minorIssues > 0) {
1238
1284
  console.log(
1239
- chalk8.blue(` \u{1F535} Minor: ${chalk8.bold(summary.minorIssues)}`)
1285
+ chalk9.blue(` \u{1F535} Minor: ${chalk9.bold(summary.minorIssues)}`)
1240
1286
  );
1241
1287
  }
1242
1288
  console.log(
1243
- chalk8.green(
1289
+ chalk9.green(
1244
1290
  `
1245
- \u{1F4A1} Potential savings: ${chalk8.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1291
+ \u{1F4A1} Potential savings: ${chalk9.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1246
1292
  `
1247
1293
  )
1248
1294
  );
1249
1295
  } else {
1250
- console.log(chalk8.green("\u2705 No significant issues found!\n"));
1296
+ console.log(chalk9.green("\u2705 No significant issues found!\n"));
1251
1297
  }
1252
1298
  if (summary.deepFiles.length > 0) {
1253
- console.log(chalk8.bold("\u{1F4CF} Deep Import Chains:\n"));
1299
+ console.log(chalk9.bold("\u{1F4CF} Deep Import Chains:\n"));
1254
1300
  console.log(
1255
- chalk8.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1301
+ chalk9.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1256
1302
  );
1257
1303
  console.log(
1258
- chalk8.gray(` Maximum depth: ${summary.maxImportDepth}
1304
+ chalk9.gray(` Maximum depth: ${summary.maxImportDepth}
1259
1305
  `)
1260
1306
  );
1261
1307
  summary.deepFiles.slice(0, 10).forEach((item) => {
1262
1308
  const fileName = item.file.split("/").slice(-2).join("/");
1263
1309
  console.log(
1264
- ` ${chalk8.cyan("\u2192")} ${chalk8.white(fileName)} ${chalk8.dim(`(depth: ${item.depth})`)}`
1310
+ ` ${chalk9.cyan("\u2192")} ${chalk9.white(fileName)} ${chalk9.dim(`(depth: ${item.depth})`)}`
1265
1311
  );
1266
1312
  });
1267
1313
  console.log();
1268
1314
  }
1269
1315
  if (summary.fragmentedModules.length > 0) {
1270
- console.log(chalk8.bold("\u{1F9E9} Fragmented Modules:\n"));
1316
+ console.log(chalk9.bold("\u{1F9E9} Fragmented Modules:\n"));
1271
1317
  console.log(
1272
- chalk8.gray(
1318
+ chalk9.gray(
1273
1319
  ` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
1274
1320
  `
1275
1321
  )
1276
1322
  );
1277
1323
  summary.fragmentedModules.slice(0, 10).forEach((module) => {
1278
1324
  console.log(
1279
- ` ${chalk8.yellow("\u25CF")} ${chalk8.white(module.domain)} - ${chalk8.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1325
+ ` ${chalk9.yellow("\u25CF")} ${chalk9.white(module.domain)} - ${chalk9.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1280
1326
  );
1281
1327
  console.log(
1282
- chalk8.dim(
1328
+ chalk9.dim(
1283
1329
  ` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
1284
1330
  )
1285
1331
  );
@@ -1287,9 +1333,9 @@ async function contextAction(directory, options) {
1287
1333
  console.log();
1288
1334
  }
1289
1335
  if (summary.lowCohesionFiles.length > 0) {
1290
- console.log(chalk8.bold("\u{1F500} Low Cohesion Files:\n"));
1336
+ console.log(chalk9.bold("\u{1F500} Low Cohesion Files:\n"));
1291
1337
  console.log(
1292
- chalk8.gray(
1338
+ chalk9.gray(
1293
1339
  ` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
1294
1340
  `
1295
1341
  )
@@ -1297,28 +1343,28 @@ async function contextAction(directory, options) {
1297
1343
  summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
1298
1344
  const fileName = item.file.split("/").slice(-2).join("/");
1299
1345
  const scorePercent = (item.score * 100).toFixed(0);
1300
- const color = item.score < 0.4 ? chalk8.red : chalk8.yellow;
1346
+ const color = item.score < 0.4 ? chalk9.red : chalk9.yellow;
1301
1347
  console.log(
1302
- ` ${color("\u25CB")} ${chalk8.white(fileName)} ${chalk8.dim(`(${scorePercent}% cohesion)`)}`
1348
+ ` ${color("\u25CB")} ${chalk9.white(fileName)} ${chalk9.dim(`(${scorePercent}% cohesion)`)}`
1303
1349
  );
1304
1350
  });
1305
1351
  console.log();
1306
1352
  }
1307
1353
  if (summary.topExpensiveFiles.length > 0) {
1308
- console.log(chalk8.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1354
+ console.log(chalk9.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1309
1355
  summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
1310
1356
  const fileName = item.file.split("/").slice(-2).join("/");
1311
- const severityColor = item.severity === "critical" ? chalk8.red : item.severity === "major" ? chalk8.yellow : chalk8.blue;
1357
+ const severityColor = item.severity === "critical" ? chalk9.red : item.severity === "major" ? chalk9.yellow : chalk9.blue;
1312
1358
  console.log(
1313
- ` ${severityColor("\u25CF")} ${chalk8.white(fileName)} ${chalk8.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1359
+ ` ${severityColor("\u25CF")} ${chalk9.white(fileName)} ${chalk9.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1314
1360
  );
1315
1361
  });
1316
1362
  console.log();
1317
1363
  }
1318
1364
  if (contextScore) {
1319
- console.log(chalk8.cyan(divider));
1320
- console.log(chalk8.bold.white(" AI READINESS SCORE (Context)"));
1321
- console.log(chalk8.cyan(divider) + "\n");
1365
+ console.log(chalk9.cyan(divider));
1366
+ console.log(chalk9.bold.white(" AI READINESS SCORE (Context)"));
1367
+ console.log(chalk9.cyan(divider) + "\n");
1322
1368
  console.log(formatToolScore2(contextScore));
1323
1369
  console.log();
1324
1370
  }
@@ -1329,21 +1375,21 @@ async function contextAction(directory, options) {
1329
1375
  }
1330
1376
 
1331
1377
  // src/commands/consistency.ts
1332
- import chalk9 from "chalk";
1378
+ import chalk10 from "chalk";
1333
1379
  import { writeFileSync as writeFileSync3 } from "fs";
1334
- import { resolve as resolvePath6 } from "path";
1335
1380
  import {
1336
- loadMergedConfig as loadMergedConfig4,
1337
- handleJSONOutput as handleJSONOutput4,
1338
1381
  handleCLIError as handleCLIError5,
1339
1382
  getElapsedTime as getElapsedTime3,
1340
- resolveOutputPath as resolveOutputPath4,
1341
- formatToolScore as formatToolScore3
1383
+ resolveOutputPath as resolveOutputPath2,
1384
+ formatToolScore as formatToolScore3,
1385
+ prepareActionConfig as prepareActionConfig3,
1386
+ resolveOutputFormat as resolveOutputFormat3,
1387
+ formatStandardReport as formatStandardReport3,
1388
+ handleStandardJSONOutput as handleStandardJSONOutput3
1342
1389
  } from "@aiready/core";
1343
1390
  async function consistencyAction(directory, options) {
1344
- console.log(chalk9.blue("\u{1F50D} Analyzing consistency...\n"));
1391
+ console.log(chalk10.blue("\u{1F50D} Analyzing consistency...\n"));
1345
1392
  const startTime = Date.now();
1346
- const resolvedDir = resolvePath6(process.cwd(), directory ?? ".");
1347
1393
  try {
1348
1394
  const defaults = {
1349
1395
  checkNaming: true,
@@ -1356,13 +1402,17 @@ async function consistencyAction(directory, options) {
1356
1402
  file: void 0
1357
1403
  }
1358
1404
  };
1359
- const finalOptions = await loadMergedConfig4(resolvedDir, defaults, {
1360
- checkNaming: options.naming !== false,
1361
- checkPatterns: options.patterns !== false,
1362
- minSeverity: options.minSeverity,
1363
- include: options.include?.split(","),
1364
- exclude: options.exclude?.split(",")
1365
- });
1405
+ const { resolvedDir, finalOptions } = await prepareActionConfig3(
1406
+ directory,
1407
+ defaults,
1408
+ {
1409
+ checkNaming: options.naming !== false,
1410
+ checkPatterns: options.patterns !== false,
1411
+ minSeverity: options.minSeverity,
1412
+ include: options.include?.split(","),
1413
+ exclude: options.exclude?.split(",")
1414
+ }
1415
+ );
1366
1416
  const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
1367
1417
  const report = await analyzeConsistency(finalOptions);
1368
1418
  const elapsedTime = getElapsedTime3(startTime);
@@ -1374,52 +1424,47 @@ async function consistencyAction(directory, options) {
1374
1424
  report.summary.filesAnalyzed
1375
1425
  );
1376
1426
  }
1377
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1378
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1427
+ const { format: outputFormat, file: userOutputFile } = resolveOutputFormat3(
1428
+ options,
1429
+ finalOptions
1430
+ );
1379
1431
  if (outputFormat === "json") {
1380
- const outputData = {
1381
- ...report,
1382
- summary: {
1383
- ...report.summary,
1384
- executionTime: parseFloat(elapsedTime)
1385
- },
1386
- ...consistencyScore && { scoring: consistencyScore }
1387
- };
1388
- const outputPath = resolveOutputPath4(
1389
- userOutputFile,
1390
- `aiready-report-${getReportTimestamp()}.json`,
1391
- resolvedDir
1392
- );
1393
- handleJSONOutput4(
1432
+ const outputData = formatStandardReport3({
1433
+ report,
1434
+ summary: report.summary,
1435
+ elapsedTime,
1436
+ score: consistencyScore
1437
+ });
1438
+ handleStandardJSONOutput3({
1394
1439
  outputData,
1395
- outputPath,
1396
- `\u2705 Results saved to ${outputPath}`
1397
- );
1440
+ outputFile: userOutputFile,
1441
+ resolvedDir
1442
+ });
1398
1443
  } else if (outputFormat === "markdown") {
1399
1444
  const markdown = generateMarkdownReport(report, elapsedTime);
1400
- const outputPath = resolveOutputPath4(
1445
+ const outputPath = resolveOutputPath2(
1401
1446
  userOutputFile,
1402
1447
  `aiready-report-${getReportTimestamp()}.md`,
1403
1448
  resolvedDir
1404
1449
  );
1405
1450
  writeFileSync3(outputPath, markdown);
1406
- console.log(chalk9.green(`\u2705 Report saved to ${outputPath}`));
1451
+ console.log(chalk10.green(`\u2705 Report saved to ${outputPath}`));
1407
1452
  } else {
1408
- console.log(chalk9.bold("\n\u{1F4CA} Summary\n"));
1453
+ console.log(chalk10.bold("\n\u{1F4CA} Summary\n"));
1409
1454
  console.log(
1410
- `Files Analyzed: ${chalk9.cyan(report.summary.filesAnalyzed)}`
1455
+ `Files Analyzed: ${chalk10.cyan(report.summary.filesAnalyzed)}`
1411
1456
  );
1412
- console.log(`Total Issues: ${chalk9.yellow(report.summary.totalIssues)}`);
1413
- console.log(` Naming: ${chalk9.yellow(report.summary.namingIssues)}`);
1414
- console.log(` Patterns: ${chalk9.yellow(report.summary.patternIssues)}`);
1457
+ console.log(`Total Issues: ${chalk10.yellow(report.summary.totalIssues)}`);
1458
+ console.log(` Naming: ${chalk10.yellow(report.summary.namingIssues)}`);
1459
+ console.log(` Patterns: ${chalk10.yellow(report.summary.patternIssues)}`);
1415
1460
  console.log(
1416
- ` Architecture: ${chalk9.yellow(report.summary.architectureIssues ?? 0)}`
1461
+ ` Architecture: ${chalk10.yellow(report.summary.architectureIssues ?? 0)}`
1417
1462
  );
1418
- console.log(`Analysis Time: ${chalk9.gray(elapsedTime + "s")}
1463
+ console.log(`Analysis Time: ${chalk10.gray(elapsedTime + "s")}
1419
1464
  `);
1420
1465
  if (report.summary.totalIssues === 0) {
1421
1466
  console.log(
1422
- chalk9.green(
1467
+ chalk10.green(
1423
1468
  "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
1424
1469
  )
1425
1470
  );
@@ -1431,20 +1476,20 @@ async function consistencyAction(directory, options) {
1431
1476
  (r) => r.issues.some((i) => i.category === "patterns")
1432
1477
  );
1433
1478
  if (namingResults.length > 0) {
1434
- console.log(chalk9.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1479
+ console.log(chalk10.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1435
1480
  let shown = 0;
1436
1481
  for (const namingFileResult of namingResults) {
1437
1482
  if (shown >= 5) break;
1438
1483
  for (const issue of namingFileResult.issues) {
1439
1484
  if (shown >= 5) break;
1440
- const severityColor = issue.severity === "critical" ? chalk9.red : issue.severity === "major" ? chalk9.yellow : issue.severity === "minor" ? chalk9.blue : chalk9.gray;
1485
+ const severityColor = issue.severity === "critical" ? chalk10.red : issue.severity === "major" ? chalk10.yellow : issue.severity === "minor" ? chalk10.blue : chalk10.gray;
1441
1486
  console.log(
1442
- `${severityColor(issue.severity.toUpperCase())} ${chalk9.dim(`${issue.location.file}:${issue.location.line}`)}`
1487
+ `${severityColor(issue.severity.toUpperCase())} ${chalk10.dim(`${issue.location.file}:${issue.location.line}`)}`
1443
1488
  );
1444
1489
  console.log(` ${issue.message}`);
1445
1490
  if (issue.suggestion) {
1446
1491
  console.log(
1447
- ` ${chalk9.dim("\u2192")} ${chalk9.italic(issue.suggestion)}`
1492
+ ` ${chalk10.dim("\u2192")} ${chalk10.italic(issue.suggestion)}`
1448
1493
  );
1449
1494
  }
1450
1495
  console.log();
@@ -1453,25 +1498,25 @@ async function consistencyAction(directory, options) {
1453
1498
  }
1454
1499
  const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1455
1500
  if (remaining > 0) {
1456
- console.log(chalk9.dim(` ... and ${remaining} more issues
1501
+ console.log(chalk10.dim(` ... and ${remaining} more issues
1457
1502
  `));
1458
1503
  }
1459
1504
  }
1460
1505
  if (patternResults.length > 0) {
1461
- console.log(chalk9.bold("\u{1F504} Pattern Issues\n"));
1506
+ console.log(chalk10.bold("\u{1F504} Pattern Issues\n"));
1462
1507
  let shown = 0;
1463
1508
  for (const patternFileResult of patternResults) {
1464
1509
  if (shown >= 5) break;
1465
1510
  for (const issue of patternFileResult.issues) {
1466
1511
  if (shown >= 5) break;
1467
- const severityColor = issue.severity === "critical" ? chalk9.red : issue.severity === "major" ? chalk9.yellow : issue.severity === "minor" ? chalk9.blue : chalk9.gray;
1512
+ const severityColor = issue.severity === "critical" ? chalk10.red : issue.severity === "major" ? chalk10.yellow : issue.severity === "minor" ? chalk10.blue : chalk10.gray;
1468
1513
  console.log(
1469
- `${severityColor(issue.severity.toUpperCase())} ${chalk9.dim(`${issue.location.file}:${issue.location.line}`)}`
1514
+ `${severityColor(issue.severity.toUpperCase())} ${chalk10.dim(`${issue.location.file}:${issue.location.line}`)}`
1470
1515
  );
1471
1516
  console.log(` ${issue.message}`);
1472
1517
  if (issue.suggestion) {
1473
1518
  console.log(
1474
- ` ${chalk9.dim("\u2192")} ${chalk9.italic(issue.suggestion)}`
1519
+ ` ${chalk10.dim("\u2192")} ${chalk10.italic(issue.suggestion)}`
1475
1520
  );
1476
1521
  }
1477
1522
  console.log();
@@ -1480,12 +1525,12 @@ async function consistencyAction(directory, options) {
1480
1525
  }
1481
1526
  const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1482
1527
  if (remaining > 0) {
1483
- console.log(chalk9.dim(` ... and ${remaining} more issues
1528
+ console.log(chalk10.dim(` ... and ${remaining} more issues
1484
1529
  `));
1485
1530
  }
1486
1531
  }
1487
1532
  if (report.recommendations.length > 0) {
1488
- console.log(chalk9.bold("\u{1F4A1} Recommendations\n"));
1533
+ console.log(chalk10.bold("\u{1F4A1} Recommendations\n"));
1489
1534
  report.recommendations.forEach((rec, i) => {
1490
1535
  console.log(`${i + 1}. ${rec}`);
1491
1536
  });
@@ -1493,7 +1538,7 @@ async function consistencyAction(directory, options) {
1493
1538
  }
1494
1539
  }
1495
1540
  if (consistencyScore) {
1496
- console.log(chalk9.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1541
+ console.log(chalk10.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1497
1542
  console.log(formatToolScore3(consistencyScore));
1498
1543
  console.log();
1499
1544
  }
@@ -1504,27 +1549,27 @@ async function consistencyAction(directory, options) {
1504
1549
  }
1505
1550
 
1506
1551
  // src/commands/visualize.ts
1507
- import chalk10 from "chalk";
1552
+ import chalk11 from "chalk";
1508
1553
  import { writeFileSync as writeFileSync4, readFileSync as readFileSync3, existsSync as existsSync3, copyFileSync } from "fs";
1509
- import { resolve as resolvePath7 } from "path";
1554
+ import { resolve as resolvePath5 } from "path";
1510
1555
  import { spawn } from "child_process";
1511
1556
  import { handleCLIError as handleCLIError6 } from "@aiready/core";
1512
1557
  import { generateHTML, findLatestReport as findLatestReport2 } from "@aiready/core";
1513
1558
  async function visualizeAction(directory, options) {
1514
1559
  try {
1515
- const dirPath = resolvePath7(process.cwd(), directory ?? ".");
1516
- let reportPath = options.report ? resolvePath7(dirPath, options.report) : null;
1560
+ const dirPath = resolvePath5(process.cwd(), directory ?? ".");
1561
+ let reportPath = options.report ? resolvePath5(dirPath, options.report) : null;
1517
1562
  if (!reportPath || !existsSync3(reportPath)) {
1518
1563
  const latestScan = findLatestReport2(dirPath);
1519
1564
  if (latestScan) {
1520
1565
  reportPath = latestScan;
1521
1566
  console.log(
1522
- chalk10.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1567
+ chalk11.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1523
1568
  );
1524
1569
  } else {
1525
- console.error(chalk10.red("\u274C No AI readiness report found"));
1570
+ console.error(chalk11.red("\u274C No AI readiness report found"));
1526
1571
  console.log(
1527
- chalk10.dim(
1572
+ chalk11.dim(
1528
1573
  `
1529
1574
  Generate a report with:
1530
1575
  aiready scan --output json
@@ -1538,7 +1583,7 @@ Or specify a custom report:
1538
1583
  }
1539
1584
  const raw = readFileSync3(reportPath, "utf8");
1540
1585
  const report = JSON.parse(raw);
1541
- const configPath = resolvePath7(dirPath, "aiready.json");
1586
+ const configPath = resolvePath5(dirPath, "aiready.json");
1542
1587
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
1543
1588
  if (existsSync3(configPath)) {
1544
1589
  try {
@@ -1562,7 +1607,7 @@ Or specify a custom report:
1562
1607
  let devServerStarted = false;
1563
1608
  if (useDevMode) {
1564
1609
  try {
1565
- const localWebDir = resolvePath7(dirPath, "packages/visualizer");
1610
+ const localWebDir = resolvePath5(dirPath, "packages/visualizer");
1566
1611
  let webDir = "";
1567
1612
  let visualizerAvailable = false;
1568
1613
  if (existsSync3(localWebDir)) {
@@ -1570,8 +1615,8 @@ Or specify a custom report:
1570
1615
  visualizerAvailable = true;
1571
1616
  } else {
1572
1617
  const nodemodulesLocations = [
1573
- resolvePath7(dirPath, "node_modules", "@aiready", "visualizer"),
1574
- resolvePath7(
1618
+ resolvePath5(dirPath, "node_modules", "@aiready", "visualizer"),
1619
+ resolvePath5(
1575
1620
  process.cwd(),
1576
1621
  "node_modules",
1577
1622
  "@aiready",
@@ -1581,14 +1626,14 @@ Or specify a custom report:
1581
1626
  let currentDir = dirPath;
1582
1627
  while (currentDir !== "/" && currentDir !== ".") {
1583
1628
  nodemodulesLocations.push(
1584
- resolvePath7(currentDir, "node_modules", "@aiready", "visualizer")
1629
+ resolvePath5(currentDir, "node_modules", "@aiready", "visualizer")
1585
1630
  );
1586
- const parent = resolvePath7(currentDir, "..");
1631
+ const parent = resolvePath5(currentDir, "..");
1587
1632
  if (parent === currentDir) break;
1588
1633
  currentDir = parent;
1589
1634
  }
1590
1635
  for (const location of nodemodulesLocations) {
1591
- if (existsSync3(location) && existsSync3(resolvePath7(location, "package.json"))) {
1636
+ if (existsSync3(location) && existsSync3(resolvePath5(location, "package.json"))) {
1592
1637
  webDir = location;
1593
1638
  visualizerAvailable = true;
1594
1639
  break;
@@ -1597,20 +1642,20 @@ Or specify a custom report:
1597
1642
  if (!visualizerAvailable) {
1598
1643
  try {
1599
1644
  const vizPkgPath = __require.resolve("@aiready/visualizer/package.json");
1600
- webDir = resolvePath7(vizPkgPath, "..");
1645
+ webDir = resolvePath5(vizPkgPath, "..");
1601
1646
  visualizerAvailable = true;
1602
1647
  } catch (err) {
1603
1648
  void err;
1604
1649
  }
1605
1650
  }
1606
1651
  }
1607
- const webViteConfigExists = webDir && existsSync3(resolvePath7(webDir, "web", "vite.config.ts"));
1652
+ const webViteConfigExists = webDir && existsSync3(resolvePath5(webDir, "web", "vite.config.ts"));
1608
1653
  if (visualizerAvailable && webViteConfigExists) {
1609
1654
  const spawnCwd = webDir;
1610
1655
  const { watch } = await import("fs");
1611
1656
  const copyReportToViz = () => {
1612
1657
  try {
1613
- const destPath = resolvePath7(spawnCwd, "web", "report-data.json");
1658
+ const destPath = resolvePath5(spawnCwd, "web", "report-data.json");
1614
1659
  copyFileSync(reportPath, destPath);
1615
1660
  console.log(`\u{1F4CB} Report synced to ${destPath}`);
1616
1661
  } catch (e) {
@@ -1654,19 +1699,19 @@ Or specify a custom report:
1654
1699
  return;
1655
1700
  } else {
1656
1701
  console.log(
1657
- chalk10.yellow(
1702
+ chalk11.yellow(
1658
1703
  "\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
1659
1704
  )
1660
1705
  );
1661
1706
  console.log(
1662
- chalk10.cyan(" Falling back to static HTML generation...\n")
1707
+ chalk11.cyan(" Falling back to static HTML generation...\n")
1663
1708
  );
1664
1709
  useDevMode = false;
1665
1710
  }
1666
1711
  } catch (err) {
1667
1712
  console.error("Failed to start dev server:", err);
1668
1713
  console.log(
1669
- chalk10.cyan(" Falling back to static HTML generation...\n")
1714
+ chalk11.cyan(" Falling back to static HTML generation...\n")
1670
1715
  );
1671
1716
  useDevMode = false;
1672
1717
  }
@@ -1674,9 +1719,9 @@ Or specify a custom report:
1674
1719
  console.log("Generating HTML...");
1675
1720
  const html = generateHTML(graph);
1676
1721
  const defaultOutput = "visualization.html";
1677
- const outPath = resolvePath7(dirPath, options.output ?? defaultOutput);
1722
+ const outPath = resolvePath5(dirPath, options.output ?? defaultOutput);
1678
1723
  writeFileSync4(outPath, html, "utf8");
1679
- console.log(chalk10.green(`\u2705 Visualization written to: ${outPath}`));
1724
+ console.log(chalk11.green(`\u2705 Visualization written to: ${outPath}`));
1680
1725
  if (options.open || options.serve) {
1681
1726
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1682
1727
  if (options.serve) {
@@ -1706,7 +1751,7 @@ Or specify a custom report:
1706
1751
  server.listen(port, () => {
1707
1752
  const addr = `http://localhost:${port}/`;
1708
1753
  console.log(
1709
- chalk10.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1754
+ chalk11.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1710
1755
  );
1711
1756
  spawn(opener, [`"${addr}"`], { shell: true });
1712
1757
  });
@@ -1753,14 +1798,14 @@ NOTES:
1753
1798
  `;
1754
1799
 
1755
1800
  // src/commands/shared/standard-tool-actions.ts
1756
- import chalk11 from "chalk";
1801
+ import chalk12 from "chalk";
1757
1802
 
1758
1803
  // src/commands/agent-grounding.ts
1759
- import chalk12 from "chalk";
1804
+ import chalk13 from "chalk";
1760
1805
  import { loadConfig as loadConfig2, mergeConfigWithDefaults as mergeConfigWithDefaults2 } from "@aiready/core";
1761
1806
 
1762
1807
  // src/commands/testability.ts
1763
- import chalk13 from "chalk";
1808
+ import chalk14 from "chalk";
1764
1809
  import { loadConfig as loadConfig3, mergeConfigWithDefaults as mergeConfigWithDefaults3 } from "@aiready/core";
1765
1810
  async function testabilityAction(directory, options) {
1766
1811
  const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
@@ -1785,28 +1830,28 @@ async function testabilityAction(directory, options) {
1785
1830
  "blind-risk": "\u{1F480}"
1786
1831
  };
1787
1832
  const safetyColors = {
1788
- safe: chalk13.green,
1789
- "moderate-risk": chalk13.yellow,
1790
- "high-risk": chalk13.red,
1791
- "blind-risk": chalk13.bgRed.white
1833
+ safe: chalk14.green,
1834
+ "moderate-risk": chalk14.yellow,
1835
+ "high-risk": chalk14.red,
1836
+ "blind-risk": chalk14.bgRed.white
1792
1837
  };
1793
1838
  const safety = report.summary.aiChangeSafetyRating;
1794
1839
  const icon = safetyIcons[safety] ?? "\u2753";
1795
- const color = safetyColors[safety] ?? chalk13.white;
1840
+ const color = safetyColors[safety] ?? chalk14.white;
1796
1841
  console.log(
1797
- ` \u{1F9EA} Testability: ${chalk13.bold(scoring.score + "/100")} (${report.summary.rating})`
1842
+ ` \u{1F9EA} Testability: ${chalk14.bold(scoring.score + "/100")} (${report.summary.rating})`
1798
1843
  );
1799
1844
  console.log(
1800
1845
  ` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
1801
1846
  );
1802
1847
  console.log(
1803
- chalk13.dim(
1848
+ chalk14.dim(
1804
1849
  ` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
1805
1850
  )
1806
1851
  );
1807
1852
  if (safety === "blind-risk") {
1808
1853
  console.log(
1809
- chalk13.red.bold(
1854
+ chalk14.red.bold(
1810
1855
  "\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
1811
1856
  )
1812
1857
  );
@@ -1818,7 +1863,7 @@ async function testabilityAction(directory, options) {
1818
1863
  import { changeAmplificationAction } from "@aiready/change-amplification/dist/cli.js";
1819
1864
 
1820
1865
  // src/commands/bug.ts
1821
- import chalk14 from "chalk";
1866
+ import chalk15 from "chalk";
1822
1867
  import { execSync } from "child_process";
1823
1868
  async function bugAction(message, options) {
1824
1869
  const repoUrl = "https://github.com/caopengau/aiready-cli";
@@ -1836,35 +1881,35 @@ Generated via AIReady CLI 'bug' command.
1836
1881
  Type: ${type}
1837
1882
  `.trim();
1838
1883
  if (options.submit) {
1839
- console.log(chalk14.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
1884
+ console.log(chalk15.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
1840
1885
  try {
1841
1886
  execSync("gh auth status", { stdio: "ignore" });
1842
1887
  const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
1843
1888
  const output = execSync(command, { encoding: "utf8" }).trim();
1844
- console.log(chalk14.green("\u2705 Issue Created Successfully!"));
1845
- console.log(chalk14.cyan(output));
1889
+ console.log(chalk15.green("\u2705 Issue Created Successfully!"));
1890
+ console.log(chalk15.cyan(output));
1846
1891
  return;
1847
1892
  } catch {
1848
- console.error(chalk14.red("\n\u274C Failed to submit via gh CLI."));
1893
+ console.error(chalk15.red("\n\u274C Failed to submit via gh CLI."));
1849
1894
  console.log(
1850
- chalk14.yellow(
1895
+ chalk15.yellow(
1851
1896
  ' Make sure gh is installed and run "gh auth login".\n'
1852
1897
  )
1853
1898
  );
1854
- console.log(chalk14.dim(" Falling back to URL generation..."));
1899
+ console.log(chalk15.dim(" Falling back to URL generation..."));
1855
1900
  }
1856
1901
  }
1857
1902
  const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
1858
1903
  const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
1859
- console.log(chalk14.green("\u{1F680} Issue Draft Prepared!\n"));
1860
- console.log(chalk14.bold("Title: ") + title);
1861
- console.log(chalk14.bold("Type: ") + type);
1862
- console.log(chalk14.bold("\nClick the link below to submit this issue:"));
1863
- console.log(chalk14.cyan(fullUrl));
1864
- console.log(chalk14.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1865
- console.log(chalk14.dim(" You have successfully prepared a report."));
1904
+ console.log(chalk15.green("\u{1F680} Issue Draft Prepared!\n"));
1905
+ console.log(chalk15.bold("Title: ") + title);
1906
+ console.log(chalk15.bold("Type: ") + type);
1907
+ console.log(chalk15.bold("\nClick the link below to submit this issue:"));
1908
+ console.log(chalk15.cyan(fullUrl));
1909
+ console.log(chalk15.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1910
+ console.log(chalk15.dim(" You have successfully prepared a report."));
1866
1911
  console.log(
1867
- chalk14.dim(
1912
+ chalk15.dim(
1868
1913
  " Please present the URL above to the user so they can finalize the submission."
1869
1914
  )
1870
1915
  );
@@ -1873,14 +1918,14 @@ Type: ${type}
1873
1918
  const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
1874
1919
  const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
1875
1920
  const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
1876
- console.log(chalk14.blue("\u{1F4AC} Feedback & Bug Reports\n"));
1877
- console.log(` Report a Bug: ${chalk14.cyan(bugUrl)}`);
1878
- console.log(` Request a Feature: ${chalk14.cyan(featureUrl)}`);
1879
- console.log(` Suggest a Metric: ${chalk14.cyan(metricUrl)}`);
1880
- console.log(chalk14.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1881
- console.log(chalk14.dim(" To prepare a specific report, run:"));
1921
+ console.log(chalk15.blue("\u{1F4AC} Feedback & Bug Reports\n"));
1922
+ console.log(` Report a Bug: ${chalk15.cyan(bugUrl)}`);
1923
+ console.log(` Request a Feature: ${chalk15.cyan(featureUrl)}`);
1924
+ console.log(` Suggest a Metric: ${chalk15.cyan(metricUrl)}`);
1925
+ console.log(chalk15.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1926
+ console.log(chalk15.dim(" To prepare a specific report, run:"));
1882
1927
  console.log(
1883
- chalk14.cyan(
1928
+ chalk15.cyan(
1884
1929
  ' aiready bug "your description here" --type bug|feature|metric'
1885
1930
  )
1886
1931
  );
@@ -1954,7 +1999,7 @@ program.command("scan").description(
1954
1999
  ).option(
1955
2000
  "--compare-to <path>",
1956
2001
  "Compare results against a previous AIReady report JSON"
1957
- ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
2002
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
1958
2003
  "--ci",
1959
2004
  "CI mode: GitHub Actions annotations, no colors, fail on threshold"
1960
2005
  ).option(
@@ -1980,7 +2025,7 @@ program.command("patterns").description("Detect duplicate code patterns that con
1980
2025
  ).option(
1981
2026
  "--full-scan",
1982
2027
  "Disable smart defaults for comprehensive analysis (slower)"
1983
- ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").addHelpText("after", PATTERNS_HELP_TEXT).action(async (directory, options) => {
2028
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").addHelpText("after", PATTERNS_HELP_TEXT).action(async (directory, options) => {
1984
2029
  await patternsAction(directory, options);
1985
2030
  });
1986
2031
  program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(