@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/chunk-HX6H3VOE.mjs +328 -0
- package/dist/chunk-L4VXALJD.mjs +280 -0
- package/dist/chunk-SK6WW6HW.mjs +325 -0
- package/dist/chunk-TKBE575H.mjs +327 -0
- package/dist/cli.js +837 -668
- package/dist/cli.mjs +578 -468
- package/dist/index.js +246 -214
- package/dist/index.mjs +7 -1
- package/package.json +13 -12
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
|
|
29
|
-
var
|
|
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
|
|
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":
|
|
@@ -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
|
|
592
|
+
var import_core9 = require("@aiready/core");
|
|
536
593
|
|
|
537
|
-
// src/
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
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: {}
|
|
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
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
`\
|
|
684
|
+
`\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
|
|
685
|
+
err.message
|
|
621
686
|
);
|
|
622
687
|
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
(
|
|
646
|
-
if (
|
|
647
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
686
|
-
|
|
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
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
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
|
-
|
|
778
|
+
};
|
|
779
|
+
async function analyzeUnified(options) {
|
|
780
|
+
const orchestrator = new UnifiedOrchestrator(import_core7.ToolRegistry);
|
|
781
|
+
return orchestrator.analyze(options);
|
|
730
782
|
}
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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(
|
|
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,
|
|
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) :
|
|
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,
|
|
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
|
|
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
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
|
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
|
|
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
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
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
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
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
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
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
|
-
|
|
1520
|
+
import_chalk9.default.white(`\u{1F4C1} Files analyzed: ${import_chalk9.default.bold(results.length)}`)
|
|
1352
1521
|
);
|
|
1353
1522
|
console.log(
|
|
1354
|
-
|
|
1355
|
-
`\u26A0 Duplicate patterns found: ${
|
|
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
|
-
|
|
1360
|
-
`\u{1F4B0} Token cost (wasted): ${
|
|
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
|
-
|
|
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
|
-
|
|
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(` ${
|
|
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
|
-
|
|
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;
|
|
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
|
-
`${
|
|
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: ${
|
|
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: ${
|
|
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
|
-
|
|
1561
|
+
import_chalk9.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1399
1562
|
);
|
|
1400
1563
|
}
|
|
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
|
-
}
|
|
1564
|
+
renderToolScoreFooter(score);
|
|
1408
1565
|
}
|
|
1409
|
-
}
|
|
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
|
|
1422
|
-
var
|
|
1576
|
+
var import_chalk10 = __toESM(require("chalk"));
|
|
1577
|
+
var import_core14 = require("@aiready/core");
|
|
1423
1578
|
async function contextAction(directory, options) {
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
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
|
-
|
|
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");
|
|
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
|
-
|
|
1610
|
+
import_chalk10.default.white(`\u{1F4C1} Files analyzed: ${import_chalk10.default.bold(summary.totalFiles)}`)
|
|
1494
1611
|
);
|
|
1495
1612
|
console.log(
|
|
1496
|
-
|
|
1497
|
-
`\u{1F4CA} Total tokens: ${
|
|
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
|
-
|
|
1502
|
-
`\u{1F4B0} Avg context budget: ${
|
|
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
|
-
|
|
1623
|
+
import_chalk10.default.white(`\u23F1 Analysis time: ${import_chalk10.default.bold(elapsedTime + "s")}
|
|
1507
1624
|
`)
|
|
1508
1625
|
);
|
|
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
|
-
);
|
|
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
|
-
` ${
|
|
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
|
-
|
|
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
|
-
` ${
|
|
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
|
-
|
|
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
|
-
}
|
|
1612
|
-
(0, import_core12.handleCLIError)(error, "Context analysis");
|
|
1613
|
-
}
|
|
1651
|
+
});
|
|
1614
1652
|
}
|
|
1615
1653
|
|
|
1616
1654
|
// src/commands/consistency.ts
|
|
1617
|
-
var
|
|
1655
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
1618
1656
|
var import_fs6 = require("fs");
|
|
1619
|
-
var
|
|
1657
|
+
var import_core15 = require("@aiready/core");
|
|
1620
1658
|
async function consistencyAction(directory, options) {
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
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
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
{
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
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
|
-
|
|
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)}`);
|
|
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: ${
|
|
1709
|
+
` Architecture: ${import_chalk11.default.yellow(summary.architectureIssues ?? 0)}`
|
|
1692
1710
|
);
|
|
1693
|
-
console.log(`Analysis Time: ${
|
|
1711
|
+
console.log(`Analysis Time: ${import_chalk11.default.gray(elapsedTime + "s")}
|
|
1694
1712
|
`);
|
|
1695
|
-
if (
|
|
1713
|
+
if (summary.totalIssues === 0) {
|
|
1696
1714
|
console.log(
|
|
1697
|
-
|
|
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(
|
|
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" ?
|
|
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())} ${
|
|
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
|
-
` ${
|
|
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(
|
|
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" ?
|
|
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())} ${
|
|
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
|
-
` ${
|
|
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
|
|
1763
|
-
console.log(
|
|
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 (
|
|
1771
|
-
console.log(
|
|
1772
|
-
console.log((0,
|
|
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
|
-
}
|
|
1777
|
-
(0, import_core13.handleCLIError)(error, "Consistency analysis");
|
|
1778
|
-
}
|
|
1784
|
+
});
|
|
1779
1785
|
}
|
|
1780
1786
|
|
|
1781
1787
|
// src/commands/visualize.ts
|
|
1782
|
-
var
|
|
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
|
|
1787
|
-
var
|
|
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,
|
|
1799
|
+
const latestScan = (0, import_core17.findLatestReport)(dirPath);
|
|
1794
1800
|
if (latestScan) {
|
|
1795
1801
|
reportPath = latestScan;
|
|
1796
1802
|
console.log(
|
|
1797
|
-
|
|
1803
|
+
import_chalk12.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1798
1804
|
);
|
|
1799
1805
|
} else {
|
|
1800
|
-
console.error(
|
|
1806
|
+
console.error(import_chalk12.default.red("\u274C No AI readiness report found"));
|
|
1801
1807
|
console.log(
|
|
1802
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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
|
|
2037
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
2032
2038
|
|
|
2033
2039
|
// src/commands/agent-grounding.ts
|
|
2034
|
-
var
|
|
2035
|
-
var import_core16 = require("@aiready/core");
|
|
2040
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
2036
2041
|
|
|
2037
2042
|
// src/commands/testability.ts
|
|
2038
|
-
var
|
|
2039
|
-
var import_core17 = require("@aiready/core");
|
|
2043
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
2040
2044
|
async function testabilityAction(directory, options) {
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
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
|
|
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(
|
|
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(
|
|
2120
|
-
console.log(
|
|
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(
|
|
2191
|
+
console.error(import_chalk17.default.red("\n\u274C Failed to submit via gh CLI."));
|
|
2124
2192
|
console.log(
|
|
2125
|
-
|
|
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(
|
|
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(
|
|
2135
|
-
console.log(
|
|
2136
|
-
console.log(
|
|
2137
|
-
console.log(
|
|
2138
|
-
console.log(
|
|
2139
|
-
console.log(
|
|
2140
|
-
console.log(
|
|
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
|
-
|
|
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(
|
|
2152
|
-
console.log(` Report a Bug: ${
|
|
2153
|
-
console.log(` Request a Feature: ${
|
|
2154
|
-
console.log(` Suggest a Metric: ${
|
|
2155
|
-
console.log(
|
|
2156
|
-
console.log(
|
|
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
|
-
|
|
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,
|
|
2334
|
+
return (0, import_path8.dirname)((0, import_url.fileURLToPath)(import_meta.url));
|
|
2176
2335
|
};
|
|
2177
2336
|
var packageJson = JSON.parse(
|
|
2178
|
-
(0,
|
|
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
|
});
|