@aiready/cli 0.14.21 → 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 chalk4 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,
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) {
@@ -388,7 +387,7 @@ async function uploadAction(file, options) {
388
387
  handleCLIError(error, "Upload");
389
388
  }
390
389
  }
391
- var uploadHelpText = `
390
+ var UPLOAD_HELP_TEXT = `
392
391
  EXAMPLES:
393
392
  $ aiready upload report.json --api-key ar_...
394
393
  $ aiready upload .aiready/latest.json
@@ -399,247 +398,285 @@ ENVIRONMENT VARIABLES:
399
398
  AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
400
399
  `;
401
400
 
402
- // src/commands/scan.ts
403
- async function scanAction(directory, options) {
404
- console.log(chalk4.blue("\u{1F680} Starting AIReady unified analysis...\n"));
405
- const startTime = Date.now();
406
- const resolvedDir = resolvePath3(process.cwd(), directory ?? ".");
407
- const repoMetadata = getRepoMetadata(resolvedDir);
408
- try {
409
- const defaults = {
410
- tools: [
411
- "pattern-detect",
412
- "context-analyzer",
413
- "naming-consistency",
414
- "ai-signal-clarity",
415
- "agent-grounding",
416
- "testability-index",
417
- "doc-drift",
418
- "dependency-health",
419
- "change-amplification"
420
- ],
421
- include: void 0,
422
- exclude: void 0,
423
- output: {
424
- format: "console",
425
- file: void 0
426
- }
427
- };
428
- let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
429
- if (options.profile) {
430
- switch (options.profile.toLowerCase()) {
431
- case "agentic":
432
- profileTools = [
433
- ToolName.AiSignalClarity,
434
- ToolName.AgentGrounding,
435
- ToolName.TestabilityIndex
436
- ];
437
- break;
438
- case "cost":
439
- profileTools = [ToolName.PatternDetect, ToolName.ContextAnalyzer];
440
- break;
441
- case "logic":
442
- profileTools = [
443
- ToolName.TestabilityIndex,
444
- ToolName.NamingConsistency,
445
- ToolName.ContextAnalyzer,
446
- ToolName.PatternDetect,
447
- ToolName.ChangeAmplification
448
- ];
449
- break;
450
- case "ui":
451
- profileTools = [
452
- ToolName.NamingConsistency,
453
- ToolName.ContextAnalyzer,
454
- ToolName.PatternDetect,
455
- ToolName.DocDrift,
456
- ToolName.AiSignalClarity
457
- ];
458
- break;
459
- case "security":
460
- profileTools = [
461
- ToolName.NamingConsistency,
462
- ToolName.TestabilityIndex
463
- ];
464
- break;
465
- case "onboarding":
466
- profileTools = [
467
- ToolName.ContextAnalyzer,
468
- ToolName.NamingConsistency,
469
- ToolName.AgentGrounding
470
- ];
471
- break;
472
- default:
473
- console.log(
474
- chalk4.yellow(
475
- `
476
- \u26A0\uFE0F Unknown profile '${options.profile}'. Using defaults.`
477
- )
478
- );
479
- }
480
- }
481
- const cliOverrides = {
482
- include: options.include?.split(","),
483
- exclude: options.exclude?.split(",")
484
- };
485
- if (profileTools) cliOverrides.tools = profileTools;
486
- const baseOptions = await loadMergedConfig(
487
- resolvedDir,
488
- defaults,
489
- cliOverrides
490
- );
491
- const finalOptions = { ...baseOptions };
492
- if (baseOptions.tools.includes(ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
493
- const { getSmartDefaults } = await import("@aiready/pattern-detect");
494
- const patternSmartDefaults = await getSmartDefaults(
495
- resolvedDir,
496
- finalOptions.toolConfigs?.[ToolName.PatternDetect] ?? {}
401
+ // src/commands/scan-config.ts
402
+ import { loadMergedConfig, ToolName as ToolName2 } from "@aiready/core";
403
+
404
+ // src/commands/scan-helpers.ts
405
+ import chalk4 from "chalk";
406
+ import { ToolName } from "@aiready/core";
407
+ function getProfileTools(profile) {
408
+ switch (profile.toLowerCase()) {
409
+ case "agentic":
410
+ return [
411
+ ToolName.AiSignalClarity,
412
+ ToolName.AgentGrounding,
413
+ ToolName.TestabilityIndex
414
+ ];
415
+ case "cost":
416
+ return [ToolName.PatternDetect, ToolName.ContextAnalyzer];
417
+ case "logic":
418
+ return [
419
+ ToolName.TestabilityIndex,
420
+ ToolName.NamingConsistency,
421
+ ToolName.ContextAnalyzer,
422
+ ToolName.PatternDetect,
423
+ ToolName.ChangeAmplification
424
+ ];
425
+ case "ui":
426
+ return [
427
+ ToolName.NamingConsistency,
428
+ ToolName.ContextAnalyzer,
429
+ ToolName.PatternDetect,
430
+ ToolName.DocDrift,
431
+ ToolName.AiSignalClarity
432
+ ];
433
+ case "security":
434
+ return [ToolName.NamingConsistency, ToolName.TestabilityIndex];
435
+ case "onboarding":
436
+ return [
437
+ ToolName.ContextAnalyzer,
438
+ ToolName.NamingConsistency,
439
+ ToolName.AgentGrounding
440
+ ];
441
+ default:
442
+ console.log(
443
+ chalk4.yellow(`
444
+ \u26A0\uFE0F Unknown profile '${profile}'. Using defaults.`)
497
445
  );
498
- if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
499
- finalOptions.toolConfigs[ToolName.PatternDetect] = {
500
- ...patternSmartDefaults,
501
- ...finalOptions.toolConfigs[ToolName.PatternDetect]
502
- };
446
+ return void 0;
447
+ }
448
+ }
449
+ function createProgressCallback() {
450
+ return (event) => {
451
+ if (event.message) {
452
+ process.stdout.write(`\r\x1B[K [${event.tool}] ${event.message}`);
453
+ return;
503
454
  }
504
- console.log(chalk4.cyan("\n=== AIReady Run Preview ==="));
505
- console.log(
506
- chalk4.white("Tools to run:"),
507
- (finalOptions.tools ?? []).join(", ")
455
+ process.stdout.write("\r\x1B[K");
456
+ console.log(chalk4.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
457
+ const toolResult = event.data;
458
+ if (toolResult && toolResult.summary) {
459
+ if (toolResult.summary.totalIssues !== void 0)
460
+ console.log(
461
+ ` Issues found: ${chalk4.bold(toolResult.summary.totalIssues)}`
462
+ );
463
+ if (toolResult.summary.score !== void 0)
464
+ console.log(
465
+ ` Tool Score: ${chalk4.bold(toolResult.summary.score)}/100`
466
+ );
467
+ if (toolResult.summary.totalFiles !== void 0)
468
+ console.log(
469
+ ` Files analyzed: ${chalk4.bold(toolResult.summary.totalFiles)}`
470
+ );
471
+ }
472
+ };
473
+ }
474
+
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(
514
+ resolvedDir,
515
+ finalOptions.toolConfigs?.[ToolName2.PatternDetect] ?? {}
508
516
  );
509
- const progressCallback = (event) => {
510
- if (event.message) {
511
- process.stdout.write(`\r\x1B[K [${event.tool}] ${event.message}`);
512
- return;
513
- }
514
- process.stdout.write("\r\x1B[K");
515
- console.log(chalk4.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
516
- const res = event.data;
517
- if (res && res.summary) {
518
- if (res.summary.totalIssues !== void 0)
519
- console.log(` Issues found: ${chalk4.bold(res.summary.totalIssues)}`);
520
- if (res.summary.score !== void 0)
521
- console.log(` Tool Score: ${chalk4.bold(res.summary.score)}/100`);
522
- if (res.summary.totalFiles !== void 0)
523
- console.log(
524
- ` Files analyzed: ${chalk4.bold(res.summary.totalFiles)}`
525
- );
526
- }
517
+ if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
518
+ finalOptions.toolConfigs[ToolName2.PatternDetect] = {
519
+ ...patternSmartDefaults,
520
+ ...finalOptions.toolConfigs[ToolName2.PatternDetect]
527
521
  };
528
- const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
529
- const results = await analyzeUnified({
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, {
530
550
  ...finalOptions,
531
- progressCallback,
532
- onProgress: () => {
533
- },
534
- suppressToolConfig: true
551
+ scoring: {
552
+ ...finalOptions.scoring,
553
+ profile: scoringProfile
554
+ }
535
555
  });
536
- printScanSummary(results, startTime);
537
- let scoringResult;
538
- if (options.score || finalOptions.scoring?.showBreakdown) {
539
- scoringResult = await scoreUnified(results, {
540
- ...finalOptions,
541
- scoring: {
542
- ...finalOptions.scoring,
543
- profile: scoringProfile
544
- }
545
- });
546
- printScoring(scoringResult, scoringProfile);
547
- if (options.compareTo) {
548
- try {
549
- const prevReport = JSON.parse(
550
- readFileSync2(resolvePath3(process.cwd(), options.compareTo), "utf8")
551
- );
552
- const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
553
- if (typeof prevScore === "number") {
554
- const diff = scoringResult.overall - prevScore;
555
- const diffStr = diff > 0 ? `+${diff}` : String(diff);
556
- if (diff > 0)
557
- console.log(
558
- chalk4.green(
559
- ` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
560
- )
561
- );
562
- else if (diff < 0)
563
- console.log(
564
- chalk4.red(
565
- ` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
566
- )
567
- );
568
- else
569
- console.log(
570
- chalk4.blue(
571
- ` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
572
- )
573
- );
574
- }
575
- } catch (e) {
576
- void e;
577
- }
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
578
623
  }
579
- const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
580
- (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
581
- 0
582
- );
583
- const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
584
- (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
585
- 0
586
- );
587
- const totalContext = Math.max(
588
- ...(scoringResult.breakdown ?? []).map(
589
- (s) => s.tokenBudget?.totalContextTokens ?? 0
590
- ),
591
- 0
592
- );
593
- if (totalContext > 0) {
594
- const unifiedBudget = calculateTokenBudget({
595
- totalContextTokens: totalContext,
596
- wastedTokens: {
597
- duplication: totalWastedDuplication,
598
- fragmentation: totalWastedFragmentation,
599
- chattiness: totalContext * 0.1
600
- // Default chattiness
601
- }
602
- });
603
- const allIssues = [];
604
- for (const toolId of results.summary.toolsRun) {
605
- if (results[toolId]?.results) {
606
- results[toolId].results.forEach((fileRes) => {
607
- if (fileRes.issues) {
608
- allIssues.push(...fileRes.issues);
609
- }
610
- });
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);
611
631
  }
612
- }
613
- const modelId = options.model ?? "gpt-5.4-mini";
614
- const roi = (await import("@aiready/core")).calculateBusinessROI({
615
- tokenWaste: unifiedBudget.wastedTokens.total,
616
- issues: allIssues,
617
- modelId
618
632
  });
619
- printBusinessImpact(roi, unifiedBudget);
620
- results.summary.businessImpact = {
621
- estimatedMonthlyWaste: roi.monthlySavings,
622
- potentialSavings: roi.monthlySavings,
623
- productivityHours: roi.productivityGainHours
624
- };
625
- scoringResult.tokenBudget = unifiedBudget;
626
- scoringResult.businessROI = roi;
627
633
  }
628
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
+ );
629
666
  console.log(
630
- chalk4.dim(
667
+ chalk6.dim(
631
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"
632
669
  )
633
670
  );
634
- console.log(chalk4.dim("\u{1F4AC} Found a bug or have a metric idea?"));
635
- console.log(chalk4.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:"));
636
673
  console.log(
637
- chalk4.cyan(
674
+ chalk6.cyan(
638
675
  ` "Any feedback for the tools? Please use 'aiready bug' to report \u2764\uFE0F"`
639
676
  )
640
677
  );
641
678
  console.log(
642
- chalk4.dim(
679
+ chalk6.dim(
643
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"
644
681
  )
645
682
  );
@@ -654,7 +691,7 @@ async function scanAction(directory, options) {
654
691
  resolvedDir
655
692
  );
656
693
  if (outputFormat === "json") {
657
- handleJSONOutput(
694
+ handleJSONOutput2(
658
695
  outputData,
659
696
  outputPath,
660
697
  `\u2705 Report saved to ${outputPath}`
@@ -662,7 +699,7 @@ async function scanAction(directory, options) {
662
699
  } else {
663
700
  try {
664
701
  writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
665
- console.log(chalk4.dim(`\u2705 Report auto-persisted to ${outputPath}`));
702
+ console.log(chalk6.dim(`\u2705 Report auto-persisted to ${outputPath}`));
666
703
  } catch (err) {
667
704
  void err;
668
705
  }
@@ -674,61 +711,83 @@ async function scanAction(directory, options) {
674
711
  });
675
712
  }
676
713
  await warnIfGraphCapExceeded(outputData, resolvedDir);
677
- if (scoringResult) {
678
- const threshold = options.threshold ? parseInt(options.threshold) : void 0;
679
- const failOnLevel = options.failOn ?? "critical";
680
- const isCI = options.ci ?? process.env.CI === "true";
681
- let shouldFail = false;
682
- let failReason = "";
683
- const report = mapToUnifiedReport(results, scoringResult);
684
- if (isCI && report.results && report.results.length > 0) {
685
- console.log(
686
- chalk4.cyan(
687
- `
688
- \u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
689
- )
690
- );
691
- emitIssuesAsAnnotations(report.results);
692
- }
693
- if (threshold && scoringResult.overall < threshold) {
694
- shouldFail = true;
695
- failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
696
- }
697
- if (failOnLevel !== "none") {
698
- if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
699
- shouldFail = true;
700
- failReason = `Found ${report.summary.criticalIssues} critical issues`;
701
- } else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
702
- shouldFail = true;
703
- failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
704
- }
705
- }
706
- if (shouldFail) {
707
- console.log(chalk4.red(`
708
- \u{1F6AB} SCAN FAILED: ${failReason}`));
709
- process.exit(1);
710
- } else {
711
- console.log(chalk4.green("\n\u2705 SCAN PASSED"));
712
- }
713
- }
714
+ await handleGatekeeper(outputData, scoringResult, options, results);
714
715
  } catch (error) {
715
716
  handleCLIError2(error, "Analysis");
716
717
  }
717
718
  }
718
- var scanHelpText = `...`;
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
+ `;
719
778
 
720
779
  // src/commands/init.ts
721
780
  import { writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
722
781
  import { join } from "path";
723
- import chalk5 from "chalk";
724
- import { ToolName as ToolName2 } from "@aiready/core";
782
+ import chalk7 from "chalk";
783
+ import { ToolName as ToolName3 } from "@aiready/core";
725
784
  async function initAction(options) {
726
785
  const fileExt = options.format === "js" ? "js" : "json";
727
786
  const fileName = fileExt === "js" ? "aiready.config.js" : "aiready.json";
728
787
  const filePath = join(process.cwd(), fileName);
729
788
  if (existsSync2(filePath) && !options.force) {
730
789
  console.error(
731
- chalk5.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
790
+ chalk7.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
732
791
  );
733
792
  process.exit(1);
734
793
  }
@@ -752,15 +811,15 @@ async function initAction(options) {
752
811
  "**/*.spec.ts"
753
812
  ],
754
813
  tools: [
755
- ToolName2.PatternDetect,
756
- ToolName2.ContextAnalyzer,
757
- ToolName2.NamingConsistency,
758
- ToolName2.AiSignalClarity,
759
- ToolName2.AgentGrounding,
760
- ToolName2.TestabilityIndex,
761
- ToolName2.DocDrift,
762
- ToolName2.DependencyHealth,
763
- ToolName2.ChangeAmplification
814
+ ToolName3.PatternDetect,
815
+ ToolName3.ContextAnalyzer,
816
+ ToolName3.NamingConsistency,
817
+ ToolName3.AiSignalClarity,
818
+ ToolName3.AgentGrounding,
819
+ ToolName3.TestabilityIndex,
820
+ ToolName3.DocDrift,
821
+ ToolName3.DependencyHealth,
822
+ ToolName3.ChangeAmplification
764
823
  ]
765
824
  },
766
825
  // Output preferences
@@ -775,7 +834,7 @@ async function initAction(options) {
775
834
  },
776
835
  // Tool-specific configurations
777
836
  tools: {
778
- [ToolName2.PatternDetect]: {
837
+ [ToolName3.PatternDetect]: {
779
838
  // Core detection thresholds
780
839
  minSimilarity: 0.4,
781
840
  // Jaccard similarity threshold (0-1)
@@ -805,7 +864,7 @@ async function initAction(options) {
805
864
  // Add any additional advanced options here
806
865
  } : {}
807
866
  },
808
- [ToolName2.ContextAnalyzer]: {
867
+ [ToolName3.ContextAnalyzer]: {
809
868
  // Smart defaults are generated dynamically based on repository size
810
869
  // These are fallback values for when smart defaults can't be calculated
811
870
  maxContextBudget: 25e3,
@@ -822,7 +881,7 @@ async function initAction(options) {
822
881
  includeNodeModules: false
823
882
  // Whether to include node_modules in analysis
824
883
  },
825
- [ToolName2.NamingConsistency]: {
884
+ [ToolName3.NamingConsistency]: {
826
885
  // Core checks
827
886
  checkNaming: true,
828
887
  // Check naming conventions and quality
@@ -869,7 +928,7 @@ async function initAction(options) {
869
928
  ],
870
929
  ...options.full ? { disableChecks: [] } : {}
871
930
  },
872
- [ToolName2.AiSignalClarity]: {
931
+ [ToolName3.AiSignalClarity]: {
873
932
  // All signal clarity checks enabled by default
874
933
  checkMagicLiterals: true,
875
934
  // Detect magic numbers and strings
@@ -888,7 +947,7 @@ async function initAction(options) {
888
947
  checkLargeFiles: true
889
948
  // Detect files that are too large
890
949
  },
891
- [ToolName2.AgentGrounding]: {
950
+ [ToolName3.AgentGrounding]: {
892
951
  // Structure clarity
893
952
  maxRecommendedDepth: 4,
894
953
  // Max directory depth before flagging as "too deep"
@@ -899,7 +958,7 @@ async function initAction(options) {
899
958
  additionalVagueNames: ["stuff", "misc", "temp", "test"]
900
959
  // Custom vague file names
901
960
  },
902
- [ToolName2.TestabilityIndex]: {
961
+ [ToolName3.TestabilityIndex]: {
903
962
  // Coverage thresholds
904
963
  minCoverageRatio: 0.3,
905
964
  // Minimum acceptable test/source ratio
@@ -909,19 +968,19 @@ async function initAction(options) {
909
968
  maxDepth: 10
910
969
  // Maximum scan depth
911
970
  },
912
- [ToolName2.DocDrift]: {
971
+ [ToolName3.DocDrift]: {
913
972
  // Drift detection
914
973
  maxCommits: 50,
915
974
  // Maximum commit distance to check for drift
916
975
  staleMonths: 3
917
976
  // Consider comments older than this as outdated
918
977
  },
919
- [ToolName2.DependencyHealth]: {
978
+ [ToolName3.DependencyHealth]: {
920
979
  // Training cutoff for AI knowledge assessment
921
980
  trainingCutoffYear: 2023
922
981
  // Year cutoff for AI training data
923
982
  },
924
- [ToolName2.ChangeAmplification]: {
983
+ [ToolName3.ChangeAmplification]: {
925
984
  // Change amplification primarily relies on global scan settings
926
985
  // No additional tool-specific configuration required
927
986
  }
@@ -950,35 +1009,36 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
950
1009
  try {
951
1010
  writeFileSync2(filePath, content, "utf8");
952
1011
  console.log(
953
- chalk5.green(`
954
- \u2705 Created default configuration: ${chalk5.bold(fileName)}`)
1012
+ chalk7.green(`
1013
+ \u2705 Created default configuration: ${chalk7.bold(fileName)}`)
955
1014
  );
956
1015
  console.log(
957
- chalk5.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:")
958
1017
  );
959
- console.log(chalk5.white(` $ aiready scan
1018
+ console.log(chalk7.white(` $ aiready scan
960
1019
  `));
961
1020
  } catch (error) {
962
- console.error(chalk5.red(`Failed to write configuration file: ${error}`));
1021
+ console.error(chalk7.red(`Failed to write configuration file: ${error}`));
963
1022
  process.exit(1);
964
1023
  }
965
1024
  }
966
1025
 
967
1026
  // src/commands/patterns.ts
968
- import chalk6 from "chalk";
969
- import { resolve as resolvePath4 } from "path";
1027
+ import chalk8 from "chalk";
970
1028
  import {
971
- loadMergedConfig as loadMergedConfig2,
972
- handleJSONOutput as handleJSONOutput2,
973
1029
  handleCLIError as handleCLIError3,
974
1030
  getElapsedTime,
975
- resolveOutputPath as resolveOutputPath2,
976
- formatToolScore
1031
+ formatToolScore,
1032
+ printTerminalHeader,
1033
+ getTerminalDivider,
1034
+ prepareActionConfig,
1035
+ resolveOutputFormat,
1036
+ formatStandardReport,
1037
+ handleStandardJSONOutput
977
1038
  } from "@aiready/core";
978
1039
  async function patternsAction(directory, options) {
979
- console.log(chalk6.blue("\u{1F50D} Analyzing patterns...\n"));
1040
+ console.log(chalk8.blue("\u{1F50D} Analyzing patterns...\n"));
980
1041
  const startTime = Date.now();
981
- const resolvedDir = resolvePath4(process.cwd(), directory ?? ".");
982
1042
  try {
983
1043
  const useSmartDefaults = !options.fullScan;
984
1044
  const defaults = {
@@ -1007,8 +1067,8 @@ async function patternsAction(directory, options) {
1007
1067
  if (options.minSharedTokens) {
1008
1068
  cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
1009
1069
  }
1010
- const finalOptions = await loadMergedConfig2(
1011
- resolvedDir,
1070
+ const { resolvedDir, finalOptions } = await prepareActionConfig(
1071
+ directory,
1012
1072
  defaults,
1013
1073
  cliOptions
1014
1074
  );
@@ -1022,60 +1082,53 @@ async function patternsAction(directory, options) {
1022
1082
  if (options.score) {
1023
1083
  patternScore = calculatePatternScore(duplicates, results.length);
1024
1084
  }
1025
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1026
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1085
+ const { format: outputFormat, file: userOutputFile } = resolveOutputFormat(
1086
+ options,
1087
+ finalOptions
1088
+ );
1027
1089
  if (outputFormat === "json") {
1028
- const outputData = {
1090
+ const outputData = formatStandardReport({
1029
1091
  results,
1030
- summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1031
- ...patternScore && { scoring: patternScore }
1032
- };
1033
- const outputPath = resolveOutputPath2(
1034
- userOutputFile,
1035
- `aiready-report-${getReportTimestamp()}.json`,
1036
- resolvedDir
1037
- );
1038
- handleJSONOutput2(
1092
+ summary,
1093
+ elapsedTime,
1094
+ score: patternScore
1095
+ });
1096
+ handleStandardJSONOutput({
1039
1097
  outputData,
1040
- outputPath,
1041
- `\u2705 Results saved to ${outputPath}`
1042
- );
1098
+ outputFile: userOutputFile,
1099
+ resolvedDir
1100
+ });
1043
1101
  } else {
1044
- const terminalWidth = process.stdout.columns || 80;
1045
- const dividerWidth = Math.min(60, terminalWidth - 2);
1046
- const divider = "\u2501".repeat(dividerWidth);
1047
- console.log(chalk6.cyan(divider));
1048
- console.log(chalk6.bold.white(" PATTERN ANALYSIS SUMMARY"));
1049
- console.log(chalk6.cyan(divider) + "\n");
1102
+ printTerminalHeader("PATTERN ANALYSIS SUMMARY");
1050
1103
  console.log(
1051
- chalk6.white(`\u{1F4C1} Files analyzed: ${chalk6.bold(results.length)}`)
1104
+ chalk8.white(`\u{1F4C1} Files analyzed: ${chalk8.bold(results.length)}`)
1052
1105
  );
1053
1106
  console.log(
1054
- chalk6.yellow(
1055
- `\u26A0 Duplicate patterns found: ${chalk6.bold(summary.totalPatterns)}`
1107
+ chalk8.yellow(
1108
+ `\u26A0 Duplicate patterns found: ${chalk8.bold(summary.totalPatterns)}`
1056
1109
  )
1057
1110
  );
1058
1111
  console.log(
1059
- chalk6.red(
1060
- `\u{1F4B0} Token cost (wasted): ${chalk6.bold(summary.totalTokenCost.toLocaleString())}`
1112
+ chalk8.red(
1113
+ `\u{1F4B0} Token cost (wasted): ${chalk8.bold(summary.totalTokenCost.toLocaleString())}`
1061
1114
  )
1062
1115
  );
1063
1116
  console.log(
1064
- chalk6.gray(`\u23F1 Analysis time: ${chalk6.bold(elapsedTime + "s")}`)
1117
+ chalk8.gray(`\u23F1 Analysis time: ${chalk8.bold(elapsedTime + "s")}`)
1065
1118
  );
1066
1119
  const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
1067
1120
  if (sortedTypes.length > 0) {
1068
- console.log(chalk6.cyan("\n" + divider));
1069
- console.log(chalk6.bold.white(" PATTERNS BY TYPE"));
1070
- console.log(chalk6.cyan(divider) + "\n");
1121
+ console.log("\n" + getTerminalDivider());
1122
+ console.log(chalk8.bold.white(" PATTERNS BY TYPE"));
1123
+ console.log(getTerminalDivider() + "\n");
1071
1124
  sortedTypes.forEach(([type, count]) => {
1072
- console.log(` ${chalk6.white(type.padEnd(15))} ${chalk6.bold(count)}`);
1125
+ console.log(` ${chalk8.white(type.padEnd(15))} ${chalk8.bold(count)}`);
1073
1126
  });
1074
1127
  }
1075
1128
  if (summary.totalPatterns > 0 && duplicates.length > 0) {
1076
- console.log(chalk6.cyan("\n" + divider));
1077
- console.log(chalk6.bold.white(" TOP DUPLICATE PATTERNS"));
1078
- console.log(chalk6.cyan(divider) + "\n");
1129
+ console.log("\n" + getTerminalDivider());
1130
+ console.log(chalk8.bold.white(" TOP DUPLICATE PATTERNS"));
1131
+ console.log(getTerminalDivider() + "\n");
1079
1132
  const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
1080
1133
  topDuplicates.forEach((dup) => {
1081
1134
  const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
@@ -1083,25 +1136,25 @@ async function patternsAction(directory, options) {
1083
1136
  const file1Name = dup.file1.split("/").pop() || dup.file1;
1084
1137
  const file2Name = dup.file2.split("/").pop() || dup.file2;
1085
1138
  console.log(
1086
- `${severityIcon} ${severity}: ${chalk6.bold(file1Name)} \u2194 ${chalk6.bold(file2Name)}`
1139
+ `${severityIcon} ${severity}: ${chalk8.bold(file1Name)} \u2194 ${chalk8.bold(file2Name)}`
1087
1140
  );
1088
1141
  console.log(
1089
- ` Similarity: ${chalk6.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk6.bold(dup.tokenCost.toLocaleString())} tokens each`
1142
+ ` Similarity: ${chalk8.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk8.bold(dup.tokenCost.toLocaleString())} tokens each`
1090
1143
  );
1091
1144
  console.log(
1092
- ` Lines: ${chalk6.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk6.cyan(dup.line2 + "-" + dup.endLine2)}
1145
+ ` Lines: ${chalk8.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk8.cyan(dup.line2 + "-" + dup.endLine2)}
1093
1146
  `
1094
1147
  );
1095
1148
  });
1096
1149
  } else {
1097
1150
  console.log(
1098
- chalk6.green("\n\u2728 Great! No duplicate patterns detected.\n")
1151
+ chalk8.green("\n\u2728 Great! No duplicate patterns detected.\n")
1099
1152
  );
1100
1153
  }
1101
1154
  if (patternScore) {
1102
- console.log(chalk6.cyan(divider));
1103
- console.log(chalk6.bold.white(" AI READINESS SCORE (Patterns)"));
1104
- console.log(chalk6.cyan(divider) + "\n");
1155
+ console.log(getTerminalDivider());
1156
+ console.log(chalk8.bold.white(" AI READINESS SCORE (Patterns)"));
1157
+ console.log(getTerminalDivider() + "\n");
1105
1158
  console.log(formatToolScore(patternScore));
1106
1159
  console.log();
1107
1160
  }
@@ -1110,7 +1163,7 @@ async function patternsAction(directory, options) {
1110
1163
  handleCLIError3(error, "Pattern analysis");
1111
1164
  }
1112
1165
  }
1113
- var patternsHelpText = `
1166
+ var PATTERNS_HELP_TEXT = `
1114
1167
  EXAMPLES:
1115
1168
  $ aiready patterns # Default analysis
1116
1169
  $ aiready patterns --similarity 0.6 # Stricter matching
@@ -1118,20 +1171,19 @@ EXAMPLES:
1118
1171
  `;
1119
1172
 
1120
1173
  // src/commands/context.ts
1121
- import chalk7 from "chalk";
1122
- import { resolve as resolvePath5 } from "path";
1174
+ import chalk9 from "chalk";
1123
1175
  import {
1124
- loadMergedConfig as loadMergedConfig3,
1125
- handleJSONOutput as handleJSONOutput3,
1126
1176
  handleCLIError as handleCLIError4,
1127
1177
  getElapsedTime as getElapsedTime2,
1128
- resolveOutputPath as resolveOutputPath3,
1129
- formatToolScore as formatToolScore2
1178
+ formatToolScore as formatToolScore2,
1179
+ prepareActionConfig as prepareActionConfig2,
1180
+ resolveOutputFormat as resolveOutputFormat2,
1181
+ formatStandardReport as formatStandardReport2,
1182
+ handleStandardJSONOutput as handleStandardJSONOutput2
1130
1183
  } from "@aiready/core";
1131
1184
  async function contextAction(directory, options) {
1132
- console.log(chalk7.blue("\u{1F9E0} Analyzing context costs...\n"));
1185
+ console.log(chalk9.blue("\u{1F9E0} Analyzing context costs...\n"));
1133
1186
  const startTime = Date.now();
1134
- const resolvedDir = resolvePath5(process.cwd(), directory ?? ".");
1135
1187
  try {
1136
1188
  const defaults = {
1137
1189
  maxDepth: 5,
@@ -1143,7 +1195,7 @@ async function contextAction(directory, options) {
1143
1195
  file: void 0
1144
1196
  }
1145
1197
  };
1146
- const baseOptions = await loadMergedConfig3(resolvedDir, defaults, {
1198
+ const { resolvedDir, finalOptions: baseOptions } = await prepareActionConfig2(directory, defaults, {
1147
1199
  maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
1148
1200
  maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
1149
1201
  include: options.include?.split(","),
@@ -1175,107 +1227,105 @@ async function contextAction(directory, options) {
1175
1227
  if (options.score) {
1176
1228
  contextScore = calculateContextScore(summary);
1177
1229
  }
1178
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1179
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1230
+ const { format: outputFormat, file: userOutputFile } = resolveOutputFormat2(
1231
+ options,
1232
+ finalOptions
1233
+ );
1180
1234
  if (outputFormat === "json") {
1181
- const outputData = {
1235
+ const outputData = formatStandardReport2({
1182
1236
  results,
1183
- summary: { ...summary, executionTime: parseFloat(elapsedTime) },
1184
- ...contextScore && { scoring: contextScore }
1185
- };
1186
- const outputPath = resolveOutputPath3(
1187
- userOutputFile,
1188
- `aiready-report-${getReportTimestamp()}.json`,
1189
- resolvedDir
1190
- );
1191
- handleJSONOutput3(
1237
+ summary,
1238
+ elapsedTime,
1239
+ score: contextScore
1240
+ });
1241
+ handleStandardJSONOutput2({
1192
1242
  outputData,
1193
- outputPath,
1194
- `\u2705 Results saved to ${outputPath}`
1195
- );
1243
+ outputFile: userOutputFile,
1244
+ resolvedDir
1245
+ });
1196
1246
  } else {
1197
1247
  const terminalWidth = process.stdout.columns ?? 80;
1198
1248
  const dividerWidth = Math.min(60, terminalWidth - 2);
1199
1249
  const divider = "\u2501".repeat(dividerWidth);
1200
- console.log(chalk7.cyan(divider));
1201
- console.log(chalk7.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1202
- console.log(chalk7.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");
1203
1253
  console.log(
1204
- chalk7.white(`\u{1F4C1} Files analyzed: ${chalk7.bold(summary.totalFiles)}`)
1254
+ chalk9.white(`\u{1F4C1} Files analyzed: ${chalk9.bold(summary.totalFiles)}`)
1205
1255
  );
1206
1256
  console.log(
1207
- chalk7.white(
1208
- `\u{1F4CA} Total tokens: ${chalk7.bold(summary.totalTokens.toLocaleString())}`
1257
+ chalk9.white(
1258
+ `\u{1F4CA} Total tokens: ${chalk9.bold(summary.totalTokens.toLocaleString())}`
1209
1259
  )
1210
1260
  );
1211
1261
  console.log(
1212
- chalk7.yellow(
1213
- `\u{1F4B0} Avg context budget: ${chalk7.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1262
+ chalk9.yellow(
1263
+ `\u{1F4B0} Avg context budget: ${chalk9.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1214
1264
  )
1215
1265
  );
1216
1266
  console.log(
1217
- chalk7.white(`\u23F1 Analysis time: ${chalk7.bold(elapsedTime + "s")}
1267
+ chalk9.white(`\u23F1 Analysis time: ${chalk9.bold(elapsedTime + "s")}
1218
1268
  `)
1219
1269
  );
1220
1270
  const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
1221
1271
  if (totalIssues > 0) {
1222
- console.log(chalk7.bold("\u26A0\uFE0F Issues Found:\n"));
1272
+ console.log(chalk9.bold("\u26A0\uFE0F Issues Found:\n"));
1223
1273
  if (summary.criticalIssues > 0) {
1224
1274
  console.log(
1225
- chalk7.red(` \u{1F534} Critical: ${chalk7.bold(summary.criticalIssues)}`)
1275
+ chalk9.red(` \u{1F534} Critical: ${chalk9.bold(summary.criticalIssues)}`)
1226
1276
  );
1227
1277
  }
1228
1278
  if (summary.majorIssues > 0) {
1229
1279
  console.log(
1230
- chalk7.yellow(` \u{1F7E1} Major: ${chalk7.bold(summary.majorIssues)}`)
1280
+ chalk9.yellow(` \u{1F7E1} Major: ${chalk9.bold(summary.majorIssues)}`)
1231
1281
  );
1232
1282
  }
1233
1283
  if (summary.minorIssues > 0) {
1234
1284
  console.log(
1235
- chalk7.blue(` \u{1F535} Minor: ${chalk7.bold(summary.minorIssues)}`)
1285
+ chalk9.blue(` \u{1F535} Minor: ${chalk9.bold(summary.minorIssues)}`)
1236
1286
  );
1237
1287
  }
1238
1288
  console.log(
1239
- chalk7.green(
1289
+ chalk9.green(
1240
1290
  `
1241
- \u{1F4A1} Potential savings: ${chalk7.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1291
+ \u{1F4A1} Potential savings: ${chalk9.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1242
1292
  `
1243
1293
  )
1244
1294
  );
1245
1295
  } else {
1246
- console.log(chalk7.green("\u2705 No significant issues found!\n"));
1296
+ console.log(chalk9.green("\u2705 No significant issues found!\n"));
1247
1297
  }
1248
1298
  if (summary.deepFiles.length > 0) {
1249
- console.log(chalk7.bold("\u{1F4CF} Deep Import Chains:\n"));
1299
+ console.log(chalk9.bold("\u{1F4CF} Deep Import Chains:\n"));
1250
1300
  console.log(
1251
- chalk7.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1301
+ chalk9.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1252
1302
  );
1253
1303
  console.log(
1254
- chalk7.gray(` Maximum depth: ${summary.maxImportDepth}
1304
+ chalk9.gray(` Maximum depth: ${summary.maxImportDepth}
1255
1305
  `)
1256
1306
  );
1257
1307
  summary.deepFiles.slice(0, 10).forEach((item) => {
1258
1308
  const fileName = item.file.split("/").slice(-2).join("/");
1259
1309
  console.log(
1260
- ` ${chalk7.cyan("\u2192")} ${chalk7.white(fileName)} ${chalk7.dim(`(depth: ${item.depth})`)}`
1310
+ ` ${chalk9.cyan("\u2192")} ${chalk9.white(fileName)} ${chalk9.dim(`(depth: ${item.depth})`)}`
1261
1311
  );
1262
1312
  });
1263
1313
  console.log();
1264
1314
  }
1265
1315
  if (summary.fragmentedModules.length > 0) {
1266
- console.log(chalk7.bold("\u{1F9E9} Fragmented Modules:\n"));
1316
+ console.log(chalk9.bold("\u{1F9E9} Fragmented Modules:\n"));
1267
1317
  console.log(
1268
- chalk7.gray(
1318
+ chalk9.gray(
1269
1319
  ` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
1270
1320
  `
1271
1321
  )
1272
1322
  );
1273
1323
  summary.fragmentedModules.slice(0, 10).forEach((module) => {
1274
1324
  console.log(
1275
- ` ${chalk7.yellow("\u25CF")} ${chalk7.white(module.domain)} - ${chalk7.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`)}`
1276
1326
  );
1277
1327
  console.log(
1278
- chalk7.dim(
1328
+ chalk9.dim(
1279
1329
  ` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
1280
1330
  )
1281
1331
  );
@@ -1283,9 +1333,9 @@ async function contextAction(directory, options) {
1283
1333
  console.log();
1284
1334
  }
1285
1335
  if (summary.lowCohesionFiles.length > 0) {
1286
- console.log(chalk7.bold("\u{1F500} Low Cohesion Files:\n"));
1336
+ console.log(chalk9.bold("\u{1F500} Low Cohesion Files:\n"));
1287
1337
  console.log(
1288
- chalk7.gray(
1338
+ chalk9.gray(
1289
1339
  ` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
1290
1340
  `
1291
1341
  )
@@ -1293,28 +1343,28 @@ async function contextAction(directory, options) {
1293
1343
  summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
1294
1344
  const fileName = item.file.split("/").slice(-2).join("/");
1295
1345
  const scorePercent = (item.score * 100).toFixed(0);
1296
- const color = item.score < 0.4 ? chalk7.red : chalk7.yellow;
1346
+ const color = item.score < 0.4 ? chalk9.red : chalk9.yellow;
1297
1347
  console.log(
1298
- ` ${color("\u25CB")} ${chalk7.white(fileName)} ${chalk7.dim(`(${scorePercent}% cohesion)`)}`
1348
+ ` ${color("\u25CB")} ${chalk9.white(fileName)} ${chalk9.dim(`(${scorePercent}% cohesion)`)}`
1299
1349
  );
1300
1350
  });
1301
1351
  console.log();
1302
1352
  }
1303
1353
  if (summary.topExpensiveFiles.length > 0) {
1304
- console.log(chalk7.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1354
+ console.log(chalk9.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1305
1355
  summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
1306
1356
  const fileName = item.file.split("/").slice(-2).join("/");
1307
- const severityColor = item.severity === "critical" ? chalk7.red : item.severity === "major" ? chalk7.yellow : chalk7.blue;
1357
+ const severityColor = item.severity === "critical" ? chalk9.red : item.severity === "major" ? chalk9.yellow : chalk9.blue;
1308
1358
  console.log(
1309
- ` ${severityColor("\u25CF")} ${chalk7.white(fileName)} ${chalk7.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1359
+ ` ${severityColor("\u25CF")} ${chalk9.white(fileName)} ${chalk9.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1310
1360
  );
1311
1361
  });
1312
1362
  console.log();
1313
1363
  }
1314
1364
  if (contextScore) {
1315
- console.log(chalk7.cyan(divider));
1316
- console.log(chalk7.bold.white(" AI READINESS SCORE (Context)"));
1317
- console.log(chalk7.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");
1318
1368
  console.log(formatToolScore2(contextScore));
1319
1369
  console.log();
1320
1370
  }
@@ -1325,21 +1375,21 @@ async function contextAction(directory, options) {
1325
1375
  }
1326
1376
 
1327
1377
  // src/commands/consistency.ts
1328
- import chalk8 from "chalk";
1378
+ import chalk10 from "chalk";
1329
1379
  import { writeFileSync as writeFileSync3 } from "fs";
1330
- import { resolve as resolvePath6 } from "path";
1331
1380
  import {
1332
- loadMergedConfig as loadMergedConfig4,
1333
- handleJSONOutput as handleJSONOutput4,
1334
1381
  handleCLIError as handleCLIError5,
1335
1382
  getElapsedTime as getElapsedTime3,
1336
- resolveOutputPath as resolveOutputPath4,
1337
- 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
1338
1389
  } from "@aiready/core";
1339
1390
  async function consistencyAction(directory, options) {
1340
- console.log(chalk8.blue("\u{1F50D} Analyzing consistency...\n"));
1391
+ console.log(chalk10.blue("\u{1F50D} Analyzing consistency...\n"));
1341
1392
  const startTime = Date.now();
1342
- const resolvedDir = resolvePath6(process.cwd(), directory ?? ".");
1343
1393
  try {
1344
1394
  const defaults = {
1345
1395
  checkNaming: true,
@@ -1352,13 +1402,17 @@ async function consistencyAction(directory, options) {
1352
1402
  file: void 0
1353
1403
  }
1354
1404
  };
1355
- const finalOptions = await loadMergedConfig4(resolvedDir, defaults, {
1356
- checkNaming: options.naming !== false,
1357
- checkPatterns: options.patterns !== false,
1358
- minSeverity: options.minSeverity,
1359
- include: options.include?.split(","),
1360
- exclude: options.exclude?.split(",")
1361
- });
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
+ );
1362
1416
  const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
1363
1417
  const report = await analyzeConsistency(finalOptions);
1364
1418
  const elapsedTime = getElapsedTime3(startTime);
@@ -1370,52 +1424,47 @@ async function consistencyAction(directory, options) {
1370
1424
  report.summary.filesAnalyzed
1371
1425
  );
1372
1426
  }
1373
- const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1374
- const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1427
+ const { format: outputFormat, file: userOutputFile } = resolveOutputFormat3(
1428
+ options,
1429
+ finalOptions
1430
+ );
1375
1431
  if (outputFormat === "json") {
1376
- const outputData = {
1377
- ...report,
1378
- summary: {
1379
- ...report.summary,
1380
- executionTime: parseFloat(elapsedTime)
1381
- },
1382
- ...consistencyScore && { scoring: consistencyScore }
1383
- };
1384
- const outputPath = resolveOutputPath4(
1385
- userOutputFile,
1386
- `aiready-report-${getReportTimestamp()}.json`,
1387
- resolvedDir
1388
- );
1389
- handleJSONOutput4(
1432
+ const outputData = formatStandardReport3({
1433
+ report,
1434
+ summary: report.summary,
1435
+ elapsedTime,
1436
+ score: consistencyScore
1437
+ });
1438
+ handleStandardJSONOutput3({
1390
1439
  outputData,
1391
- outputPath,
1392
- `\u2705 Results saved to ${outputPath}`
1393
- );
1440
+ outputFile: userOutputFile,
1441
+ resolvedDir
1442
+ });
1394
1443
  } else if (outputFormat === "markdown") {
1395
1444
  const markdown = generateMarkdownReport(report, elapsedTime);
1396
- const outputPath = resolveOutputPath4(
1445
+ const outputPath = resolveOutputPath2(
1397
1446
  userOutputFile,
1398
1447
  `aiready-report-${getReportTimestamp()}.md`,
1399
1448
  resolvedDir
1400
1449
  );
1401
1450
  writeFileSync3(outputPath, markdown);
1402
- console.log(chalk8.green(`\u2705 Report saved to ${outputPath}`));
1451
+ console.log(chalk10.green(`\u2705 Report saved to ${outputPath}`));
1403
1452
  } else {
1404
- console.log(chalk8.bold("\n\u{1F4CA} Summary\n"));
1453
+ console.log(chalk10.bold("\n\u{1F4CA} Summary\n"));
1405
1454
  console.log(
1406
- `Files Analyzed: ${chalk8.cyan(report.summary.filesAnalyzed)}`
1455
+ `Files Analyzed: ${chalk10.cyan(report.summary.filesAnalyzed)}`
1407
1456
  );
1408
- console.log(`Total Issues: ${chalk8.yellow(report.summary.totalIssues)}`);
1409
- console.log(` Naming: ${chalk8.yellow(report.summary.namingIssues)}`);
1410
- console.log(` Patterns: ${chalk8.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)}`);
1411
1460
  console.log(
1412
- ` Architecture: ${chalk8.yellow(report.summary.architectureIssues ?? 0)}`
1461
+ ` Architecture: ${chalk10.yellow(report.summary.architectureIssues ?? 0)}`
1413
1462
  );
1414
- console.log(`Analysis Time: ${chalk8.gray(elapsedTime + "s")}
1463
+ console.log(`Analysis Time: ${chalk10.gray(elapsedTime + "s")}
1415
1464
  `);
1416
1465
  if (report.summary.totalIssues === 0) {
1417
1466
  console.log(
1418
- chalk8.green(
1467
+ chalk10.green(
1419
1468
  "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
1420
1469
  )
1421
1470
  );
@@ -1427,20 +1476,20 @@ async function consistencyAction(directory, options) {
1427
1476
  (r) => r.issues.some((i) => i.category === "patterns")
1428
1477
  );
1429
1478
  if (namingResults.length > 0) {
1430
- console.log(chalk8.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1479
+ console.log(chalk10.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1431
1480
  let shown = 0;
1432
- for (const result of namingResults) {
1481
+ for (const namingFileResult of namingResults) {
1433
1482
  if (shown >= 5) break;
1434
- for (const issue of result.issues) {
1483
+ for (const issue of namingFileResult.issues) {
1435
1484
  if (shown >= 5) break;
1436
- const severityColor = issue.severity === "critical" ? chalk8.red : issue.severity === "major" ? chalk8.yellow : issue.severity === "minor" ? chalk8.blue : chalk8.gray;
1485
+ const severityColor = issue.severity === "critical" ? chalk10.red : issue.severity === "major" ? chalk10.yellow : issue.severity === "minor" ? chalk10.blue : chalk10.gray;
1437
1486
  console.log(
1438
- `${severityColor(issue.severity.toUpperCase())} ${chalk8.dim(`${issue.location.file}:${issue.location.line}`)}`
1487
+ `${severityColor(issue.severity.toUpperCase())} ${chalk10.dim(`${issue.location.file}:${issue.location.line}`)}`
1439
1488
  );
1440
1489
  console.log(` ${issue.message}`);
1441
1490
  if (issue.suggestion) {
1442
1491
  console.log(
1443
- ` ${chalk8.dim("\u2192")} ${chalk8.italic(issue.suggestion)}`
1492
+ ` ${chalk10.dim("\u2192")} ${chalk10.italic(issue.suggestion)}`
1444
1493
  );
1445
1494
  }
1446
1495
  console.log();
@@ -1449,25 +1498,25 @@ async function consistencyAction(directory, options) {
1449
1498
  }
1450
1499
  const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1451
1500
  if (remaining > 0) {
1452
- console.log(chalk8.dim(` ... and ${remaining} more issues
1501
+ console.log(chalk10.dim(` ... and ${remaining} more issues
1453
1502
  `));
1454
1503
  }
1455
1504
  }
1456
1505
  if (patternResults.length > 0) {
1457
- console.log(chalk8.bold("\u{1F504} Pattern Issues\n"));
1506
+ console.log(chalk10.bold("\u{1F504} Pattern Issues\n"));
1458
1507
  let shown = 0;
1459
- for (const result of patternResults) {
1508
+ for (const patternFileResult of patternResults) {
1460
1509
  if (shown >= 5) break;
1461
- for (const issue of result.issues) {
1510
+ for (const issue of patternFileResult.issues) {
1462
1511
  if (shown >= 5) break;
1463
- const severityColor = issue.severity === "critical" ? chalk8.red : issue.severity === "major" ? chalk8.yellow : issue.severity === "minor" ? chalk8.blue : chalk8.gray;
1512
+ const severityColor = issue.severity === "critical" ? chalk10.red : issue.severity === "major" ? chalk10.yellow : issue.severity === "minor" ? chalk10.blue : chalk10.gray;
1464
1513
  console.log(
1465
- `${severityColor(issue.severity.toUpperCase())} ${chalk8.dim(`${issue.location.file}:${issue.location.line}`)}`
1514
+ `${severityColor(issue.severity.toUpperCase())} ${chalk10.dim(`${issue.location.file}:${issue.location.line}`)}`
1466
1515
  );
1467
1516
  console.log(` ${issue.message}`);
1468
1517
  if (issue.suggestion) {
1469
1518
  console.log(
1470
- ` ${chalk8.dim("\u2192")} ${chalk8.italic(issue.suggestion)}`
1519
+ ` ${chalk10.dim("\u2192")} ${chalk10.italic(issue.suggestion)}`
1471
1520
  );
1472
1521
  }
1473
1522
  console.log();
@@ -1476,12 +1525,12 @@ async function consistencyAction(directory, options) {
1476
1525
  }
1477
1526
  const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1478
1527
  if (remaining > 0) {
1479
- console.log(chalk8.dim(` ... and ${remaining} more issues
1528
+ console.log(chalk10.dim(` ... and ${remaining} more issues
1480
1529
  `));
1481
1530
  }
1482
1531
  }
1483
1532
  if (report.recommendations.length > 0) {
1484
- console.log(chalk8.bold("\u{1F4A1} Recommendations\n"));
1533
+ console.log(chalk10.bold("\u{1F4A1} Recommendations\n"));
1485
1534
  report.recommendations.forEach((rec, i) => {
1486
1535
  console.log(`${i + 1}. ${rec}`);
1487
1536
  });
@@ -1489,7 +1538,7 @@ async function consistencyAction(directory, options) {
1489
1538
  }
1490
1539
  }
1491
1540
  if (consistencyScore) {
1492
- console.log(chalk8.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1541
+ console.log(chalk10.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1493
1542
  console.log(formatToolScore3(consistencyScore));
1494
1543
  console.log();
1495
1544
  }
@@ -1500,27 +1549,27 @@ async function consistencyAction(directory, options) {
1500
1549
  }
1501
1550
 
1502
1551
  // src/commands/visualize.ts
1503
- import chalk9 from "chalk";
1552
+ import chalk11 from "chalk";
1504
1553
  import { writeFileSync as writeFileSync4, readFileSync as readFileSync3, existsSync as existsSync3, copyFileSync } from "fs";
1505
- import { resolve as resolvePath7 } from "path";
1554
+ import { resolve as resolvePath5 } from "path";
1506
1555
  import { spawn } from "child_process";
1507
1556
  import { handleCLIError as handleCLIError6 } from "@aiready/core";
1508
1557
  import { generateHTML, findLatestReport as findLatestReport2 } from "@aiready/core";
1509
1558
  async function visualizeAction(directory, options) {
1510
1559
  try {
1511
- const dirPath = resolvePath7(process.cwd(), directory ?? ".");
1512
- 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;
1513
1562
  if (!reportPath || !existsSync3(reportPath)) {
1514
1563
  const latestScan = findLatestReport2(dirPath);
1515
1564
  if (latestScan) {
1516
1565
  reportPath = latestScan;
1517
1566
  console.log(
1518
- chalk9.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1567
+ chalk11.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1519
1568
  );
1520
1569
  } else {
1521
- console.error(chalk9.red("\u274C No AI readiness report found"));
1570
+ console.error(chalk11.red("\u274C No AI readiness report found"));
1522
1571
  console.log(
1523
- chalk9.dim(
1572
+ chalk11.dim(
1524
1573
  `
1525
1574
  Generate a report with:
1526
1575
  aiready scan --output json
@@ -1534,7 +1583,7 @@ Or specify a custom report:
1534
1583
  }
1535
1584
  const raw = readFileSync3(reportPath, "utf8");
1536
1585
  const report = JSON.parse(raw);
1537
- const configPath = resolvePath7(dirPath, "aiready.json");
1586
+ const configPath = resolvePath5(dirPath, "aiready.json");
1538
1587
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
1539
1588
  if (existsSync3(configPath)) {
1540
1589
  try {
@@ -1558,7 +1607,7 @@ Or specify a custom report:
1558
1607
  let devServerStarted = false;
1559
1608
  if (useDevMode) {
1560
1609
  try {
1561
- const localWebDir = resolvePath7(dirPath, "packages/visualizer");
1610
+ const localWebDir = resolvePath5(dirPath, "packages/visualizer");
1562
1611
  let webDir = "";
1563
1612
  let visualizerAvailable = false;
1564
1613
  if (existsSync3(localWebDir)) {
@@ -1566,8 +1615,8 @@ Or specify a custom report:
1566
1615
  visualizerAvailable = true;
1567
1616
  } else {
1568
1617
  const nodemodulesLocations = [
1569
- resolvePath7(dirPath, "node_modules", "@aiready", "visualizer"),
1570
- resolvePath7(
1618
+ resolvePath5(dirPath, "node_modules", "@aiready", "visualizer"),
1619
+ resolvePath5(
1571
1620
  process.cwd(),
1572
1621
  "node_modules",
1573
1622
  "@aiready",
@@ -1577,14 +1626,14 @@ Or specify a custom report:
1577
1626
  let currentDir = dirPath;
1578
1627
  while (currentDir !== "/" && currentDir !== ".") {
1579
1628
  nodemodulesLocations.push(
1580
- resolvePath7(currentDir, "node_modules", "@aiready", "visualizer")
1629
+ resolvePath5(currentDir, "node_modules", "@aiready", "visualizer")
1581
1630
  );
1582
- const parent = resolvePath7(currentDir, "..");
1631
+ const parent = resolvePath5(currentDir, "..");
1583
1632
  if (parent === currentDir) break;
1584
1633
  currentDir = parent;
1585
1634
  }
1586
1635
  for (const location of nodemodulesLocations) {
1587
- if (existsSync3(location) && existsSync3(resolvePath7(location, "package.json"))) {
1636
+ if (existsSync3(location) && existsSync3(resolvePath5(location, "package.json"))) {
1588
1637
  webDir = location;
1589
1638
  visualizerAvailable = true;
1590
1639
  break;
@@ -1593,20 +1642,20 @@ Or specify a custom report:
1593
1642
  if (!visualizerAvailable) {
1594
1643
  try {
1595
1644
  const vizPkgPath = __require.resolve("@aiready/visualizer/package.json");
1596
- webDir = resolvePath7(vizPkgPath, "..");
1645
+ webDir = resolvePath5(vizPkgPath, "..");
1597
1646
  visualizerAvailable = true;
1598
1647
  } catch (err) {
1599
1648
  void err;
1600
1649
  }
1601
1650
  }
1602
1651
  }
1603
- const webViteConfigExists = webDir && existsSync3(resolvePath7(webDir, "web", "vite.config.ts"));
1652
+ const webViteConfigExists = webDir && existsSync3(resolvePath5(webDir, "web", "vite.config.ts"));
1604
1653
  if (visualizerAvailable && webViteConfigExists) {
1605
1654
  const spawnCwd = webDir;
1606
1655
  const { watch } = await import("fs");
1607
1656
  const copyReportToViz = () => {
1608
1657
  try {
1609
- const destPath = resolvePath7(spawnCwd, "web", "report-data.json");
1658
+ const destPath = resolvePath5(spawnCwd, "web", "report-data.json");
1610
1659
  copyFileSync(reportPath, destPath);
1611
1660
  console.log(`\u{1F4CB} Report synced to ${destPath}`);
1612
1661
  } catch (e) {
@@ -1650,19 +1699,19 @@ Or specify a custom report:
1650
1699
  return;
1651
1700
  } else {
1652
1701
  console.log(
1653
- chalk9.yellow(
1702
+ chalk11.yellow(
1654
1703
  "\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
1655
1704
  )
1656
1705
  );
1657
1706
  console.log(
1658
- chalk9.cyan(" Falling back to static HTML generation...\n")
1707
+ chalk11.cyan(" Falling back to static HTML generation...\n")
1659
1708
  );
1660
1709
  useDevMode = false;
1661
1710
  }
1662
1711
  } catch (err) {
1663
1712
  console.error("Failed to start dev server:", err);
1664
1713
  console.log(
1665
- chalk9.cyan(" Falling back to static HTML generation...\n")
1714
+ chalk11.cyan(" Falling back to static HTML generation...\n")
1666
1715
  );
1667
1716
  useDevMode = false;
1668
1717
  }
@@ -1670,9 +1719,9 @@ Or specify a custom report:
1670
1719
  console.log("Generating HTML...");
1671
1720
  const html = generateHTML(graph);
1672
1721
  const defaultOutput = "visualization.html";
1673
- const outPath = resolvePath7(dirPath, options.output ?? defaultOutput);
1722
+ const outPath = resolvePath5(dirPath, options.output ?? defaultOutput);
1674
1723
  writeFileSync4(outPath, html, "utf8");
1675
- console.log(chalk9.green(`\u2705 Visualization written to: ${outPath}`));
1724
+ console.log(chalk11.green(`\u2705 Visualization written to: ${outPath}`));
1676
1725
  if (options.open || options.serve) {
1677
1726
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1678
1727
  if (options.serve) {
@@ -1702,7 +1751,7 @@ Or specify a custom report:
1702
1751
  server.listen(port, () => {
1703
1752
  const addr = `http://localhost:${port}/`;
1704
1753
  console.log(
1705
- chalk9.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1754
+ chalk11.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1706
1755
  );
1707
1756
  spawn(opener, [`"${addr}"`], { shell: true });
1708
1757
  });
@@ -1721,7 +1770,7 @@ Or specify a custom report:
1721
1770
  handleCLIError6(err, "Visualization");
1722
1771
  }
1723
1772
  }
1724
- var visualizeHelpText = `
1773
+ var VISUALIZE_HELP_TEXT = `
1725
1774
  EXAMPLES:
1726
1775
  $ aiready visualize . # Auto-detects latest report, generates HTML
1727
1776
  $ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
@@ -1738,7 +1787,7 @@ NOTES:
1738
1787
  - --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
1739
1788
  When --dev is not available, it falls back to static HTML generation.
1740
1789
  `;
1741
- var visualiseHelpText = `
1790
+ var VISUALISE_HELP_TEXT = `
1742
1791
  EXAMPLES:
1743
1792
  $ aiready visualise . # Auto-detects latest report
1744
1793
  $ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
@@ -1749,14 +1798,14 @@ NOTES:
1749
1798
  `;
1750
1799
 
1751
1800
  // src/commands/shared/standard-tool-actions.ts
1752
- import chalk10 from "chalk";
1801
+ import chalk12 from "chalk";
1753
1802
 
1754
1803
  // src/commands/agent-grounding.ts
1755
- import chalk11 from "chalk";
1804
+ import chalk13 from "chalk";
1756
1805
  import { loadConfig as loadConfig2, mergeConfigWithDefaults as mergeConfigWithDefaults2 } from "@aiready/core";
1757
1806
 
1758
1807
  // src/commands/testability.ts
1759
- import chalk12 from "chalk";
1808
+ import chalk14 from "chalk";
1760
1809
  import { loadConfig as loadConfig3, mergeConfigWithDefaults as mergeConfigWithDefaults3 } from "@aiready/core";
1761
1810
  async function testabilityAction(directory, options) {
1762
1811
  const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
@@ -1781,28 +1830,28 @@ async function testabilityAction(directory, options) {
1781
1830
  "blind-risk": "\u{1F480}"
1782
1831
  };
1783
1832
  const safetyColors = {
1784
- safe: chalk12.green,
1785
- "moderate-risk": chalk12.yellow,
1786
- "high-risk": chalk12.red,
1787
- "blind-risk": chalk12.bgRed.white
1833
+ safe: chalk14.green,
1834
+ "moderate-risk": chalk14.yellow,
1835
+ "high-risk": chalk14.red,
1836
+ "blind-risk": chalk14.bgRed.white
1788
1837
  };
1789
1838
  const safety = report.summary.aiChangeSafetyRating;
1790
1839
  const icon = safetyIcons[safety] ?? "\u2753";
1791
- const color = safetyColors[safety] ?? chalk12.white;
1840
+ const color = safetyColors[safety] ?? chalk14.white;
1792
1841
  console.log(
1793
- ` \u{1F9EA} Testability: ${chalk12.bold(scoring.score + "/100")} (${report.summary.rating})`
1842
+ ` \u{1F9EA} Testability: ${chalk14.bold(scoring.score + "/100")} (${report.summary.rating})`
1794
1843
  );
1795
1844
  console.log(
1796
1845
  ` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
1797
1846
  );
1798
1847
  console.log(
1799
- chalk12.dim(
1848
+ chalk14.dim(
1800
1849
  ` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
1801
1850
  )
1802
1851
  );
1803
1852
  if (safety === "blind-risk") {
1804
1853
  console.log(
1805
- chalk12.red.bold(
1854
+ chalk14.red.bold(
1806
1855
  "\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
1807
1856
  )
1808
1857
  );
@@ -1814,7 +1863,7 @@ async function testabilityAction(directory, options) {
1814
1863
  import { changeAmplificationAction } from "@aiready/change-amplification/dist/cli.js";
1815
1864
 
1816
1865
  // src/commands/bug.ts
1817
- import chalk13 from "chalk";
1866
+ import chalk15 from "chalk";
1818
1867
  import { execSync } from "child_process";
1819
1868
  async function bugAction(message, options) {
1820
1869
  const repoUrl = "https://github.com/caopengau/aiready-cli";
@@ -1832,35 +1881,35 @@ Generated via AIReady CLI 'bug' command.
1832
1881
  Type: ${type}
1833
1882
  `.trim();
1834
1883
  if (options.submit) {
1835
- console.log(chalk13.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
1884
+ console.log(chalk15.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
1836
1885
  try {
1837
1886
  execSync("gh auth status", { stdio: "ignore" });
1838
1887
  const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
1839
1888
  const output = execSync(command, { encoding: "utf8" }).trim();
1840
- console.log(chalk13.green("\u2705 Issue Created Successfully!"));
1841
- console.log(chalk13.cyan(output));
1889
+ console.log(chalk15.green("\u2705 Issue Created Successfully!"));
1890
+ console.log(chalk15.cyan(output));
1842
1891
  return;
1843
1892
  } catch {
1844
- console.error(chalk13.red("\n\u274C Failed to submit via gh CLI."));
1893
+ console.error(chalk15.red("\n\u274C Failed to submit via gh CLI."));
1845
1894
  console.log(
1846
- chalk13.yellow(
1895
+ chalk15.yellow(
1847
1896
  ' Make sure gh is installed and run "gh auth login".\n'
1848
1897
  )
1849
1898
  );
1850
- console.log(chalk13.dim(" Falling back to URL generation..."));
1899
+ console.log(chalk15.dim(" Falling back to URL generation..."));
1851
1900
  }
1852
1901
  }
1853
1902
  const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
1854
1903
  const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
1855
- console.log(chalk13.green("\u{1F680} Issue Draft Prepared!\n"));
1856
- console.log(chalk13.bold("Title: ") + title);
1857
- console.log(chalk13.bold("Type: ") + type);
1858
- console.log(chalk13.bold("\nClick the link below to submit this issue:"));
1859
- console.log(chalk13.cyan(fullUrl));
1860
- console.log(chalk13.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1861
- console.log(chalk13.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."));
1862
1911
  console.log(
1863
- chalk13.dim(
1912
+ chalk15.dim(
1864
1913
  " Please present the URL above to the user so they can finalize the submission."
1865
1914
  )
1866
1915
  );
@@ -1869,19 +1918,19 @@ Type: ${type}
1869
1918
  const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
1870
1919
  const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
1871
1920
  const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
1872
- console.log(chalk13.blue("\u{1F4AC} Feedback & Bug Reports\n"));
1873
- console.log(` Report a Bug: ${chalk13.cyan(bugUrl)}`);
1874
- console.log(` Request a Feature: ${chalk13.cyan(featureUrl)}`);
1875
- console.log(` Suggest a Metric: ${chalk13.cyan(metricUrl)}`);
1876
- console.log(chalk13.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1877
- console.log(chalk13.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:"));
1878
1927
  console.log(
1879
- chalk13.cyan(
1928
+ chalk15.cyan(
1880
1929
  ' aiready bug "your description here" --type bug|feature|metric'
1881
1930
  )
1882
1931
  );
1883
1932
  }
1884
- var bugHelpText = `
1933
+ var BUG_HELP_TEXT = `
1885
1934
  EXAMPLES:
1886
1935
  $ aiready bug # Show general links
1887
1936
  $ aiready bug "Naming check is too slow" # Prepare a pre-filled bug report
@@ -1950,14 +1999,14 @@ program.command("scan").description(
1950
1999
  ).option(
1951
2000
  "--compare-to <path>",
1952
2001
  "Compare results against a previous AIReady report JSON"
1953
- ).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(
1954
2003
  "--ci",
1955
2004
  "CI mode: GitHub Actions annotations, no colors, fail on threshold"
1956
2005
  ).option(
1957
2006
  "--fail-on <level>",
1958
2007
  "Fail on issues: critical, major, any",
1959
2008
  "critical"
1960
- ).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", scanHelpText).action(async (directory, options) => {
2009
+ ).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", SCAN_HELP_TEXT).action(async (directory, options) => {
1961
2010
  await scanAction(directory, options);
1962
2011
  });
1963
2012
  program.command("init").description("Generate a default configuration (aiready.json)").option("-f, --force", "Overwrite existing configuration file").option(
@@ -1976,7 +2025,7 @@ program.command("patterns").description("Detect duplicate code patterns that con
1976
2025
  ).option(
1977
2026
  "--full-scan",
1978
2027
  "Disable smart defaults for comprehensive analysis (slower)"
1979
- ).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", patternsHelpText).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) => {
1980
2029
  await patternsAction(directory, options);
1981
2030
  });
1982
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(
@@ -2012,7 +2061,7 @@ program.command("visualise").description("Alias for visualize (British spelling)
2012
2061
  "--dev",
2013
2062
  "Start Vite dev server (live reload) for interactive development",
2014
2063
  true
2015
- ).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
2064
+ ).addHelpText("after", VISUALISE_HELP_TEXT).action(async (directory, options) => {
2016
2065
  await visualizeAction(directory, options);
2017
2066
  });
2018
2067
  program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
@@ -2030,7 +2079,7 @@ program.command("visualize").description("Generate interactive visualization fro
2030
2079
  "--dev",
2031
2080
  "Start Vite dev server (live reload) for interactive development",
2032
2081
  false
2033
- ).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
2082
+ ).addHelpText("after", VISUALIZE_HELP_TEXT).action(async (directory, options) => {
2034
2083
  await visualizeAction(directory, options);
2035
2084
  });
2036
2085
  program.command("change-amplification").description("Analyze graph metrics for change amplification").argument("[directory]", "Directory to analyze", ".").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)").action(async (directory, options) => {
@@ -2039,10 +2088,10 @@ program.command("change-amplification").description("Analyze graph metrics for c
2039
2088
  program.command("testability").description("Analyze test coverage and AI readiness").argument("[directory]", "Directory to analyze", ".").option("--min-coverage <ratio>", "Minimum acceptable coverage ratio", "0.3").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)").action(async (directory, options) => {
2040
2089
  await testabilityAction(directory, options);
2041
2090
  });
2042
- program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", uploadHelpText).action(async (file, options) => {
2091
+ program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", UPLOAD_HELP_TEXT).action(async (file, options) => {
2043
2092
  await uploadAction(file, options);
2044
2093
  });
2045
- program.command("bug").description("Report a bug or provide feedback (Agent-friendly)").argument("[message]", "Short description of the issue").option("-t, --type <type>", "Issue type: bug, feature, metric", "bug").option("--submit", "Submit the issue directly using the GitHub CLI (gh)").addHelpText("after", bugHelpText).action(async (message, options) => {
2094
+ program.command("bug").description("Report a bug or provide feedback (Agent-friendly)").argument("[message]", "Short description of the issue").option("-t, --type <type>", "Issue type: bug, feature, metric", "bug").option("--submit", "Submit the issue directly using the GitHub CLI (gh)").addHelpText("after", BUG_HELP_TEXT).action(async (message, options) => {
2046
2095
  await bugAction(message, options);
2047
2096
  });
2048
2097
  program.parse();