@aiready/cli 0.14.8 ā 0.14.10
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/.turbo/turbo-build.log +28 -29
- package/.turbo/turbo-test.log +74 -76
- package/dist/chunk-HBPSESJV.mjs +289 -0
- package/dist/chunk-JRRBBFYB.mjs +307 -0
- package/dist/chunk-YP2EVXQN.mjs +303 -0
- package/dist/chunk-ZQOTGPK4.mjs +289 -0
- package/dist/cli.js +71 -65
- package/dist/cli.mjs +48 -46
- package/dist/index.js +25 -21
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
- package/src/cli.ts +7 -5
- package/src/commands/bug.ts +1 -1
- package/src/commands/consistency.ts +5 -5
- package/src/commands/context.ts +4 -4
- package/src/commands/patterns.ts +3 -3
- package/src/commands/report-formatter.ts +23 -10
- package/src/commands/scan.ts +18 -18
- package/src/commands/upload.ts +6 -6
- package/src/commands/visualize.ts +4 -4
- package/src/index.ts +49 -28
- package/src/utils/helpers.ts +30 -3
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
__require,
|
|
4
4
|
analyzeUnified,
|
|
5
5
|
scoreUnified
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JRRBBFYB.mjs";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -134,7 +134,7 @@ import {
|
|
|
134
134
|
function printScanSummary(results, startTime) {
|
|
135
135
|
console.log(chalk2.cyan("\n=== AIReady Run Summary ==="));
|
|
136
136
|
console.log(
|
|
137
|
-
` Total issues (all tools): ${chalk2.bold(String(results.summary.totalIssues
|
|
137
|
+
` Total issues (all tools): ${chalk2.bold(String(results.summary.totalIssues ?? 0))}`
|
|
138
138
|
);
|
|
139
139
|
console.log(
|
|
140
140
|
` Execution time: ${chalk2.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
|
|
@@ -169,7 +169,7 @@ function printScoring(scoringResult, scoringProfile) {
|
|
|
169
169
|
);
|
|
170
170
|
});
|
|
171
171
|
const allRecs = scoringResult.breakdown.flatMap(
|
|
172
|
-
(t) => (t.recommendations
|
|
172
|
+
(t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
|
|
173
173
|
).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
|
|
174
174
|
if (allRecs.length > 0) {
|
|
175
175
|
console.log(chalk2.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
|
|
@@ -223,8 +223,8 @@ import { handleCLIError } from "@aiready/core";
|
|
|
223
223
|
async function uploadAction(file, options) {
|
|
224
224
|
const startTime = Date.now();
|
|
225
225
|
const filePath = resolvePath2(process.cwd(), file);
|
|
226
|
-
const serverUrl = options.server
|
|
227
|
-
const apiKey = options.apiKey
|
|
226
|
+
const serverUrl = options.server ?? process.env.AIREADY_SERVER ?? "https://dev.platform.getaiready.dev";
|
|
227
|
+
const apiKey = options.apiKey ?? process.env.AIREADY_API_KEY;
|
|
228
228
|
if (!apiKey) {
|
|
229
229
|
console.error(chalk3.red("\u274C API Key is required for upload."));
|
|
230
230
|
console.log(
|
|
@@ -249,7 +249,7 @@ async function uploadAction(file, options) {
|
|
|
249
249
|
const reportContent = fs.readFileSync(filePath, "utf-8");
|
|
250
250
|
const reportData = JSON.parse(reportContent);
|
|
251
251
|
console.log(chalk3.dim(` Successfully parsed report JSON.`));
|
|
252
|
-
const repoId = options.repoId
|
|
252
|
+
const repoId = options.repoId ?? reportData.repository?.repoId;
|
|
253
253
|
const response = await fetch(`${serverUrl}/api/analysis/upload`, {
|
|
254
254
|
method: "POST",
|
|
255
255
|
headers: {
|
|
@@ -268,12 +268,12 @@ async function uploadAction(file, options) {
|
|
|
268
268
|
uploadResult = await response.json();
|
|
269
269
|
} else {
|
|
270
270
|
const text = await response.text();
|
|
271
|
-
uploadResult = { error: text
|
|
271
|
+
uploadResult = { error: text ?? response.statusText };
|
|
272
272
|
}
|
|
273
273
|
if (!response.ok) {
|
|
274
274
|
console.error(
|
|
275
275
|
chalk3.red(
|
|
276
|
-
`\u274C Upload failed: ${uploadResult.error
|
|
276
|
+
`\u274C Upload failed: ${uploadResult.error ?? response.statusText}`
|
|
277
277
|
)
|
|
278
278
|
);
|
|
279
279
|
if (contentType?.includes("text/html")) {
|
|
@@ -324,7 +324,7 @@ ENVIRONMENT VARIABLES:
|
|
|
324
324
|
async function scanAction(directory, options) {
|
|
325
325
|
console.log(chalk4.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
326
326
|
const startTime = Date.now();
|
|
327
|
-
const resolvedDir = resolvePath3(process.cwd(), directory
|
|
327
|
+
const resolvedDir = resolvePath3(process.cwd(), directory ?? ".");
|
|
328
328
|
const repoMetadata = getRepoMetadata(resolvedDir);
|
|
329
329
|
try {
|
|
330
330
|
const defaults = {
|
|
@@ -414,7 +414,7 @@ async function scanAction(directory, options) {
|
|
|
414
414
|
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
415
415
|
const patternSmartDefaults = await getSmartDefaults(
|
|
416
416
|
resolvedDir,
|
|
417
|
-
finalOptions.toolConfigs?.[ToolName.PatternDetect]
|
|
417
|
+
finalOptions.toolConfigs?.[ToolName.PatternDetect] ?? {}
|
|
418
418
|
);
|
|
419
419
|
if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
|
|
420
420
|
finalOptions.toolConfigs[ToolName.PatternDetect] = {
|
|
@@ -425,7 +425,7 @@ async function scanAction(directory, options) {
|
|
|
425
425
|
console.log(chalk4.cyan("\n=== AIReady Run Preview ==="));
|
|
426
426
|
console.log(
|
|
427
427
|
chalk4.white("Tools to run:"),
|
|
428
|
-
(finalOptions.tools
|
|
428
|
+
(finalOptions.tools ?? []).join(", ")
|
|
429
429
|
);
|
|
430
430
|
const progressCallback = (event) => {
|
|
431
431
|
if (event.message) {
|
|
@@ -446,7 +446,7 @@ async function scanAction(directory, options) {
|
|
|
446
446
|
);
|
|
447
447
|
}
|
|
448
448
|
};
|
|
449
|
-
const scoringProfile = options.profile
|
|
449
|
+
const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
|
|
450
450
|
const results = await analyzeUnified({
|
|
451
451
|
...finalOptions,
|
|
452
452
|
progressCallback,
|
|
@@ -470,7 +470,7 @@ async function scanAction(directory, options) {
|
|
|
470
470
|
const prevReport = JSON.parse(
|
|
471
471
|
readFileSync2(resolvePath3(process.cwd(), options.compareTo), "utf8")
|
|
472
472
|
);
|
|
473
|
-
const prevScore = prevReport.scoring?.overall
|
|
473
|
+
const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
|
|
474
474
|
if (typeof prevScore === "number") {
|
|
475
475
|
const diff = scoringResult.overall - prevScore;
|
|
476
476
|
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
@@ -497,17 +497,17 @@ async function scanAction(directory, options) {
|
|
|
497
497
|
void e;
|
|
498
498
|
}
|
|
499
499
|
}
|
|
500
|
-
const totalWastedDuplication = (scoringResult.breakdown
|
|
501
|
-
(sum, s) => sum + (s.tokenBudget?.wastedTokens
|
|
500
|
+
const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
|
|
501
|
+
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
|
|
502
502
|
0
|
|
503
503
|
);
|
|
504
|
-
const totalWastedFragmentation = (scoringResult.breakdown
|
|
505
|
-
(sum, s) => sum + (s.tokenBudget?.wastedTokens
|
|
504
|
+
const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
|
|
505
|
+
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
|
|
506
506
|
0
|
|
507
507
|
);
|
|
508
508
|
const totalContext = Math.max(
|
|
509
|
-
...(scoringResult.breakdown
|
|
510
|
-
(s) => s.tokenBudget?.totalContextTokens
|
|
509
|
+
...(scoringResult.breakdown ?? []).map(
|
|
510
|
+
(s) => s.tokenBudget?.totalContextTokens ?? 0
|
|
511
511
|
),
|
|
512
512
|
0
|
|
513
513
|
);
|
|
@@ -531,7 +531,7 @@ async function scanAction(directory, options) {
|
|
|
531
531
|
});
|
|
532
532
|
}
|
|
533
533
|
}
|
|
534
|
-
const modelId = options.model
|
|
534
|
+
const modelId = options.model ?? "gpt-5.4-mini";
|
|
535
535
|
const roi = (await import("@aiready/core")).calculateBusinessROI({
|
|
536
536
|
tokenWaste: unifiedBudget.wastedTokens.total,
|
|
537
537
|
issues: allIssues,
|
|
@@ -568,9 +568,9 @@ async function scanAction(directory, options) {
|
|
|
568
568
|
...mapToUnifiedReport(results, scoringResult),
|
|
569
569
|
repository: repoMetadata
|
|
570
570
|
};
|
|
571
|
-
const outputFormat = options.output
|
|
571
|
+
const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
|
|
572
572
|
const outputPath = resolveOutputPath(
|
|
573
|
-
options.outputFile
|
|
573
|
+
options.outputFile ?? finalOptions.output?.file,
|
|
574
574
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
575
575
|
resolvedDir
|
|
576
576
|
);
|
|
@@ -597,8 +597,8 @@ async function scanAction(directory, options) {
|
|
|
597
597
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
598
598
|
if (scoringResult) {
|
|
599
599
|
const threshold = options.threshold ? parseInt(options.threshold) : void 0;
|
|
600
|
-
const failOnLevel = options.failOn
|
|
601
|
-
const isCI = options.ci
|
|
600
|
+
const failOnLevel = options.failOn ?? "critical";
|
|
601
|
+
const isCI = options.ci ?? process.env.CI === "true";
|
|
602
602
|
let shouldFail = false;
|
|
603
603
|
let failReason = "";
|
|
604
604
|
const report = mapToUnifiedReport(results, scoringResult);
|
|
@@ -789,7 +789,7 @@ import {
|
|
|
789
789
|
async function patternsAction(directory, options) {
|
|
790
790
|
console.log(chalk6.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
791
791
|
const startTime = Date.now();
|
|
792
|
-
const resolvedDir = resolvePath4(process.cwd(), directory
|
|
792
|
+
const resolvedDir = resolvePath4(process.cwd(), directory ?? ".");
|
|
793
793
|
try {
|
|
794
794
|
const useSmartDefaults = !options.fullScan;
|
|
795
795
|
const defaults = {
|
|
@@ -833,8 +833,8 @@ async function patternsAction(directory, options) {
|
|
|
833
833
|
if (options.score) {
|
|
834
834
|
patternScore = calculatePatternScore(duplicates, results.length);
|
|
835
835
|
}
|
|
836
|
-
const outputFormat = options.output
|
|
837
|
-
const userOutputFile = options.outputFile
|
|
836
|
+
const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
|
|
837
|
+
const userOutputFile = options.outputFile ?? finalOptions.output?.file;
|
|
838
838
|
if (outputFormat === "json") {
|
|
839
839
|
const outputData = {
|
|
840
840
|
results,
|
|
@@ -942,7 +942,7 @@ import {
|
|
|
942
942
|
async function contextAction(directory, options) {
|
|
943
943
|
console.log(chalk7.blue("\u{1F9E0} Analyzing context costs...\n"));
|
|
944
944
|
const startTime = Date.now();
|
|
945
|
-
const resolvedDir = resolvePath5(process.cwd(), directory
|
|
945
|
+
const resolvedDir = resolvePath5(process.cwd(), directory ?? ".");
|
|
946
946
|
try {
|
|
947
947
|
const defaults = {
|
|
948
948
|
maxDepth: 5,
|
|
@@ -986,8 +986,8 @@ async function contextAction(directory, options) {
|
|
|
986
986
|
if (options.score) {
|
|
987
987
|
contextScore = calculateContextScore(summary);
|
|
988
988
|
}
|
|
989
|
-
const outputFormat = options.output
|
|
990
|
-
const userOutputFile = options.outputFile
|
|
989
|
+
const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
|
|
990
|
+
const userOutputFile = options.outputFile ?? finalOptions.output?.file;
|
|
991
991
|
if (outputFormat === "json") {
|
|
992
992
|
const outputData = {
|
|
993
993
|
results,
|
|
@@ -1005,7 +1005,7 @@ async function contextAction(directory, options) {
|
|
|
1005
1005
|
`\u2705 Results saved to ${outputPath}`
|
|
1006
1006
|
);
|
|
1007
1007
|
} else {
|
|
1008
|
-
const terminalWidth = process.stdout.columns
|
|
1008
|
+
const terminalWidth = process.stdout.columns ?? 80;
|
|
1009
1009
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1010
1010
|
const divider = "\u2501".repeat(dividerWidth);
|
|
1011
1011
|
console.log(chalk7.cyan(divider));
|
|
@@ -1150,7 +1150,7 @@ import {
|
|
|
1150
1150
|
async function consistencyAction(directory, options) {
|
|
1151
1151
|
console.log(chalk8.blue("\u{1F50D} Analyzing consistency...\n"));
|
|
1152
1152
|
const startTime = Date.now();
|
|
1153
|
-
const resolvedDir = resolvePath6(process.cwd(), directory
|
|
1153
|
+
const resolvedDir = resolvePath6(process.cwd(), directory ?? ".");
|
|
1154
1154
|
try {
|
|
1155
1155
|
const defaults = {
|
|
1156
1156
|
checkNaming: true,
|
|
@@ -1175,14 +1175,14 @@ async function consistencyAction(directory, options) {
|
|
|
1175
1175
|
const elapsedTime = getElapsedTime3(startTime);
|
|
1176
1176
|
let consistencyScore;
|
|
1177
1177
|
if (options.score) {
|
|
1178
|
-
const issues = report.results?.flatMap((r) => r.issues)
|
|
1178
|
+
const issues = report.results?.flatMap((r) => r.issues) ?? [];
|
|
1179
1179
|
consistencyScore = calculateConsistencyScore(
|
|
1180
1180
|
issues,
|
|
1181
1181
|
report.summary.filesAnalyzed
|
|
1182
1182
|
);
|
|
1183
1183
|
}
|
|
1184
|
-
const outputFormat = options.output
|
|
1185
|
-
const userOutputFile = options.outputFile
|
|
1184
|
+
const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
|
|
1185
|
+
const userOutputFile = options.outputFile ?? finalOptions.output?.file;
|
|
1186
1186
|
if (outputFormat === "json") {
|
|
1187
1187
|
const outputData = {
|
|
1188
1188
|
...report,
|
|
@@ -1220,7 +1220,7 @@ async function consistencyAction(directory, options) {
|
|
|
1220
1220
|
console.log(` Naming: ${chalk8.yellow(report.summary.namingIssues)}`);
|
|
1221
1221
|
console.log(` Patterns: ${chalk8.yellow(report.summary.patternIssues)}`);
|
|
1222
1222
|
console.log(
|
|
1223
|
-
` Architecture: ${chalk8.yellow(report.summary.architectureIssues
|
|
1223
|
+
` Architecture: ${chalk8.yellow(report.summary.architectureIssues ?? 0)}`
|
|
1224
1224
|
);
|
|
1225
1225
|
console.log(`Analysis Time: ${chalk8.gray(elapsedTime + "s")}
|
|
1226
1226
|
`);
|
|
@@ -1319,7 +1319,7 @@ import { handleCLIError as handleCLIError6 } from "@aiready/core";
|
|
|
1319
1319
|
import { generateHTML, findLatestReport as findLatestReport2 } from "@aiready/core";
|
|
1320
1320
|
async function visualizeAction(directory, options) {
|
|
1321
1321
|
try {
|
|
1322
|
-
const dirPath = resolvePath7(process.cwd(), directory
|
|
1322
|
+
const dirPath = resolvePath7(process.cwd(), directory ?? ".");
|
|
1323
1323
|
let reportPath = options.report ? resolvePath7(dirPath, options.report) : null;
|
|
1324
1324
|
if (!reportPath || !existsSync3(reportPath)) {
|
|
1325
1325
|
const latestScan = findLatestReport2(dirPath);
|
|
@@ -1365,7 +1365,7 @@ Or specify a custom report:
|
|
|
1365
1365
|
console.log("Building graph from report...");
|
|
1366
1366
|
const { GraphBuilder } = await import("@aiready/visualizer/graph");
|
|
1367
1367
|
const graph = GraphBuilder.buildFromReport(report, dirPath);
|
|
1368
|
-
let useDevMode = options.dev
|
|
1368
|
+
let useDevMode = options.dev ?? false;
|
|
1369
1369
|
let devServerStarted = false;
|
|
1370
1370
|
if (useDevMode) {
|
|
1371
1371
|
try {
|
|
@@ -1481,7 +1481,7 @@ Or specify a custom report:
|
|
|
1481
1481
|
console.log("Generating HTML...");
|
|
1482
1482
|
const html = generateHTML(graph);
|
|
1483
1483
|
const defaultOutput = "visualization.html";
|
|
1484
|
-
const outPath = resolvePath7(dirPath, options.output
|
|
1484
|
+
const outPath = resolvePath7(dirPath, options.output ?? defaultOutput);
|
|
1485
1485
|
writeFileSync4(outPath, html, "utf8");
|
|
1486
1486
|
console.log(chalk9.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1487
1487
|
if (options.open || options.serve) {
|
|
@@ -1493,7 +1493,7 @@ Or specify a custom report:
|
|
|
1493
1493
|
const fsp = await import("fs/promises");
|
|
1494
1494
|
const server = http.createServer(async (req, res) => {
|
|
1495
1495
|
try {
|
|
1496
|
-
const urlPath = req.url
|
|
1496
|
+
const urlPath = req.url ?? "/";
|
|
1497
1497
|
if (urlPath === "/" || urlPath === "/index.html") {
|
|
1498
1498
|
const content = await fsp.readFile(outPath, "utf8");
|
|
1499
1499
|
res.writeHead(200, {
|
|
@@ -1631,7 +1631,7 @@ async function bugAction(message, options) {
|
|
|
1631
1631
|
const repoUrl = "https://github.com/caopengau/aiready-cli";
|
|
1632
1632
|
const repoSlug = "caopengau/aiready-cli";
|
|
1633
1633
|
if (message) {
|
|
1634
|
-
const type = options.type
|
|
1634
|
+
const type = options.type ?? "bug";
|
|
1635
1635
|
const title = `[${type.toUpperCase()}] ${message}`;
|
|
1636
1636
|
const label = type === "bug" ? "bug" : type === "feature" ? "enhancement" : "metric";
|
|
1637
1637
|
const body = `
|
|
@@ -1719,15 +1719,17 @@ AI READINESS SCORING:
|
|
|
1719
1719
|
EXAMPLES:
|
|
1720
1720
|
$ aiready scan # Comprehensive analysis with AI Readiness Score
|
|
1721
1721
|
$ aiready scan --no-score # Run scan without score calculation
|
|
1722
|
-
$ aiready
|
|
1722
|
+
$ aiready init # Create a default aiready.json configuration
|
|
1723
|
+
$ aiready init --full # Create configuration with ALL available options
|
|
1723
1724
|
$ npx @aiready/cli scan # Industry standard way to run standard scan
|
|
1724
1725
|
$ aiready scan --output json # Output raw JSON for piping
|
|
1725
1726
|
|
|
1726
1727
|
GETTING STARTED:
|
|
1727
|
-
1. Run 'aiready
|
|
1728
|
-
2.
|
|
1729
|
-
3.
|
|
1730
|
-
4.
|
|
1728
|
+
1. Run 'aiready init' to create a persistent 'aiready.json' config file
|
|
1729
|
+
2. Run 'aiready scan' to analyze your codebase and get an AI Readiness Score
|
|
1730
|
+
3. Use 'aiready init --full' to see every fine-tuning parameter available
|
|
1731
|
+
4. Use '--profile agentic' for agent-focused analysis
|
|
1732
|
+
5. Set up CI/CD with '--threshold' for quality gates
|
|
1731
1733
|
|
|
1732
1734
|
CONFIGURATION:
|
|
1733
1735
|
Config files (searched upward): aiready.json, .aiready.json, aiready.config.*
|
package/dist/index.js
CHANGED
|
@@ -84,7 +84,7 @@ function sanitizeToolConfig(config) {
|
|
|
84
84
|
async function analyzeUnified(options) {
|
|
85
85
|
await (0, import_core.initializeParsers)();
|
|
86
86
|
const startTime = Date.now();
|
|
87
|
-
const requestedTools = options.tools
|
|
87
|
+
const requestedTools = options.tools ?? [
|
|
88
88
|
"patterns",
|
|
89
89
|
"context",
|
|
90
90
|
"consistency"
|
|
@@ -106,7 +106,7 @@ async function analyzeUnified(options) {
|
|
|
106
106
|
for (const toolName of requestedTools) {
|
|
107
107
|
let provider = import_core.ToolRegistry.find(toolName);
|
|
108
108
|
if (!provider) {
|
|
109
|
-
const packageName = TOOL_PACKAGE_MAP[toolName]
|
|
109
|
+
const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
|
|
110
110
|
try {
|
|
111
111
|
await import(packageName);
|
|
112
112
|
provider = import_core.ToolRegistry.find(toolName);
|
|
@@ -184,29 +184,15 @@ async function analyzeUnified(options) {
|
|
|
184
184
|
} else {
|
|
185
185
|
result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
|
|
186
186
|
}
|
|
187
|
-
const toolFiles = output.summary?.totalFiles
|
|
187
|
+
const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
|
|
188
188
|
if (toolFiles > result.summary.totalFiles) {
|
|
189
189
|
result.summary.totalFiles = toolFiles;
|
|
190
190
|
}
|
|
191
191
|
const issueCount = output.results.reduce(
|
|
192
|
-
(sum, file) => sum + (file.issues?.length
|
|
192
|
+
(sum, file) => sum + (file.issues?.length ?? 0),
|
|
193
193
|
0
|
|
194
194
|
);
|
|
195
195
|
result.summary.totalIssues += issueCount;
|
|
196
|
-
if (provider.alias && Array.isArray(provider.alias)) {
|
|
197
|
-
for (const alias of provider.alias) {
|
|
198
|
-
if (!result[alias]) {
|
|
199
|
-
result[alias] = output;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
const camelCaseId = provider.id.replace(
|
|
204
|
-
/-([a-z])/g,
|
|
205
|
-
(g) => g[1].toUpperCase()
|
|
206
|
-
);
|
|
207
|
-
if (camelCaseId !== provider.id && !result[camelCaseId]) {
|
|
208
|
-
result[camelCaseId] = output;
|
|
209
|
-
}
|
|
210
196
|
} catch (err) {
|
|
211
197
|
console.error(`\u274C Error running tool '${provider.id}':`, err);
|
|
212
198
|
}
|
|
@@ -221,6 +207,24 @@ async function analyzeUnified(options) {
|
|
|
221
207
|
tools: result.summary.toolConfigs
|
|
222
208
|
});
|
|
223
209
|
result.summary.executionTime = Date.now() - startTime;
|
|
210
|
+
const keyMappings = {
|
|
211
|
+
"pattern-detect": ["patternDetect", "patterns"],
|
|
212
|
+
"context-analyzer": ["contextAnalyzer", "context"],
|
|
213
|
+
"naming-consistency": ["namingConsistency", "consistency"],
|
|
214
|
+
"ai-signal-clarity": ["aiSignalClarity"],
|
|
215
|
+
"agent-grounding": ["agentGrounding"],
|
|
216
|
+
"testability-index": ["testabilityIndex", "testability"],
|
|
217
|
+
"doc-drift": ["docDrift"],
|
|
218
|
+
"dependency-health": ["dependencyHealth", "deps"],
|
|
219
|
+
"change-amplification": ["changeAmplification"]
|
|
220
|
+
};
|
|
221
|
+
for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
|
|
222
|
+
if (result[kebabKey]) {
|
|
223
|
+
for (const alias of aliases) {
|
|
224
|
+
result[alias] = result[kebabKey];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
224
228
|
return result;
|
|
225
229
|
}
|
|
226
230
|
async function scoreUnified(results, options) {
|
|
@@ -235,7 +239,7 @@ async function scoreUnified(results, options) {
|
|
|
235
239
|
if (!toolScore.tokenBudget) {
|
|
236
240
|
if (toolId === import_core.ToolName.PatternDetect && output.duplicates) {
|
|
237
241
|
const wastedTokens = output.duplicates.reduce(
|
|
238
|
-
(sum, d) => sum + (d.tokenCost
|
|
242
|
+
(sum, d) => sum + (d.tokenCost ?? 0),
|
|
239
243
|
0
|
|
240
244
|
);
|
|
241
245
|
toolScore.tokenBudget = (0, import_core.calculateTokenBudget)({
|
|
@@ -251,7 +255,7 @@ async function scoreUnified(results, options) {
|
|
|
251
255
|
totalContextTokens: output.summary.totalTokens,
|
|
252
256
|
wastedTokens: {
|
|
253
257
|
duplication: 0,
|
|
254
|
-
fragmentation: output.summary.totalPotentialSavings
|
|
258
|
+
fragmentation: output.summary.totalPotentialSavings ?? 0,
|
|
255
259
|
chattiness: 0
|
|
256
260
|
}
|
|
257
261
|
});
|
|
@@ -296,7 +300,7 @@ function generateUnifiedSummary(result) {
|
|
|
296
300
|
const toolResult = result[provider.id];
|
|
297
301
|
if (toolResult) {
|
|
298
302
|
const issueCount = toolResult.results.reduce(
|
|
299
|
-
(sum, r) => sum + (r.issues?.length
|
|
303
|
+
(sum, r) => sum + (r.issues?.length ?? 0),
|
|
300
304
|
0
|
|
301
305
|
);
|
|
302
306
|
output += `\u2022 ${provider.id}: ${issueCount} issues
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/cli",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.10",
|
|
4
4
|
"description": "Unified CLI for AIReady analysis tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"chalk": "^5.3.0",
|
|
13
13
|
"commander": "^14.0.0",
|
|
14
|
-
"@aiready/agent-grounding": "0.13.
|
|
15
|
-
"@aiready/consistency": "0.20.
|
|
16
|
-
"@aiready/
|
|
17
|
-
"@aiready/
|
|
18
|
-
"@aiready/
|
|
19
|
-
"@aiready/doc-drift": "0.13.
|
|
20
|
-
"@aiready/change-amplification": "0.13.
|
|
21
|
-
"@aiready/ai-signal-clarity": "0.13.
|
|
22
|
-
"@aiready/
|
|
23
|
-
"@aiready/
|
|
24
|
-
"@aiready/
|
|
14
|
+
"@aiready/agent-grounding": "0.13.7",
|
|
15
|
+
"@aiready/consistency": "0.20.7",
|
|
16
|
+
"@aiready/core": "0.23.8",
|
|
17
|
+
"@aiready/deps": "0.13.7",
|
|
18
|
+
"@aiready/context-analyzer": "0.21.11",
|
|
19
|
+
"@aiready/doc-drift": "0.13.7",
|
|
20
|
+
"@aiready/change-amplification": "0.13.7",
|
|
21
|
+
"@aiready/ai-signal-clarity": "0.13.8",
|
|
22
|
+
"@aiready/pattern-detect": "0.16.7",
|
|
23
|
+
"@aiready/testability": "0.6.7",
|
|
24
|
+
"@aiready/visualizer": "0.6.7"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^24.0.0",
|
package/src/cli.ts
CHANGED
|
@@ -49,15 +49,17 @@ AI READINESS SCORING:
|
|
|
49
49
|
EXAMPLES:
|
|
50
50
|
$ aiready scan # Comprehensive analysis with AI Readiness Score
|
|
51
51
|
$ aiready scan --no-score # Run scan without score calculation
|
|
52
|
-
$ aiready
|
|
52
|
+
$ aiready init # Create a default aiready.json configuration
|
|
53
|
+
$ aiready init --full # Create configuration with ALL available options
|
|
53
54
|
$ npx @aiready/cli scan # Industry standard way to run standard scan
|
|
54
55
|
$ aiready scan --output json # Output raw JSON for piping
|
|
55
56
|
|
|
56
57
|
GETTING STARTED:
|
|
57
|
-
1. Run 'aiready
|
|
58
|
-
2.
|
|
59
|
-
3.
|
|
60
|
-
4.
|
|
58
|
+
1. Run 'aiready init' to create a persistent 'aiready.json' config file
|
|
59
|
+
2. Run 'aiready scan' to analyze your codebase and get an AI Readiness Score
|
|
60
|
+
3. Use 'aiready init --full' to see every fine-tuning parameter available
|
|
61
|
+
4. Use '--profile agentic' for agent-focused analysis
|
|
62
|
+
5. Set up CI/CD with '--threshold' for quality gates
|
|
61
63
|
|
|
62
64
|
CONFIGURATION:
|
|
63
65
|
Config files (searched upward): aiready.json, .aiready.json, aiready.config.*
|
package/src/commands/bug.ts
CHANGED
|
@@ -11,7 +11,7 @@ export async function bugAction(message: string | undefined, options: any) {
|
|
|
11
11
|
|
|
12
12
|
if (message) {
|
|
13
13
|
// Agent-assisted pre-filled issue
|
|
14
|
-
const type = options.type
|
|
14
|
+
const type = options.type ?? 'bug';
|
|
15
15
|
const title = `[${type.toUpperCase()}] ${message}`;
|
|
16
16
|
const label =
|
|
17
17
|
type === 'bug' ? 'bug' : type === 'feature' ? 'enhancement' : 'metric';
|
|
@@ -34,7 +34,7 @@ export async function consistencyAction(
|
|
|
34
34
|
console.log(chalk.blue('š Analyzing consistency...\n'));
|
|
35
35
|
|
|
36
36
|
const startTime = Date.now();
|
|
37
|
-
const resolvedDir = resolvePath(process.cwd(), directory
|
|
37
|
+
const resolvedDir = resolvePath(process.cwd(), directory ?? '.');
|
|
38
38
|
|
|
39
39
|
try {
|
|
40
40
|
// Define defaults
|
|
@@ -69,7 +69,7 @@ export async function consistencyAction(
|
|
|
69
69
|
// Calculate score if requested
|
|
70
70
|
let consistencyScore: ToolScoringOutput | undefined;
|
|
71
71
|
if (options.score) {
|
|
72
|
-
const issues = report.results?.flatMap((r: any) => r.issues)
|
|
72
|
+
const issues = report.results?.flatMap((r: any) => r.issues) ?? [];
|
|
73
73
|
consistencyScore = calculateConsistencyScore(
|
|
74
74
|
issues,
|
|
75
75
|
report.summary.filesAnalyzed
|
|
@@ -77,8 +77,8 @@ export async function consistencyAction(
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const outputFormat =
|
|
80
|
-
options.output
|
|
81
|
-
const userOutputFile = options.outputFile
|
|
80
|
+
options.output ?? finalOptions.output?.format ?? 'console';
|
|
81
|
+
const userOutputFile = options.outputFile ?? finalOptions.output?.file;
|
|
82
82
|
|
|
83
83
|
if (outputFormat === 'json') {
|
|
84
84
|
const outputData = {
|
|
@@ -121,7 +121,7 @@ export async function consistencyAction(
|
|
|
121
121
|
console.log(` Naming: ${chalk.yellow(report.summary.namingIssues)}`);
|
|
122
122
|
console.log(` Patterns: ${chalk.yellow(report.summary.patternIssues)}`);
|
|
123
123
|
console.log(
|
|
124
|
-
` Architecture: ${chalk.yellow(report.summary.architectureIssues
|
|
124
|
+
` Architecture: ${chalk.yellow(report.summary.architectureIssues ?? 0)}`
|
|
125
125
|
);
|
|
126
126
|
console.log(`Analysis Time: ${chalk.gray(elapsedTime + 's')}\n`);
|
|
127
127
|
|
package/src/commands/context.ts
CHANGED
|
@@ -32,7 +32,7 @@ export async function contextAction(
|
|
|
32
32
|
console.log(chalk.blue('š§ Analyzing context costs...\n'));
|
|
33
33
|
|
|
34
34
|
const startTime = Date.now();
|
|
35
|
-
const resolvedDir = resolvePath(process.cwd(), directory
|
|
35
|
+
const resolvedDir = resolvePath(process.cwd(), directory ?? '.');
|
|
36
36
|
|
|
37
37
|
try {
|
|
38
38
|
// Define defaults
|
|
@@ -94,8 +94,8 @@ export async function contextAction(
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
const outputFormat =
|
|
97
|
-
options.output
|
|
98
|
-
const userOutputFile = options.outputFile
|
|
97
|
+
options.output ?? finalOptions.output?.format ?? 'console';
|
|
98
|
+
const userOutputFile = options.outputFile ?? finalOptions.output?.file;
|
|
99
99
|
|
|
100
100
|
if (outputFormat === 'json') {
|
|
101
101
|
const outputData = {
|
|
@@ -117,7 +117,7 @@ export async function contextAction(
|
|
|
117
117
|
);
|
|
118
118
|
} else {
|
|
119
119
|
// Console output - format the results nicely
|
|
120
|
-
const terminalWidth = process.stdout.columns
|
|
120
|
+
const terminalWidth = process.stdout.columns ?? 80;
|
|
121
121
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
122
122
|
const divider = 'ā'.repeat(dividerWidth);
|
|
123
123
|
|
package/src/commands/patterns.ts
CHANGED
|
@@ -35,7 +35,7 @@ export async function patternsAction(
|
|
|
35
35
|
console.log(chalk.blue('š Analyzing patterns...\n'));
|
|
36
36
|
|
|
37
37
|
const startTime = Date.now();
|
|
38
|
-
const resolvedDir = resolvePath(process.cwd(), directory
|
|
38
|
+
const resolvedDir = resolvePath(process.cwd(), directory ?? '.');
|
|
39
39
|
|
|
40
40
|
try {
|
|
41
41
|
// Determine if smart defaults should be used
|
|
@@ -100,8 +100,8 @@ export async function patternsAction(
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
const outputFormat =
|
|
103
|
-
options.output
|
|
104
|
-
const userOutputFile = options.outputFile
|
|
103
|
+
options.output ?? finalOptions.output?.format ?? 'console';
|
|
104
|
+
const userOutputFile = options.outputFile ?? finalOptions.output?.file;
|
|
105
105
|
|
|
106
106
|
if (outputFormat === 'json') {
|
|
107
107
|
const outputData = {
|
|
@@ -8,12 +8,15 @@ import {
|
|
|
8
8
|
} from '@aiready/core';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Handle console output for the scan results
|
|
11
|
+
* Handle console output for the scan results.
|
|
12
|
+
*
|
|
13
|
+
* @param results - The combined results from all tools.
|
|
14
|
+
* @param startTime - The timestamp when the scan started.
|
|
12
15
|
*/
|
|
13
16
|
export function printScanSummary(results: any, startTime: number) {
|
|
14
17
|
console.log(chalk.cyan('\n=== AIReady Run Summary ==='));
|
|
15
18
|
console.log(
|
|
16
|
-
` Total issues (all tools): ${chalk.bold(String(results.summary.totalIssues
|
|
19
|
+
` Total issues (all tools): ${chalk.bold(String(results.summary.totalIssues ?? 0))}`
|
|
17
20
|
);
|
|
18
21
|
console.log(
|
|
19
22
|
` Execution time: ${chalk.bold(((Date.now() - startTime) / 1000).toFixed(2) + 's')}`
|
|
@@ -21,7 +24,10 @@ export function printScanSummary(results: any, startTime: number) {
|
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
|
-
* Print business impact analysis
|
|
27
|
+
* Print business impact analysis based on ROI and budget metrics.
|
|
28
|
+
*
|
|
29
|
+
* @param roi - Calculated Return on Investment metrics.
|
|
30
|
+
* @param unifiedBudget - Consolidated context budget metrics.
|
|
25
31
|
*/
|
|
26
32
|
export function printBusinessImpact(roi: any, unifiedBudget: any) {
|
|
27
33
|
console.log(chalk.bold('\nš° Business Impact Analysis (Monthly)'));
|
|
@@ -40,7 +46,10 @@ export function printBusinessImpact(roi: any, unifiedBudget: any) {
|
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
/**
|
|
43
|
-
* Print detailed scoring breakdown
|
|
49
|
+
* Print detailed scoring breakdown by tool.
|
|
50
|
+
*
|
|
51
|
+
* @param scoringResult - The overall scoring result.
|
|
52
|
+
* @param scoringProfile - The name of the scoring profile used.
|
|
44
53
|
*/
|
|
45
54
|
export function printScoring(
|
|
46
55
|
scoringResult: ScoringResult,
|
|
@@ -52,7 +61,7 @@ export function printScoring(
|
|
|
52
61
|
|
|
53
62
|
if (scoringResult.breakdown) {
|
|
54
63
|
console.log(chalk.bold('\nTool breakdown:'));
|
|
55
|
-
scoringResult.breakdown.forEach((tool) => {
|
|
64
|
+
scoringResult.breakdown.forEach((tool: any) => {
|
|
56
65
|
const rating = getRating(tool.score);
|
|
57
66
|
const emoji = getRatingDisplay(rating).emoji;
|
|
58
67
|
console.log(
|
|
@@ -62,15 +71,15 @@ export function printScoring(
|
|
|
62
71
|
|
|
63
72
|
// Top Actionable Recommendations
|
|
64
73
|
const allRecs = scoringResult.breakdown
|
|
65
|
-
.flatMap((t) =>
|
|
66
|
-
(t.recommendations
|
|
74
|
+
.flatMap((t: any) =>
|
|
75
|
+
(t.recommendations ?? []).map((r: any) => ({ ...r, tool: t.toolName }))
|
|
67
76
|
)
|
|
68
|
-
.sort((a, b) => b.estimatedImpact - a.estimatedImpact)
|
|
77
|
+
.sort((a: any, b: any) => b.estimatedImpact - a.estimatedImpact)
|
|
69
78
|
.slice(0, 3);
|
|
70
79
|
|
|
71
80
|
if (allRecs.length > 0) {
|
|
72
81
|
console.log(chalk.bold('\nšÆ Top Actionable Recommendations:'));
|
|
73
|
-
allRecs.forEach((rec, i) => {
|
|
82
|
+
allRecs.forEach((rec: any, i: number) => {
|
|
74
83
|
const priorityIcon =
|
|
75
84
|
rec.priority === 'high'
|
|
76
85
|
? 'š“'
|
|
@@ -87,7 +96,11 @@ export function printScoring(
|
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
/**
|
|
90
|
-
* Normalize
|
|
99
|
+
* Normalize and map tool-specific results to a unified report structure.
|
|
100
|
+
*
|
|
101
|
+
* @param res - Raw unified results object.
|
|
102
|
+
* @param scoring - Optional scoring result to include.
|
|
103
|
+
* @returns Enhanced report with totals and scoring.
|
|
91
104
|
*/
|
|
92
105
|
export function mapToUnifiedReport(
|
|
93
106
|
res: any,
|