@aiready/cli 0.14.25 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -25,15 +25,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli.ts
27
27
  var import_commander = require("commander");
28
- var import_fs8 = require("fs");
29
- var import_path7 = require("path");
28
+ var import_fs9 = require("fs");
29
+ var import_path8 = require("path");
30
30
  var import_url = require("url");
31
31
 
32
32
  // src/commands/scan.ts
33
33
  var import_chalk6 = __toESM(require("chalk"));
34
34
  var import_fs4 = require("fs");
35
35
  var import_path4 = require("path");
36
- var import_core9 = require("@aiready/core");
36
+ var import_core10 = require("@aiready/core");
37
37
 
38
38
  // src/utils/index.ts
39
39
  var import_core2 = require("@aiready/core");
@@ -45,8 +45,8 @@ var import_chalk = __toESM(require("chalk"));
45
45
  var import_core = require("@aiready/core");
46
46
  async function warnIfGraphCapExceeded(report, dirPath) {
47
47
  try {
48
- const { loadConfig: loadConfig4 } = await import("@aiready/core");
49
- void loadConfig4;
48
+ const { loadConfig: loadConfig2 } = await import("@aiready/core");
49
+ void loadConfig2;
50
50
  let graphConfig = { maxNodes: 400, maxEdges: 600 };
51
51
  const configPath = (0, import_path.resolve)(dirPath, "aiready.json");
52
52
  if ((0, import_fs.existsSync)(configPath)) {
@@ -409,6 +409,62 @@ var import_core6 = require("@aiready/core");
409
409
  // src/commands/scan-helpers.ts
410
410
  var import_chalk4 = __toESM(require("chalk"));
411
411
  var import_core5 = require("@aiready/core");
412
+ async function executeToolAction(directory, options, config) {
413
+ console.log(import_chalk4.default.blue(`${config.emoji} ${config.label}...
414
+ `));
415
+ const startTime = Date.now();
416
+ try {
417
+ const { resolvedDir, finalOptions: baseOptions } = await (0, import_core5.prepareActionConfig)(
418
+ directory,
419
+ config.defaults,
420
+ config.getCliOptions(options)
421
+ );
422
+ let finalOptions = baseOptions;
423
+ if (config.preAnalyze) {
424
+ finalOptions = await config.preAnalyze(resolvedDir, finalOptions);
425
+ }
426
+ const { analyze, generateSummary, calculateScore } = await config.importTool();
427
+ const results = await analyze(finalOptions);
428
+ const elapsedTime = (0, import_core5.getElapsedTime)(startTime);
429
+ const summary = generateSummary(results);
430
+ let toolScore;
431
+ if (options.score && calculateScore) {
432
+ const resultsAny = results;
433
+ const scoreData = resultsAny.duplicates || resultsAny.issues || results;
434
+ const filesCount = resultsAny.length || resultsAny.summary?.filesAnalyzed || resultsAny.summary?.totalFiles;
435
+ toolScore = calculateScore(scoreData, filesCount);
436
+ }
437
+ const { format: outputFormat, file: userOutputFile } = (0, import_core5.resolveOutputFormat)(
438
+ options,
439
+ finalOptions
440
+ );
441
+ const outputData = (0, import_core5.formatStandardReport)({
442
+ results,
443
+ summary,
444
+ elapsedTime,
445
+ score: toolScore
446
+ });
447
+ if (outputFormat === "json") {
448
+ (0, import_core5.handleStandardJSONOutput)({
449
+ outputData,
450
+ outputFile: userOutputFile,
451
+ resolvedDir
452
+ });
453
+ } else {
454
+ config.renderConsole({
455
+ results,
456
+ summary,
457
+ elapsedTime,
458
+ score: toolScore,
459
+ finalOptions
460
+ });
461
+ }
462
+ return outputData;
463
+ } catch (error) {
464
+ (0, import_core5.handleCLIError)(error, config.label);
465
+ return void 0;
466
+ }
467
+ }
412
468
  function getProfileTools(profile) {
413
469
  switch (profile.toLowerCase()) {
414
470
  case "agentic":
@@ -488,7 +544,8 @@ var SCAN_DEFAULTS = {
488
544
  "testability-index",
489
545
  "doc-drift",
490
546
  "dependency-health",
491
- "change-amplification"
547
+ "change-amplification",
548
+ "contract-enforcement"
492
549
  ],
493
550
  include: void 0,
494
551
  exclude: void 0,
@@ -532,9 +589,9 @@ async function resolveScanConfig(resolvedDir, options) {
532
589
  var import_chalk5 = __toESM(require("chalk"));
533
590
  var import_fs3 = require("fs");
534
591
  var import_path3 = require("path");
535
- var import_core8 = require("@aiready/core");
592
+ var import_core9 = require("@aiready/core");
536
593
 
537
- // src/index.ts
594
+ // src/orchestrator.ts
538
595
  var import_core7 = require("@aiready/core");
539
596
  var TOOL_PACKAGE_MAP = {
540
597
  [import_core7.ToolName.PatternDetect]: "@aiready/pattern-detect",
@@ -546,6 +603,7 @@ var TOOL_PACKAGE_MAP = {
546
603
  [import_core7.ToolName.DocDrift]: "@aiready/doc-drift",
547
604
  [import_core7.ToolName.DependencyHealth]: "@aiready/deps",
548
605
  [import_core7.ToolName.ChangeAmplification]: "@aiready/change-amplification",
606
+ [import_core7.ToolName.ContractEnforcement]: "@aiready/contract-enforcement",
549
607
  // Aliases handled by registry
550
608
  patterns: "@aiready/pattern-detect",
551
609
  duplicates: "@aiready/pattern-detect",
@@ -556,218 +614,261 @@ var TOOL_PACKAGE_MAP = {
556
614
  grounding: "@aiready/agent-grounding",
557
615
  testability: "@aiready/testability",
558
616
  "deps-health": "@aiready/deps",
559
- "change-amp": "@aiready/change-amplification"
617
+ "change-amp": "@aiready/change-amplification",
618
+ contract: "@aiready/contract-enforcement"
560
619
  };
561
- function sanitizeConfigRecursive(obj) {
562
- if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
563
- const sanitized = {};
564
- const infraToStrip = [
565
- "rootDir",
566
- "onProgress",
567
- "progressCallback",
568
- "streamResults",
569
- "batchSize",
570
- "useSmartDefaults"
571
- ];
572
- for (const [key, value] of Object.entries(obj)) {
573
- if (infraToStrip.includes(key)) continue;
574
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
575
- sanitized[key] = sanitizeConfigRecursive(value);
576
- } else {
577
- sanitized[key] = value;
578
- }
620
+ var UnifiedOrchestrator = class {
621
+ /**
622
+ * Initialize orchestrator with a tool registry.
623
+ * Injection pattern helps with testability and AI readiness score.
624
+ */
625
+ constructor(registry = import_core7.ToolRegistry) {
626
+ this.registry = registry;
579
627
  }
580
- return sanitized;
581
- }
582
- function sanitizeToolConfig(config) {
583
- return sanitizeConfigRecursive(config);
584
- }
585
- async function analyzeUnified(options) {
586
- await (0, import_core7.initializeParsers)();
587
- const startTime = Date.now();
588
- const requestedTools = options.tools ?? [
589
- "patterns",
590
- "context",
591
- "consistency"
592
- ];
593
- const result = {
594
- summary: {
595
- totalIssues: 0,
596
- criticalIssues: 0,
597
- // Added as per instruction
598
- majorIssues: 0,
599
- // Added as per instruction
600
- totalFiles: 0,
601
- toolsRun: [],
602
- executionTime: 0,
603
- config: options,
604
- toolConfigs: {}
628
+ /**
629
+ * Deeply sanitizes a configuration object.
630
+ */
631
+ sanitizeConfig(obj) {
632
+ if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
633
+ const sanitized = {};
634
+ const infraToStrip = [
635
+ "rootDir",
636
+ "onProgress",
637
+ "progressCallback",
638
+ "streamResults",
639
+ "batchSize",
640
+ "useSmartDefaults"
641
+ ];
642
+ for (const [key, value] of Object.entries(obj)) {
643
+ if (infraToStrip.includes(key)) continue;
644
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
645
+ sanitized[key] = this.sanitizeConfig(value);
646
+ } else {
647
+ sanitized[key] = value;
648
+ }
605
649
  }
606
- };
607
- for (const toolName of requestedTools) {
608
- let provider = import_core7.ToolRegistry.find(toolName);
609
- if (!provider) {
610
- const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
611
- try {
612
- await import(packageName);
613
- provider = import_core7.ToolRegistry.find(toolName);
614
- if (provider) {
615
- console.log(
616
- `\u2705 Successfully loaded tool provider: ${toolName} from ${packageName}`
617
- );
618
- } else {
650
+ return sanitized;
651
+ }
652
+ /**
653
+ * Performs the unified analysis.
654
+ */
655
+ async analyze(options) {
656
+ await (0, import_core7.initializeParsers)();
657
+ const startTime = Date.now();
658
+ const requestedTools = options.tools ?? [
659
+ "patterns",
660
+ "context",
661
+ "consistency"
662
+ ];
663
+ const result = {
664
+ summary: {
665
+ totalIssues: 0,
666
+ criticalIssues: 0,
667
+ majorIssues: 0,
668
+ totalFiles: 0,
669
+ toolsRun: [],
670
+ executionTime: 0,
671
+ config: options,
672
+ toolConfigs: {}
673
+ }
674
+ };
675
+ for (const toolName of requestedTools) {
676
+ let provider = this.registry.find(toolName);
677
+ if (!provider) {
678
+ const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
679
+ try {
680
+ await import(packageName);
681
+ provider = this.registry.find(toolName);
682
+ } catch (err) {
619
683
  console.log(
620
- `\u26A0\uFE0F Loaded ${packageName} but provider ${toolName} still not found in registry.`
684
+ `\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
685
+ err.message
621
686
  );
622
687
  }
623
- } catch (err) {
624
- console.log(
625
- `\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
626
- err.message
688
+ }
689
+ if (!provider) {
690
+ console.warn(
691
+ `\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
627
692
  );
693
+ continue;
628
694
  }
629
- }
630
- if (!provider) {
631
- console.warn(
632
- `\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
633
- );
634
- continue;
635
- }
636
- try {
637
- const sanitizedOptions = { ...options };
638
- delete sanitizedOptions.onProgress;
639
- delete sanitizedOptions.progressCallback;
640
- const toolOptions = {
641
- rootDir: options.rootDir
642
- // Always include rootDir
643
- };
644
- [...import_core7.GLOBAL_INFRA_OPTIONS, ...import_core7.COMMON_FINE_TUNING_OPTIONS].forEach(
645
- (key) => {
646
- if (key in options && key !== "toolConfigs" && key !== "tools") {
647
- toolOptions[key] = options[key];
695
+ try {
696
+ const toolOptions = {
697
+ rootDir: options.rootDir
698
+ };
699
+ [...import_core7.GLOBAL_INFRA_OPTIONS, ...import_core7.COMMON_FINE_TUNING_OPTIONS].forEach(
700
+ (key) => {
701
+ if (key in options && key !== "toolConfigs" && key !== "tools") {
702
+ toolOptions[key] = options[key];
703
+ }
704
+ }
705
+ );
706
+ if (options.toolConfigs?.[provider.id]) {
707
+ Object.assign(toolOptions, options.toolConfigs[provider.id]);
708
+ } else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
709
+ Object.assign(toolOptions, options.tools[provider.id]);
710
+ }
711
+ toolOptions.onProgress = (processed, total, msg) => {
712
+ if (options.progressCallback) {
713
+ options.progressCallback({
714
+ tool: provider.id,
715
+ processed,
716
+ total,
717
+ message: msg
718
+ });
648
719
  }
720
+ };
721
+ const output = await provider.analyze(toolOptions);
722
+ if (output.metadata) {
723
+ output.metadata.config = this.sanitizeConfig(toolOptions);
649
724
  }
650
- );
651
- if (options.toolConfigs?.[provider.id]) {
652
- Object.assign(toolOptions, options.toolConfigs[provider.id]);
653
- } else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
654
- Object.assign(toolOptions, options.tools[provider.id]);
655
- } else if (options[provider.id]) {
656
- Object.assign(toolOptions, options[provider.id]);
657
- }
658
- toolOptions.onProgress = (processed, total, message) => {
659
725
  if (options.progressCallback) {
660
- options.progressCallback({
661
- tool: provider.id,
662
- processed,
663
- total,
664
- message
665
- });
726
+ options.progressCallback({ tool: provider.id, data: output });
666
727
  }
667
- };
668
- const output = await provider.analyze(toolOptions);
669
- if (output.metadata) {
670
- output.metadata.config = sanitizeToolConfig(toolOptions);
671
- }
672
- if (options.progressCallback) {
673
- options.progressCallback({ tool: provider.id, data: output });
674
- }
675
- result[provider.id] = output;
676
- result.summary.toolsRun.push(provider.id);
677
- if (output.summary?.config) {
678
- result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
679
- output.summary.config
680
- );
681
- } else if (output.metadata?.config) {
682
- result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
683
- output.metadata.config
728
+ result[provider.id] = output;
729
+ result.summary.toolsRun.push(provider.id);
730
+ const toolConfig = output.summary?.config ?? output.metadata?.config ?? toolOptions;
731
+ result.summary.toolConfigs[provider.id] = this.sanitizeConfig(toolConfig);
732
+ const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
733
+ if (toolFiles > result.summary.totalFiles) {
734
+ result.summary.totalFiles = toolFiles;
735
+ }
736
+ const issueCount = output.results.reduce(
737
+ (sum, file) => sum + (file.issues?.length ?? 0),
738
+ 0
684
739
  );
685
- } else {
686
- result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
687
- }
688
- const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
689
- if (toolFiles > result.summary.totalFiles) {
690
- result.summary.totalFiles = toolFiles;
740
+ result.summary.totalIssues += issueCount;
741
+ } catch (err) {
742
+ console.error(`\u274C Error running tool '${provider.id}':`, err);
691
743
  }
692
- const issueCount = output.results.reduce(
693
- (sum, file) => sum + (file.issues?.length ?? 0),
694
- 0
695
- );
696
- result.summary.totalIssues += issueCount;
697
- } catch (err) {
698
- console.error(`\u274C Error running tool '${provider.id}':`, err);
699
744
  }
745
+ result.summary.config = this.sanitizeConfig({
746
+ scan: {
747
+ tools: requestedTools,
748
+ include: options.include,
749
+ exclude: options.exclude
750
+ },
751
+ tools: result.summary.toolConfigs
752
+ });
753
+ result.summary.executionTime = Date.now() - startTime;
754
+ this.applyLegacyKeys(result);
755
+ return result;
700
756
  }
701
- result.summary.config = sanitizeConfigRecursive({
702
- scan: {
703
- tools: requestedTools,
704
- include: options.include,
705
- exclude: options.exclude
706
- },
707
- // Use 'tools' for tool-specific configurations to match AIReadyConfig
708
- tools: result.summary.toolConfigs
709
- });
710
- result.summary.executionTime = Date.now() - startTime;
711
- const keyMappings = {
712
- "pattern-detect": ["patternDetect", "patterns"],
713
- "context-analyzer": ["contextAnalyzer", "context"],
714
- "naming-consistency": ["namingConsistency", "consistency"],
715
- "ai-signal-clarity": ["aiSignalClarity"],
716
- "agent-grounding": ["agentGrounding"],
717
- "testability-index": ["testabilityIndex", "testability"],
718
- "doc-drift": ["docDrift"],
719
- "dependency-health": ["dependencyHealth", "deps"],
720
- "change-amplification": ["changeAmplification"]
721
- };
722
- for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
723
- if (result[kebabKey]) {
724
- for (const alias of aliases) {
725
- result[alias] = result[kebabKey];
757
+ applyLegacyKeys(result) {
758
+ const keyMappings = {
759
+ "pattern-detect": ["patternDetect", "patterns"],
760
+ "context-analyzer": ["contextAnalyzer", "context"],
761
+ "naming-consistency": ["namingConsistency", "consistency"],
762
+ "ai-signal-clarity": ["aiSignalClarity"],
763
+ "agent-grounding": ["agentGrounding"],
764
+ "testability-index": ["testabilityIndex", "testability"],
765
+ "doc-drift": ["docDrift"],
766
+ "dependency-health": ["dependencyHealth", "deps"],
767
+ "change-amplification": ["changeAmplification"],
768
+ "contract-enforcement": ["contractEnforcement", "contract"]
769
+ };
770
+ for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
771
+ if (result[kebabKey]) {
772
+ for (const alias of aliases) {
773
+ result[alias] = result[kebabKey];
774
+ }
726
775
  }
727
776
  }
728
777
  }
729
- return result;
778
+ };
779
+ async function analyzeUnified(options) {
780
+ const orchestrator = new UnifiedOrchestrator(import_core7.ToolRegistry);
781
+ return orchestrator.analyze(options);
730
782
  }
731
- async function scoreUnified(results, options) {
732
- const toolScores = /* @__PURE__ */ new Map();
733
- for (const toolId of results.summary.toolsRun) {
734
- const provider = import_core7.ToolRegistry.get(toolId);
735
- if (!provider) continue;
736
- const output = results[toolId];
737
- if (!output) continue;
738
- try {
739
- const toolScore = provider.score(output, options);
740
- if (!toolScore.tokenBudget) {
741
- if (toolId === import_core7.ToolName.PatternDetect && output.duplicates) {
742
- const wastedTokens = output.duplicates.reduce(
743
- (sum, d) => sum + (d.tokenCost ?? 0),
744
- 0
745
- );
746
- toolScore.tokenBudget = (0, import_core7.calculateTokenBudget)({
747
- totalContextTokens: wastedTokens * 2,
748
- wastedTokens: {
749
- duplication: wastedTokens,
750
- fragmentation: 0,
751
- chattiness: 0
752
- }
753
- });
754
- } else if (toolId === import_core7.ToolName.ContextAnalyzer && output.summary) {
755
- toolScore.tokenBudget = (0, import_core7.calculateTokenBudget)({
756
- totalContextTokens: output.summary.totalTokens,
757
- wastedTokens: {
758
- duplication: 0,
759
- fragmentation: output.summary.totalPotentialSavings ?? 0,
760
- chattiness: 0
761
- }
762
- });
783
+
784
+ // src/scoring-orchestrator.ts
785
+ var import_core8 = require("@aiready/core");
786
+ var ScoringOrchestrator = class {
787
+ /**
788
+ * Initialize scoring orchestrator with a tool registry.
789
+ * Injection pattern helps with testability and AI readiness score.
790
+ */
791
+ constructor(registry = import_core8.ToolRegistry) {
792
+ this.registry = registry;
793
+ }
794
+ /**
795
+ * Calculates scores for all analyzed tools.
796
+ */
797
+ async score(results, options) {
798
+ const toolScores = /* @__PURE__ */ new Map();
799
+ for (const toolId of results.summary.toolsRun) {
800
+ const provider = this.registry.get(toolId);
801
+ if (!provider) continue;
802
+ const output = results[toolId];
803
+ if (!output) continue;
804
+ try {
805
+ const toolScore = provider.score(output, options);
806
+ if (!toolScore.tokenBudget) {
807
+ if (toolId === import_core8.ToolName.PatternDetect && output.duplicates) {
808
+ const wastedTokens = output.duplicates.reduce(
809
+ (sum, d) => sum + (d.tokenCost ?? 0),
810
+ 0
811
+ );
812
+ toolScore.tokenBudget = (0, import_core8.calculateTokenBudget)({
813
+ totalContextTokens: wastedTokens * 2,
814
+ wastedTokens: {
815
+ duplication: wastedTokens,
816
+ fragmentation: 0,
817
+ chattiness: 0
818
+ }
819
+ });
820
+ } else if (toolId === import_core8.ToolName.ContextAnalyzer && output.summary) {
821
+ toolScore.tokenBudget = (0, import_core8.calculateTokenBudget)({
822
+ totalContextTokens: output.summary.totalTokens,
823
+ wastedTokens: {
824
+ duplication: 0,
825
+ fragmentation: output.summary.totalPotentialSavings ?? 0,
826
+ chattiness: 0
827
+ }
828
+ });
829
+ }
763
830
  }
831
+ toolScores.set(toolId, toolScore);
832
+ } catch (err) {
833
+ console.error(`\u274C Error scoring tool '${toolId}':`, err);
834
+ }
835
+ }
836
+ if (toolScores.size === 0) {
837
+ return this.emptyScoringResult();
838
+ }
839
+ return (0, import_core8.calculateOverallScore)(toolScores, options, void 0);
840
+ }
841
+ /**
842
+ * Generate human-readable summary of unified results.
843
+ */
844
+ generateSummary(result) {
845
+ const { summary } = result;
846
+ let output = `\u{1F680} AIReady Analysis Complete
847
+
848
+ `;
849
+ output += `\u{1F4CA} Summary:
850
+ `;
851
+ output += ` Tools run: ${summary.toolsRun.join(", ")}
852
+ `;
853
+ output += ` Total issues found: ${summary.totalIssues}
854
+ `;
855
+ output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
856
+
857
+ `;
858
+ for (const provider of this.registry.getAll()) {
859
+ const toolResult = result[provider.id];
860
+ if (toolResult) {
861
+ const issueCount = toolResult.results.reduce(
862
+ (sum, r) => sum + (r.issues?.length ?? 0),
863
+ 0
864
+ );
865
+ output += `\u2022 ${provider.id}: ${issueCount} issues
866
+ `;
764
867
  }
765
- toolScores.set(toolId, toolScore);
766
- } catch (err) {
767
- console.error(`\u274C Error scoring tool '${toolId}':`, err);
768
868
  }
869
+ return output;
769
870
  }
770
- if (toolScores.size === 0) {
871
+ emptyScoringResult() {
771
872
  return {
772
873
  overall: 0,
773
874
  rating: "Critical",
@@ -781,7 +882,10 @@ async function scoreUnified(results, options) {
781
882
  }
782
883
  };
783
884
  }
784
- return (0, import_core7.calculateOverallScore)(toolScores, options, void 0);
885
+ };
886
+ async function scoreUnified(results, options) {
887
+ const orchestrator = new ScoringOrchestrator(import_core8.ToolRegistry);
888
+ return orchestrator.score(results, options);
785
889
  }
786
890
 
787
891
  // src/commands/scan-orchestrator.ts
@@ -870,7 +974,7 @@ async function handleBusinessImpactMetrics(results, scoringResult, modelId) {
870
974
  0
871
975
  );
872
976
  if (totalContext > 0) {
873
- const unifiedBudget = (0, import_core8.calculateTokenBudget)({
977
+ const unifiedBudget = (0, import_core9.calculateTokenBudget)({
874
978
  totalContextTokens: totalContext,
875
979
  wastedTokens: {
876
980
  duplication: totalWastedDuplication,
@@ -911,7 +1015,7 @@ async function scanAction(directory, options) {
911
1015
  console.log(import_chalk6.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
912
1016
  const startTime = Date.now();
913
1017
  const resolvedDir = (0, import_path4.resolve)(process.cwd(), directory ?? ".");
914
- const repoMetadata = (0, import_core9.getRepoMetadata)(resolvedDir);
1018
+ const repoMetadata = (0, import_core10.getRepoMetadata)(resolvedDir);
915
1019
  try {
916
1020
  const finalOptions = await resolveScanConfig(resolvedDir, options);
917
1021
  const { results, scoringResult } = await runUnifiedScan(
@@ -942,13 +1046,13 @@ async function scanAction(directory, options) {
942
1046
  repository: repoMetadata
943
1047
  };
944
1048
  const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
945
- const outputPath = (0, import_core9.resolveOutputPath)(
1049
+ const outputPath = (0, import_core10.resolveOutputPath)(
946
1050
  options.outputFile ?? finalOptions.output?.file,
947
1051
  `aiready-report-${(0, import_core2.getReportTimestamp)()}.json`,
948
1052
  resolvedDir
949
1053
  );
950
1054
  if (outputFormat === "json") {
951
- (0, import_core9.handleJSONOutput)(
1055
+ (0, import_core10.handleJSONOutput)(
952
1056
  outputData,
953
1057
  outputPath,
954
1058
  `\u2705 Report saved to ${outputPath}`
@@ -968,15 +1072,43 @@ async function scanAction(directory, options) {
968
1072
  });
969
1073
  }
970
1074
  await warnIfGraphCapExceeded(outputData, resolvedDir);
971
- await handleGatekeeper(outputData, scoringResult, options, results);
1075
+ await handleGatekeeper(
1076
+ outputData,
1077
+ scoringResult,
1078
+ options,
1079
+ finalOptions,
1080
+ results
1081
+ );
1082
+ const isCI = options.ci ?? process.env.CI === "true";
1083
+ if (!isCI) {
1084
+ console.log(
1085
+ import_chalk6.default.dim(
1086
+ "\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"
1087
+ )
1088
+ );
1089
+ console.log(import_chalk6.default.bold("\u{1F4C8} Want to see the full interactive report?"));
1090
+ console.log(
1091
+ import_chalk6.default.cyan(
1092
+ ` Upload this report to: ${import_chalk6.default.bold("https://platform.getaiready.dev")}`
1093
+ )
1094
+ );
1095
+ console.log(
1096
+ import_chalk6.default.dim(" Or run: ") + import_chalk6.default.white(`aiready upload ${outputPath}`)
1097
+ );
1098
+ console.log(
1099
+ import_chalk6.default.dim(
1100
+ "\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"
1101
+ )
1102
+ );
1103
+ }
972
1104
  } catch (error) {
973
- (0, import_core9.handleCLIError)(error, "Analysis");
1105
+ (0, import_core10.handleCLIError)(error, "Analysis");
974
1106
  }
975
1107
  }
976
- async function handleGatekeeper(outputData, scoringResult, options, results) {
1108
+ async function handleGatekeeper(outputData, scoringResult, options, finalOptions, results) {
977
1109
  if (!scoringResult) return;
978
- const threshold = options.threshold ? parseInt(options.threshold) : void 0;
979
- const failOnLevel = options.failOn ?? "critical";
1110
+ const threshold = options.threshold ? parseInt(options.threshold) : finalOptions.threshold;
1111
+ const failOnLevel = options.failOn ?? finalOptions.failOn ?? "critical";
980
1112
  const isCI = options.ci ?? process.env.CI === "true";
981
1113
  let shouldFail = false;
982
1114
  let failReason = "";
@@ -988,7 +1120,7 @@ async function handleGatekeeper(outputData, scoringResult, options, results) {
988
1120
  \u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
989
1121
  )
990
1122
  );
991
- (0, import_core9.emitIssuesAsAnnotations)(report.results);
1123
+ (0, import_core10.emitIssuesAsAnnotations)(report.results);
992
1124
  }
993
1125
  if (threshold && scoringResult.overall < threshold) {
994
1126
  shouldFail = true;
@@ -1037,7 +1169,7 @@ ${import_chalk6.default.bold("CI/CD Integration:")}
1037
1169
  var import_fs5 = require("fs");
1038
1170
  var import_path5 = require("path");
1039
1171
  var import_chalk7 = __toESM(require("chalk"));
1040
- var import_core10 = require("@aiready/core");
1172
+ var import_core11 = require("@aiready/core");
1041
1173
  async function initAction(options) {
1042
1174
  const fileExt = options.format === "js" ? "js" : "json";
1043
1175
  const fileName = fileExt === "js" ? "aiready.config.js" : "aiready.json";
@@ -1068,15 +1200,15 @@ async function initAction(options) {
1068
1200
  "**/*.spec.ts"
1069
1201
  ],
1070
1202
  tools: [
1071
- import_core10.ToolName.PatternDetect,
1072
- import_core10.ToolName.ContextAnalyzer,
1073
- import_core10.ToolName.NamingConsistency,
1074
- import_core10.ToolName.AiSignalClarity,
1075
- import_core10.ToolName.AgentGrounding,
1076
- import_core10.ToolName.TestabilityIndex,
1077
- import_core10.ToolName.DocDrift,
1078
- import_core10.ToolName.DependencyHealth,
1079
- import_core10.ToolName.ChangeAmplification
1203
+ import_core11.ToolName.PatternDetect,
1204
+ import_core11.ToolName.ContextAnalyzer,
1205
+ import_core11.ToolName.NamingConsistency,
1206
+ import_core11.ToolName.AiSignalClarity,
1207
+ import_core11.ToolName.AgentGrounding,
1208
+ import_core11.ToolName.TestabilityIndex,
1209
+ import_core11.ToolName.DocDrift,
1210
+ import_core11.ToolName.DependencyHealth,
1211
+ import_core11.ToolName.ChangeAmplification
1080
1212
  ]
1081
1213
  },
1082
1214
  // Output preferences
@@ -1091,7 +1223,7 @@ async function initAction(options) {
1091
1223
  },
1092
1224
  // Tool-specific configurations
1093
1225
  tools: {
1094
- [import_core10.ToolName.PatternDetect]: {
1226
+ [import_core11.ToolName.PatternDetect]: {
1095
1227
  // Core detection thresholds
1096
1228
  minSimilarity: 0.4,
1097
1229
  // Jaccard similarity threshold (0-1)
@@ -1121,7 +1253,7 @@ async function initAction(options) {
1121
1253
  // Add any additional advanced options here
1122
1254
  } : {}
1123
1255
  },
1124
- [import_core10.ToolName.ContextAnalyzer]: {
1256
+ [import_core11.ToolName.ContextAnalyzer]: {
1125
1257
  // Smart defaults are generated dynamically based on repository size
1126
1258
  // These are fallback values for when smart defaults can't be calculated
1127
1259
  maxContextBudget: 25e3,
@@ -1138,7 +1270,7 @@ async function initAction(options) {
1138
1270
  includeNodeModules: false
1139
1271
  // Whether to include node_modules in analysis
1140
1272
  },
1141
- [import_core10.ToolName.NamingConsistency]: {
1273
+ [import_core11.ToolName.NamingConsistency]: {
1142
1274
  // Core checks
1143
1275
  checkNaming: true,
1144
1276
  // Check naming conventions and quality
@@ -1185,7 +1317,7 @@ async function initAction(options) {
1185
1317
  ],
1186
1318
  ...options.full ? { disableChecks: [] } : {}
1187
1319
  },
1188
- [import_core10.ToolName.AiSignalClarity]: {
1320
+ [import_core11.ToolName.AiSignalClarity]: {
1189
1321
  // All signal clarity checks enabled by default
1190
1322
  checkMagicLiterals: true,
1191
1323
  // Detect magic numbers and strings
@@ -1204,7 +1336,7 @@ async function initAction(options) {
1204
1336
  checkLargeFiles: true
1205
1337
  // Detect files that are too large
1206
1338
  },
1207
- [import_core10.ToolName.AgentGrounding]: {
1339
+ [import_core11.ToolName.AgentGrounding]: {
1208
1340
  // Structure clarity
1209
1341
  maxRecommendedDepth: 4,
1210
1342
  // Max directory depth before flagging as "too deep"
@@ -1215,7 +1347,7 @@ async function initAction(options) {
1215
1347
  additionalVagueNames: ["stuff", "misc", "temp", "test"]
1216
1348
  // Custom vague file names
1217
1349
  },
1218
- [import_core10.ToolName.TestabilityIndex]: {
1350
+ [import_core11.ToolName.TestabilityIndex]: {
1219
1351
  // Coverage thresholds
1220
1352
  minCoverageRatio: 0.3,
1221
1353
  // Minimum acceptable test/source ratio
@@ -1225,19 +1357,19 @@ async function initAction(options) {
1225
1357
  maxDepth: 10
1226
1358
  // Maximum scan depth
1227
1359
  },
1228
- [import_core10.ToolName.DocDrift]: {
1360
+ [import_core11.ToolName.DocDrift]: {
1229
1361
  // Drift detection
1230
1362
  maxCommits: 50,
1231
1363
  // Maximum commit distance to check for drift
1232
1364
  staleMonths: 3
1233
1365
  // Consider comments older than this as outdated
1234
1366
  },
1235
- [import_core10.ToolName.DependencyHealth]: {
1367
+ [import_core11.ToolName.DependencyHealth]: {
1236
1368
  // Training cutoff for AI knowledge assessment
1237
1369
  trainingCutoffYear: 2023
1238
1370
  // Year cutoff for AI training data
1239
1371
  },
1240
- [import_core10.ToolName.ChangeAmplification]: {
1372
+ [import_core11.ToolName.ChangeAmplification]: {
1241
1373
  // Change amplification primarily relies on global scan settings
1242
1374
  // No additional tool-specific configuration required
1243
1375
  }
@@ -1281,134 +1413,157 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
1281
1413
  }
1282
1414
 
1283
1415
  // src/commands/patterns.ts
1416
+ var import_chalk9 = __toESM(require("chalk"));
1417
+ var import_core13 = require("@aiready/core");
1418
+
1419
+ // src/utils/terminal-renderers.ts
1284
1420
  var import_chalk8 = __toESM(require("chalk"));
1285
- var import_core11 = require("@aiready/core");
1286
- async function patternsAction(directory, options) {
1287
- console.log(import_chalk8.default.blue("\u{1F50D} Analyzing patterns...\n"));
1288
- const startTime = Date.now();
1289
- try {
1290
- const useSmartDefaults = !options.fullScan;
1291
- const defaults = {
1292
- useSmartDefaults,
1293
- include: void 0,
1294
- exclude: void 0,
1295
- output: {
1296
- format: "console",
1297
- file: void 0
1298
- }
1299
- };
1300
- if (!useSmartDefaults) {
1301
- defaults.minSimilarity = 0.4;
1302
- defaults.minLines = 5;
1303
- }
1304
- const cliOptions = {
1305
- minSimilarity: options.similarity ? parseFloat(options.similarity) : void 0,
1306
- minLines: options.minLines ? parseInt(options.minLines) : void 0,
1307
- useSmartDefaults,
1308
- include: options.include?.split(","),
1309
- exclude: options.exclude?.split(",")
1310
- };
1311
- if (options.maxCandidates) {
1312
- cliOptions.maxCandidatesPerBlock = parseInt(options.maxCandidates);
1313
- }
1314
- if (options.minSharedTokens) {
1315
- cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
1316
- }
1317
- const { resolvedDir, finalOptions } = await (0, import_core11.prepareActionConfig)(
1318
- directory,
1319
- defaults,
1320
- cliOptions
1421
+ var import_core12 = require("@aiready/core");
1422
+ var SAFETY_ICONS = {
1423
+ safe: "\u2705",
1424
+ "moderate-risk": "\u26A0\uFE0F ",
1425
+ "high-risk": "\u{1F534}",
1426
+ "blind-risk": "\u{1F480}"
1427
+ };
1428
+ var SAFETY_COLORS = {
1429
+ safe: import_chalk8.default.green,
1430
+ "moderate-risk": import_chalk8.default.yellow,
1431
+ "high-risk": import_chalk8.default.red,
1432
+ "blind-risk": import_chalk8.default.bgRed.white
1433
+ };
1434
+ function renderToolHeader(label, emoji, score, rating) {
1435
+ console.log(
1436
+ ` ${emoji} ${label}: ${import_chalk8.default.bold(score + "/100")} (${rating})`
1437
+ );
1438
+ }
1439
+ function renderSafetyRating(safety) {
1440
+ const icon = SAFETY_ICONS[safety] ?? "\u2753";
1441
+ const color = SAFETY_COLORS[safety] ?? import_chalk8.default.white;
1442
+ console.log(
1443
+ ` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
1444
+ );
1445
+ }
1446
+ function renderIssueSummaryBlock(summary) {
1447
+ const total = (summary.criticalIssues || 0) + (summary.majorIssues || 0) + (summary.minorIssues || 0);
1448
+ if (total === 0) {
1449
+ console.log(import_chalk8.default.green("\u2705 No significant issues found!\n"));
1450
+ return;
1451
+ }
1452
+ console.log(import_chalk8.default.bold("\u26A0\uFE0F Issues Found:\n"));
1453
+ if (summary.criticalIssues > 0)
1454
+ console.log(
1455
+ import_chalk8.default.red(` \u{1F534} Critical: ${import_chalk8.default.bold(summary.criticalIssues)}`)
1321
1456
  );
1322
- const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
1323
- const { results, duplicates } = await analyzePatterns(
1324
- finalOptions
1457
+ if (summary.majorIssues > 0)
1458
+ console.log(
1459
+ import_chalk8.default.yellow(` \u{1F7E1} Major: ${import_chalk8.default.bold(summary.majorIssues)}`)
1325
1460
  );
1326
- const elapsedTime = (0, import_core11.getElapsedTime)(startTime);
1327
- const summary = generateSummary(results);
1328
- let patternScore;
1329
- if (options.score) {
1330
- patternScore = calculatePatternScore(duplicates, results.length);
1331
- }
1332
- const { format: outputFormat, file: userOutputFile } = (0, import_core11.resolveOutputFormat)(
1333
- options,
1334
- finalOptions
1461
+ if (summary.minorIssues > 0)
1462
+ console.log(import_chalk8.default.blue(` \u{1F535} Minor: ${import_chalk8.default.bold(summary.minorIssues)}`));
1463
+ if (summary.totalPotentialSavings) {
1464
+ console.log(
1465
+ import_chalk8.default.green(
1466
+ `
1467
+ \u{1F4A1} Potential savings: ${import_chalk8.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1468
+ `
1469
+ )
1335
1470
  );
1336
- if (outputFormat === "json") {
1337
- const outputData = (0, import_core11.formatStandardReport)({
1338
- results,
1339
- summary,
1340
- elapsedTime,
1341
- score: patternScore
1342
- });
1343
- (0, import_core11.handleStandardJSONOutput)({
1344
- outputData,
1345
- outputFile: userOutputFile,
1346
- resolvedDir
1347
- });
1348
- } else {
1349
- (0, import_core11.printTerminalHeader)("PATTERN ANALYSIS SUMMARY");
1471
+ }
1472
+ }
1473
+ function renderSubSection(title) {
1474
+ console.log("\n" + (0, import_core12.getTerminalDivider)());
1475
+ console.log(import_chalk8.default.bold.white(` ${title.toUpperCase()}`));
1476
+ console.log((0, import_core12.getTerminalDivider)() + "\n");
1477
+ }
1478
+ function renderToolScoreFooter(score) {
1479
+ if (score) {
1480
+ console.log(`
1481
+ \u{1F4CA} AI Readiness Score (${score.toolName || "Tool"})
1482
+ `);
1483
+ console.log((0, import_core12.formatToolScore)(score));
1484
+ console.log();
1485
+ }
1486
+ }
1487
+
1488
+ // src/commands/patterns.ts
1489
+ async function patternsAction(directory, options) {
1490
+ return await executeToolAction(directory, options, {
1491
+ toolName: "pattern-detect",
1492
+ label: "Pattern analysis",
1493
+ emoji: "\u{1F50D}",
1494
+ defaults: {
1495
+ useSmartDefaults: !options.fullScan,
1496
+ include: void 0,
1497
+ exclude: void 0,
1498
+ output: { format: "console", file: void 0 },
1499
+ minSimilarity: options.fullScan ? 0.4 : void 0,
1500
+ minLines: options.fullScan ? 5 : void 0
1501
+ },
1502
+ getCliOptions: (opts) => ({
1503
+ minSimilarity: opts.similarity ? parseFloat(opts.similarity) : void 0,
1504
+ minLines: opts.minLines ? parseInt(opts.minLines) : void 0,
1505
+ maxCandidatesPerBlock: opts.maxCandidates ? parseInt(opts.maxCandidates) : void 0,
1506
+ minSharedTokens: opts.minSharedTokens ? parseInt(opts.minSharedTokens) : void 0
1507
+ }),
1508
+ importTool: async () => {
1509
+ const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
1510
+ return {
1511
+ analyze: analyzePatterns,
1512
+ generateSummary,
1513
+ calculateScore: calculatePatternScore
1514
+ };
1515
+ },
1516
+ renderConsole: ({ results, summary, elapsedTime, score }) => {
1517
+ const duplicates = results.duplicates || [];
1518
+ (0, import_core13.printTerminalHeader)("PATTERN ANALYSIS SUMMARY");
1350
1519
  console.log(
1351
- import_chalk8.default.white(`\u{1F4C1} Files analyzed: ${import_chalk8.default.bold(results.length)}`)
1520
+ import_chalk9.default.white(`\u{1F4C1} Files analyzed: ${import_chalk9.default.bold(results.length)}`)
1352
1521
  );
1353
1522
  console.log(
1354
- import_chalk8.default.yellow(
1355
- `\u26A0 Duplicate patterns found: ${import_chalk8.default.bold(summary.totalPatterns)}`
1523
+ import_chalk9.default.yellow(
1524
+ `\u26A0 Duplicate patterns found: ${import_chalk9.default.bold(summary.totalPatterns)}`
1356
1525
  )
1357
1526
  );
1358
1527
  console.log(
1359
- import_chalk8.default.red(
1360
- `\u{1F4B0} Token cost (wasted): ${import_chalk8.default.bold(summary.totalTokenCost.toLocaleString())}`
1528
+ import_chalk9.default.red(
1529
+ `\u{1F4B0} Token cost (wasted): ${import_chalk9.default.bold(summary.totalTokenCost.toLocaleString())}`
1361
1530
  )
1362
1531
  );
1363
1532
  console.log(
1364
- import_chalk8.default.gray(`\u23F1 Analysis time: ${import_chalk8.default.bold(elapsedTime + "s")}`)
1533
+ import_chalk9.default.gray(`\u23F1 Analysis time: ${import_chalk9.default.bold(elapsedTime + "s")}`)
1365
1534
  );
1366
1535
  const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
1367
1536
  if (sortedTypes.length > 0) {
1368
- console.log("\n" + (0, import_core11.getTerminalDivider)());
1369
- console.log(import_chalk8.default.bold.white(" PATTERNS BY TYPE"));
1370
- console.log((0, import_core11.getTerminalDivider)() + "\n");
1537
+ renderSubSection("Patterns By Type");
1371
1538
  sortedTypes.forEach(([type, count]) => {
1372
- console.log(` ${import_chalk8.default.white(type.padEnd(15))} ${import_chalk8.default.bold(count)}`);
1539
+ console.log(` ${import_chalk9.default.white(type.padEnd(15))} ${import_chalk9.default.bold(count)}`);
1373
1540
  });
1374
1541
  }
1375
1542
  if (summary.totalPatterns > 0 && duplicates.length > 0) {
1376
- console.log("\n" + (0, import_core11.getTerminalDivider)());
1377
- console.log(import_chalk8.default.bold.white(" TOP DUPLICATE PATTERNS"));
1378
- console.log((0, import_core11.getTerminalDivider)() + "\n");
1379
- const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
1380
- topDuplicates.forEach((dup) => {
1381
- const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
1382
- const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
1383
- const file1Name = dup.file1.split("/").pop() || dup.file1;
1384
- const file2Name = dup.file2.split("/").pop() || dup.file2;
1543
+ renderSubSection("Top Duplicate Patterns");
1544
+ [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10).forEach((dup) => {
1545
+ const isHigh = dup.similarity > 0.9;
1546
+ const icon = dup.similarity > 0.95 ? "\u{1F534}" : isHigh ? "\u{1F7E1}" : "\u{1F535}";
1547
+ const label = dup.similarity > 0.95 ? "CRITICAL" : isHigh ? "HIGH" : "MEDIUM";
1385
1548
  console.log(
1386
- `${severityIcon} ${severity}: ${import_chalk8.default.bold(file1Name)} \u2194 ${import_chalk8.default.bold(file2Name)}`
1549
+ `${icon} ${label}: ${import_chalk9.default.bold(dup.file1.split("/").pop())} \u2194 ${import_chalk9.default.bold(dup.file2.split("/").pop())}`
1387
1550
  );
1388
1551
  console.log(
1389
- ` Similarity: ${import_chalk8.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk8.default.bold(dup.tokenCost.toLocaleString())} tokens each`
1552
+ ` Similarity: ${import_chalk9.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk9.default.bold(dup.tokenCost.toLocaleString())} tokens each`
1390
1553
  );
1391
1554
  console.log(
1392
- ` Lines: ${import_chalk8.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk8.default.cyan(dup.line2 + "-" + dup.endLine2)}
1555
+ ` Lines: ${import_chalk9.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk9.default.cyan(dup.line2 + "-" + dup.endLine2)}
1393
1556
  `
1394
1557
  );
1395
1558
  });
1396
1559
  } else {
1397
1560
  console.log(
1398
- import_chalk8.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
1561
+ import_chalk9.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
1399
1562
  );
1400
1563
  }
1401
- if (patternScore) {
1402
- console.log((0, import_core11.getTerminalDivider)());
1403
- console.log(import_chalk8.default.bold.white(" AI READINESS SCORE (Patterns)"));
1404
- console.log((0, import_core11.getTerminalDivider)() + "\n");
1405
- console.log((0, import_core11.formatToolScore)(patternScore));
1406
- console.log();
1407
- }
1564
+ renderToolScoreFooter(score);
1408
1565
  }
1409
- } catch (error) {
1410
- (0, import_core11.handleCLIError)(error, "Pattern analysis");
1411
- }
1566
+ });
1412
1567
  }
1413
1568
  var PATTERNS_HELP_TEXT = `
1414
1569
  EXAMPLES:
@@ -1418,283 +1573,146 @@ EXAMPLES:
1418
1573
  `;
1419
1574
 
1420
1575
  // src/commands/context.ts
1421
- var import_chalk9 = __toESM(require("chalk"));
1422
- var import_core12 = require("@aiready/core");
1576
+ var import_chalk10 = __toESM(require("chalk"));
1577
+ var import_core14 = require("@aiready/core");
1423
1578
  async function contextAction(directory, options) {
1424
- console.log(import_chalk9.default.blue("\u{1F9E0} Analyzing context costs...\n"));
1425
- const startTime = Date.now();
1426
- try {
1427
- const defaults = {
1579
+ return await executeToolAction(directory, options, {
1580
+ toolName: "context-analyzer",
1581
+ label: "Context analysis",
1582
+ emoji: "\u{1F9E0}",
1583
+ defaults: {
1428
1584
  maxDepth: 5,
1429
1585
  maxContextBudget: 1e4,
1430
1586
  include: void 0,
1431
1587
  exclude: void 0,
1432
- output: {
1433
- format: "console",
1434
- file: void 0
1435
- }
1436
- };
1437
- const { resolvedDir, finalOptions: baseOptions } = await (0, import_core12.prepareActionConfig)(directory, defaults, {
1438
- maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
1439
- maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
1440
- include: options.include?.split(","),
1441
- exclude: options.exclude?.split(",")
1442
- });
1443
- let finalOptions = { ...baseOptions };
1444
- const { getSmartDefaults } = await import("@aiready/context-analyzer");
1445
- const contextSmartDefaults = await getSmartDefaults(
1446
- resolvedDir,
1447
- baseOptions
1448
- );
1449
- finalOptions = { ...contextSmartDefaults, ...finalOptions };
1450
- console.log("\u{1F4CB} Configuration:");
1451
- console.log(` Max depth: ${finalOptions.maxDepth}`);
1452
- console.log(` Max context budget: ${finalOptions.maxContextBudget}`);
1453
- console.log(
1454
- ` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
1455
- );
1456
- console.log(
1457
- ` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
1458
- );
1459
- console.log(` Analysis focus: ${finalOptions.focus}`);
1460
- console.log("");
1461
- const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
1462
- const results = await analyzeContext(finalOptions);
1463
- const elapsedTime = (0, import_core12.getElapsedTime)(startTime);
1464
- const summary = generateSummary(results);
1465
- let contextScore;
1466
- if (options.score) {
1467
- contextScore = calculateContextScore(summary);
1468
- }
1469
- const { format: outputFormat, file: userOutputFile } = (0, import_core12.resolveOutputFormat)(
1470
- options,
1471
- finalOptions
1472
- );
1473
- if (outputFormat === "json") {
1474
- const outputData = (0, import_core12.formatStandardReport)({
1475
- results,
1476
- summary,
1477
- elapsedTime,
1478
- score: contextScore
1479
- });
1480
- (0, import_core12.handleStandardJSONOutput)({
1481
- outputData,
1482
- outputFile: userOutputFile,
1483
- resolvedDir
1484
- });
1485
- } else {
1486
- const terminalWidth = process.stdout.columns ?? 80;
1487
- const dividerWidth = Math.min(60, terminalWidth - 2);
1488
- const divider = "\u2501".repeat(dividerWidth);
1489
- console.log(import_chalk9.default.cyan(divider));
1490
- console.log(import_chalk9.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
1491
- console.log(import_chalk9.default.cyan(divider) + "\n");
1588
+ output: { format: "console", file: void 0 }
1589
+ },
1590
+ getCliOptions: (opts) => ({
1591
+ maxDepth: opts.maxDepth ? parseInt(opts.maxDepth) : void 0,
1592
+ maxContextBudget: opts.maxContext ? parseInt(opts.maxContext) : void 0
1593
+ }),
1594
+ preAnalyze: async (resolvedDir, baseOptions) => {
1595
+ const { getSmartDefaults } = await import("@aiready/context-analyzer");
1596
+ const smartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
1597
+ return { ...smartDefaults, ...baseOptions };
1598
+ },
1599
+ importTool: async () => {
1600
+ const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
1601
+ return {
1602
+ analyze: analyzeContext,
1603
+ generateSummary,
1604
+ calculateScore: calculateContextScore
1605
+ };
1606
+ },
1607
+ renderConsole: ({ summary, elapsedTime, score }) => {
1608
+ (0, import_core14.printTerminalHeader)("CONTEXT ANALYSIS SUMMARY");
1492
1609
  console.log(
1493
- import_chalk9.default.white(`\u{1F4C1} Files analyzed: ${import_chalk9.default.bold(summary.totalFiles)}`)
1610
+ import_chalk10.default.white(`\u{1F4C1} Files analyzed: ${import_chalk10.default.bold(summary.totalFiles)}`)
1494
1611
  );
1495
1612
  console.log(
1496
- import_chalk9.default.white(
1497
- `\u{1F4CA} Total tokens: ${import_chalk9.default.bold(summary.totalTokens.toLocaleString())}`
1613
+ import_chalk10.default.white(
1614
+ `\u{1F4CA} Total tokens: ${import_chalk10.default.bold(summary.totalTokens.toLocaleString())}`
1498
1615
  )
1499
1616
  );
1500
1617
  console.log(
1501
- import_chalk9.default.yellow(
1502
- `\u{1F4B0} Avg context budget: ${import_chalk9.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1618
+ import_chalk10.default.yellow(
1619
+ `\u{1F4B0} Avg context budget: ${import_chalk10.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
1503
1620
  )
1504
1621
  );
1505
1622
  console.log(
1506
- import_chalk9.default.white(`\u23F1 Analysis time: ${import_chalk9.default.bold(elapsedTime + "s")}
1623
+ import_chalk10.default.white(`\u23F1 Analysis time: ${import_chalk10.default.bold(elapsedTime + "s")}
1507
1624
  `)
1508
1625
  );
1509
- const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
1510
- if (totalIssues > 0) {
1511
- console.log(import_chalk9.default.bold("\u26A0\uFE0F Issues Found:\n"));
1512
- if (summary.criticalIssues > 0) {
1513
- console.log(
1514
- import_chalk9.default.red(` \u{1F534} Critical: ${import_chalk9.default.bold(summary.criticalIssues)}`)
1515
- );
1516
- }
1517
- if (summary.majorIssues > 0) {
1518
- console.log(
1519
- import_chalk9.default.yellow(` \u{1F7E1} Major: ${import_chalk9.default.bold(summary.majorIssues)}`)
1520
- );
1521
- }
1522
- if (summary.minorIssues > 0) {
1523
- console.log(
1524
- import_chalk9.default.blue(` \u{1F535} Minor: ${import_chalk9.default.bold(summary.minorIssues)}`)
1525
- );
1526
- }
1527
- console.log(
1528
- import_chalk9.default.green(
1529
- `
1530
- \u{1F4A1} Potential savings: ${import_chalk9.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
1531
- `
1532
- )
1533
- );
1534
- } else {
1535
- console.log(import_chalk9.default.green("\u2705 No significant issues found!\n"));
1536
- }
1537
- if (summary.deepFiles.length > 0) {
1538
- console.log(import_chalk9.default.bold("\u{1F4CF} Deep Import Chains:\n"));
1539
- console.log(
1540
- import_chalk9.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
1541
- );
1542
- console.log(
1543
- import_chalk9.default.gray(` Maximum depth: ${summary.maxImportDepth}
1544
- `)
1545
- );
1626
+ renderIssueSummaryBlock(summary);
1627
+ if (summary.deepFiles && summary.deepFiles.length > 0) {
1628
+ renderSubSection("Deep Import Chains");
1546
1629
  summary.deepFiles.slice(0, 10).forEach((item) => {
1547
1630
  const fileName = item.file.split("/").slice(-2).join("/");
1548
1631
  console.log(
1549
- ` ${import_chalk9.default.cyan("\u2192")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(depth: ${item.depth})`)}`
1632
+ ` ${import_chalk10.default.cyan("\u2192")} ${import_chalk10.default.white(fileName)} ${import_chalk10.default.dim(`(depth: ${item.depth})`)}`
1550
1633
  );
1551
1634
  });
1552
- console.log();
1553
1635
  }
1554
- if (summary.fragmentedModules.length > 0) {
1555
- console.log(import_chalk9.default.bold("\u{1F9E9} Fragmented Modules:\n"));
1556
- console.log(
1557
- import_chalk9.default.gray(
1558
- ` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
1559
- `
1560
- )
1561
- );
1636
+ if (summary.fragmentedModules && summary.fragmentedModules.length > 0) {
1637
+ renderSubSection("Fragmented Modules");
1562
1638
  summary.fragmentedModules.slice(0, 10).forEach((module2) => {
1563
1639
  console.log(
1564
- ` ${import_chalk9.default.yellow("\u25CF")} ${import_chalk9.default.white(module2.domain)} - ${import_chalk9.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1640
+ ` ${import_chalk10.default.yellow("\u25CF")} ${import_chalk10.default.white(module2.domain)} - ${import_chalk10.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
1565
1641
  );
1566
1642
  console.log(
1567
- import_chalk9.default.dim(
1643
+ import_chalk10.default.dim(
1568
1644
  ` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
1569
1645
  )
1570
1646
  );
1571
1647
  });
1572
- console.log();
1573
- }
1574
- if (summary.lowCohesionFiles.length > 0) {
1575
- console.log(import_chalk9.default.bold("\u{1F500} Low Cohesion Files:\n"));
1576
- console.log(
1577
- import_chalk9.default.gray(
1578
- ` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
1579
- `
1580
- )
1581
- );
1582
- summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
1583
- const fileName = item.file.split("/").slice(-2).join("/");
1584
- const scorePercent = (item.score * 100).toFixed(0);
1585
- const color = item.score < 0.4 ? import_chalk9.default.red : import_chalk9.default.yellow;
1586
- console.log(
1587
- ` ${color("\u25CB")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${scorePercent}% cohesion)`)}`
1588
- );
1589
- });
1590
- console.log();
1591
- }
1592
- if (summary.topExpensiveFiles.length > 0) {
1593
- console.log(import_chalk9.default.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
1594
- summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
1595
- const fileName = item.file.split("/").slice(-2).join("/");
1596
- const severityColor = item.severity === "critical" ? import_chalk9.default.red : item.severity === "major" ? import_chalk9.default.yellow : import_chalk9.default.blue;
1597
- console.log(
1598
- ` ${severityColor("\u25CF")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
1599
- );
1600
- });
1601
- console.log();
1602
- }
1603
- if (contextScore) {
1604
- console.log(import_chalk9.default.cyan(divider));
1605
- console.log(import_chalk9.default.bold.white(" AI READINESS SCORE (Context)"));
1606
- console.log(import_chalk9.default.cyan(divider) + "\n");
1607
- console.log((0, import_core12.formatToolScore)(contextScore));
1608
- console.log();
1609
1648
  }
1649
+ renderToolScoreFooter(score);
1610
1650
  }
1611
- } catch (error) {
1612
- (0, import_core12.handleCLIError)(error, "Context analysis");
1613
- }
1651
+ });
1614
1652
  }
1615
1653
 
1616
1654
  // src/commands/consistency.ts
1617
- var import_chalk10 = __toESM(require("chalk"));
1655
+ var import_chalk11 = __toESM(require("chalk"));
1618
1656
  var import_fs6 = require("fs");
1619
- var import_core13 = require("@aiready/core");
1657
+ var import_core15 = require("@aiready/core");
1620
1658
  async function consistencyAction(directory, options) {
1621
- console.log(import_chalk10.default.blue("\u{1F50D} Analyzing consistency...\n"));
1622
- const startTime = Date.now();
1623
- try {
1624
- const defaults = {
1659
+ return await executeToolAction(directory, options, {
1660
+ toolName: "naming-consistency",
1661
+ label: "Consistency analysis",
1662
+ emoji: "\u{1F50D}",
1663
+ defaults: {
1625
1664
  checkNaming: true,
1626
1665
  checkPatterns: true,
1627
1666
  minSeverity: "info",
1628
1667
  include: void 0,
1629
1668
  exclude: void 0,
1630
- output: {
1631
- format: "console",
1632
- file: void 0
1633
- }
1634
- };
1635
- const { resolvedDir, finalOptions } = await (0, import_core13.prepareActionConfig)(
1636
- directory,
1637
- defaults,
1638
- {
1639
- checkNaming: options.naming !== false,
1640
- checkPatterns: options.patterns !== false,
1641
- minSeverity: options.minSeverity,
1642
- include: options.include?.split(","),
1643
- exclude: options.exclude?.split(",")
1669
+ output: { format: "console", file: void 0 }
1670
+ },
1671
+ getCliOptions: (opts) => ({
1672
+ checkNaming: opts.naming !== false,
1673
+ checkPatterns: opts.patterns !== false,
1674
+ minSeverity: opts.minSeverity
1675
+ }),
1676
+ importTool: async () => {
1677
+ const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
1678
+ return {
1679
+ analyze: analyzeConsistency,
1680
+ generateSummary: (report) => report.summary,
1681
+ calculateScore: (summary, _resultsCount) => {
1682
+ return calculateConsistencyScore(
1683
+ summary.results?.flatMap((r) => r.issues) ?? [],
1684
+ summary.summary.filesAnalyzed
1685
+ );
1686
+ }
1687
+ };
1688
+ },
1689
+ renderConsole: ({ results, summary, elapsedTime, score, finalOptions }) => {
1690
+ const report = results;
1691
+ const { format: outputFormat, file: userOutputFile } = (0, import_core15.resolveOutputFormat)(options, finalOptions);
1692
+ if (outputFormat === "markdown") {
1693
+ const markdown = generateMarkdownReport(report, elapsedTime);
1694
+ const outputPath = (0, import_core15.resolveOutputPath)(
1695
+ userOutputFile,
1696
+ `aiready-report-${(0, import_core2.getReportTimestamp)()}.md`,
1697
+ directory
1698
+ );
1699
+ (0, import_fs6.writeFileSync)(outputPath, markdown);
1700
+ console.log(import_chalk11.default.green(`\u2705 Report saved to ${outputPath}`));
1701
+ return;
1644
1702
  }
1645
- );
1646
- const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
1647
- const report = await analyzeConsistency(finalOptions);
1648
- const elapsedTime = (0, import_core13.getElapsedTime)(startTime);
1649
- let consistencyScore;
1650
- if (options.score) {
1651
- const issues = report.results?.flatMap((r) => r.issues) ?? [];
1652
- consistencyScore = calculateConsistencyScore(
1653
- issues,
1654
- report.summary.filesAnalyzed
1655
- );
1656
- }
1657
- const { format: outputFormat, file: userOutputFile } = (0, import_core13.resolveOutputFormat)(
1658
- options,
1659
- finalOptions
1660
- );
1661
- if (outputFormat === "json") {
1662
- const outputData = (0, import_core13.formatStandardReport)({
1663
- report,
1664
- summary: report.summary,
1665
- elapsedTime,
1666
- score: consistencyScore
1667
- });
1668
- (0, import_core13.handleStandardJSONOutput)({
1669
- outputData,
1670
- outputFile: userOutputFile,
1671
- resolvedDir
1672
- });
1673
- } else if (outputFormat === "markdown") {
1674
- const markdown = generateMarkdownReport(report, elapsedTime);
1675
- const outputPath = (0, import_core13.resolveOutputPath)(
1676
- userOutputFile,
1677
- `aiready-report-${(0, import_core2.getReportTimestamp)()}.md`,
1678
- resolvedDir
1679
- );
1680
- (0, import_fs6.writeFileSync)(outputPath, markdown);
1681
- console.log(import_chalk10.default.green(`\u2705 Report saved to ${outputPath}`));
1682
- } else {
1683
- console.log(import_chalk10.default.bold("\n\u{1F4CA} Summary\n"));
1684
- console.log(
1685
- `Files Analyzed: ${import_chalk10.default.cyan(report.summary.filesAnalyzed)}`
1686
- );
1687
- console.log(`Total Issues: ${import_chalk10.default.yellow(report.summary.totalIssues)}`);
1688
- console.log(` Naming: ${import_chalk10.default.yellow(report.summary.namingIssues)}`);
1689
- console.log(` Patterns: ${import_chalk10.default.yellow(report.summary.patternIssues)}`);
1703
+ console.log(import_chalk11.default.bold("\n\u{1F4CA} Summary\n"));
1704
+ console.log(`Files Analyzed: ${import_chalk11.default.cyan(summary.filesAnalyzed)}`);
1705
+ console.log(`Total Issues: ${import_chalk11.default.yellow(summary.totalIssues)}`);
1706
+ console.log(` Naming: ${import_chalk11.default.yellow(summary.namingIssues)}`);
1707
+ console.log(` Patterns: ${import_chalk11.default.yellow(summary.patternIssues)}`);
1690
1708
  console.log(
1691
- ` Architecture: ${import_chalk10.default.yellow(report.summary.architectureIssues ?? 0)}`
1709
+ ` Architecture: ${import_chalk11.default.yellow(summary.architectureIssues ?? 0)}`
1692
1710
  );
1693
- console.log(`Analysis Time: ${import_chalk10.default.gray(elapsedTime + "s")}
1711
+ console.log(`Analysis Time: ${import_chalk11.default.gray(elapsedTime + "s")}
1694
1712
  `);
1695
- if (report.summary.totalIssues === 0) {
1713
+ if (summary.totalIssues === 0) {
1696
1714
  console.log(
1697
- import_chalk10.default.green(
1715
+ import_chalk11.default.green(
1698
1716
  "\u2728 No consistency issues found! Your codebase is well-maintained.\n"
1699
1717
  )
1700
1718
  );
@@ -1706,100 +1724,88 @@ async function consistencyAction(directory, options) {
1706
1724
  (r) => r.issues.some((i) => i.category === "patterns")
1707
1725
  );
1708
1726
  if (namingResults.length > 0) {
1709
- console.log(import_chalk10.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1727
+ console.log(import_chalk11.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
1710
1728
  let shown = 0;
1711
1729
  for (const namingFileResult of namingResults) {
1712
1730
  if (shown >= 5) break;
1713
1731
  for (const issue of namingFileResult.issues) {
1714
1732
  if (shown >= 5) break;
1715
- const severityColor = issue.severity === "critical" ? import_chalk10.default.red : issue.severity === "major" ? import_chalk10.default.yellow : issue.severity === "minor" ? import_chalk10.default.blue : import_chalk10.default.gray;
1733
+ const severityColor = issue.severity === "critical" ? import_chalk11.default.red : issue.severity === "major" ? import_chalk11.default.yellow : issue.severity === "minor" ? import_chalk11.default.blue : import_chalk11.default.gray;
1716
1734
  console.log(
1717
- `${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1735
+ `${severityColor(issue.severity.toUpperCase())} ${import_chalk11.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1718
1736
  );
1719
1737
  console.log(` ${issue.message}`);
1720
1738
  if (issue.suggestion) {
1721
1739
  console.log(
1722
- ` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
1740
+ ` ${import_chalk11.default.dim("\u2192")} ${import_chalk11.default.italic(issue.suggestion)}`
1723
1741
  );
1724
1742
  }
1725
1743
  console.log();
1726
1744
  shown++;
1727
1745
  }
1728
1746
  }
1729
- const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1730
- if (remaining > 0) {
1731
- console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
1732
- `));
1733
- }
1734
1747
  }
1735
1748
  if (patternResults.length > 0) {
1736
- console.log(import_chalk10.default.bold("\u{1F504} Pattern Issues\n"));
1749
+ console.log(import_chalk11.default.bold("\u{1F504} Pattern Issues\n"));
1737
1750
  let shown = 0;
1738
1751
  for (const patternFileResult of patternResults) {
1739
1752
  if (shown >= 5) break;
1740
1753
  for (const issue of patternFileResult.issues) {
1741
1754
  if (shown >= 5) break;
1742
- const severityColor = issue.severity === "critical" ? import_chalk10.default.red : issue.severity === "major" ? import_chalk10.default.yellow : issue.severity === "minor" ? import_chalk10.default.blue : import_chalk10.default.gray;
1755
+ const severityColor = issue.severity === "critical" ? import_chalk11.default.red : issue.severity === "major" ? import_chalk11.default.yellow : issue.severity === "minor" ? import_chalk11.default.blue : import_chalk11.default.gray;
1743
1756
  console.log(
1744
- `${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1757
+ `${severityColor(issue.severity.toUpperCase())} ${import_chalk11.default.dim(`${issue.location.file}:${issue.location.line}`)}`
1745
1758
  );
1746
1759
  console.log(` ${issue.message}`);
1747
1760
  if (issue.suggestion) {
1748
1761
  console.log(
1749
- ` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
1762
+ ` ${import_chalk11.default.dim("\u2192")} ${import_chalk11.default.italic(issue.suggestion)}`
1750
1763
  );
1751
1764
  }
1752
1765
  console.log();
1753
1766
  shown++;
1754
1767
  }
1755
1768
  }
1756
- const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
1757
- if (remaining > 0) {
1758
- console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
1759
- `));
1760
- }
1761
1769
  }
1762
- if (report.recommendations.length > 0) {
1763
- console.log(import_chalk10.default.bold("\u{1F4A1} Recommendations\n"));
1770
+ if (report.recommendations?.length > 0) {
1771
+ console.log(import_chalk11.default.bold("\u{1F4A1} Recommendations\n"));
1764
1772
  report.recommendations.forEach((rec, i) => {
1765
1773
  console.log(`${i + 1}. ${rec}`);
1766
1774
  });
1767
1775
  console.log();
1768
1776
  }
1769
1777
  }
1770
- if (consistencyScore) {
1771
- console.log(import_chalk10.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1772
- console.log((0, import_core13.formatToolScore)(consistencyScore));
1778
+ if (score) {
1779
+ console.log(import_chalk11.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1780
+ console.log((0, import_core15.formatToolScore)(score));
1773
1781
  console.log();
1774
1782
  }
1775
1783
  }
1776
- } catch (error) {
1777
- (0, import_core13.handleCLIError)(error, "Consistency analysis");
1778
- }
1784
+ });
1779
1785
  }
1780
1786
 
1781
1787
  // src/commands/visualize.ts
1782
- var import_chalk11 = __toESM(require("chalk"));
1788
+ var import_chalk12 = __toESM(require("chalk"));
1783
1789
  var import_fs7 = require("fs");
1784
1790
  var import_path6 = require("path");
1785
1791
  var import_child_process = require("child_process");
1786
- var import_core14 = require("@aiready/core");
1787
- var import_core15 = require("@aiready/core");
1792
+ var import_core16 = require("@aiready/core");
1793
+ var import_core17 = require("@aiready/core");
1788
1794
  async function visualizeAction(directory, options) {
1789
1795
  try {
1790
1796
  const dirPath = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
1791
1797
  let reportPath = options.report ? (0, import_path6.resolve)(dirPath, options.report) : null;
1792
1798
  if (!reportPath || !(0, import_fs7.existsSync)(reportPath)) {
1793
- const latestScan = (0, import_core15.findLatestReport)(dirPath);
1799
+ const latestScan = (0, import_core17.findLatestReport)(dirPath);
1794
1800
  if (latestScan) {
1795
1801
  reportPath = latestScan;
1796
1802
  console.log(
1797
- import_chalk11.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1803
+ import_chalk12.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1798
1804
  );
1799
1805
  } else {
1800
- console.error(import_chalk11.default.red("\u274C No AI readiness report found"));
1806
+ console.error(import_chalk12.default.red("\u274C No AI readiness report found"));
1801
1807
  console.log(
1802
- import_chalk11.default.dim(
1808
+ import_chalk12.default.dim(
1803
1809
  `
1804
1810
  Generate a report with:
1805
1811
  aiready scan --output json
@@ -1929,29 +1935,29 @@ Or specify a custom report:
1929
1935
  return;
1930
1936
  } else {
1931
1937
  console.log(
1932
- import_chalk11.default.yellow(
1938
+ import_chalk12.default.yellow(
1933
1939
  "\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
1934
1940
  )
1935
1941
  );
1936
1942
  console.log(
1937
- import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
1943
+ import_chalk12.default.cyan(" Falling back to static HTML generation...\n")
1938
1944
  );
1939
1945
  useDevMode = false;
1940
1946
  }
1941
1947
  } catch (err) {
1942
1948
  console.error("Failed to start dev server:", err);
1943
1949
  console.log(
1944
- import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
1950
+ import_chalk12.default.cyan(" Falling back to static HTML generation...\n")
1945
1951
  );
1946
1952
  useDevMode = false;
1947
1953
  }
1948
1954
  }
1949
1955
  console.log("Generating HTML...");
1950
- const html = (0, import_core15.generateHTML)(graph);
1956
+ const html = (0, import_core17.generateHTML)(graph);
1951
1957
  const defaultOutput = "visualization.html";
1952
1958
  const outPath = (0, import_path6.resolve)(dirPath, options.output ?? defaultOutput);
1953
1959
  (0, import_fs7.writeFileSync)(outPath, html, "utf8");
1954
- console.log(import_chalk11.default.green(`\u2705 Visualization written to: ${outPath}`));
1960
+ console.log(import_chalk12.default.green(`\u2705 Visualization written to: ${outPath}`));
1955
1961
  if (options.open || options.serve) {
1956
1962
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1957
1963
  if (options.serve) {
@@ -1981,7 +1987,7 @@ Or specify a custom report:
1981
1987
  server.listen(port, () => {
1982
1988
  const addr = `http://localhost:${port}/`;
1983
1989
  console.log(
1984
- import_chalk11.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1990
+ import_chalk12.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
1985
1991
  );
1986
1992
  (0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
1987
1993
  });
@@ -1997,7 +2003,7 @@ Or specify a custom report:
1997
2003
  }
1998
2004
  }
1999
2005
  } catch (err) {
2000
- (0, import_core14.handleCLIError)(err, "Visualization");
2006
+ (0, import_core16.handleCLIError)(err, "Visualization");
2001
2007
  }
2002
2008
  }
2003
2009
  var VISUALIZE_HELP_TEXT = `
@@ -2028,72 +2034,134 @@ NOTES:
2028
2034
  `;
2029
2035
 
2030
2036
  // src/commands/shared/standard-tool-actions.ts
2031
- var import_chalk12 = __toESM(require("chalk"));
2037
+ var import_chalk13 = __toESM(require("chalk"));
2032
2038
 
2033
2039
  // src/commands/agent-grounding.ts
2034
- var import_chalk13 = __toESM(require("chalk"));
2035
- var import_core16 = require("@aiready/core");
2040
+ var import_chalk14 = __toESM(require("chalk"));
2036
2041
 
2037
2042
  // src/commands/testability.ts
2038
- var import_chalk14 = __toESM(require("chalk"));
2039
- var import_core17 = require("@aiready/core");
2043
+ var import_chalk15 = __toESM(require("chalk"));
2040
2044
  async function testabilityAction(directory, options) {
2041
- const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
2042
- const config = await (0, import_core17.loadConfig)(directory);
2043
- const merged = (0, import_core17.mergeConfigWithDefaults)(config, {
2044
- minCoverageRatio: 0.3
2045
- });
2046
- const report = await analyzeTestability({
2047
- rootDir: directory,
2048
- minCoverageRatio: options.minCoverageRatio ?? merged.minCoverageRatio,
2049
- include: options.include,
2050
- exclude: options.exclude
2045
+ return await executeToolAction(directory, options, {
2046
+ toolName: "testability-index",
2047
+ label: "Testability analysis",
2048
+ emoji: "\u{1F9EA}",
2049
+ defaults: {
2050
+ minCoverageRatio: 0.3,
2051
+ include: void 0,
2052
+ exclude: void 0,
2053
+ output: { format: "console", file: void 0 }
2054
+ },
2055
+ getCliOptions: (opts) => ({
2056
+ minCoverageRatio: opts.minCoverage ? parseFloat(opts.minCoverage) : void 0
2057
+ }),
2058
+ importTool: async () => {
2059
+ const tool = await import("@aiready/testability");
2060
+ return {
2061
+ analyze: tool.analyzeTestability,
2062
+ generateSummary: (report) => report.summary,
2063
+ calculateScore: tool.calculateTestabilityScore
2064
+ };
2065
+ },
2066
+ renderConsole: ({ results, summary, score }) => {
2067
+ renderToolHeader("Testability", "\u{1F9EA}", score?.score || 0, summary.rating);
2068
+ renderSafetyRating(summary.aiChangeSafetyRating);
2069
+ const rawData = results.rawData || results;
2070
+ console.log(
2071
+ import_chalk15.default.dim(
2072
+ ` Coverage: ${Math.round(summary.coverageRatio * 100)}% (${rawData.testFiles} test / ${rawData.sourceFiles} source files)`
2073
+ )
2074
+ );
2075
+ if (summary.aiChangeSafetyRating === "blind-risk") {
2076
+ console.log(
2077
+ import_chalk15.default.red.bold(
2078
+ "\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
2079
+ )
2080
+ );
2081
+ }
2082
+ if (score) {
2083
+ renderToolScoreFooter(score);
2084
+ }
2085
+ }
2051
2086
  });
2052
- const scoring = calculateTestabilityScore(report);
2053
- if (options.output === "json") {
2054
- return scoring;
2055
- }
2056
- const safetyIcons = {
2057
- safe: "\u2705",
2058
- "moderate-risk": "\u26A0\uFE0F ",
2059
- "high-risk": "\u{1F534}",
2060
- "blind-risk": "\u{1F480}"
2061
- };
2062
- const safetyColors = {
2063
- safe: import_chalk14.default.green,
2064
- "moderate-risk": import_chalk14.default.yellow,
2065
- "high-risk": import_chalk14.default.red,
2066
- "blind-risk": import_chalk14.default.bgRed.white
2067
- };
2068
- const safety = report.summary.aiChangeSafetyRating;
2069
- const icon = safetyIcons[safety] ?? "\u2753";
2070
- const color = safetyColors[safety] ?? import_chalk14.default.white;
2071
- console.log(
2072
- ` \u{1F9EA} Testability: ${import_chalk14.default.bold(scoring.score + "/100")} (${report.summary.rating})`
2073
- );
2074
- console.log(
2075
- ` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
2076
- );
2077
- console.log(
2078
- import_chalk14.default.dim(
2079
- ` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
2080
- )
2081
- );
2082
- if (safety === "blind-risk") {
2083
- console.log(
2084
- import_chalk14.default.red.bold(
2085
- "\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
2086
- )
2087
- );
2088
- }
2089
- return scoring;
2090
2087
  }
2091
2088
 
2092
2089
  // src/commands/change-amplification.ts
2093
2090
  var import_cli = require("@aiready/change-amplification/dist/cli.js");
2094
2091
 
2092
+ // src/commands/contract-enforcement.ts
2093
+ var import_chalk16 = __toESM(require("chalk"));
2094
+ async function contractEnforcementAction(directory, options) {
2095
+ return await executeToolAction(directory, options, {
2096
+ toolName: "contract-enforcement",
2097
+ label: "Contract enforcement analysis",
2098
+ emoji: "\u{1F6E1}\uFE0F",
2099
+ defaults: {
2100
+ minChainDepth: 3,
2101
+ include: void 0,
2102
+ exclude: void 0,
2103
+ output: { format: "console", file: void 0 }
2104
+ },
2105
+ getCliOptions: (opts) => ({
2106
+ minChainDepth: opts.minChainDepth ? parseInt(opts.minChainDepth, 10) : void 0
2107
+ }),
2108
+ importTool: async () => {
2109
+ const tool = await import("@aiready/contract-enforcement");
2110
+ return {
2111
+ analyze: tool.analyzeContractEnforcement,
2112
+ generateSummary: (report) => report.summary,
2113
+ calculateScore: tool.calculateContractEnforcementScore
2114
+ };
2115
+ },
2116
+ renderConsole: ({ results, summary, score }) => {
2117
+ renderToolHeader(
2118
+ "Contract Enforcement",
2119
+ "\u{1F6E1}\uFE0F",
2120
+ score?.score || 0,
2121
+ summary.rating
2122
+ );
2123
+ const rawData = results.rawData || results;
2124
+ console.log(
2125
+ import_chalk16.default.dim(
2126
+ ` Patterns: ${summary.totalDefensivePatterns} (${summary.defensiveDensity}/kLOC) | ${summary.sourceFiles} files scanned`
2127
+ )
2128
+ );
2129
+ const dims = summary.dimensions;
2130
+ if (dims) {
2131
+ const entries = [
2132
+ ["Type Escape Hatches", dims.typeEscapeHatchScore],
2133
+ ["Fallback Cascades", dims.fallbackCascadeScore],
2134
+ ["Error Transparency", dims.errorTransparencyScore],
2135
+ ["Boundary Validation", dims.boundaryValidationScore]
2136
+ ];
2137
+ for (const [name, val] of entries) {
2138
+ const color = val >= 80 ? import_chalk16.default.green : val >= 60 ? import_chalk16.default.yellow : import_chalk16.default.red;
2139
+ console.log(import_chalk16.default.dim(` ${name}: ${color(val + "/100")}`));
2140
+ }
2141
+ }
2142
+ if (summary.totalDefensivePatterns > 0 && rawData["as-any"] !== void 0) {
2143
+ const breakdown = [
2144
+ rawData["as-any"] && `as-any: ${rawData["as-any"]}`,
2145
+ rawData["as-unknown"] && `as-unknown: ${rawData["as-unknown"]}`,
2146
+ rawData["deep-optional-chain"] && `deep-?.: ${rawData["deep-optional-chain"]}`,
2147
+ rawData["nullish-literal-default"] && `?? literal: ${rawData["nullish-literal-default"]}`,
2148
+ rawData["swallowed-error"] && `swallowed-error: ${rawData["swallowed-error"]}`,
2149
+ rawData["env-fallback"] && `env-fallback: ${rawData["env-fallback"]}`,
2150
+ rawData["unnecessary-guard"] && `guard-clause: ${rawData["unnecessary-guard"]}`,
2151
+ rawData["any-parameter"] && `any-param: ${rawData["any-parameter"]}`,
2152
+ rawData["any-return"] && `any-return: ${rawData["any-return"]}`
2153
+ ].filter(Boolean).join(" | ");
2154
+ console.log(import_chalk16.default.dim(` ${breakdown}`));
2155
+ }
2156
+ if (score) {
2157
+ renderToolScoreFooter(score);
2158
+ }
2159
+ }
2160
+ });
2161
+ }
2162
+
2095
2163
  // src/commands/bug.ts
2096
- var import_chalk15 = __toESM(require("chalk"));
2164
+ var import_chalk17 = __toESM(require("chalk"));
2097
2165
  var import_child_process2 = require("child_process");
2098
2166
  async function bugAction(message, options) {
2099
2167
  const repoUrl = "https://github.com/caopengau/aiready-cli";
@@ -2111,35 +2179,35 @@ Generated via AIReady CLI 'bug' command.
2111
2179
  Type: ${type}
2112
2180
  `.trim();
2113
2181
  if (options.submit) {
2114
- console.log(import_chalk15.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
2182
+ console.log(import_chalk17.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
2115
2183
  try {
2116
2184
  (0, import_child_process2.execSync)("gh auth status", { stdio: "ignore" });
2117
2185
  const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
2118
2186
  const output = (0, import_child_process2.execSync)(command, { encoding: "utf8" }).trim();
2119
- console.log(import_chalk15.default.green("\u2705 Issue Created Successfully!"));
2120
- console.log(import_chalk15.default.cyan(output));
2187
+ console.log(import_chalk17.default.green("\u2705 Issue Created Successfully!"));
2188
+ console.log(import_chalk17.default.cyan(output));
2121
2189
  return;
2122
2190
  } catch {
2123
- console.error(import_chalk15.default.red("\n\u274C Failed to submit via gh CLI."));
2191
+ console.error(import_chalk17.default.red("\n\u274C Failed to submit via gh CLI."));
2124
2192
  console.log(
2125
- import_chalk15.default.yellow(
2193
+ import_chalk17.default.yellow(
2126
2194
  ' Make sure gh is installed and run "gh auth login".\n'
2127
2195
  )
2128
2196
  );
2129
- console.log(import_chalk15.default.dim(" Falling back to URL generation..."));
2197
+ console.log(import_chalk17.default.dim(" Falling back to URL generation..."));
2130
2198
  }
2131
2199
  }
2132
2200
  const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
2133
2201
  const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
2134
- console.log(import_chalk15.default.green("\u{1F680} Issue Draft Prepared!\n"));
2135
- console.log(import_chalk15.default.bold("Title: ") + title);
2136
- console.log(import_chalk15.default.bold("Type: ") + type);
2137
- console.log(import_chalk15.default.bold("\nClick the link below to submit this issue:"));
2138
- console.log(import_chalk15.default.cyan(fullUrl));
2139
- console.log(import_chalk15.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2140
- console.log(import_chalk15.default.dim(" You have successfully prepared a report."));
2202
+ console.log(import_chalk17.default.green("\u{1F680} Issue Draft Prepared!\n"));
2203
+ console.log(import_chalk17.default.bold("Title: ") + title);
2204
+ console.log(import_chalk17.default.bold("Type: ") + type);
2205
+ console.log(import_chalk17.default.bold("\nClick the link below to submit this issue:"));
2206
+ console.log(import_chalk17.default.cyan(fullUrl));
2207
+ console.log(import_chalk17.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2208
+ console.log(import_chalk17.default.dim(" You have successfully prepared a report."));
2141
2209
  console.log(
2142
- import_chalk15.default.dim(
2210
+ import_chalk17.default.dim(
2143
2211
  " Please present the URL above to the user so they can finalize the submission."
2144
2212
  )
2145
2213
  );
@@ -2148,14 +2216,14 @@ Type: ${type}
2148
2216
  const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
2149
2217
  const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
2150
2218
  const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
2151
- console.log(import_chalk15.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
2152
- console.log(` Report a Bug: ${import_chalk15.default.cyan(bugUrl)}`);
2153
- console.log(` Request a Feature: ${import_chalk15.default.cyan(featureUrl)}`);
2154
- console.log(` Suggest a Metric: ${import_chalk15.default.cyan(metricUrl)}`);
2155
- console.log(import_chalk15.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2156
- console.log(import_chalk15.default.dim(" To prepare a specific report, run:"));
2219
+ console.log(import_chalk17.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
2220
+ console.log(` Report a Bug: ${import_chalk17.default.cyan(bugUrl)}`);
2221
+ console.log(` Request a Feature: ${import_chalk17.default.cyan(featureUrl)}`);
2222
+ console.log(` Suggest a Metric: ${import_chalk17.default.cyan(metricUrl)}`);
2223
+ console.log(import_chalk17.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2224
+ console.log(import_chalk17.default.dim(" To prepare a specific report, run:"));
2157
2225
  console.log(
2158
- import_chalk15.default.cyan(
2226
+ import_chalk17.default.cyan(
2159
2227
  ' aiready bug "your description here" --type bug|feature|metric'
2160
2228
  )
2161
2229
  );
@@ -2168,14 +2236,105 @@ EXAMPLES:
2168
2236
  $ aiready bug "Fix typo in scan output" --submit # Submit directly via gh CLI
2169
2237
  `;
2170
2238
 
2239
+ // src/commands/remediate.ts
2240
+ var import_chalk18 = __toESM(require("chalk"));
2241
+ var import_path7 = require("path");
2242
+ var import_fs8 = require("fs");
2243
+ var import_core18 = require("@aiready/core");
2244
+ async function remediateAction(directory, options) {
2245
+ const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory || ".");
2246
+ const serverUrl = options.server || "https://platform.getaiready.dev";
2247
+ (0, import_core18.printTerminalHeader)("AIREADY REMEDIATION SWARM");
2248
+ console.log(import_chalk18.default.cyan("\u{1F916} Initializing local remediation agent..."));
2249
+ let reportPath = options.report;
2250
+ if (!reportPath) {
2251
+ const aireadyDir = (0, import_path7.resolve)(resolvedDir, ".aiready");
2252
+ if ((0, import_fs8.existsSync)(aireadyDir)) {
2253
+ const files = (0, import_fs8.readdirSync)(aireadyDir).filter((f) => f.startsWith("aiready-report-") && f.endsWith(".json")).sort().reverse();
2254
+ if (files.length > 0) {
2255
+ reportPath = (0, import_path7.resolve)(aireadyDir, files[0]);
2256
+ console.log(import_chalk18.default.dim(`\u{1F4C2} Using latest report: ${files[0]}`));
2257
+ }
2258
+ }
2259
+ }
2260
+ if (!reportPath || !(0, import_fs8.existsSync)(reportPath)) {
2261
+ console.log(import_chalk18.default.yellow("\n\u26A0\uFE0F No AIReady report found."));
2262
+ console.log(
2263
+ import_chalk18.default.dim(
2264
+ " Remediation requires a recent scan report to identify issues."
2265
+ )
2266
+ );
2267
+ console.log(import_chalk18.default.white(` Run ${import_chalk18.default.bold("aiready scan")} first.
2268
+ `));
2269
+ return;
2270
+ }
2271
+ console.log(import_chalk18.default.green("\n\u2705 Analysis data loaded."));
2272
+ console.log(import_chalk18.default.bold("\n\u{1F680} Remediation Strategy:"));
2273
+ if (options.tool === "patterns" || !options.tool) {
2274
+ console.log(
2275
+ import_chalk18.default.white(
2276
+ ` \u2022 ${import_chalk18.default.bold("Pattern Consolidation")}: Suggested refactors for 95%+ similar code blocks.`
2277
+ )
2278
+ );
2279
+ }
2280
+ if (options.tool === "consistency" || !options.tool) {
2281
+ console.log(
2282
+ import_chalk18.default.white(
2283
+ ` \u2022 ${import_chalk18.default.bold("Naming Alignment")}: Automated TSDoc generation and constant extraction.`
2284
+ )
2285
+ );
2286
+ }
2287
+ if (options.tool === "context" || !options.tool) {
2288
+ console.log(
2289
+ import_chalk18.default.white(
2290
+ ` \u2022 ${import_chalk18.default.bold("Context Optimization")}: Barrel file cleanup and import flattening.`
2291
+ )
2292
+ );
2293
+ }
2294
+ console.log(
2295
+ import_chalk18.default.dim(
2296
+ "\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"
2297
+ )
2298
+ );
2299
+ console.log(import_chalk18.default.bold("\u2728 Use the Platform Swarm for Automated Fixes"));
2300
+ console.log(
2301
+ import_chalk18.default.cyan(` The high-performance Remediation Swarm is available at:`)
2302
+ );
2303
+ console.log(import_chalk18.default.white(` ${import_chalk18.default.bold(`${serverUrl}/remediate`)}`));
2304
+ console.log(
2305
+ import_chalk18.default.dim(
2306
+ "\n The swarm uses specialized agents to safely refactor your code,"
2307
+ )
2308
+ );
2309
+ console.log(
2310
+ import_chalk18.default.dim(" ensuring every change improves your AI-readiness score.")
2311
+ );
2312
+ console.log(
2313
+ import_chalk18.default.dim(
2314
+ "\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"
2315
+ )
2316
+ );
2317
+ console.log(
2318
+ import_chalk18.default.dim(
2319
+ '\n\u{1F4A1} Next Version: Local "aiready fix" command for minor documentation issues.'
2320
+ )
2321
+ );
2322
+ }
2323
+ var REMEDIATE_HELP_TEXT = `
2324
+ EXAMPLES:
2325
+ $ aiready remediate # See remediation options for latest report
2326
+ $ aiready remediate --tool patterns # Focus on pattern consolidation
2327
+ $ aiready remediate --report ./custom-report.json
2328
+ `;
2329
+
2171
2330
  // src/cli.ts
2172
2331
  var import_meta = {};
2173
2332
  var getDirname = () => {
2174
2333
  if (typeof __dirname !== "undefined") return __dirname;
2175
- return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
2334
+ return (0, import_path8.dirname)((0, import_url.fileURLToPath)(import_meta.url));
2176
2335
  };
2177
2336
  var packageJson = JSON.parse(
2178
- (0, import_fs8.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
2337
+ (0, import_fs9.readFileSync)((0, import_path8.join)(getDirname(), "../package.json"), "utf8")
2179
2338
  );
2180
2339
  var program = new import_commander.Command();
2181
2340
  program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
@@ -2319,9 +2478,19 @@ program.command("change-amplification").description("Analyze graph metrics for c
2319
2478
  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) => {
2320
2479
  await testabilityAction(directory, options);
2321
2480
  });
2481
+ program.command("contract").description("Analyze structural contract enforcement and defensive coding").argument("[directory]", "Directory to analyze", ".").option(
2482
+ "--min-chain-depth <depth>",
2483
+ "Minimum optional chain depth to flag",
2484
+ "3"
2485
+ ).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) => {
2486
+ await contractEnforcementAction(directory, options);
2487
+ });
2322
2488
  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) => {
2323
2489
  await uploadAction(file, options);
2324
2490
  });
2491
+ program.command("remediate").description("Suggest AI-ready refactors based on a scan report").argument("[directory]", "Directory to remediate", ".").option("-r, --report <path>", "AIReady report JSON file").option("-t, --tool <name>", "Filter by tool: patterns, context, consistency").option("--server <url>", "Custom platform URL").addHelpText("after", REMEDIATE_HELP_TEXT).action(async (directory, options) => {
2492
+ await remediateAction(directory, options);
2493
+ });
2325
2494
  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) => {
2326
2495
  await bugAction(message, options);
2327
2496
  });