@aiready/cli 0.14.25 → 0.14.26
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/chunk-L4VXALJD.mjs +280 -0
- package/dist/chunk-SK6WW6HW.mjs +325 -0
- package/dist/cli.js +633 -662
- package/dist/cli.mjs +382 -467
- package/dist/index.js +242 -213
- package/dist/index.mjs +7 -1
- package/package.json +12 -12
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var import_url = require("url");
|
|
|
33
33
|
var import_chalk6 = __toESM(require("chalk"));
|
|
34
34
|
var import_fs4 = require("fs");
|
|
35
35
|
var import_path4 = require("path");
|
|
36
|
-
var
|
|
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:
|
|
49
|
-
void
|
|
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":
|
|
@@ -532,9 +588,9 @@ async function resolveScanConfig(resolvedDir, options) {
|
|
|
532
588
|
var import_chalk5 = __toESM(require("chalk"));
|
|
533
589
|
var import_fs3 = require("fs");
|
|
534
590
|
var import_path3 = require("path");
|
|
535
|
-
var
|
|
591
|
+
var import_core9 = require("@aiready/core");
|
|
536
592
|
|
|
537
|
-
// src/
|
|
593
|
+
// src/orchestrator.ts
|
|
538
594
|
var import_core7 = require("@aiready/core");
|
|
539
595
|
var TOOL_PACKAGE_MAP = {
|
|
540
596
|
[import_core7.ToolName.PatternDetect]: "@aiready/pattern-detect",
|
|
@@ -558,216 +614,257 @@ var TOOL_PACKAGE_MAP = {
|
|
|
558
614
|
"deps-health": "@aiready/deps",
|
|
559
615
|
"change-amp": "@aiready/change-amplification"
|
|
560
616
|
};
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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
|
-
}
|
|
617
|
+
var UnifiedOrchestrator = class {
|
|
618
|
+
/**
|
|
619
|
+
* Initialize orchestrator with a tool registry.
|
|
620
|
+
* Injection pattern helps with testability and AI readiness score.
|
|
621
|
+
*/
|
|
622
|
+
constructor(registry = import_core7.ToolRegistry) {
|
|
623
|
+
this.registry = registry;
|
|
579
624
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
toolsRun: [],
|
|
602
|
-
executionTime: 0,
|
|
603
|
-
config: options,
|
|
604
|
-
toolConfigs: {}
|
|
625
|
+
/**
|
|
626
|
+
* Deeply sanitizes a configuration object.
|
|
627
|
+
*/
|
|
628
|
+
sanitizeConfig(obj) {
|
|
629
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
|
|
630
|
+
const sanitized = {};
|
|
631
|
+
const infraToStrip = [
|
|
632
|
+
"rootDir",
|
|
633
|
+
"onProgress",
|
|
634
|
+
"progressCallback",
|
|
635
|
+
"streamResults",
|
|
636
|
+
"batchSize",
|
|
637
|
+
"useSmartDefaults"
|
|
638
|
+
];
|
|
639
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
640
|
+
if (infraToStrip.includes(key)) continue;
|
|
641
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
642
|
+
sanitized[key] = this.sanitizeConfig(value);
|
|
643
|
+
} else {
|
|
644
|
+
sanitized[key] = value;
|
|
645
|
+
}
|
|
605
646
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
647
|
+
return sanitized;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Performs the unified analysis.
|
|
651
|
+
*/
|
|
652
|
+
async analyze(options) {
|
|
653
|
+
await (0, import_core7.initializeParsers)();
|
|
654
|
+
const startTime = Date.now();
|
|
655
|
+
const requestedTools = options.tools ?? [
|
|
656
|
+
"patterns",
|
|
657
|
+
"context",
|
|
658
|
+
"consistency"
|
|
659
|
+
];
|
|
660
|
+
const result = {
|
|
661
|
+
summary: {
|
|
662
|
+
totalIssues: 0,
|
|
663
|
+
criticalIssues: 0,
|
|
664
|
+
majorIssues: 0,
|
|
665
|
+
totalFiles: 0,
|
|
666
|
+
toolsRun: [],
|
|
667
|
+
executionTime: 0,
|
|
668
|
+
config: options,
|
|
669
|
+
toolConfigs: {}
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
for (const toolName of requestedTools) {
|
|
673
|
+
let provider = this.registry.find(toolName);
|
|
674
|
+
if (!provider) {
|
|
675
|
+
const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
|
|
676
|
+
try {
|
|
677
|
+
await import(packageName);
|
|
678
|
+
provider = this.registry.find(toolName);
|
|
679
|
+
} catch (err) {
|
|
619
680
|
console.log(
|
|
620
|
-
`\
|
|
681
|
+
`\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
|
|
682
|
+
err.message
|
|
621
683
|
);
|
|
622
684
|
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
685
|
+
}
|
|
686
|
+
if (!provider) {
|
|
687
|
+
console.warn(
|
|
688
|
+
`\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
|
|
627
689
|
);
|
|
690
|
+
continue;
|
|
628
691
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
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];
|
|
692
|
+
try {
|
|
693
|
+
const toolOptions = {
|
|
694
|
+
rootDir: options.rootDir
|
|
695
|
+
};
|
|
696
|
+
[...import_core7.GLOBAL_INFRA_OPTIONS, ...import_core7.COMMON_FINE_TUNING_OPTIONS].forEach(
|
|
697
|
+
(key) => {
|
|
698
|
+
if (key in options && key !== "toolConfigs" && key !== "tools") {
|
|
699
|
+
toolOptions[key] = options[key];
|
|
700
|
+
}
|
|
648
701
|
}
|
|
702
|
+
);
|
|
703
|
+
if (options.toolConfigs?.[provider.id]) {
|
|
704
|
+
Object.assign(toolOptions, options.toolConfigs[provider.id]);
|
|
705
|
+
} else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
|
|
706
|
+
Object.assign(toolOptions, options.tools[provider.id]);
|
|
707
|
+
}
|
|
708
|
+
toolOptions.onProgress = (processed, total, msg) => {
|
|
709
|
+
if (options.progressCallback) {
|
|
710
|
+
options.progressCallback({
|
|
711
|
+
tool: provider.id,
|
|
712
|
+
processed,
|
|
713
|
+
total,
|
|
714
|
+
message: msg
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
const output = await provider.analyze(toolOptions);
|
|
719
|
+
if (output.metadata) {
|
|
720
|
+
output.metadata.config = this.sanitizeConfig(toolOptions);
|
|
649
721
|
}
|
|
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
722
|
if (options.progressCallback) {
|
|
660
|
-
options.progressCallback({
|
|
661
|
-
tool: provider.id,
|
|
662
|
-
processed,
|
|
663
|
-
total,
|
|
664
|
-
message
|
|
665
|
-
});
|
|
723
|
+
options.progressCallback({ tool: provider.id, data: output });
|
|
666
724
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
|
725
|
+
result[provider.id] = output;
|
|
726
|
+
result.summary.toolsRun.push(provider.id);
|
|
727
|
+
const toolConfig = output.summary?.config ?? output.metadata?.config ?? toolOptions;
|
|
728
|
+
result.summary.toolConfigs[provider.id] = this.sanitizeConfig(toolConfig);
|
|
729
|
+
const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
|
|
730
|
+
if (toolFiles > result.summary.totalFiles) {
|
|
731
|
+
result.summary.totalFiles = toolFiles;
|
|
732
|
+
}
|
|
733
|
+
const issueCount = output.results.reduce(
|
|
734
|
+
(sum, file) => sum + (file.issues?.length ?? 0),
|
|
735
|
+
0
|
|
684
736
|
);
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
|
|
689
|
-
if (toolFiles > result.summary.totalFiles) {
|
|
690
|
-
result.summary.totalFiles = toolFiles;
|
|
737
|
+
result.summary.totalIssues += issueCount;
|
|
738
|
+
} catch (err) {
|
|
739
|
+
console.error(`\u274C Error running tool '${provider.id}':`, err);
|
|
691
740
|
}
|
|
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
741
|
}
|
|
742
|
+
result.summary.config = this.sanitizeConfig({
|
|
743
|
+
scan: {
|
|
744
|
+
tools: requestedTools,
|
|
745
|
+
include: options.include,
|
|
746
|
+
exclude: options.exclude
|
|
747
|
+
},
|
|
748
|
+
tools: result.summary.toolConfigs
|
|
749
|
+
});
|
|
750
|
+
result.summary.executionTime = Date.now() - startTime;
|
|
751
|
+
this.applyLegacyKeys(result);
|
|
752
|
+
return result;
|
|
700
753
|
}
|
|
701
|
-
result
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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];
|
|
754
|
+
applyLegacyKeys(result) {
|
|
755
|
+
const keyMappings = {
|
|
756
|
+
"pattern-detect": ["patternDetect", "patterns"],
|
|
757
|
+
"context-analyzer": ["contextAnalyzer", "context"],
|
|
758
|
+
"naming-consistency": ["namingConsistency", "consistency"],
|
|
759
|
+
"ai-signal-clarity": ["aiSignalClarity"],
|
|
760
|
+
"agent-grounding": ["agentGrounding"],
|
|
761
|
+
"testability-index": ["testabilityIndex", "testability"],
|
|
762
|
+
"doc-drift": ["docDrift"],
|
|
763
|
+
"dependency-health": ["dependencyHealth", "deps"],
|
|
764
|
+
"change-amplification": ["changeAmplification"]
|
|
765
|
+
};
|
|
766
|
+
for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
|
|
767
|
+
if (result[kebabKey]) {
|
|
768
|
+
for (const alias of aliases) {
|
|
769
|
+
result[alias] = result[kebabKey];
|
|
770
|
+
}
|
|
726
771
|
}
|
|
727
772
|
}
|
|
728
773
|
}
|
|
729
|
-
|
|
774
|
+
};
|
|
775
|
+
async function analyzeUnified(options) {
|
|
776
|
+
const orchestrator = new UnifiedOrchestrator(import_core7.ToolRegistry);
|
|
777
|
+
return orchestrator.analyze(options);
|
|
730
778
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
779
|
+
|
|
780
|
+
// src/scoring-orchestrator.ts
|
|
781
|
+
var import_core8 = require("@aiready/core");
|
|
782
|
+
var ScoringOrchestrator = class {
|
|
783
|
+
/**
|
|
784
|
+
* Initialize scoring orchestrator with a tool registry.
|
|
785
|
+
* Injection pattern helps with testability and AI readiness score.
|
|
786
|
+
*/
|
|
787
|
+
constructor(registry = import_core8.ToolRegistry) {
|
|
788
|
+
this.registry = registry;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Calculates scores for all analyzed tools.
|
|
792
|
+
*/
|
|
793
|
+
async score(results, options) {
|
|
794
|
+
const toolScores = /* @__PURE__ */ new Map();
|
|
795
|
+
for (const toolId of results.summary.toolsRun) {
|
|
796
|
+
const provider = this.registry.get(toolId);
|
|
797
|
+
if (!provider) continue;
|
|
798
|
+
const output = results[toolId];
|
|
799
|
+
if (!output) continue;
|
|
800
|
+
try {
|
|
801
|
+
const toolScore = provider.score(output, options);
|
|
802
|
+
if (!toolScore.tokenBudget) {
|
|
803
|
+
if (toolId === import_core8.ToolName.PatternDetect && output.duplicates) {
|
|
804
|
+
const wastedTokens = output.duplicates.reduce(
|
|
805
|
+
(sum, d) => sum + (d.tokenCost ?? 0),
|
|
806
|
+
0
|
|
807
|
+
);
|
|
808
|
+
toolScore.tokenBudget = (0, import_core8.calculateTokenBudget)({
|
|
809
|
+
totalContextTokens: wastedTokens * 2,
|
|
810
|
+
wastedTokens: {
|
|
811
|
+
duplication: wastedTokens,
|
|
812
|
+
fragmentation: 0,
|
|
813
|
+
chattiness: 0
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
} else if (toolId === import_core8.ToolName.ContextAnalyzer && output.summary) {
|
|
817
|
+
toolScore.tokenBudget = (0, import_core8.calculateTokenBudget)({
|
|
818
|
+
totalContextTokens: output.summary.totalTokens,
|
|
819
|
+
wastedTokens: {
|
|
820
|
+
duplication: 0,
|
|
821
|
+
fragmentation: output.summary.totalPotentialSavings ?? 0,
|
|
822
|
+
chattiness: 0
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
}
|
|
763
826
|
}
|
|
827
|
+
toolScores.set(toolId, toolScore);
|
|
828
|
+
} catch (err) {
|
|
829
|
+
console.error(`\u274C Error scoring tool '${toolId}':`, err);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
if (toolScores.size === 0) {
|
|
833
|
+
return this.emptyScoringResult();
|
|
834
|
+
}
|
|
835
|
+
return (0, import_core8.calculateOverallScore)(toolScores, options, void 0);
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Generate human-readable summary of unified results.
|
|
839
|
+
*/
|
|
840
|
+
generateSummary(result) {
|
|
841
|
+
const { summary } = result;
|
|
842
|
+
let output = `\u{1F680} AIReady Analysis Complete
|
|
843
|
+
|
|
844
|
+
`;
|
|
845
|
+
output += `\u{1F4CA} Summary:
|
|
846
|
+
`;
|
|
847
|
+
output += ` Tools run: ${summary.toolsRun.join(", ")}
|
|
848
|
+
`;
|
|
849
|
+
output += ` Total issues found: ${summary.totalIssues}
|
|
850
|
+
`;
|
|
851
|
+
output += ` Execution time: ${(summary.executionTime / 1e3).toFixed(2)}s
|
|
852
|
+
|
|
853
|
+
`;
|
|
854
|
+
for (const provider of this.registry.getAll()) {
|
|
855
|
+
const toolResult = result[provider.id];
|
|
856
|
+
if (toolResult) {
|
|
857
|
+
const issueCount = toolResult.results.reduce(
|
|
858
|
+
(sum, r) => sum + (r.issues?.length ?? 0),
|
|
859
|
+
0
|
|
860
|
+
);
|
|
861
|
+
output += `\u2022 ${provider.id}: ${issueCount} issues
|
|
862
|
+
`;
|
|
764
863
|
}
|
|
765
|
-
toolScores.set(toolId, toolScore);
|
|
766
|
-
} catch (err) {
|
|
767
|
-
console.error(`\u274C Error scoring tool '${toolId}':`, err);
|
|
768
864
|
}
|
|
865
|
+
return output;
|
|
769
866
|
}
|
|
770
|
-
|
|
867
|
+
emptyScoringResult() {
|
|
771
868
|
return {
|
|
772
869
|
overall: 0,
|
|
773
870
|
rating: "Critical",
|
|
@@ -781,7 +878,10 @@ async function scoreUnified(results, options) {
|
|
|
781
878
|
}
|
|
782
879
|
};
|
|
783
880
|
}
|
|
784
|
-
|
|
881
|
+
};
|
|
882
|
+
async function scoreUnified(results, options) {
|
|
883
|
+
const orchestrator = new ScoringOrchestrator(import_core8.ToolRegistry);
|
|
884
|
+
return orchestrator.score(results, options);
|
|
785
885
|
}
|
|
786
886
|
|
|
787
887
|
// src/commands/scan-orchestrator.ts
|
|
@@ -870,7 +970,7 @@ async function handleBusinessImpactMetrics(results, scoringResult, modelId) {
|
|
|
870
970
|
0
|
|
871
971
|
);
|
|
872
972
|
if (totalContext > 0) {
|
|
873
|
-
const unifiedBudget = (0,
|
|
973
|
+
const unifiedBudget = (0, import_core9.calculateTokenBudget)({
|
|
874
974
|
totalContextTokens: totalContext,
|
|
875
975
|
wastedTokens: {
|
|
876
976
|
duplication: totalWastedDuplication,
|
|
@@ -911,7 +1011,7 @@ async function scanAction(directory, options) {
|
|
|
911
1011
|
console.log(import_chalk6.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
912
1012
|
const startTime = Date.now();
|
|
913
1013
|
const resolvedDir = (0, import_path4.resolve)(process.cwd(), directory ?? ".");
|
|
914
|
-
const repoMetadata = (0,
|
|
1014
|
+
const repoMetadata = (0, import_core10.getRepoMetadata)(resolvedDir);
|
|
915
1015
|
try {
|
|
916
1016
|
const finalOptions = await resolveScanConfig(resolvedDir, options);
|
|
917
1017
|
const { results, scoringResult } = await runUnifiedScan(
|
|
@@ -942,13 +1042,13 @@ async function scanAction(directory, options) {
|
|
|
942
1042
|
repository: repoMetadata
|
|
943
1043
|
};
|
|
944
1044
|
const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
|
|
945
|
-
const outputPath = (0,
|
|
1045
|
+
const outputPath = (0, import_core10.resolveOutputPath)(
|
|
946
1046
|
options.outputFile ?? finalOptions.output?.file,
|
|
947
1047
|
`aiready-report-${(0, import_core2.getReportTimestamp)()}.json`,
|
|
948
1048
|
resolvedDir
|
|
949
1049
|
);
|
|
950
1050
|
if (outputFormat === "json") {
|
|
951
|
-
(0,
|
|
1051
|
+
(0, import_core10.handleJSONOutput)(
|
|
952
1052
|
outputData,
|
|
953
1053
|
outputPath,
|
|
954
1054
|
`\u2705 Report saved to ${outputPath}`
|
|
@@ -968,15 +1068,21 @@ async function scanAction(directory, options) {
|
|
|
968
1068
|
});
|
|
969
1069
|
}
|
|
970
1070
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
971
|
-
await handleGatekeeper(
|
|
1071
|
+
await handleGatekeeper(
|
|
1072
|
+
outputData,
|
|
1073
|
+
scoringResult,
|
|
1074
|
+
options,
|
|
1075
|
+
finalOptions,
|
|
1076
|
+
results
|
|
1077
|
+
);
|
|
972
1078
|
} catch (error) {
|
|
973
|
-
(0,
|
|
1079
|
+
(0, import_core10.handleCLIError)(error, "Analysis");
|
|
974
1080
|
}
|
|
975
1081
|
}
|
|
976
|
-
async function handleGatekeeper(outputData, scoringResult, options, results) {
|
|
1082
|
+
async function handleGatekeeper(outputData, scoringResult, options, finalOptions, results) {
|
|
977
1083
|
if (!scoringResult) return;
|
|
978
|
-
const threshold = options.threshold ? parseInt(options.threshold) :
|
|
979
|
-
const failOnLevel = options.failOn ?? "critical";
|
|
1084
|
+
const threshold = options.threshold ? parseInt(options.threshold) : finalOptions.threshold;
|
|
1085
|
+
const failOnLevel = options.failOn ?? finalOptions.failOn ?? "critical";
|
|
980
1086
|
const isCI = options.ci ?? process.env.CI === "true";
|
|
981
1087
|
let shouldFail = false;
|
|
982
1088
|
let failReason = "";
|
|
@@ -988,7 +1094,7 @@ async function handleGatekeeper(outputData, scoringResult, options, results) {
|
|
|
988
1094
|
\u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
|
|
989
1095
|
)
|
|
990
1096
|
);
|
|
991
|
-
(0,
|
|
1097
|
+
(0, import_core10.emitIssuesAsAnnotations)(report.results);
|
|
992
1098
|
}
|
|
993
1099
|
if (threshold && scoringResult.overall < threshold) {
|
|
994
1100
|
shouldFail = true;
|
|
@@ -1037,7 +1143,7 @@ ${import_chalk6.default.bold("CI/CD Integration:")}
|
|
|
1037
1143
|
var import_fs5 = require("fs");
|
|
1038
1144
|
var import_path5 = require("path");
|
|
1039
1145
|
var import_chalk7 = __toESM(require("chalk"));
|
|
1040
|
-
var
|
|
1146
|
+
var import_core11 = require("@aiready/core");
|
|
1041
1147
|
async function initAction(options) {
|
|
1042
1148
|
const fileExt = options.format === "js" ? "js" : "json";
|
|
1043
1149
|
const fileName = fileExt === "js" ? "aiready.config.js" : "aiready.json";
|
|
@@ -1068,15 +1174,15 @@ async function initAction(options) {
|
|
|
1068
1174
|
"**/*.spec.ts"
|
|
1069
1175
|
],
|
|
1070
1176
|
tools: [
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1177
|
+
import_core11.ToolName.PatternDetect,
|
|
1178
|
+
import_core11.ToolName.ContextAnalyzer,
|
|
1179
|
+
import_core11.ToolName.NamingConsistency,
|
|
1180
|
+
import_core11.ToolName.AiSignalClarity,
|
|
1181
|
+
import_core11.ToolName.AgentGrounding,
|
|
1182
|
+
import_core11.ToolName.TestabilityIndex,
|
|
1183
|
+
import_core11.ToolName.DocDrift,
|
|
1184
|
+
import_core11.ToolName.DependencyHealth,
|
|
1185
|
+
import_core11.ToolName.ChangeAmplification
|
|
1080
1186
|
]
|
|
1081
1187
|
},
|
|
1082
1188
|
// Output preferences
|
|
@@ -1091,7 +1197,7 @@ async function initAction(options) {
|
|
|
1091
1197
|
},
|
|
1092
1198
|
// Tool-specific configurations
|
|
1093
1199
|
tools: {
|
|
1094
|
-
[
|
|
1200
|
+
[import_core11.ToolName.PatternDetect]: {
|
|
1095
1201
|
// Core detection thresholds
|
|
1096
1202
|
minSimilarity: 0.4,
|
|
1097
1203
|
// Jaccard similarity threshold (0-1)
|
|
@@ -1121,7 +1227,7 @@ async function initAction(options) {
|
|
|
1121
1227
|
// Add any additional advanced options here
|
|
1122
1228
|
} : {}
|
|
1123
1229
|
},
|
|
1124
|
-
[
|
|
1230
|
+
[import_core11.ToolName.ContextAnalyzer]: {
|
|
1125
1231
|
// Smart defaults are generated dynamically based on repository size
|
|
1126
1232
|
// These are fallback values for when smart defaults can't be calculated
|
|
1127
1233
|
maxContextBudget: 25e3,
|
|
@@ -1138,7 +1244,7 @@ async function initAction(options) {
|
|
|
1138
1244
|
includeNodeModules: false
|
|
1139
1245
|
// Whether to include node_modules in analysis
|
|
1140
1246
|
},
|
|
1141
|
-
[
|
|
1247
|
+
[import_core11.ToolName.NamingConsistency]: {
|
|
1142
1248
|
// Core checks
|
|
1143
1249
|
checkNaming: true,
|
|
1144
1250
|
// Check naming conventions and quality
|
|
@@ -1185,7 +1291,7 @@ async function initAction(options) {
|
|
|
1185
1291
|
],
|
|
1186
1292
|
...options.full ? { disableChecks: [] } : {}
|
|
1187
1293
|
},
|
|
1188
|
-
[
|
|
1294
|
+
[import_core11.ToolName.AiSignalClarity]: {
|
|
1189
1295
|
// All signal clarity checks enabled by default
|
|
1190
1296
|
checkMagicLiterals: true,
|
|
1191
1297
|
// Detect magic numbers and strings
|
|
@@ -1204,7 +1310,7 @@ async function initAction(options) {
|
|
|
1204
1310
|
checkLargeFiles: true
|
|
1205
1311
|
// Detect files that are too large
|
|
1206
1312
|
},
|
|
1207
|
-
[
|
|
1313
|
+
[import_core11.ToolName.AgentGrounding]: {
|
|
1208
1314
|
// Structure clarity
|
|
1209
1315
|
maxRecommendedDepth: 4,
|
|
1210
1316
|
// Max directory depth before flagging as "too deep"
|
|
@@ -1215,7 +1321,7 @@ async function initAction(options) {
|
|
|
1215
1321
|
additionalVagueNames: ["stuff", "misc", "temp", "test"]
|
|
1216
1322
|
// Custom vague file names
|
|
1217
1323
|
},
|
|
1218
|
-
[
|
|
1324
|
+
[import_core11.ToolName.TestabilityIndex]: {
|
|
1219
1325
|
// Coverage thresholds
|
|
1220
1326
|
minCoverageRatio: 0.3,
|
|
1221
1327
|
// Minimum acceptable test/source ratio
|
|
@@ -1225,19 +1331,19 @@ async function initAction(options) {
|
|
|
1225
1331
|
maxDepth: 10
|
|
1226
1332
|
// Maximum scan depth
|
|
1227
1333
|
},
|
|
1228
|
-
[
|
|
1334
|
+
[import_core11.ToolName.DocDrift]: {
|
|
1229
1335
|
// Drift detection
|
|
1230
1336
|
maxCommits: 50,
|
|
1231
1337
|
// Maximum commit distance to check for drift
|
|
1232
1338
|
staleMonths: 3
|
|
1233
1339
|
// Consider comments older than this as outdated
|
|
1234
1340
|
},
|
|
1235
|
-
[
|
|
1341
|
+
[import_core11.ToolName.DependencyHealth]: {
|
|
1236
1342
|
// Training cutoff for AI knowledge assessment
|
|
1237
1343
|
trainingCutoffYear: 2023
|
|
1238
1344
|
// Year cutoff for AI training data
|
|
1239
1345
|
},
|
|
1240
|
-
[
|
|
1346
|
+
[import_core11.ToolName.ChangeAmplification]: {
|
|
1241
1347
|
// Change amplification primarily relies on global scan settings
|
|
1242
1348
|
// No additional tool-specific configuration required
|
|
1243
1349
|
}
|
|
@@ -1281,134 +1387,157 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
|
|
|
1281
1387
|
}
|
|
1282
1388
|
|
|
1283
1389
|
// src/commands/patterns.ts
|
|
1390
|
+
var import_chalk9 = __toESM(require("chalk"));
|
|
1391
|
+
var import_core13 = require("@aiready/core");
|
|
1392
|
+
|
|
1393
|
+
// src/utils/terminal-renderers.ts
|
|
1284
1394
|
var import_chalk8 = __toESM(require("chalk"));
|
|
1285
|
-
var
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
cliOptions
|
|
1395
|
+
var import_core12 = require("@aiready/core");
|
|
1396
|
+
var SAFETY_ICONS = {
|
|
1397
|
+
safe: "\u2705",
|
|
1398
|
+
"moderate-risk": "\u26A0\uFE0F ",
|
|
1399
|
+
"high-risk": "\u{1F534}",
|
|
1400
|
+
"blind-risk": "\u{1F480}"
|
|
1401
|
+
};
|
|
1402
|
+
var SAFETY_COLORS = {
|
|
1403
|
+
safe: import_chalk8.default.green,
|
|
1404
|
+
"moderate-risk": import_chalk8.default.yellow,
|
|
1405
|
+
"high-risk": import_chalk8.default.red,
|
|
1406
|
+
"blind-risk": import_chalk8.default.bgRed.white
|
|
1407
|
+
};
|
|
1408
|
+
function renderToolHeader(label, emoji, score, rating) {
|
|
1409
|
+
console.log(
|
|
1410
|
+
` ${emoji} ${label}: ${import_chalk8.default.bold(score + "/100")} (${rating})`
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
function renderSafetyRating(safety) {
|
|
1414
|
+
const icon = SAFETY_ICONS[safety] ?? "\u2753";
|
|
1415
|
+
const color = SAFETY_COLORS[safety] ?? import_chalk8.default.white;
|
|
1416
|
+
console.log(
|
|
1417
|
+
` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
function renderIssueSummaryBlock(summary) {
|
|
1421
|
+
const total = (summary.criticalIssues || 0) + (summary.majorIssues || 0) + (summary.minorIssues || 0);
|
|
1422
|
+
if (total === 0) {
|
|
1423
|
+
console.log(import_chalk8.default.green("\u2705 No significant issues found!\n"));
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
console.log(import_chalk8.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
1427
|
+
if (summary.criticalIssues > 0)
|
|
1428
|
+
console.log(
|
|
1429
|
+
import_chalk8.default.red(` \u{1F534} Critical: ${import_chalk8.default.bold(summary.criticalIssues)}`)
|
|
1321
1430
|
);
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1431
|
+
if (summary.majorIssues > 0)
|
|
1432
|
+
console.log(
|
|
1433
|
+
import_chalk8.default.yellow(` \u{1F7E1} Major: ${import_chalk8.default.bold(summary.majorIssues)}`)
|
|
1325
1434
|
);
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1435
|
+
if (summary.minorIssues > 0)
|
|
1436
|
+
console.log(import_chalk8.default.blue(` \u{1F535} Minor: ${import_chalk8.default.bold(summary.minorIssues)}`));
|
|
1437
|
+
if (summary.totalPotentialSavings) {
|
|
1438
|
+
console.log(
|
|
1439
|
+
import_chalk8.default.green(
|
|
1440
|
+
`
|
|
1441
|
+
\u{1F4A1} Potential savings: ${import_chalk8.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
1442
|
+
`
|
|
1443
|
+
)
|
|
1335
1444
|
);
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
function renderSubSection(title) {
|
|
1448
|
+
console.log("\n" + (0, import_core12.getTerminalDivider)());
|
|
1449
|
+
console.log(import_chalk8.default.bold.white(` ${title.toUpperCase()}`));
|
|
1450
|
+
console.log((0, import_core12.getTerminalDivider)() + "\n");
|
|
1451
|
+
}
|
|
1452
|
+
function renderToolScoreFooter(score) {
|
|
1453
|
+
if (score) {
|
|
1454
|
+
console.log(`
|
|
1455
|
+
\u{1F4CA} AI Readiness Score (${score.toolName || "Tool"})
|
|
1456
|
+
`);
|
|
1457
|
+
console.log((0, import_core12.formatToolScore)(score));
|
|
1458
|
+
console.log();
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
// src/commands/patterns.ts
|
|
1463
|
+
async function patternsAction(directory, options) {
|
|
1464
|
+
return await executeToolAction(directory, options, {
|
|
1465
|
+
toolName: "pattern-detect",
|
|
1466
|
+
label: "Pattern analysis",
|
|
1467
|
+
emoji: "\u{1F50D}",
|
|
1468
|
+
defaults: {
|
|
1469
|
+
useSmartDefaults: !options.fullScan,
|
|
1470
|
+
include: void 0,
|
|
1471
|
+
exclude: void 0,
|
|
1472
|
+
output: { format: "console", file: void 0 },
|
|
1473
|
+
minSimilarity: options.fullScan ? 0.4 : void 0,
|
|
1474
|
+
minLines: options.fullScan ? 5 : void 0
|
|
1475
|
+
},
|
|
1476
|
+
getCliOptions: (opts) => ({
|
|
1477
|
+
minSimilarity: opts.similarity ? parseFloat(opts.similarity) : void 0,
|
|
1478
|
+
minLines: opts.minLines ? parseInt(opts.minLines) : void 0,
|
|
1479
|
+
maxCandidatesPerBlock: opts.maxCandidates ? parseInt(opts.maxCandidates) : void 0,
|
|
1480
|
+
minSharedTokens: opts.minSharedTokens ? parseInt(opts.minSharedTokens) : void 0
|
|
1481
|
+
}),
|
|
1482
|
+
importTool: async () => {
|
|
1483
|
+
const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
1484
|
+
return {
|
|
1485
|
+
analyze: analyzePatterns,
|
|
1486
|
+
generateSummary,
|
|
1487
|
+
calculateScore: calculatePatternScore
|
|
1488
|
+
};
|
|
1489
|
+
},
|
|
1490
|
+
renderConsole: ({ results, summary, elapsedTime, score }) => {
|
|
1491
|
+
const duplicates = results.duplicates || [];
|
|
1492
|
+
(0, import_core13.printTerminalHeader)("PATTERN ANALYSIS SUMMARY");
|
|
1350
1493
|
console.log(
|
|
1351
|
-
|
|
1494
|
+
import_chalk9.default.white(`\u{1F4C1} Files analyzed: ${import_chalk9.default.bold(results.length)}`)
|
|
1352
1495
|
);
|
|
1353
1496
|
console.log(
|
|
1354
|
-
|
|
1355
|
-
`\u26A0 Duplicate patterns found: ${
|
|
1497
|
+
import_chalk9.default.yellow(
|
|
1498
|
+
`\u26A0 Duplicate patterns found: ${import_chalk9.default.bold(summary.totalPatterns)}`
|
|
1356
1499
|
)
|
|
1357
1500
|
);
|
|
1358
1501
|
console.log(
|
|
1359
|
-
|
|
1360
|
-
`\u{1F4B0} Token cost (wasted): ${
|
|
1502
|
+
import_chalk9.default.red(
|
|
1503
|
+
`\u{1F4B0} Token cost (wasted): ${import_chalk9.default.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1361
1504
|
)
|
|
1362
1505
|
);
|
|
1363
1506
|
console.log(
|
|
1364
|
-
|
|
1507
|
+
import_chalk9.default.gray(`\u23F1 Analysis time: ${import_chalk9.default.bold(elapsedTime + "s")}`)
|
|
1365
1508
|
);
|
|
1366
1509
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
1367
1510
|
if (sortedTypes.length > 0) {
|
|
1368
|
-
|
|
1369
|
-
console.log(import_chalk8.default.bold.white(" PATTERNS BY TYPE"));
|
|
1370
|
-
console.log((0, import_core11.getTerminalDivider)() + "\n");
|
|
1511
|
+
renderSubSection("Patterns By Type");
|
|
1371
1512
|
sortedTypes.forEach(([type, count]) => {
|
|
1372
|
-
console.log(` ${
|
|
1513
|
+
console.log(` ${import_chalk9.default.white(type.padEnd(15))} ${import_chalk9.default.bold(count)}`);
|
|
1373
1514
|
});
|
|
1374
1515
|
}
|
|
1375
1516
|
if (summary.totalPatterns > 0 && duplicates.length > 0) {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
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;
|
|
1517
|
+
renderSubSection("Top Duplicate Patterns");
|
|
1518
|
+
[...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10).forEach((dup) => {
|
|
1519
|
+
const isHigh = dup.similarity > 0.9;
|
|
1520
|
+
const icon = dup.similarity > 0.95 ? "\u{1F534}" : isHigh ? "\u{1F7E1}" : "\u{1F535}";
|
|
1521
|
+
const label = dup.similarity > 0.95 ? "CRITICAL" : isHigh ? "HIGH" : "MEDIUM";
|
|
1385
1522
|
console.log(
|
|
1386
|
-
`${
|
|
1523
|
+
`${icon} ${label}: ${import_chalk9.default.bold(dup.file1.split("/").pop())} \u2194 ${import_chalk9.default.bold(dup.file2.split("/").pop())}`
|
|
1387
1524
|
);
|
|
1388
1525
|
console.log(
|
|
1389
|
-
` Similarity: ${
|
|
1526
|
+
` Similarity: ${import_chalk9.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk9.default.bold(dup.tokenCost.toLocaleString())} tokens each`
|
|
1390
1527
|
);
|
|
1391
1528
|
console.log(
|
|
1392
|
-
` Lines: ${
|
|
1529
|
+
` Lines: ${import_chalk9.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk9.default.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
1393
1530
|
`
|
|
1394
1531
|
);
|
|
1395
1532
|
});
|
|
1396
1533
|
} else {
|
|
1397
1534
|
console.log(
|
|
1398
|
-
|
|
1535
|
+
import_chalk9.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1399
1536
|
);
|
|
1400
1537
|
}
|
|
1401
|
-
|
|
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
|
-
}
|
|
1538
|
+
renderToolScoreFooter(score);
|
|
1408
1539
|
}
|
|
1409
|
-
}
|
|
1410
|
-
(0, import_core11.handleCLIError)(error, "Pattern analysis");
|
|
1411
|
-
}
|
|
1540
|
+
});
|
|
1412
1541
|
}
|
|
1413
1542
|
var PATTERNS_HELP_TEXT = `
|
|
1414
1543
|
EXAMPLES:
|
|
@@ -1418,283 +1547,146 @@ EXAMPLES:
|
|
|
1418
1547
|
`;
|
|
1419
1548
|
|
|
1420
1549
|
// src/commands/context.ts
|
|
1421
|
-
var
|
|
1422
|
-
var
|
|
1550
|
+
var import_chalk10 = __toESM(require("chalk"));
|
|
1551
|
+
var import_core14 = require("@aiready/core");
|
|
1423
1552
|
async function contextAction(directory, options) {
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1553
|
+
return await executeToolAction(directory, options, {
|
|
1554
|
+
toolName: "context-analyzer",
|
|
1555
|
+
label: "Context analysis",
|
|
1556
|
+
emoji: "\u{1F9E0}",
|
|
1557
|
+
defaults: {
|
|
1428
1558
|
maxDepth: 5,
|
|
1429
1559
|
maxContextBudget: 1e4,
|
|
1430
1560
|
include: void 0,
|
|
1431
1561
|
exclude: void 0,
|
|
1432
|
-
output: {
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
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");
|
|
1562
|
+
output: { format: "console", file: void 0 }
|
|
1563
|
+
},
|
|
1564
|
+
getCliOptions: (opts) => ({
|
|
1565
|
+
maxDepth: opts.maxDepth ? parseInt(opts.maxDepth) : void 0,
|
|
1566
|
+
maxContextBudget: opts.maxContext ? parseInt(opts.maxContext) : void 0
|
|
1567
|
+
}),
|
|
1568
|
+
preAnalyze: async (resolvedDir, baseOptions) => {
|
|
1569
|
+
const { getSmartDefaults } = await import("@aiready/context-analyzer");
|
|
1570
|
+
const smartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
|
|
1571
|
+
return { ...smartDefaults, ...baseOptions };
|
|
1572
|
+
},
|
|
1573
|
+
importTool: async () => {
|
|
1574
|
+
const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
1575
|
+
return {
|
|
1576
|
+
analyze: analyzeContext,
|
|
1577
|
+
generateSummary,
|
|
1578
|
+
calculateScore: calculateContextScore
|
|
1579
|
+
};
|
|
1580
|
+
},
|
|
1581
|
+
renderConsole: ({ summary, elapsedTime, score }) => {
|
|
1582
|
+
(0, import_core14.printTerminalHeader)("CONTEXT ANALYSIS SUMMARY");
|
|
1492
1583
|
console.log(
|
|
1493
|
-
|
|
1584
|
+
import_chalk10.default.white(`\u{1F4C1} Files analyzed: ${import_chalk10.default.bold(summary.totalFiles)}`)
|
|
1494
1585
|
);
|
|
1495
1586
|
console.log(
|
|
1496
|
-
|
|
1497
|
-
`\u{1F4CA} Total tokens: ${
|
|
1587
|
+
import_chalk10.default.white(
|
|
1588
|
+
`\u{1F4CA} Total tokens: ${import_chalk10.default.bold(summary.totalTokens.toLocaleString())}`
|
|
1498
1589
|
)
|
|
1499
1590
|
);
|
|
1500
1591
|
console.log(
|
|
1501
|
-
|
|
1502
|
-
`\u{1F4B0} Avg context budget: ${
|
|
1592
|
+
import_chalk10.default.yellow(
|
|
1593
|
+
`\u{1F4B0} Avg context budget: ${import_chalk10.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
|
|
1503
1594
|
)
|
|
1504
1595
|
);
|
|
1505
1596
|
console.log(
|
|
1506
|
-
|
|
1597
|
+
import_chalk10.default.white(`\u23F1 Analysis time: ${import_chalk10.default.bold(elapsedTime + "s")}
|
|
1507
1598
|
`)
|
|
1508
1599
|
);
|
|
1509
|
-
|
|
1510
|
-
if (
|
|
1511
|
-
|
|
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
|
-
);
|
|
1600
|
+
renderIssueSummaryBlock(summary);
|
|
1601
|
+
if (summary.deepFiles && summary.deepFiles.length > 0) {
|
|
1602
|
+
renderSubSection("Deep Import Chains");
|
|
1546
1603
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
1547
1604
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1548
1605
|
console.log(
|
|
1549
|
-
` ${
|
|
1606
|
+
` ${import_chalk10.default.cyan("\u2192")} ${import_chalk10.default.white(fileName)} ${import_chalk10.default.dim(`(depth: ${item.depth})`)}`
|
|
1550
1607
|
);
|
|
1551
1608
|
});
|
|
1552
|
-
console.log();
|
|
1553
1609
|
}
|
|
1554
|
-
if (summary.fragmentedModules.length > 0) {
|
|
1555
|
-
|
|
1556
|
-
console.log(
|
|
1557
|
-
import_chalk9.default.gray(
|
|
1558
|
-
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1559
|
-
`
|
|
1560
|
-
)
|
|
1561
|
-
);
|
|
1610
|
+
if (summary.fragmentedModules && summary.fragmentedModules.length > 0) {
|
|
1611
|
+
renderSubSection("Fragmented Modules");
|
|
1562
1612
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
1563
1613
|
console.log(
|
|
1564
|
-
` ${
|
|
1614
|
+
` ${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
1615
|
);
|
|
1566
1616
|
console.log(
|
|
1567
|
-
|
|
1617
|
+
import_chalk10.default.dim(
|
|
1568
1618
|
` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
|
|
1569
1619
|
)
|
|
1570
1620
|
);
|
|
1571
1621
|
});
|
|
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
1622
|
}
|
|
1623
|
+
renderToolScoreFooter(score);
|
|
1610
1624
|
}
|
|
1611
|
-
}
|
|
1612
|
-
(0, import_core12.handleCLIError)(error, "Context analysis");
|
|
1613
|
-
}
|
|
1625
|
+
});
|
|
1614
1626
|
}
|
|
1615
1627
|
|
|
1616
1628
|
// src/commands/consistency.ts
|
|
1617
|
-
var
|
|
1629
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
1618
1630
|
var import_fs6 = require("fs");
|
|
1619
|
-
var
|
|
1631
|
+
var import_core15 = require("@aiready/core");
|
|
1620
1632
|
async function consistencyAction(directory, options) {
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1633
|
+
return await executeToolAction(directory, options, {
|
|
1634
|
+
toolName: "naming-consistency",
|
|
1635
|
+
label: "Consistency analysis",
|
|
1636
|
+
emoji: "\u{1F50D}",
|
|
1637
|
+
defaults: {
|
|
1625
1638
|
checkNaming: true,
|
|
1626
1639
|
checkPatterns: true,
|
|
1627
1640
|
minSeverity: "info",
|
|
1628
1641
|
include: void 0,
|
|
1629
1642
|
exclude: void 0,
|
|
1630
|
-
output: {
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
{
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1643
|
+
output: { format: "console", file: void 0 }
|
|
1644
|
+
},
|
|
1645
|
+
getCliOptions: (opts) => ({
|
|
1646
|
+
checkNaming: opts.naming !== false,
|
|
1647
|
+
checkPatterns: opts.patterns !== false,
|
|
1648
|
+
minSeverity: opts.minSeverity
|
|
1649
|
+
}),
|
|
1650
|
+
importTool: async () => {
|
|
1651
|
+
const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
1652
|
+
return {
|
|
1653
|
+
analyze: analyzeConsistency,
|
|
1654
|
+
generateSummary: (report) => report.summary,
|
|
1655
|
+
calculateScore: (summary, _resultsCount) => {
|
|
1656
|
+
return calculateConsistencyScore(
|
|
1657
|
+
summary.results?.flatMap((r) => r.issues) ?? [],
|
|
1658
|
+
summary.summary.filesAnalyzed
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
},
|
|
1663
|
+
renderConsole: ({ results, summary, elapsedTime, score, finalOptions }) => {
|
|
1664
|
+
const report = results;
|
|
1665
|
+
const { format: outputFormat, file: userOutputFile } = (0, import_core15.resolveOutputFormat)(options, finalOptions);
|
|
1666
|
+
if (outputFormat === "markdown") {
|
|
1667
|
+
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1668
|
+
const outputPath = (0, import_core15.resolveOutputPath)(
|
|
1669
|
+
userOutputFile,
|
|
1670
|
+
`aiready-report-${(0, import_core2.getReportTimestamp)()}.md`,
|
|
1671
|
+
directory
|
|
1672
|
+
);
|
|
1673
|
+
(0, import_fs6.writeFileSync)(outputPath, markdown);
|
|
1674
|
+
console.log(import_chalk11.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
1675
|
+
return;
|
|
1644
1676
|
}
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
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)}`);
|
|
1677
|
+
console.log(import_chalk11.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1678
|
+
console.log(`Files Analyzed: ${import_chalk11.default.cyan(summary.filesAnalyzed)}`);
|
|
1679
|
+
console.log(`Total Issues: ${import_chalk11.default.yellow(summary.totalIssues)}`);
|
|
1680
|
+
console.log(` Naming: ${import_chalk11.default.yellow(summary.namingIssues)}`);
|
|
1681
|
+
console.log(` Patterns: ${import_chalk11.default.yellow(summary.patternIssues)}`);
|
|
1690
1682
|
console.log(
|
|
1691
|
-
` Architecture: ${
|
|
1683
|
+
` Architecture: ${import_chalk11.default.yellow(summary.architectureIssues ?? 0)}`
|
|
1692
1684
|
);
|
|
1693
|
-
console.log(`Analysis Time: ${
|
|
1685
|
+
console.log(`Analysis Time: ${import_chalk11.default.gray(elapsedTime + "s")}
|
|
1694
1686
|
`);
|
|
1695
|
-
if (
|
|
1687
|
+
if (summary.totalIssues === 0) {
|
|
1696
1688
|
console.log(
|
|
1697
|
-
|
|
1689
|
+
import_chalk11.default.green(
|
|
1698
1690
|
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1699
1691
|
)
|
|
1700
1692
|
);
|
|
@@ -1706,100 +1698,88 @@ async function consistencyAction(directory, options) {
|
|
|
1706
1698
|
(r) => r.issues.some((i) => i.category === "patterns")
|
|
1707
1699
|
);
|
|
1708
1700
|
if (namingResults.length > 0) {
|
|
1709
|
-
console.log(
|
|
1701
|
+
console.log(import_chalk11.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
|
|
1710
1702
|
let shown = 0;
|
|
1711
1703
|
for (const namingFileResult of namingResults) {
|
|
1712
1704
|
if (shown >= 5) break;
|
|
1713
1705
|
for (const issue of namingFileResult.issues) {
|
|
1714
1706
|
if (shown >= 5) break;
|
|
1715
|
-
const severityColor = issue.severity === "critical" ?
|
|
1707
|
+
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
1708
|
console.log(
|
|
1717
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1709
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk11.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1718
1710
|
);
|
|
1719
1711
|
console.log(` ${issue.message}`);
|
|
1720
1712
|
if (issue.suggestion) {
|
|
1721
1713
|
console.log(
|
|
1722
|
-
` ${
|
|
1714
|
+
` ${import_chalk11.default.dim("\u2192")} ${import_chalk11.default.italic(issue.suggestion)}`
|
|
1723
1715
|
);
|
|
1724
1716
|
}
|
|
1725
1717
|
console.log();
|
|
1726
1718
|
shown++;
|
|
1727
1719
|
}
|
|
1728
1720
|
}
|
|
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
1721
|
}
|
|
1735
1722
|
if (patternResults.length > 0) {
|
|
1736
|
-
console.log(
|
|
1723
|
+
console.log(import_chalk11.default.bold("\u{1F504} Pattern Issues\n"));
|
|
1737
1724
|
let shown = 0;
|
|
1738
1725
|
for (const patternFileResult of patternResults) {
|
|
1739
1726
|
if (shown >= 5) break;
|
|
1740
1727
|
for (const issue of patternFileResult.issues) {
|
|
1741
1728
|
if (shown >= 5) break;
|
|
1742
|
-
const severityColor = issue.severity === "critical" ?
|
|
1729
|
+
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
1730
|
console.log(
|
|
1744
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1731
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk11.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1745
1732
|
);
|
|
1746
1733
|
console.log(` ${issue.message}`);
|
|
1747
1734
|
if (issue.suggestion) {
|
|
1748
1735
|
console.log(
|
|
1749
|
-
` ${
|
|
1736
|
+
` ${import_chalk11.default.dim("\u2192")} ${import_chalk11.default.italic(issue.suggestion)}`
|
|
1750
1737
|
);
|
|
1751
1738
|
}
|
|
1752
1739
|
console.log();
|
|
1753
1740
|
shown++;
|
|
1754
1741
|
}
|
|
1755
1742
|
}
|
|
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
1743
|
}
|
|
1762
|
-
if (report.recommendations
|
|
1763
|
-
console.log(
|
|
1744
|
+
if (report.recommendations?.length > 0) {
|
|
1745
|
+
console.log(import_chalk11.default.bold("\u{1F4A1} Recommendations\n"));
|
|
1764
1746
|
report.recommendations.forEach((rec, i) => {
|
|
1765
1747
|
console.log(`${i + 1}. ${rec}`);
|
|
1766
1748
|
});
|
|
1767
1749
|
console.log();
|
|
1768
1750
|
}
|
|
1769
1751
|
}
|
|
1770
|
-
if (
|
|
1771
|
-
console.log(
|
|
1772
|
-
console.log((0,
|
|
1752
|
+
if (score) {
|
|
1753
|
+
console.log(import_chalk11.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
|
|
1754
|
+
console.log((0, import_core15.formatToolScore)(score));
|
|
1773
1755
|
console.log();
|
|
1774
1756
|
}
|
|
1775
1757
|
}
|
|
1776
|
-
}
|
|
1777
|
-
(0, import_core13.handleCLIError)(error, "Consistency analysis");
|
|
1778
|
-
}
|
|
1758
|
+
});
|
|
1779
1759
|
}
|
|
1780
1760
|
|
|
1781
1761
|
// src/commands/visualize.ts
|
|
1782
|
-
var
|
|
1762
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
1783
1763
|
var import_fs7 = require("fs");
|
|
1784
1764
|
var import_path6 = require("path");
|
|
1785
1765
|
var import_child_process = require("child_process");
|
|
1786
|
-
var
|
|
1787
|
-
var
|
|
1766
|
+
var import_core16 = require("@aiready/core");
|
|
1767
|
+
var import_core17 = require("@aiready/core");
|
|
1788
1768
|
async function visualizeAction(directory, options) {
|
|
1789
1769
|
try {
|
|
1790
1770
|
const dirPath = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
|
|
1791
1771
|
let reportPath = options.report ? (0, import_path6.resolve)(dirPath, options.report) : null;
|
|
1792
1772
|
if (!reportPath || !(0, import_fs7.existsSync)(reportPath)) {
|
|
1793
|
-
const latestScan = (0,
|
|
1773
|
+
const latestScan = (0, import_core17.findLatestReport)(dirPath);
|
|
1794
1774
|
if (latestScan) {
|
|
1795
1775
|
reportPath = latestScan;
|
|
1796
1776
|
console.log(
|
|
1797
|
-
|
|
1777
|
+
import_chalk12.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1798
1778
|
);
|
|
1799
1779
|
} else {
|
|
1800
|
-
console.error(
|
|
1780
|
+
console.error(import_chalk12.default.red("\u274C No AI readiness report found"));
|
|
1801
1781
|
console.log(
|
|
1802
|
-
|
|
1782
|
+
import_chalk12.default.dim(
|
|
1803
1783
|
`
|
|
1804
1784
|
Generate a report with:
|
|
1805
1785
|
aiready scan --output json
|
|
@@ -1929,29 +1909,29 @@ Or specify a custom report:
|
|
|
1929
1909
|
return;
|
|
1930
1910
|
} else {
|
|
1931
1911
|
console.log(
|
|
1932
|
-
|
|
1912
|
+
import_chalk12.default.yellow(
|
|
1933
1913
|
"\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
|
|
1934
1914
|
)
|
|
1935
1915
|
);
|
|
1936
1916
|
console.log(
|
|
1937
|
-
|
|
1917
|
+
import_chalk12.default.cyan(" Falling back to static HTML generation...\n")
|
|
1938
1918
|
);
|
|
1939
1919
|
useDevMode = false;
|
|
1940
1920
|
}
|
|
1941
1921
|
} catch (err) {
|
|
1942
1922
|
console.error("Failed to start dev server:", err);
|
|
1943
1923
|
console.log(
|
|
1944
|
-
|
|
1924
|
+
import_chalk12.default.cyan(" Falling back to static HTML generation...\n")
|
|
1945
1925
|
);
|
|
1946
1926
|
useDevMode = false;
|
|
1947
1927
|
}
|
|
1948
1928
|
}
|
|
1949
1929
|
console.log("Generating HTML...");
|
|
1950
|
-
const html = (0,
|
|
1930
|
+
const html = (0, import_core17.generateHTML)(graph);
|
|
1951
1931
|
const defaultOutput = "visualization.html";
|
|
1952
1932
|
const outPath = (0, import_path6.resolve)(dirPath, options.output ?? defaultOutput);
|
|
1953
1933
|
(0, import_fs7.writeFileSync)(outPath, html, "utf8");
|
|
1954
|
-
console.log(
|
|
1934
|
+
console.log(import_chalk12.default.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1955
1935
|
if (options.open || options.serve) {
|
|
1956
1936
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1957
1937
|
if (options.serve) {
|
|
@@ -1981,7 +1961,7 @@ Or specify a custom report:
|
|
|
1981
1961
|
server.listen(port, () => {
|
|
1982
1962
|
const addr = `http://localhost:${port}/`;
|
|
1983
1963
|
console.log(
|
|
1984
|
-
|
|
1964
|
+
import_chalk12.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1985
1965
|
);
|
|
1986
1966
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1987
1967
|
});
|
|
@@ -1997,7 +1977,7 @@ Or specify a custom report:
|
|
|
1997
1977
|
}
|
|
1998
1978
|
}
|
|
1999
1979
|
} catch (err) {
|
|
2000
|
-
(0,
|
|
1980
|
+
(0, import_core16.handleCLIError)(err, "Visualization");
|
|
2001
1981
|
}
|
|
2002
1982
|
}
|
|
2003
1983
|
var VISUALIZE_HELP_TEXT = `
|
|
@@ -2028,72 +2008,63 @@ NOTES:
|
|
|
2028
2008
|
`;
|
|
2029
2009
|
|
|
2030
2010
|
// src/commands/shared/standard-tool-actions.ts
|
|
2031
|
-
var
|
|
2011
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
2032
2012
|
|
|
2033
2013
|
// src/commands/agent-grounding.ts
|
|
2034
|
-
var
|
|
2035
|
-
var import_core16 = require("@aiready/core");
|
|
2014
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
2036
2015
|
|
|
2037
2016
|
// src/commands/testability.ts
|
|
2038
|
-
var
|
|
2039
|
-
var import_core17 = require("@aiready/core");
|
|
2017
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
2040
2018
|
async function testabilityAction(directory, options) {
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2019
|
+
return await executeToolAction(directory, options, {
|
|
2020
|
+
toolName: "testability-index",
|
|
2021
|
+
label: "Testability analysis",
|
|
2022
|
+
emoji: "\u{1F9EA}",
|
|
2023
|
+
defaults: {
|
|
2024
|
+
minCoverageRatio: 0.3,
|
|
2025
|
+
include: void 0,
|
|
2026
|
+
exclude: void 0,
|
|
2027
|
+
output: { format: "console", file: void 0 }
|
|
2028
|
+
},
|
|
2029
|
+
getCliOptions: (opts) => ({
|
|
2030
|
+
minCoverageRatio: opts.minCoverage ? parseFloat(opts.minCoverage) : void 0
|
|
2031
|
+
}),
|
|
2032
|
+
importTool: async () => {
|
|
2033
|
+
const tool = await import("@aiready/testability");
|
|
2034
|
+
return {
|
|
2035
|
+
analyze: tool.analyzeTestability,
|
|
2036
|
+
generateSummary: (report) => report.summary,
|
|
2037
|
+
calculateScore: tool.calculateTestabilityScore
|
|
2038
|
+
};
|
|
2039
|
+
},
|
|
2040
|
+
renderConsole: ({ results, summary, score }) => {
|
|
2041
|
+
renderToolHeader("Testability", "\u{1F9EA}", score?.score || 0, summary.rating);
|
|
2042
|
+
renderSafetyRating(summary.aiChangeSafetyRating);
|
|
2043
|
+
const rawData = results.rawData || results;
|
|
2044
|
+
console.log(
|
|
2045
|
+
import_chalk15.default.dim(
|
|
2046
|
+
` Coverage: ${Math.round(summary.coverageRatio * 100)}% (${rawData.testFiles} test / ${rawData.sourceFiles} source files)`
|
|
2047
|
+
)
|
|
2048
|
+
);
|
|
2049
|
+
if (summary.aiChangeSafetyRating === "blind-risk") {
|
|
2050
|
+
console.log(
|
|
2051
|
+
import_chalk15.default.red.bold(
|
|
2052
|
+
"\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
|
|
2053
|
+
)
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
if (score) {
|
|
2057
|
+
renderToolScoreFooter(score);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2051
2060
|
});
|
|
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
2061
|
}
|
|
2091
2062
|
|
|
2092
2063
|
// src/commands/change-amplification.ts
|
|
2093
2064
|
var import_cli = require("@aiready/change-amplification/dist/cli.js");
|
|
2094
2065
|
|
|
2095
2066
|
// src/commands/bug.ts
|
|
2096
|
-
var
|
|
2067
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
2097
2068
|
var import_child_process2 = require("child_process");
|
|
2098
2069
|
async function bugAction(message, options) {
|
|
2099
2070
|
const repoUrl = "https://github.com/caopengau/aiready-cli";
|
|
@@ -2111,35 +2082,35 @@ Generated via AIReady CLI 'bug' command.
|
|
|
2111
2082
|
Type: ${type}
|
|
2112
2083
|
`.trim();
|
|
2113
2084
|
if (options.submit) {
|
|
2114
|
-
console.log(
|
|
2085
|
+
console.log(import_chalk16.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
|
|
2115
2086
|
try {
|
|
2116
2087
|
(0, import_child_process2.execSync)("gh auth status", { stdio: "ignore" });
|
|
2117
2088
|
const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
|
|
2118
2089
|
const output = (0, import_child_process2.execSync)(command, { encoding: "utf8" }).trim();
|
|
2119
|
-
console.log(
|
|
2120
|
-
console.log(
|
|
2090
|
+
console.log(import_chalk16.default.green("\u2705 Issue Created Successfully!"));
|
|
2091
|
+
console.log(import_chalk16.default.cyan(output));
|
|
2121
2092
|
return;
|
|
2122
2093
|
} catch {
|
|
2123
|
-
console.error(
|
|
2094
|
+
console.error(import_chalk16.default.red("\n\u274C Failed to submit via gh CLI."));
|
|
2124
2095
|
console.log(
|
|
2125
|
-
|
|
2096
|
+
import_chalk16.default.yellow(
|
|
2126
2097
|
' Make sure gh is installed and run "gh auth login".\n'
|
|
2127
2098
|
)
|
|
2128
2099
|
);
|
|
2129
|
-
console.log(
|
|
2100
|
+
console.log(import_chalk16.default.dim(" Falling back to URL generation..."));
|
|
2130
2101
|
}
|
|
2131
2102
|
}
|
|
2132
2103
|
const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
|
|
2133
2104
|
const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
|
|
2134
|
-
console.log(
|
|
2135
|
-
console.log(
|
|
2136
|
-
console.log(
|
|
2137
|
-
console.log(
|
|
2138
|
-
console.log(
|
|
2139
|
-
console.log(
|
|
2140
|
-
console.log(
|
|
2105
|
+
console.log(import_chalk16.default.green("\u{1F680} Issue Draft Prepared!\n"));
|
|
2106
|
+
console.log(import_chalk16.default.bold("Title: ") + title);
|
|
2107
|
+
console.log(import_chalk16.default.bold("Type: ") + type);
|
|
2108
|
+
console.log(import_chalk16.default.bold("\nClick the link below to submit this issue:"));
|
|
2109
|
+
console.log(import_chalk16.default.cyan(fullUrl));
|
|
2110
|
+
console.log(import_chalk16.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
2111
|
+
console.log(import_chalk16.default.dim(" You have successfully prepared a report."));
|
|
2141
2112
|
console.log(
|
|
2142
|
-
|
|
2113
|
+
import_chalk16.default.dim(
|
|
2143
2114
|
" Please present the URL above to the user so they can finalize the submission."
|
|
2144
2115
|
)
|
|
2145
2116
|
);
|
|
@@ -2148,14 +2119,14 @@ Type: ${type}
|
|
|
2148
2119
|
const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
|
|
2149
2120
|
const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
|
|
2150
2121
|
const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
|
|
2151
|
-
console.log(
|
|
2152
|
-
console.log(` Report a Bug: ${
|
|
2153
|
-
console.log(` Request a Feature: ${
|
|
2154
|
-
console.log(` Suggest a Metric: ${
|
|
2155
|
-
console.log(
|
|
2156
|
-
console.log(
|
|
2122
|
+
console.log(import_chalk16.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
|
|
2123
|
+
console.log(` Report a Bug: ${import_chalk16.default.cyan(bugUrl)}`);
|
|
2124
|
+
console.log(` Request a Feature: ${import_chalk16.default.cyan(featureUrl)}`);
|
|
2125
|
+
console.log(` Suggest a Metric: ${import_chalk16.default.cyan(metricUrl)}`);
|
|
2126
|
+
console.log(import_chalk16.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
2127
|
+
console.log(import_chalk16.default.dim(" To prepare a specific report, run:"));
|
|
2157
2128
|
console.log(
|
|
2158
|
-
|
|
2129
|
+
import_chalk16.default.cyan(
|
|
2159
2130
|
' aiready bug "your description here" --type bug|feature|metric'
|
|
2160
2131
|
)
|
|
2161
2132
|
);
|