@aiready/cli 0.14.22 → 0.14.24

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